예제 #1
0
    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)
예제 #2
0
    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)
예제 #3
0
    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
예제 #5
0
    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)
예제 #6
0
    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)
예제 #7
0
    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)
예제 #8
0
 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 = []
예제 #9
0
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')
예제 #10
0
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)
예제 #11
0
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)
예제 #12
0
    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)