def append_cell_value(self, column_family_id, column, value): """Appends a value to an existing cell. .. 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 value: bytes :param value: The value to append to the existing value in the cell. If the targeted cell is unset, it will be treated as containing the empty string. """ column = _to_bytes(column) value = _to_bytes(value) rule_pb = data_pb2.ReadModifyWriteRule(family_name=column_family_id, column_qualifier=column, append_value=value) self._rule_pb_list.append(rule_pb)
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 = _timestamp_to_microseconds(timestamp) 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 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)
def to_dict(self): """Convert the cells to a dictionary. This is intended to be used with HappyBase, so the column family and column qualiers are combined (with ``:``). :rtype: dict :returns: Dictionary containing all the data in the cells of this row. """ result = {} for column_family_id, columns in six.iteritems(self._cells): for column_qual, cells in six.iteritems(columns): key = (_to_bytes(column_family_id) + b':' + _to_bytes(column_qual)) result[key] = cells return result
def to_pb(self): """Converts the :class:`RowFilter` to a protobuf. :rtype: :class:`.data_pb2.RowFilter` :returns: The converted current object. """ self._check_single_value() row_filter_kwargs = {} if self.row_key_regex_filter is not None: row_filter_kwargs['row_key_regex_filter'] = _to_bytes( self.row_key_regex_filter) if self.family_name_regex_filter is not None: row_filter_kwargs['family_name_regex_filter'] = ( self.family_name_regex_filter) if self.column_qualifier_regex_filter is not None: row_filter_kwargs['column_qualifier_regex_filter'] = _to_bytes( self.column_qualifier_regex_filter) if self.value_regex_filter is not None: row_filter_kwargs['value_regex_filter'] = _to_bytes( self.value_regex_filter) if self.column_range_filter is not None: row_filter_kwargs['column_range_filter'] = ( self.column_range_filter.to_pb()) if self.timestamp_range_filter is not None: row_filter_kwargs['timestamp_range_filter'] = ( self.timestamp_range_filter.to_pb()) if self.value_range_filter is not None: row_filter_kwargs['value_range_filter'] = ( self.value_range_filter.to_pb()) if self.cells_per_row_offset_filter is not None: row_filter_kwargs['cells_per_row_offset_filter'] = ( self.cells_per_row_offset_filter) if self.cells_per_row_limit_filter is not None: row_filter_kwargs['cells_per_row_limit_filter'] = ( self.cells_per_row_limit_filter) if self.cells_per_column_limit_filter is not None: row_filter_kwargs['cells_per_column_limit_filter'] = ( self.cells_per_column_limit_filter) if self.row_sample_filter is not None: row_filter_kwargs['row_sample_filter'] = ( self.row_sample_filter) if self.strip_value_transformer is not None: row_filter_kwargs['strip_value_transformer'] = ( self.strip_value_transformer) return data_pb2.RowFilter(**row_filter_kwargs)
def to_pb(self): """Converts the :class:`CellValueRange` to a protobuf. :rtype: :class:`.data_pb2.ValueRange` :returns: The converted current object. """ value_range_kwargs = {} if self.start_value is not None: if self.inclusive_start: key = 'start_value_inclusive' else: key = 'start_value_exclusive' value_range_kwargs[key] = _to_bytes(self.start_value) if self.end_value is not None: if self.inclusive_end: key = 'end_value_inclusive' else: key = 'end_value_exclusive' value_range_kwargs[key] = _to_bytes(self.end_value) return data_pb2.ValueRange(**value_range_kwargs)
def to_pb(self): """Converts the :class:`ColumnRange` to a protobuf. :rtype: :class:`.data_pb2.ColumnRange` :returns: The converted current object. """ column_range_kwargs = {'family_name': self.column_family_id} if self.start_column is not None: if self.inclusive_start: key = 'start_qualifier_inclusive' else: key = 'start_qualifier_exclusive' column_range_kwargs[key] = _to_bytes(self.start_column) if self.end_column is not None: if self.inclusive_end: key = 'end_qualifier_inclusive' else: key = 'end_qualifier_exclusive' column_range_kwargs[key] = _to_bytes(self.end_column) return data_pb2.ColumnRange(**column_range_kwargs)
def __init__(self, row_key, table, filter_=None): self._row_key = _to_bytes(row_key) 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 _next_char(str_val, index): """Gets the next character based on a position in a string. :type str_val: str :param str_val: A string containing the character to update. :type index: int :param index: An integer index in ``str_val``. :rtype: str :returns: The next character after the character at ``index`` in ``str_val``. """ if six.PY3: # pragma: NO COVER ord_val = str_val[index] else: ord_val = ord(str_val[index]) return _to_bytes(chr(ord_val + 1), encoding='latin-1')
def _string_successor(str_val): """Increment and truncate a byte string. Determines shortest string that sorts after the given string when compared using regular string comparison semantics. Borrowed from gcloud-golang. Increments the last byte that is smaller than ``0xFF``, and drops everything after it. If the string only contains ``0xFF`` bytes, ``''`` is returned. :type str_val: str :param str_val: String to increment. :rtype: str :returns: The next string in lexical order after ``str_val``. """ str_val = _to_bytes(str_val, encoding='latin-1') if str_val == b'': return str_val index = len(str_val) - 1 while index >= 0: if six.PY3: # pragma: NO COVER if str_val[index] != 0xff: break else: if str_val[index] != b'\xff': break index -= 1 if index == -1: return b'' return str_val[:index] + _next_char(str_val, index)
def _create_row_request(table_name, row_key=None, start_key=None, end_key=None, filter_=None, allow_row_interleaving=None, limit=None): """Creates a request to read rows in a table. :type table_name: str :param table_name: The name of the table to read from. :type row_key: bytes :param row_key: (Optional) The key of a specific row to read from. :type start_key: bytes :param start_key: (Optional) The beginning of a range of row keys to read from. The range will include ``start_key``. If left empty, will be interpreted as the empty string. :type end_key: bytes :param end_key: (Optional) The end of a range of row keys to read from. The range will not include ``end_key``. If left empty, will be interpreted as an infinite string. :type filter_: :class:`.row.RowFilter`, :class:`.row.RowFilterChain`, :class:`.row.RowFilterUnion` or :class:`.row.ConditionalRowFilter` :param filter_: (Optional) The filter to apply to the contents of the specified row(s). If unset, reads the entire table. :type allow_row_interleaving: bool :param allow_row_interleaving: (Optional) By default, rows are read sequentially, producing results which are guaranteed to arrive in increasing row order. Setting ``allow_row_interleaving`` to :data:`True` allows multiple rows to be interleaved in the response stream, which increases throughput but breaks this guarantee, and may force the client to use more memory to buffer partially-received rows. :type limit: int :param limit: (Optional) The read will terminate after committing to N rows' worth of results. The default (zero) is to return all results. Note that if ``allow_row_interleaving`` is set to :data:`True`, partial results may be returned for more than N rows. However, only N ``commit_row`` chunks will be sent. :rtype: :class:`data_messages_pb2.ReadRowsRequest` :returns: The ``ReadRowsRequest`` protobuf corresponding to the inputs. :raises: :class:`ValueError <exceptions.ValueError>` if both ``row_key`` and one of ``start_key`` and ``end_key`` are set """ request_kwargs = {'table_name': table_name} if (row_key is not None and (start_key is not None or end_key is not None)): raise ValueError('Row key and row range cannot be ' 'set simultaneously') if row_key is not None: request_kwargs['row_key'] = _to_bytes(row_key) if start_key is not None or end_key is not None: range_kwargs = {} if start_key is not None: range_kwargs['start_key'] = _to_bytes(start_key) if end_key is not None: range_kwargs['end_key'] = _to_bytes(end_key) row_range = data_pb2.RowRange(**range_kwargs) request_kwargs['row_range'] = row_range if filter_ is not None: request_kwargs['filter'] = filter_.to_pb() if allow_row_interleaving is not None: request_kwargs['allow_row_interleaving'] = allow_row_interleaving if limit is not None: request_kwargs['num_rows_limit'] = limit return data_messages_pb2.ReadRowsRequest(**request_kwargs)
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 _callFUT(self, *args, **kwargs): from gcloud_bigtable._helpers import _to_bytes return _to_bytes(*args, **kwargs)