From 51743b35cd91780153cf10453626343c173b33a8 Mon Sep 17 00:00:00 2001 From: Danny Hermes Date: Fri, 15 Jan 2016 09:10:07 -0800 Subject: [PATCH 1/2] Adding Bigtable Row.increment_cell_value. Similar to #1388. The API accepts integers and then encodes them as bytes when stored in the table. --- gcloud/bigtable/row.py | 30 ++++++++++++++++++++++++++++++ gcloud/bigtable/test_row.py | 17 +++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/gcloud/bigtable/row.py b/gcloud/bigtable/row.py index c32ebf46869c..465269036eb8 100644 --- a/gcloud/bigtable/row.py +++ b/gcloud/bigtable/row.py @@ -123,6 +123,36 @@ def _get_mutations(self, state=None): else: return self._false_pb_mutations + def increment_cell_value(self, column_family_id, column, int_value): + """Increments a value in an existing cell. + Assumes the value in the cell is stored as a 64 bit integer + serialized to bytes. + .. note:: + This method adds a read-modify rule protobuf to the accumulated + read-modify rules on this :class:`Row`, but does not make an API + request. To actually send an API request (with the rules) to the + Google Cloud Bigtable API, call :meth:`commit_modifications`. + :type column_family_id: str + :param column_family_id: The column family that contains the column. + Must be of the form + ``[_a-zA-Z0-9][-_.a-zA-Z0-9]*``. + :type column: bytes + :param column: The column within the column family where the cell + is located. + :type int_value: int + :param int_value: The value to increment the existing value in the cell + by. If the targeted cell is unset, it will be treated + as containing a zero. Otherwise, the targeted cell + must contain an 8-byte value (interpreted as a 64-bit + big-endian signed integer), or the entire request + will fail. + """ + column = _to_bytes(column) + rule_pb = data_pb2.ReadModifyWriteRule(family_name=column_family_id, + column_qualifier=column, + increment_amount=int_value) + self._rule_pb_list.append(rule_pb) + 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 bae06179def3..cbf1ecc51f77 100644 --- a/gcloud/bigtable/test_row.py +++ b/gcloud/bigtable/test_row.py @@ -106,6 +106,23 @@ def test_append_cell_value(self): append_value=value) self.assertEqual(row._rule_pb_list, [expected_pb]) + def test_increment_cell_value(self): + from gcloud.bigtable._generated import bigtable_data_pb2 as data_pb2 + + table = object() + row_key = b'row_key' + row = self._makeOne(row_key, table) + self.assertEqual(row._rule_pb_list, []) + + column = b'column' + column_family_id = u'column_family_id' + int_value = 281330 + row.increment_cell_value(column_family_id, column, int_value) + expected_pb = data_pb2.ReadModifyWriteRule( + family_name=column_family_id, column_qualifier=column, + increment_amount=int_value) + self.assertEqual(row._rule_pb_list, [expected_pb]) + class Test_BoolFilter(unittest2.TestCase): From 46c6e5ab7fdc407e59dad78380a06de1a9660f43 Mon Sep 17 00:00:00 2001 From: Danny Hermes Date: Fri, 15 Jan 2016 09:14:04 -0800 Subject: [PATCH 2/2] Moving _get_mutations helper above public Row methods. --- gcloud/bigtable/row.py | 60 +++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/gcloud/bigtable/row.py b/gcloud/bigtable/row.py index 465269036eb8..fb103c362ac0 100644 --- a/gcloud/bigtable/row.py +++ b/gcloud/bigtable/row.py @@ -62,6 +62,36 @@ def __init__(self, row_key, table, filter_=None): self._true_pb_mutations = [] self._false_pb_mutations = [] + 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 + def append_cell_value(self, column_family_id, column, value): """Appends a value to an existing cell. @@ -93,36 +123,6 @@ 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 - def increment_cell_value(self, column_family_id, column, int_value): """Increments a value in an existing cell. Assumes the value in the cell is stored as a 64 bit integer