diff --git a/gcloud/bigtable/row.py b/gcloud/bigtable/row.py index d9569dad0690..95af344049ac 100644 --- a/gcloud/bigtable/row.py +++ b/gcloud/bigtable/row.py @@ -49,6 +49,77 @@ def __ne__(self, other): return not self.__eq__(other) +class _BoolFilter(RowFilter): + """Row filter that uses a boolean flag. + + :type flag: bool + :param flag: An indicator if a setting is turned on or off. + """ + + def __init__(self, flag): + self.flag = flag + + def __eq__(self, other): + if not isinstance(other, self.__class__): + return False + return other.flag == self.flag + + +class SinkFilter(_BoolFilter): + """Advanced row filter to skip parent filters. + + :type flag: bool + :param flag: ADVANCED USE ONLY. Hook for introspection into the row filter. + Outputs all cells directly to the output of the read rather + than to any parent filter. Cannot be used within the + ``predicate_filter``, ``true_filter``, or ``false_filter`` + of a :class:`ConditionalRowFilter`. + """ + + def to_pb(self): + """Converts the row filter to a protobuf. + + :rtype: :class:`.data_pb2.RowFilter` + :returns: The converted current object. + """ + return data_pb2.RowFilter(sink=self.flag) + + +class PassAllFilter(_BoolFilter): + """Row filter equivalent to not filtering at all. + + :type flag: bool + :param flag: Matches all cells, regardless of input. Functionally + equivalent to leaving ``filter`` unset, but included for + completeness. + """ + + def to_pb(self): + """Converts the row filter to a protobuf. + + :rtype: :class:`.data_pb2.RowFilter` + :returns: The converted current object. + """ + return data_pb2.RowFilter(pass_all_filter=self.flag) + + +class BlockAllFilter(_BoolFilter): + """Row filter that doesn't match any cells. + + :type flag: bool + :param flag: Does not match any cells, regardless of input. Useful for + temporarily disabling just part of a filter. + """ + + def to_pb(self): + """Converts the row filter to a protobuf. + + :rtype: :class:`.data_pb2.RowFilter` + :returns: The converted current object. + """ + return data_pb2.RowFilter(block_all_filter=self.flag) + + class _RegexFilter(RowFilter): """Row filter that uses a regular expression. @@ -253,3 +324,21 @@ def to_pb(self): :returns: The converted current object. """ return data_pb2.RowFilter(cells_per_column_limit_filter=self.num_cells) + + +class StripValueTransformerFilter(_BoolFilter): + """Row filter that transforms cells into empty string (0 bytes). + + :type flag: bool + :param flag: If :data:`True`, replaces each cell's value with the empty + string. As the name indicates, this is more useful as a + transformer than a generic query / filter. + """ + + def to_pb(self): + """Converts the row filter to a protobuf. + + :rtype: :class:`.data_pb2.RowFilter` + :returns: The converted current object. + """ + return data_pb2.RowFilter(strip_value_transformer=self.flag) diff --git a/gcloud/bigtable/test_row.py b/gcloud/bigtable/test_row.py index 9eb6cec54555..c0e44d18c46b 100644 --- a/gcloud/bigtable/test_row.py +++ b/gcloud/bigtable/test_row.py @@ -48,6 +48,97 @@ def test_constructor_with_non_bytes(self): self._makeOne(row_key, None) +class Test_BoolFilter(unittest2.TestCase): + + def _getTargetClass(self): + from gcloud.bigtable.row import _BoolFilter + return _BoolFilter + + def _makeOne(self, *args, **kwargs): + return self._getTargetClass()(*args, **kwargs) + + def test_constructor(self): + flag = object() + row_filter = self._makeOne(flag) + self.assertTrue(row_filter.flag is flag) + + def test___eq__type_differ(self): + flag = object() + row_filter1 = self._makeOne(flag) + row_filter2 = object() + self.assertNotEqual(row_filter1, row_filter2) + + def test___eq__same_value(self): + flag = object() + row_filter1 = self._makeOne(flag) + row_filter2 = self._makeOne(flag) + self.assertEqual(row_filter1, row_filter2) + + def test___ne__same_value(self): + flag = object() + row_filter1 = self._makeOne(flag) + row_filter2 = self._makeOne(flag) + comparison_val = (row_filter1 != row_filter2) + self.assertFalse(comparison_val) + + +class TestSinkFilter(unittest2.TestCase): + + def _getTargetClass(self): + from gcloud.bigtable.row import SinkFilter + return SinkFilter + + def _makeOne(self, *args, **kwargs): + return self._getTargetClass()(*args, **kwargs) + + def test_to_pb(self): + from gcloud.bigtable._generated import bigtable_data_pb2 as data_pb2 + + flag = True + row_filter = self._makeOne(flag) + pb_val = row_filter.to_pb() + expected_pb = data_pb2.RowFilter(sink=flag) + self.assertEqual(pb_val, expected_pb) + + +class TestPassAllFilter(unittest2.TestCase): + + def _getTargetClass(self): + from gcloud.bigtable.row import PassAllFilter + return PassAllFilter + + def _makeOne(self, *args, **kwargs): + return self._getTargetClass()(*args, **kwargs) + + def test_to_pb(self): + from gcloud.bigtable._generated import bigtable_data_pb2 as data_pb2 + + flag = True + row_filter = self._makeOne(flag) + pb_val = row_filter.to_pb() + expected_pb = data_pb2.RowFilter(pass_all_filter=flag) + self.assertEqual(pb_val, expected_pb) + + +class TestBlockAllFilter(unittest2.TestCase): + + def _getTargetClass(self): + from gcloud.bigtable.row import BlockAllFilter + return BlockAllFilter + + def _makeOne(self, *args, **kwargs): + return self._getTargetClass()(*args, **kwargs) + + def test_to_pb(self): + from gcloud.bigtable._generated import bigtable_data_pb2 as data_pb2 + + flag = True + row_filter = self._makeOne(flag) + pb_val = row_filter.to_pb() + expected_pb = data_pb2.RowFilter(block_all_filter=flag) + self.assertEqual(pb_val, expected_pb) + + class Test_RegexFilter(unittest2.TestCase): def _getTargetClass(self): @@ -64,20 +155,20 @@ def test_constructor(self): def test___eq__type_differ(self): regex = object() - row_filter1 = self._makeOne(regex=regex) + row_filter1 = self._makeOne(regex) row_filter2 = object() self.assertNotEqual(row_filter1, row_filter2) def test___eq__same_value(self): regex = object() - row_filter1 = self._makeOne(regex=regex) - row_filter2 = self._makeOne(regex=regex) + row_filter1 = self._makeOne(regex) + row_filter2 = self._makeOne(regex) self.assertEqual(row_filter1, row_filter2) def test___ne__same_value(self): regex = object() - row_filter1 = self._makeOne(regex=regex) - row_filter2 = self._makeOne(regex=regex) + row_filter1 = self._makeOne(regex) + row_filter2 = self._makeOne(regex) comparison_val = (row_filter1 != row_filter2) self.assertFalse(comparison_val) @@ -174,20 +265,20 @@ def test_constructor(self): def test___eq__type_differ(self): num_cells = object() - row_filter1 = self._makeOne(num_cells=num_cells) + row_filter1 = self._makeOne(num_cells) row_filter2 = object() self.assertNotEqual(row_filter1, row_filter2) def test___eq__same_value(self): num_cells = object() - row_filter1 = self._makeOne(num_cells=num_cells) - row_filter2 = self._makeOne(num_cells=num_cells) + row_filter1 = self._makeOne(num_cells) + row_filter2 = self._makeOne(num_cells) self.assertEqual(row_filter1, row_filter2) def test___ne__same_value(self): num_cells = object() - row_filter1 = self._makeOne(num_cells=num_cells) - row_filter2 = self._makeOne(num_cells=num_cells) + row_filter1 = self._makeOne(num_cells) + row_filter2 = self._makeOne(num_cells) comparison_val = (row_filter1 != row_filter2) self.assertFalse(comparison_val) @@ -248,3 +339,22 @@ def test_to_pb(self): expected_pb = data_pb2.RowFilter( cells_per_column_limit_filter=num_cells) self.assertEqual(pb_val, expected_pb) + + +class TestStripValueTransformerFilter(unittest2.TestCase): + + def _getTargetClass(self): + from gcloud.bigtable.row import StripValueTransformerFilter + return StripValueTransformerFilter + + def _makeOne(self, *args, **kwargs): + return self._getTargetClass()(*args, **kwargs) + + def test_to_pb(self): + from gcloud.bigtable._generated import bigtable_data_pb2 as data_pb2 + + flag = True + row_filter = self._makeOne(flag) + pb_val = row_filter.to_pb() + expected_pb = data_pb2.RowFilter(strip_value_transformer=flag) + self.assertEqual(pb_val, expected_pb)