def test_delete_cells_with_string_columns(self): from gcloud.bigtable._generated import bigtable_data_pb2 as data_pb2 row_key = b'row_key' column_family_id = u'column_family_id' column1 = u'column1' column1_bytes = b'column1' column2 = u'column2' column2_bytes = b'column2' table = object() row = self._makeOne(row_key, table) columns = [column1, column2] self.assertEqual(row._pb_mutations, []) row.delete_cells(column_family_id, columns) expected_pb1 = data_pb2.Mutation( delete_from_column=data_pb2.Mutation.DeleteFromColumn( family_name=column_family_id, column_qualifier=column1_bytes, ), ) expected_pb2 = data_pb2.Mutation( delete_from_column=data_pb2.Mutation.DeleteFromColumn( family_name=column_family_id, column_qualifier=column2_bytes, ), ) self.assertEqual(row._pb_mutations, [expected_pb1, expected_pb2])
def _delete_cells(self, column_family_id, columns, time_range=None, state=None): """Helper for :meth:`delete_cell` and :meth:`delete_cells`. ``state`` is unused by :class:`DirectRow` but is used by subclasses. :type column_family_id: str :param column_family_id: The column family that contains the column or columns with cells being deleted. Must be of the form ``[_a-zA-Z0-9][-_.a-zA-Z0-9]*``. :type columns: :class:`list` of :class:`str` / :func:`unicode <unicode>`, or :class:`object` :param columns: The columns within the column family that will have cells deleted. If :attr:`ALL_COLUMNS` is used then the entire column family will be deleted from the row. :type time_range: :class:`TimestampRange` :param time_range: (Optional) The range of time within which cells should be deleted. :type state: bool :param state: (Optional) The state that is passed along to :meth:`_get_mutations`. """ mutations_list = self._get_mutations(state) if columns is self.ALL_COLUMNS: mutation_val = data_pb2.Mutation.DeleteFromFamily( family_name=column_family_id, ) mutation_pb = data_pb2.Mutation(delete_from_family=mutation_val) mutations_list.append(mutation_pb) else: delete_kwargs = {} if time_range is not None: delete_kwargs['time_range'] = time_range.to_pb() to_append = [] for column in columns: column = _to_bytes(column) # time_range will never change if present, but the rest of # delete_kwargs will delete_kwargs.update( family_name=column_family_id, column_qualifier=column, ) mutation_val = data_pb2.Mutation.DeleteFromColumn( **delete_kwargs) mutation_pb = data_pb2.Mutation( delete_from_column=mutation_val) to_append.append(mutation_pb) # We don't add the mutations until all columns have been # processed without error. mutations_list.extend(to_append)
def _set_cell_helper(self, column=None, column_bytes=None, value=b'foobar', timestamp=None, timestamp_micros=-1): import six import struct from gcloud.bigtable._generated import bigtable_data_pb2 as data_pb2 row_key = b'row_key' column_family_id = u'column_family_id' if column is None: column = b'column' table = object() row = self._makeOne(row_key, table) self.assertEqual(row._pb_mutations, []) row.set_cell(column_family_id, column, value, timestamp=timestamp) if isinstance(value, six.integer_types): value = struct.pack('>q', value) expected_pb = data_pb2.Mutation( set_cell=data_pb2.Mutation.SetCell( family_name=column_family_id, column_qualifier=column_bytes or column, timestamp_micros=timestamp_micros, value=value, ), ) self.assertEqual(row._pb_mutations, [expected_pb])
def test_delete(self): from gcloud.bigtable._generated import bigtable_data_pb2 as data_pb2 row_key = b'row_key' row = self._makeOne(row_key, object()) self.assertEqual(row._pb_mutations, []) row.delete() expected_pb = data_pb2.Mutation( delete_from_row=data_pb2.Mutation.DeleteFromRow(), ) self.assertEqual(row._pb_mutations, [expected_pb])
def test_commit(self): from google.protobuf import empty_pb2 from gcloud.bigtable._generated import bigtable_data_pb2 as data_pb2 from gcloud.bigtable._generated import ( bigtable_service_messages_pb2 as messages_pb2) from gcloud.bigtable._testing import _FakeStub row_key = b'row_key' table_name = 'projects/more-stuff' column_family_id = u'column_family_id' column = b'column' timeout_seconds = 711 client = _Client(timeout_seconds=timeout_seconds) table = _Table(table_name, client=client) row = self._makeOne(row_key, table) # Create request_pb value = b'bytes-value' mutation = data_pb2.Mutation( set_cell=data_pb2.Mutation.SetCell( family_name=column_family_id, column_qualifier=column, timestamp_micros=-1, # Default value. value=value, ), ) request_pb = messages_pb2.MutateRowRequest( table_name=table_name, row_key=row_key, mutations=[mutation], ) # Create response_pb response_pb = empty_pb2.Empty() # Patch the stub used by the API method. client._data_stub = stub = _FakeStub(response_pb) # Create expected_result. expected_result = None # commit() has no return value when no filter. # Perform the method and check the result. row.set_cell(column_family_id, column, value) result = row.commit() self.assertEqual(result, expected_result) self.assertEqual(stub.method_calls, [( 'MutateRow', (request_pb, timeout_seconds), {}, )]) self.assertEqual(row._pb_mutations, [])
def _set_cell(self, column_family_id, column, value, timestamp=None, state=None): """Helper for :meth:`set_cell` Adds a mutation to set the value in a specific cell. ``state`` is unused by :class:`DirectRow` but is used by subclasses. :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 value: bytes or :class:`int` :param value: The value to set in the cell. If an integer is used, will be interpreted as a 64-bit big-endian signed integer (8 bytes). :type timestamp: :class:`datetime.datetime` :param timestamp: (Optional) The timestamp of the operation. :type state: bool :param state: (Optional) The state that is passed along to :meth:`_get_mutations`. """ column = _to_bytes(column) if isinstance(value, six.integer_types): value = _PACK_I64(value) value = _to_bytes(value) if timestamp is None: # Use -1 for current Bigtable server time. timestamp_micros = -1 else: timestamp_micros = _microseconds_from_datetime(timestamp) # Truncate to millisecond granularity. timestamp_micros -= (timestamp_micros % 1000) mutation_val = data_pb2.Mutation.SetCell( family_name=column_family_id, column_qualifier=column, timestamp_micros=timestamp_micros, value=value, ) mutation_pb = data_pb2.Mutation(set_cell=mutation_val) self._get_mutations(state).append(mutation_pb)
def _delete(self, state=None): """Helper for :meth:`delete` Adds a delete mutation (for the entire row) to the accumulated mutations. ``state`` is unused by :class:`DirectRow` but is used by subclasses. :type state: bool :param state: (Optional) The state that is passed along to :meth:`_get_mutations`. """ mutation_val = data_pb2.Mutation.DeleteFromRow() mutation_pb = data_pb2.Mutation(delete_from_row=mutation_val) self._get_mutations(state).append(mutation_pb)
def delete(self, state=None): """Deletes this row from the table. .. note:: This method adds a mutation to the accumulated mutations on this :class:`Row`, but does not make an API request. To actually send an API request (with the mutations) to the Google Cloud Bigtable API, call :meth:`commit`. :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`. """ mutation_val = data_pb2.Mutation.DeleteFromRow() mutation_pb = data_pb2.Mutation(delete_from_row=mutation_val) self._get_mutations(state).append(mutation_pb)
def test_delete_cells_all_columns(self): from gcloud.bigtable._generated import bigtable_data_pb2 as data_pb2 row_key = b'row_key' column_family_id = u'column_family_id' table = object() row = self._makeOne(row_key, table) klass = self._getTargetClass() self.assertEqual(row._pb_mutations, []) row.delete_cells(column_family_id, klass.ALL_COLUMNS) expected_pb = data_pb2.Mutation( delete_from_family=data_pb2.Mutation.DeleteFromFamily( family_name=column_family_id, ), ) self.assertEqual(row._pb_mutations, [expected_pb])
def _delete_cells_helper(self, time_range=None): from gcloud.bigtable._generated import bigtable_data_pb2 as data_pb2 row_key = b'row_key' column = b'column' column_family_id = u'column_family_id' table = object() row = self._makeOne(row_key, table) columns = [column] self.assertEqual(row._pb_mutations, []) row.delete_cells(column_family_id, columns, time_range=time_range) expected_pb = data_pb2.Mutation( delete_from_column=data_pb2.Mutation.DeleteFromColumn( family_name=column_family_id, column_qualifier=column, ), ) if time_range is not None: expected_pb.delete_from_column.time_range.CopyFrom( time_range.to_pb()) self.assertEqual(row._pb_mutations, [expected_pb])
def delete_cells(self, column_family_id, columns, time_range=None, state=None): """Deletes cells in this row. .. note:: This method adds a mutation to the accumulated mutations on this :class:`Row`, but does not make an API request. To actually send an API request (with the mutations) to the Google Cloud Bigtable API, call :meth:`commit`. :type column_family_id: str :param column_family_id: The column family that contains the column or columns with cells being deleted. Must be of the form ``[_a-zA-Z0-9][-_.a-zA-Z0-9]*``. :type columns: :class:`list` of :class:`str` / :func:`unicode <unicode>`, or :class:`object` :param columns: The columns within the column family that will have cells deleted. If :attr:`Row.ALL_COLUMNS` is used then the entire column family will be deleted from the row. :type time_range: :class:`TimestampRange` :param time_range: (Optional) The range of time within which cells should be deleted. :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`. """ mutations_list = self._get_mutations(state) if columns is self.ALL_COLUMNS: mutation_val = data_pb2.Mutation.DeleteFromFamily( family_name=column_family_id, ) mutation_pb = data_pb2.Mutation(delete_from_family=mutation_val) mutations_list.append(mutation_pb) else: delete_kwargs = {} if time_range is not None: delete_kwargs['time_range'] = time_range.to_pb() to_append = [] for column in columns: column = _to_bytes(column) # time_range will never change if present, but the rest of # delete_kwargs will delete_kwargs.update( family_name=column_family_id, column_qualifier=column, ) mutation_val = data_pb2.Mutation.DeleteFromColumn( **delete_kwargs) mutation_pb = data_pb2.Mutation( delete_from_column=mutation_val) to_append.append(mutation_pb) # We don't add the mutations until all columns have been # processed without error. mutations_list.extend(to_append)
def set_cell(self, column_family_id, column, value, timestamp=None, state=None): """Sets a value in this row. The cell is determined by the ``row_key`` of the :class:`Row` and the ``column``. The ``column`` must be in an existing :class:`.column_family.ColumnFamily` (as determined by ``column_family_id``). .. note:: This method adds a mutation to the accumulated mutations on this :class:`Row`, but does not make an API request. To actually send an API request (with the mutations) to the Google Cloud Bigtable API, call :meth:`commit`. :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 value: bytes or :class:`int` :param value: The value to set in the cell. If an integer is used, will be interpreted as a 64-bit big-endian signed integer (8 bytes). :type timestamp: :class:`datetime.datetime` :param timestamp: (Optional) The timestamp of the operation. :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`. """ column = _to_bytes(column) if isinstance(value, six.integer_types): value = _PACK_I64(value) value = _to_bytes(value) if timestamp is None: # Use -1 for current Bigtable server time. timestamp_micros = -1 else: timestamp_micros = _microseconds_from_datetime(timestamp) # Truncate to millisecond granularity. timestamp_micros -= (timestamp_micros % 1000) mutation_val = data_pb2.Mutation.SetCell( family_name=column_family_id, column_qualifier=column, timestamp_micros=timestamp_micros, value=value, ) mutation_pb = data_pb2.Mutation(set_cell=mutation_val) self._get_mutations(state).append(mutation_pb)
def test_commit(self): from gcloud.bigtable._generated import bigtable_data_pb2 as data_pb2 from gcloud.bigtable._generated import ( bigtable_service_messages_pb2 as messages_pb2) from gcloud.bigtable._testing import _FakeStub from gcloud.bigtable.row_filters import RowSampleFilter row_key = b'row_key' table_name = 'projects/more-stuff' column_family_id1 = u'column_family_id1' column_family_id2 = u'column_family_id2' column_family_id3 = u'column_family_id3' column1 = b'column1' column2 = b'column2' timeout_seconds = 262 client = _Client(timeout_seconds=timeout_seconds) table = _Table(table_name, client=client) row_filter = RowSampleFilter(0.33) row = self._makeOne(row_key, table, filter_=row_filter) # Create request_pb value1 = b'bytes-value' mutation1 = data_pb2.Mutation( set_cell=data_pb2.Mutation.SetCell( family_name=column_family_id1, column_qualifier=column1, timestamp_micros=-1, # Default value. value=value1, ), ) mutation2 = data_pb2.Mutation( delete_from_row=data_pb2.Mutation.DeleteFromRow(), ) mutation3 = data_pb2.Mutation( delete_from_column=data_pb2.Mutation.DeleteFromColumn( family_name=column_family_id2, column_qualifier=column2, ), ) mutation4 = data_pb2.Mutation( delete_from_family=data_pb2.Mutation.DeleteFromFamily( family_name=column_family_id3, ), ) request_pb = messages_pb2.CheckAndMutateRowRequest( table_name=table_name, row_key=row_key, predicate_filter=row_filter.to_pb(), true_mutations=[mutation1, mutation3, mutation4], false_mutations=[mutation2], ) # Create response_pb predicate_matched = True response_pb = messages_pb2.CheckAndMutateRowResponse( predicate_matched=predicate_matched) # Patch the stub used by the API method. client._data_stub = stub = _FakeStub(response_pb) # Create expected_result. expected_result = predicate_matched # Perform the method and check the result. row.set_cell(column_family_id1, column1, value1, state=True) row.delete(state=False) row.delete_cell(column_family_id2, column2, state=True) row.delete_cells(column_family_id3, row.ALL_COLUMNS, state=True) result = row.commit() self.assertEqual(result, expected_result) self.assertEqual(stub.method_calls, [( 'CheckAndMutateRow', (request_pb, timeout_seconds), {}, )]) self.assertEqual(row._true_pb_mutations, []) self.assertEqual(row._false_pb_mutations, [])