Skip to content

Commit dc97772

Browse files
committed
Implementing Bigtable ColumnRangeFilter.
1 parent cf82bac commit dc97772

File tree

2 files changed

+195
-0
lines changed

2 files changed

+195
-0
lines changed

gcloud/bigtable/row.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,79 @@ def to_pb(self):
227227
return data_pb2.RowFilter(column_qualifier_regex_filter=self.regex)
228228

229229

230+
class ColumnRangeFilter(RowFilter):
231+
"""A row filter to restrict to a range of columns.
232+
233+
Both the start and end column can be included or excluded in the range.
234+
By default, we include them both, but this can be changed with optional
235+
flags.
236+
237+
:type column_family_id: str
238+
:param column_family_id: The column family that contains the columns. Must
239+
be of the form ``[_a-zA-Z0-9][-_.a-zA-Z0-9]*``.
240+
241+
:type start_column: bytes
242+
:param start_column: The start of the range of columns. If no value is
243+
used, the backend applies no upper bound to the
244+
values.
245+
246+
:type end_column: bytes
247+
:param end_column: The end of the range of columns. If no value is used,
248+
the backend applies no upper bound to the values.
249+
250+
:type inclusive_start: bool
251+
:param inclusive_start: Boolean indicating if the start column should be
252+
included in the range (or excluded).
253+
254+
:type inclusive_end: bool
255+
:param inclusive_end: Boolean indicating if the end column should be
256+
included in the range (or excluded).
257+
"""
258+
259+
def __init__(self, column_family_id, start_column=None, end_column=None,
260+
inclusive_start=True, inclusive_end=True):
261+
self.column_family_id = column_family_id
262+
self.start_column = start_column
263+
self.end_column = end_column
264+
self.inclusive_start = inclusive_start
265+
self.inclusive_end = inclusive_end
266+
267+
def __eq__(self, other):
268+
if not isinstance(other, self.__class__):
269+
return False
270+
return (other.column_family_id == self.column_family_id and
271+
other.start_column == self.start_column and
272+
other.end_column == self.end_column and
273+
other.inclusive_start == self.inclusive_start and
274+
other.inclusive_end == self.inclusive_end)
275+
276+
def to_pb(self):
277+
"""Converts the row filter to a protobuf.
278+
279+
First converts to a :class:`.data_pb2.ColumnRange` and then uses it
280+
in the ``column_range_filter`` field.
281+
282+
:rtype: :class:`.data_pb2.RowFilter`
283+
:returns: The converted current object.
284+
"""
285+
column_range_kwargs = {'family_name': self.column_family_id}
286+
if self.start_column is not None:
287+
if self.inclusive_start:
288+
key = 'start_qualifier_inclusive'
289+
else:
290+
key = 'start_qualifier_exclusive'
291+
column_range_kwargs[key] = _to_bytes(self.start_column)
292+
if self.end_column is not None:
293+
if self.inclusive_end:
294+
key = 'end_qualifier_inclusive'
295+
else:
296+
key = 'end_qualifier_exclusive'
297+
column_range_kwargs[key] = _to_bytes(self.end_column)
298+
299+
column_range = data_pb2.ColumnRange(**column_range_kwargs)
300+
return data_pb2.RowFilter(column_range_filter=column_range)
301+
302+
230303
class ValueRegexFilter(_RegexFilter):
231304
"""Row filter for a value regular expression.
232305

gcloud/bigtable/test_row.py

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,128 @@ def test_to_pb(self):
230230
self.assertEqual(pb_val, expected_pb)
231231

232232

233+
class TestColumnRangeFilter(unittest2.TestCase):
234+
235+
def _getTargetClass(self):
236+
from gcloud.bigtable.row import ColumnRangeFilter
237+
return ColumnRangeFilter
238+
239+
def _makeOne(self, *args, **kwargs):
240+
return self._getTargetClass()(*args, **kwargs)
241+
242+
def test_constructor_defaults(self):
243+
column_family_id = object()
244+
row_filter = self._makeOne(column_family_id)
245+
self.assertTrue(row_filter.column_family_id is column_family_id)
246+
self.assertEqual(row_filter.start_column, None)
247+
self.assertEqual(row_filter.end_column, None)
248+
self.assertTrue(row_filter.inclusive_start)
249+
self.assertTrue(row_filter.inclusive_end)
250+
251+
def test_constructor_explicit(self):
252+
column_family_id = object()
253+
start_column = object()
254+
end_column = object()
255+
inclusive_start = object()
256+
inclusive_end = object()
257+
row_filter = self._makeOne(column_family_id, start_column=start_column,
258+
end_column=end_column,
259+
inclusive_start=inclusive_start,
260+
inclusive_end=inclusive_end)
261+
self.assertTrue(row_filter.column_family_id is column_family_id)
262+
self.assertTrue(row_filter.start_column is start_column)
263+
self.assertTrue(row_filter.end_column is end_column)
264+
self.assertTrue(row_filter.inclusive_start is inclusive_start)
265+
self.assertTrue(row_filter.inclusive_end is inclusive_end)
266+
267+
def test___eq__(self):
268+
column_family_id = object()
269+
start_column = object()
270+
end_column = object()
271+
inclusive_start = object()
272+
inclusive_end = object()
273+
row_filter1 = self._makeOne(column_family_id,
274+
start_column=start_column,
275+
end_column=end_column,
276+
inclusive_start=inclusive_start,
277+
inclusive_end=inclusive_end)
278+
row_filter2 = self._makeOne(column_family_id,
279+
start_column=start_column,
280+
end_column=end_column,
281+
inclusive_start=inclusive_start,
282+
inclusive_end=inclusive_end)
283+
self.assertEqual(row_filter1, row_filter2)
284+
285+
def test___eq__type_differ(self):
286+
column_family_id = object()
287+
row_filter1 = self._makeOne(column_family_id)
288+
row_filter2 = object()
289+
self.assertNotEqual(row_filter1, row_filter2)
290+
291+
def test_to_pb(self):
292+
from gcloud.bigtable._generated import bigtable_data_pb2 as data_pb2
293+
294+
column_family_id = u'column-family-id'
295+
row_filter = self._makeOne(column_family_id)
296+
col_range_pb = data_pb2.ColumnRange(family_name=column_family_id)
297+
expected_pb = data_pb2.RowFilter(column_range_filter=col_range_pb)
298+
self.assertEqual(row_filter.to_pb(), expected_pb)
299+
300+
def test_to_pb_inclusive_start(self):
301+
from gcloud.bigtable._generated import bigtable_data_pb2 as data_pb2
302+
303+
column_family_id = u'column-family-id'
304+
column = b'column'
305+
row_filter = self._makeOne(column_family_id, start_column=column)
306+
col_range_pb = data_pb2.ColumnRange(
307+
family_name=column_family_id,
308+
start_qualifier_inclusive=column,
309+
)
310+
expected_pb = data_pb2.RowFilter(column_range_filter=col_range_pb)
311+
self.assertEqual(row_filter.to_pb(), expected_pb)
312+
313+
def test_to_pb_exclusive_start(self):
314+
from gcloud.bigtable._generated import bigtable_data_pb2 as data_pb2
315+
316+
column_family_id = u'column-family-id'
317+
column = b'column'
318+
row_filter = self._makeOne(column_family_id, start_column=column,
319+
inclusive_start=False)
320+
col_range_pb = data_pb2.ColumnRange(
321+
family_name=column_family_id,
322+
start_qualifier_exclusive=column,
323+
)
324+
expected_pb = data_pb2.RowFilter(column_range_filter=col_range_pb)
325+
self.assertEqual(row_filter.to_pb(), expected_pb)
326+
327+
def test_to_pb_inclusive_end(self):
328+
from gcloud.bigtable._generated import bigtable_data_pb2 as data_pb2
329+
330+
column_family_id = u'column-family-id'
331+
column = b'column'
332+
row_filter = self._makeOne(column_family_id, end_column=column)
333+
col_range_pb = data_pb2.ColumnRange(
334+
family_name=column_family_id,
335+
end_qualifier_inclusive=column,
336+
)
337+
expected_pb = data_pb2.RowFilter(column_range_filter=col_range_pb)
338+
self.assertEqual(row_filter.to_pb(), expected_pb)
339+
340+
def test_to_pb_exclusive_end(self):
341+
from gcloud.bigtable._generated import bigtable_data_pb2 as data_pb2
342+
343+
column_family_id = u'column-family-id'
344+
column = b'column'
345+
row_filter = self._makeOne(column_family_id, end_column=column,
346+
inclusive_end=False)
347+
col_range_pb = data_pb2.ColumnRange(
348+
family_name=column_family_id,
349+
end_qualifier_exclusive=column,
350+
)
351+
expected_pb = data_pb2.RowFilter(column_range_filter=col_range_pb)
352+
self.assertEqual(row_filter.to_pb(), expected_pb)
353+
354+
233355
class TestValueRegexFilter(unittest2.TestCase):
234356

235357
def _getTargetClass(self):

0 commit comments

Comments
 (0)