Skip to content

Commit e1fe6a4

Browse files
committed
Adding Bigtable RowFilter base class.
Also adding regex filters for a row key (bytes) and a family name (string). These come from https://github.com/GoogleCloudPlatform/cloud-bigtable-client/blob/6a498cd3e660c7ed18299e980c1658d67661e69b/bigtable-protos/src/main/proto/google/bigtable/v1/bigtable_data.proto#L321-L404 In addition to more classes for primitive properties, parent classes are forthcoming to handle the non-primitive cases of filter Chain, Interleave and Condition (ternary). Also renaming some redunant unit test names in test_column_family.py.
1 parent 977b7f8 commit e1fe6a4

3 files changed

Lines changed: 211 additions & 11 deletions

File tree

gcloud/bigtable/row.py

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717

1818
from gcloud._helpers import _to_bytes
19+
from gcloud.bigtable._generated import bigtable_data_pb2 as data_pb2
1920

2021

2122
class Row(object):
@@ -31,3 +32,111 @@ class Row(object):
3132
def __init__(self, row_key, table):
3233
self._row_key = _to_bytes(row_key)
3334
self._table = table
35+
36+
37+
class RowFilter(object):
38+
"""Basic filter to apply to cells in a row.
39+
40+
These values can be combined via :class:`RowFilterChain`,
41+
:class:`RowFilterUnion` and :class:`ConditionalRowFilter`.
42+
43+
.. note::
44+
45+
This class is a do-nothing base class for all row filters.
46+
"""
47+
48+
def to_pb(self):
49+
"""Converts the :class:`RowFilter` to a protobuf.
50+
51+
:raises: :class:`NotImplementedError <exceptions.NotImplementedError>`
52+
always since a virtual class.
53+
"""
54+
raise NotImplementedError
55+
56+
def __ne__(self, other):
57+
return not self.__eq__(other)
58+
59+
60+
class _RegexFilter(RowFilter):
61+
"""Row filter that uses a regular expression.
62+
63+
The ``regex`` must be valid RE2 patterns. See Google's
64+
`RE2 reference`_ for the accepted syntax.
65+
66+
.. _RE2 reference: https://github.com/google/re2/wiki/Syntax
67+
68+
:type regex: bytes or str
69+
:param regex: A regular expression (RE2) for some row filter.
70+
"""
71+
72+
def __init__(self, regex):
73+
self.regex = regex
74+
75+
def __eq__(self, other):
76+
if not isinstance(other, self.__class__):
77+
return False
78+
return other.regex == self.regex
79+
80+
def to_pb(self):
81+
"""Converts the :class:`_RegexFilter` to a protobuf.
82+
83+
:raises: :class:`NotImplementedError <exceptions.NotImplementedError>`
84+
always since a virtual class.
85+
"""
86+
raise NotImplementedError
87+
88+
89+
class RowKeyRegexFilter(_RegexFilter):
90+
"""Row filter for a row key regular expression.
91+
92+
The ``regex`` must be valid RE2 patterns. See Google's
93+
`RE2 reference`_ for the accepted syntax.
94+
95+
.. _RE2 reference: https://github.com/google/re2/wiki/Syntax
96+
97+
.. note::
98+
99+
Special care need be used with the expression used. Since
100+
each of these properties can contain arbitrary bytes, the ``\\C``
101+
escape sequence must be used if a true wildcard is desired. The ``.``
102+
character will not match the new line character ``\\n``, which may be
103+
present in a binary value.
104+
105+
:type regex: bytes
106+
:param regex: A regular expression (RE2) to match cells from rows with row
107+
keys that satisfy this regex. For a
108+
``CheckAndMutateRowRequest``, this filter is unnecessary
109+
since the row key is already specified.
110+
"""
111+
112+
def to_pb(self):
113+
"""Converts the row filter to a protobuf.
114+
115+
:rtype: :class:`.data_pb2.RowFilter`
116+
:returns: The converted current object.
117+
"""
118+
return data_pb2.RowFilter(row_key_regex_filter=self.regex)
119+
120+
121+
class FamilyNameRegexFilter(_RegexFilter):
122+
"""Row filter for a family name regular expression.
123+
124+
The ``regex`` must be valid RE2 patterns. See Google's
125+
`RE2 reference`_ for the accepted syntax.
126+
127+
.. _RE2 reference: https://github.com/google/re2/wiki/Syntax
128+
129+
:type regex: str
130+
:param regex: A regular expression (RE2) to match cells from columns in a
131+
given column family. For technical reasons, the regex must
132+
not contain the ``':'`` character, even if it is not being
133+
used as a literal.
134+
"""
135+
136+
def to_pb(self):
137+
"""Converts the row filter to a protobuf.
138+
139+
:rtype: :class:`.data_pb2.RowFilter`
140+
:returns: The converted current object.
141+
"""
142+
return data_pb2.RowFilter(family_name_regex_filter=self.regex)

gcloud/bigtable/test_column_family.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -84,16 +84,16 @@ def _getTargetClass(self):
8484
def _makeOne(self, *args, **kwargs):
8585
return self._getTargetClass()(*args, **kwargs)
8686

87-
def test___eq__max_num_versions(self):
88-
gc_rule1 = self._makeOne(2)
89-
gc_rule2 = self._makeOne(2)
90-
self.assertEqual(gc_rule1, gc_rule2)
91-
9287
def test___eq__type_differ(self):
9388
gc_rule1 = self._makeOne(10)
9489
gc_rule2 = object()
9590
self.assertNotEqual(gc_rule1, gc_rule2)
9691

92+
def test___eq__same_value(self):
93+
gc_rule1 = self._makeOne(2)
94+
gc_rule2 = self._makeOne(2)
95+
self.assertEqual(gc_rule1, gc_rule2)
96+
9797
def test___ne__same_value(self):
9898
gc_rule1 = self._makeOne(99)
9999
gc_rule2 = self._makeOne(99)
@@ -119,18 +119,18 @@ def _getTargetClass(self):
119119
def _makeOne(self, *args, **kwargs):
120120
return self._getTargetClass()(*args, **kwargs)
121121

122-
def test___eq__max_age(self):
123-
max_age = object()
124-
gc_rule1 = self._makeOne(max_age=max_age)
125-
gc_rule2 = self._makeOne(max_age=max_age)
126-
self.assertEqual(gc_rule1, gc_rule2)
127-
128122
def test___eq__type_differ(self):
129123
max_age = object()
130124
gc_rule1 = self._makeOne(max_age=max_age)
131125
gc_rule2 = object()
132126
self.assertNotEqual(gc_rule1, gc_rule2)
133127

128+
def test___eq__same_value(self):
129+
max_age = object()
130+
gc_rule1 = self._makeOne(max_age=max_age)
131+
gc_rule2 = self._makeOne(max_age=max_age)
132+
self.assertEqual(gc_rule1, gc_rule2)
133+
134134
def test___ne__same_value(self):
135135
max_age = object()
136136
gc_rule1 = self._makeOne(max_age=max_age)

gcloud/bigtable/test_row.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,94 @@ def test_constructor_with_non_bytes(self):
4646
row_key = object()
4747
with self.assertRaises(TypeError):
4848
self._makeOne(row_key, None)
49+
50+
51+
class TestRowFilter(unittest2.TestCase):
52+
53+
def _getTargetClass(self):
54+
from gcloud.bigtable.row import RowFilter
55+
return RowFilter
56+
57+
def _makeOne(self, *args, **kwargs):
58+
return self._getTargetClass()(*args, **kwargs)
59+
60+
def test_to_pb_virtual(self):
61+
row_filter = self._makeOne()
62+
self.assertRaises(NotImplementedError, row_filter.to_pb)
63+
64+
65+
class Test_RegexFilter(unittest2.TestCase):
66+
67+
def _getTargetClass(self):
68+
from gcloud.bigtable.row import _RegexFilter
69+
return _RegexFilter
70+
71+
def _makeOne(self, *args, **kwargs):
72+
return self._getTargetClass()(*args, **kwargs)
73+
74+
def test_constructor(self):
75+
regex = object()
76+
row_filter = self._makeOne(regex)
77+
self.assertTrue(row_filter.regex is regex)
78+
79+
def test_to_pb_virtual(self):
80+
regex = object()
81+
row_filter = self._makeOne(regex=regex)
82+
self.assertRaises(NotImplementedError, row_filter.to_pb)
83+
84+
def test___eq__type_differ(self):
85+
regex = object()
86+
row_filter1 = self._makeOne(regex=regex)
87+
row_filter2 = object()
88+
self.assertNotEqual(row_filter1, row_filter2)
89+
90+
def test___eq__same_value(self):
91+
regex = object()
92+
row_filter1 = self._makeOne(regex=regex)
93+
row_filter2 = self._makeOne(regex=regex)
94+
self.assertEqual(row_filter1, row_filter2)
95+
96+
def test___ne__same_value(self):
97+
regex = object()
98+
row_filter1 = self._makeOne(regex=regex)
99+
row_filter2 = self._makeOne(regex=regex)
100+
comparison_val = (row_filter1 != row_filter2)
101+
self.assertFalse(comparison_val)
102+
103+
104+
class TestRowKeyRegexFilter(unittest2.TestCase):
105+
106+
def _getTargetClass(self):
107+
from gcloud.bigtable.row import RowKeyRegexFilter
108+
return RowKeyRegexFilter
109+
110+
def _makeOne(self, *args, **kwargs):
111+
return self._getTargetClass()(*args, **kwargs)
112+
113+
def test_to_pb(self):
114+
from gcloud.bigtable._generated import bigtable_data_pb2 as data_pb2
115+
116+
regex = b'row-key-regex'
117+
row_filter = self._makeOne(regex)
118+
pb_val = row_filter.to_pb()
119+
expected_pb = data_pb2.RowFilter(row_key_regex_filter=regex)
120+
self.assertEqual(pb_val, expected_pb)
121+
122+
123+
class TestFamilyNameRegexFilter(unittest2.TestCase):
124+
125+
def _getTargetClass(self):
126+
from gcloud.bigtable.row import FamilyNameRegexFilter
127+
return FamilyNameRegexFilter
128+
129+
def _makeOne(self, *args, **kwargs):
130+
return self._getTargetClass()(*args, **kwargs)
131+
132+
def test_to_pb(self):
133+
from gcloud.bigtable._generated import bigtable_data_pb2 as data_pb2
134+
135+
regex = u'family-regex'
136+
row_filter = self._makeOne(regex)
137+
pb_val = row_filter.to_pb()
138+
expected_pb = data_pb2.RowFilter(family_name_regex_filter=regex)
139+
self.assertEqual(pb_val, expected_pb)

0 commit comments

Comments
 (0)