From ecf37774590926d1dcd86bfad0a8f964d19c5d69 Mon Sep 17 00:00:00 2001 From: Danny Hermes Date: Fri, 15 Jan 2016 01:48:16 -0800 Subject: [PATCH] Adding tracking mutations to Bigtable row. Also adding _get_mutations helper to grab mutations relevant to the non-conditional/True/False state of a mutation. --- gcloud/bigtable/row.py | 48 +++++++++++++++++++++++++++++++++++++ gcloud/bigtable/test_row.py | 40 +++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) diff --git a/gcloud/bigtable/row.py b/gcloud/bigtable/row.py index ef4b7ef6fa6c..c32ebf46869c 100644 --- a/gcloud/bigtable/row.py +++ b/gcloud/bigtable/row.py @@ -23,6 +23,16 @@ class Row(object): """Representation of a Google Cloud Bigtable Row. + .. note:: + + A :class:`Row` accumulates mutations locally via the :meth:`set_cell`, + :meth:`delete`, :meth:`delete_cell` and :meth:`delete_cells` methods. + To actually send these mutations to the Google Cloud Bigtable API, you + must call :meth:`commit`. If a ``filter_`` is set on the :class:`Row`, + the mutations must have an associated state: :data:`True` or + :data:`False`. The mutations will be applied conditionally, based on + whether the filter matches any cells in the :class:`Row` or not. + :type row_key: bytes :param row_key: The key for the current row. @@ -43,6 +53,14 @@ def __init__(self, row_key, table, filter_=None): self._table = table self._filter = filter_ self._rule_pb_list = [] + if self._filter is None: + self._pb_mutations = [] + self._true_pb_mutations = None + self._false_pb_mutations = None + else: + self._pb_mutations = None + self._true_pb_mutations = [] + self._false_pb_mutations = [] def append_cell_value(self, column_family_id, column, value): """Appends a value to an existing cell. @@ -75,6 +93,36 @@ def append_cell_value(self, column_family_id, column, value): append_value=value) self._rule_pb_list.append(rule_pb) + def _get_mutations(self, state=None): + """Gets the list of mutations for a given state. + + If the state is :data`None` but there is a filter set, then we've + reached an invalid state. Similarly if no filter is set but the + state is not :data:`None`. + + :type state: bool + :param state: (Optional) The state that the mutation should be + applied in. Unset if the mutation is not conditional, + otherwise :data:`True` or :data:`False`. + + :rtype: list + :returns: The list to add new mutations to (for the current state). + :raises: :class:`ValueError ` + """ + if state is None: + if self._filter is not None: + raise ValueError('A filter is set on the current row, but no ' + 'state given for the mutation') + return self._pb_mutations + else: + if self._filter is None: + raise ValueError('No filter was set on the current row, but a ' + 'state was given for the mutation') + if state: + return self._true_pb_mutations + else: + return self._false_pb_mutations + class RowFilter(object): """Basic filter to apply to cells in a row. diff --git a/gcloud/bigtable/test_row.py b/gcloud/bigtable/test_row.py index ea41c5d6ccc5..bae06179def3 100644 --- a/gcloud/bigtable/test_row.py +++ b/gcloud/bigtable/test_row.py @@ -49,6 +49,46 @@ def test_constructor_with_non_bytes(self): with self.assertRaises(TypeError): self._makeOne(row_key, None) + def _get_mutations_helper(self, filter_=None, state=None): + row_key = b'row_key' + row = self._makeOne(row_key, None, filter_=filter_) + # Mock the mutations with unique objects so we can compare. + row._pb_mutations = no_bool = object() + row._true_pb_mutations = true_mutations = object() + row._false_pb_mutations = false_mutations = object() + + mutations = row._get_mutations(state) + return (no_bool, true_mutations, false_mutations), mutations + + def test__get_mutations_no_filter(self): + (no_bool, _, _), mutations = self._get_mutations_helper() + self.assertTrue(mutations is no_bool) + + def test__get_mutations_no_filter_bad_state(self): + state = object() # State should be null when no filter. + with self.assertRaises(ValueError): + self._get_mutations_helper(state=state) + + def test__get_mutations_with_filter_true_state(self): + filter_ = object() + state = True + (_, true_filter, _), mutations = self._get_mutations_helper( + filter_=filter_, state=state) + self.assertTrue(mutations is true_filter) + + def test__get_mutations_with_filter_false_state(self): + filter_ = object() + state = False + (_, _, false_filter), mutations = self._get_mutations_helper( + filter_=filter_, state=state) + self.assertTrue(mutations is false_filter) + + def test__get_mutations_with_filter_bad_state(self): + filter_ = object() + state = None + with self.assertRaises(ValueError): + self._get_mutations_helper(filter_=filter_, state=state) + def test_append_cell_value(self): from gcloud.bigtable._generated import bigtable_data_pb2 as data_pb2