Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 9e2b07d

Browse filesBrowse files
committed
Merge pull request #1321 from dhermes/bigtable-row-filter-8
Implementing Bigtable TimestampRangeFilter.
2 parents c216a4e + 52e1867 commit 9e2b07d
Copy full SHA for 9e2b07d

File tree

Expand file treeCollapse file tree

2 files changed

+183
-0
lines changed
Filter options
Expand file treeCollapse file tree

2 files changed

+183
-0
lines changed

‎gcloud/bigtable/row.py

Copy file name to clipboardExpand all lines: gcloud/bigtable/row.py
+69Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"""User friendly container for Google Cloud Bigtable Row."""
1616

1717

18+
from gcloud._helpers import _microseconds_from_datetime
1819
from gcloud._helpers import _to_bytes
1920
from gcloud.bigtable._generated import bigtable_data_pb2 as data_pb2
2021

@@ -252,6 +253,74 @@ def to_pb(self):
252253
return data_pb2.RowFilter(column_qualifier_regex_filter=self.regex)
253254

254255

256+
class TimestampRange(object):
257+
"""Range of time with inclusive lower and exclusive upper bounds.
258+
259+
:type start: :class:`datetime.datetime`
260+
:param start: (Optional) The (inclusive) lower bound of the timestamp
261+
range. If omitted, defaults to Unix epoch.
262+
263+
:type end: :class:`datetime.datetime`
264+
:param end: (Optional) The (exclusive) upper bound of the timestamp
265+
range. If omitted, no upper bound is used.
266+
"""
267+
268+
def __init__(self, start=None, end=None):
269+
self.start = start
270+
self.end = end
271+
272+
def __eq__(self, other):
273+
if not isinstance(other, self.__class__):
274+
return False
275+
return (other.start == self.start and
276+
other.end == self.end)
277+
278+
def __ne__(self, other):
279+
return not self.__eq__(other)
280+
281+
def to_pb(self):
282+
"""Converts the :class:`TimestampRange` to a protobuf.
283+
284+
:rtype: :class:`.data_pb2.TimestampRange`
285+
:returns: The converted current object.
286+
"""
287+
timestamp_range_kwargs = {}
288+
if self.start is not None:
289+
timestamp_range_kwargs['start_timestamp_micros'] = (
290+
_microseconds_from_datetime(self.start))
291+
if self.end is not None:
292+
timestamp_range_kwargs['end_timestamp_micros'] = (
293+
_microseconds_from_datetime(self.end))
294+
return data_pb2.TimestampRange(**timestamp_range_kwargs)
295+
296+
297+
class TimestampRangeFilter(RowFilter):
298+
"""Row filter that limits cells to a range of time.
299+
300+
:type range_: :class:`TimestampRange`
301+
:param range_: Range of time that cells should match against.
302+
"""
303+
304+
def __init__(self, range_):
305+
self.range_ = range_
306+
307+
def __eq__(self, other):
308+
if not isinstance(other, self.__class__):
309+
return False
310+
return other.range_ == self.range_
311+
312+
def to_pb(self):
313+
"""Converts the row filter to a protobuf.
314+
315+
First converts the ``range_`` on the current object to a protobuf and
316+
then uses it in the ``timestamp_range_filter`` field.
317+
318+
:rtype: :class:`.data_pb2.RowFilter`
319+
:returns: The converted current object.
320+
"""
321+
return data_pb2.RowFilter(timestamp_range_filter=self.range_.to_pb())
322+
323+
255324
class ColumnRangeFilter(RowFilter):
256325
"""A row filter to restrict to a range of columns.
257326

‎gcloud/bigtable/test_row.py

Copy file name to clipboardExpand all lines: gcloud/bigtable/test_row.py
+114Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,120 @@ def test_to_pb_exclusive_end(self):
398398
self.assertEqual(row_filter.to_pb(), expected_pb)
399399

400400

401+
class TestTimestampRange(unittest2.TestCase):
402+
403+
def _getTargetClass(self):
404+
from gcloud.bigtable.row import TimestampRange
405+
return TimestampRange
406+
407+
def _makeOne(self, *args, **kwargs):
408+
return self._getTargetClass()(*args, **kwargs)
409+
410+
def test_constructor(self):
411+
start = object()
412+
end = object()
413+
time_range = self._makeOne(start=start, end=end)
414+
self.assertTrue(time_range.start is start)
415+
self.assertTrue(time_range.end is end)
416+
417+
def test___eq__(self):
418+
start = object()
419+
end = object()
420+
time_range1 = self._makeOne(start=start, end=end)
421+
time_range2 = self._makeOne(start=start, end=end)
422+
self.assertEqual(time_range1, time_range2)
423+
424+
def test___eq__type_differ(self):
425+
start = object()
426+
end = object()
427+
time_range1 = self._makeOne(start=start, end=end)
428+
time_range2 = object()
429+
self.assertNotEqual(time_range1, time_range2)
430+
431+
def test___ne__same_value(self):
432+
start = object()
433+
end = object()
434+
time_range1 = self._makeOne(start=start, end=end)
435+
time_range2 = self._makeOne(start=start, end=end)
436+
comparison_val = (time_range1 != time_range2)
437+
self.assertFalse(comparison_val)
438+
439+
def _to_pb_helper(self, start_micros=None, end_micros=None):
440+
import datetime
441+
from gcloud._helpers import _EPOCH
442+
from gcloud.bigtable._generated import bigtable_data_pb2 as data_pb2
443+
444+
pb_kwargs = {}
445+
446+
start = None
447+
if start_micros is not None:
448+
start = _EPOCH + datetime.timedelta(microseconds=start_micros)
449+
pb_kwargs['start_timestamp_micros'] = start_micros
450+
end = None
451+
if end_micros is not None:
452+
end = _EPOCH + datetime.timedelta(microseconds=end_micros)
453+
pb_kwargs['end_timestamp_micros'] = end_micros
454+
time_range = self._makeOne(start=start, end=end)
455+
456+
expected_pb = data_pb2.TimestampRange(**pb_kwargs)
457+
self.assertEqual(time_range.to_pb(), expected_pb)
458+
459+
def test_to_pb(self):
460+
# Makes sure already milliseconds granularity
461+
start_micros = 30871000
462+
end_micros = 12939371000
463+
self._to_pb_helper(start_micros=start_micros,
464+
end_micros=end_micros)
465+
466+
def test_to_pb_start_only(self):
467+
# Makes sure already milliseconds granularity
468+
start_micros = 30871000
469+
self._to_pb_helper(start_micros=start_micros)
470+
471+
def test_to_pb_end_only(self):
472+
# Makes sure already milliseconds granularity
473+
end_micros = 12939371000
474+
self._to_pb_helper(end_micros=end_micros)
475+
476+
477+
class TestTimestampRangeFilter(unittest2.TestCase):
478+
479+
def _getTargetClass(self):
480+
from gcloud.bigtable.row import TimestampRangeFilter
481+
return TimestampRangeFilter
482+
483+
def _makeOne(self, *args, **kwargs):
484+
return self._getTargetClass()(*args, **kwargs)
485+
486+
def test_constructor(self):
487+
range_ = object()
488+
row_filter = self._makeOne(range_)
489+
self.assertTrue(row_filter.range_ is range_)
490+
491+
def test___eq__type_differ(self):
492+
range_ = object()
493+
row_filter1 = self._makeOne(range_)
494+
row_filter2 = object()
495+
self.assertNotEqual(row_filter1, row_filter2)
496+
497+
def test___eq__same_value(self):
498+
range_ = object()
499+
row_filter1 = self._makeOne(range_)
500+
row_filter2 = self._makeOne(range_)
501+
self.assertEqual(row_filter1, row_filter2)
502+
503+
def test_to_pb(self):
504+
from gcloud.bigtable._generated import bigtable_data_pb2 as data_pb2
505+
from gcloud.bigtable.row import TimestampRange
506+
507+
range_ = TimestampRange()
508+
row_filter = self._makeOne(range_)
509+
pb_val = row_filter.to_pb()
510+
expected_pb = data_pb2.RowFilter(
511+
timestamp_range_filter=data_pb2.TimestampRange())
512+
self.assertEqual(pb_val, expected_pb)
513+
514+
401515
class TestValueRegexFilter(unittest2.TestCase):
402516

403517
def _getTargetClass(self):

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.