Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions gcloud/bigtable/row.py
Original file line number Diff line number Diff line change
Expand Up @@ -661,3 +661,60 @@ def to_pb(self):
:returns: The converted current object.
"""
return data_pb2.RowFilter(apply_label_transformer=self.label)


class ConditionalRowFilter(RowFilter):
"""Conditional row filter which exhibits ternary behavior.

Executes one of two filters based on another filter. If the ``base_filter``
returns any cells in the row, then ``true_filter`` is executed. If not,
then ``false_filter`` is executed.

.. note::

The ``base_filter`` does not execute atomically with the true and false
filters, which may lead to inconsistent or unexpected results.

Additionally, executing a :class:`ConditionalRowFilter` has poor
performance on the server, especially when ``false_filter`` is set.

:type base_filter: :class:`RowFilter`
:param base_filter: The filter to condition on before executing the
true/false filters.

:type true_filter: :class:`RowFilter`
:param true_filter: (Optional) The filter to execute if there are any cells
matching ``base_filter``. If not provided, no results
will be returned in the true case.

:type false_filter: :class:`RowFilter`
:param false_filter: (Optional) The filter to execute if there are no cells
matching ``base_filter``. If not provided, no results
will be returned in the false case.
"""

def __init__(self, base_filter, true_filter=None, false_filter=None):
self.base_filter = base_filter
self.true_filter = true_filter
self.false_filter = false_filter

def __eq__(self, other):
if not isinstance(other, self.__class__):
return False
return (other.base_filter == self.base_filter and
other.true_filter == self.true_filter and
other.false_filter == self.false_filter)

def to_pb(self):
"""Converts the row filter to a protobuf.

:rtype: :class:`.data_pb2.RowFilter`
:returns: The converted current object.
"""
condition_kwargs = {'predicate_filter': self.base_filter.to_pb()}
if self.true_filter is not None:
condition_kwargs['true_filter'] = self.true_filter.to_pb()
if self.false_filter is not None:
condition_kwargs['false_filter'] = self.false_filter.to_pb()
condition = data_pb2.RowFilter.Condition(**condition_kwargs)
return data_pb2.RowFilter(condition=condition)
115 changes: 115 additions & 0 deletions gcloud/bigtable/test_row.py
Original file line number Diff line number Diff line change
Expand Up @@ -779,3 +779,118 @@ def test_to_pb(self):
pb_val = row_filter.to_pb()
expected_pb = data_pb2.RowFilter(apply_label_transformer=label)
self.assertEqual(pb_val, expected_pb)


class TestConditionalRowFilter(unittest2.TestCase):

def _getTargetClass(self):
from gcloud.bigtable.row import ConditionalRowFilter
return ConditionalRowFilter

def _makeOne(self, *args, **kwargs):
return self._getTargetClass()(*args, **kwargs)

def test_constructor(self):
base_filter = object()
true_filter = object()
false_filter = object()
cond_filter = self._makeOne(base_filter,
true_filter=true_filter,
false_filter=false_filter)
self.assertTrue(cond_filter.base_filter is base_filter)
self.assertTrue(cond_filter.true_filter is true_filter)
self.assertTrue(cond_filter.false_filter is false_filter)

def test___eq__(self):
base_filter = object()
true_filter = object()
false_filter = object()
cond_filter1 = self._makeOne(base_filter,
true_filter=true_filter,
false_filter=false_filter)
cond_filter2 = self._makeOne(base_filter,
true_filter=true_filter,
false_filter=false_filter)
self.assertEqual(cond_filter1, cond_filter2)

def test___eq__type_differ(self):
base_filter = object()
true_filter = object()
false_filter = object()
cond_filter1 = self._makeOne(base_filter,
true_filter=true_filter,
false_filter=false_filter)
cond_filter2 = object()
self.assertNotEqual(cond_filter1, cond_filter2)

def test_to_pb(self):
from gcloud.bigtable._generated import bigtable_data_pb2 as data_pb2
from gcloud.bigtable.row import CellsRowOffsetFilter
from gcloud.bigtable.row import RowSampleFilter
from gcloud.bigtable.row import StripValueTransformerFilter

row_filter1 = StripValueTransformerFilter(True)
row_filter1_pb = row_filter1.to_pb()

row_filter2 = RowSampleFilter(0.25)
row_filter2_pb = row_filter2.to_pb()

row_filter3 = CellsRowOffsetFilter(11)
row_filter3_pb = row_filter3.to_pb()

row_filter4 = self._makeOne(row_filter1, true_filter=row_filter2,
false_filter=row_filter3)
filter_pb = row_filter4.to_pb()

expected_pb = data_pb2.RowFilter(
condition=data_pb2.RowFilter.Condition(
predicate_filter=row_filter1_pb,
true_filter=row_filter2_pb,
false_filter=row_filter3_pb,
),
)
self.assertEqual(filter_pb, expected_pb)

def test_to_pb_true_only(self):
from gcloud.bigtable._generated import bigtable_data_pb2 as data_pb2
from gcloud.bigtable.row import RowSampleFilter
from gcloud.bigtable.row import StripValueTransformerFilter

row_filter1 = StripValueTransformerFilter(True)
row_filter1_pb = row_filter1.to_pb()

row_filter2 = RowSampleFilter(0.25)
row_filter2_pb = row_filter2.to_pb()

row_filter3 = self._makeOne(row_filter1, true_filter=row_filter2)
filter_pb = row_filter3.to_pb()

expected_pb = data_pb2.RowFilter(
condition=data_pb2.RowFilter.Condition(
predicate_filter=row_filter1_pb,
true_filter=row_filter2_pb,
),
)
self.assertEqual(filter_pb, expected_pb)

def test_to_pb_false_only(self):
from gcloud.bigtable._generated import bigtable_data_pb2 as data_pb2
from gcloud.bigtable.row import RowSampleFilter
from gcloud.bigtable.row import StripValueTransformerFilter

row_filter1 = StripValueTransformerFilter(True)
row_filter1_pb = row_filter1.to_pb()

row_filter2 = RowSampleFilter(0.25)
row_filter2_pb = row_filter2.to_pb()

row_filter3 = self._makeOne(row_filter1, false_filter=row_filter2)
filter_pb = row_filter3.to_pb()

expected_pb = data_pb2.RowFilter(
condition=data_pb2.RowFilter.Condition(
predicate_filter=row_filter1_pb,
false_filter=row_filter2_pb,
),
)
self.assertEqual(filter_pb, expected_pb)