Source code for gcloud_bigtable.column_family

# Copyright 2015 Google Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""User friendly container for Google Cloud Bigtable Column Family."""


from gcloud_bigtable._generated import bigtable_table_data_pb2 as data_pb2
from gcloud_bigtable._generated import (
    bigtable_table_service_messages_pb2 as messages_pb2)
from gcloud_bigtable._helpers import _duration_pb_to_timedelta
from gcloud_bigtable._helpers import _timedelta_to_duration_pb
from gcloud_bigtable._helpers import make_stub
from gcloud_bigtable.constants import TABLE_ADMIN_HOST
from gcloud_bigtable.constants import TABLE_ADMIN_PORT
from gcloud_bigtable.constants import TABLE_STUB_FACTORY


[docs]class GarbageCollectionRule(object): """Table garbage collection rule. Cells in the table fitting the rule will be deleted during garbage collection. These values can be combined via :class:`GarbageCollectionRuleUnion` and :class:`GarbageCollectionRuleIntersection`. .. note:: At most one of ``max_num_versions`` and ``max_age`` can be specified at once. .. note:: A string ``gc_expression`` can also be used with API requests, but that value would be superceded by a ``gc_rule``. As a result, we don't support that feature and instead support via this native object. :type max_num_versions: integer :param max_num_versions: The maximum number of versions :type max_age: :class:`datetime.timedelta` :param max_age: The maximum age allowed for a cell in the table. :raises: :class:`ValueError` if both ``max_num_versions`` and ``max_age`` are set. """ def __init__(self, max_num_versions=None, max_age=None): if max_num_versions is not None and max_age is not None: raise ValueError('At most one of max_num_versions and ' 'max_age can be set') self.max_num_versions = max_num_versions self.max_age = max_age def __eq__(self, other): if not isinstance(other, self.__class__): return False return (other.max_num_versions == self.max_num_versions and other.max_age == self.max_age) def __ne__(self, other): return not self.__eq__(other)
[docs] def to_pb(self): """Converts the :class:`GarbageCollectionRule` to a protobuf. :rtype: :class:`data_pb2.GcRule` :returns: The converted current object. """ gc_rule_kwargs = {} if self.max_num_versions is not None: gc_rule_kwargs['max_num_versions'] = self.max_num_versions if self.max_age is not None: gc_rule_kwargs['max_age'] = _timedelta_to_duration_pb(self.max_age) return data_pb2.GcRule(**gc_rule_kwargs)
[docs]class GarbageCollectionRuleUnion(object): """Union of garbage collection rules. :type rules: list :param rules: List of garbage collection rules, unions and/or intersections. """ def __init__(self, rules=None): self.rules = rules def __eq__(self, other): if not isinstance(other, self.__class__): return False return other.rules == self.rules def __ne__(self, other): return not self.__eq__(other)
[docs] def to_pb(self): """Converts the union into a single gc rule as a protobuf. :rtype: :class:`data_pb2.GcRule` :returns: The converted current object. """ union = data_pb2.GcRule.Union( rules=[rule.to_pb() for rule in self.rules]) return data_pb2.GcRule(union=union)
[docs]class GarbageCollectionRuleIntersection(object): """Intersection of garbage collection rules. :type rules: list :param rules: List of garbage collection rules, unions and/or intersections. """ def __init__(self, rules=None): self.rules = rules def __eq__(self, other): if not isinstance(other, self.__class__): return False return other.rules == self.rules def __ne__(self, other): return not self.__eq__(other)
[docs] def to_pb(self): """Converts the intersection into a single gc rule as a protobuf. :rtype: :class:`data_pb2.GcRule` :returns: The converted current object. """ intersection = data_pb2.GcRule.Intersection( rules=[rule.to_pb() for rule in self.rules]) return data_pb2.GcRule(intersection=intersection)
[docs]class ColumnFamily(object): """Representation of a Google Cloud Bigtable Column Family. We can use a :class:`ColumnFamily` to: * :meth:`create` itself * :meth:`update` itself * :meth:`delete` itself :type column_family_id: string :param column_family_id: The ID of the column family. :type table: :class:`.table.Table` :param table: The table that owns the column family. :type gc_rule: :class:`GarbageCollectionRule`, :class:`GarbageCollectionRuleUnion` or :class:`GarbageCollectionRuleIntersection` :param gc_rule: (Optional) The garbage collection settings for this column family. """ def __init__(self, column_family_id, table, gc_rule=None): self.column_family_id = column_family_id self._table = table self.gc_rule = gc_rule @property def table(self): """Getter for column family's table. :rtype: :class:`.table.Table` :returns: The table stored on the column family. """ return self._table @property def client(self): """Getter for column family's client. :rtype: :class:`.client.Client` :returns: The client that owns this column family. """ return self.table.client @property def timeout_seconds(self): """Getter for column family's default timeout seconds. :rtype: integer :returns: The timeout seconds default. """ return self.table.timeout_seconds @property def name(self): """Column family name used in requests. .. note:: This property will not change if ``column_family_id`` does not, but the return value is not cached. The table name is of the form ``"projects/../zones/../clusters/../tables/../columnFamilies/.."`` :rtype: string :returns: The column family name. """ return self.table.name + '/columnFamilies/' + self.column_family_id def __eq__(self, other): if not isinstance(other, self.__class__): return False return (other.column_family_id == self.column_family_id and other.gc_rule == self.gc_rule and other.table == self.table) def __ne__(self, other): return not self.__eq__(other)
[docs] def create(self, timeout_seconds=None): """Create this column family. :type timeout_seconds: integer :param timeout_seconds: Number of seconds for request time-out. If not passed, defaults to value set on column family. """ if self.gc_rule is None: column_family = data_pb2.ColumnFamily() else: column_family = data_pb2.ColumnFamily(gc_rule=self.gc_rule.to_pb()) request_pb = messages_pb2.CreateColumnFamilyRequest( name=self.table.name, column_family_id=self.column_family_id, column_family=column_family, ) stub = make_stub(self.client, TABLE_STUB_FACTORY, TABLE_ADMIN_HOST, TABLE_ADMIN_PORT) with stub: timeout_seconds = timeout_seconds or self.timeout_seconds response = stub.CreateColumnFamily.async(request_pb, timeout_seconds) # We expect a `data_pb2.ColumnFamily` response.result()
[docs] def update(self, timeout_seconds=None): """Update this column family. .. note:: The Bigtable Table Admin API currently returns ``BigtableTableService.UpdateColumnFamily is not yet implemented`` when this method is used. It's unclear when this method will actually be supported by the API. :type timeout_seconds: integer :param timeout_seconds: Number of seconds for request time-out. If not passed, defaults to value set on column family. """ request_kwargs = {'name': self.name} if self.gc_rule is not None: request_kwargs['gc_rule'] = self.gc_rule.to_pb() request_pb = data_pb2.ColumnFamily(**request_kwargs) stub = make_stub(self.client, TABLE_STUB_FACTORY, TABLE_ADMIN_HOST, TABLE_ADMIN_PORT) with stub: timeout_seconds = timeout_seconds or self.timeout_seconds response = stub.UpdateColumnFamily.async(request_pb, timeout_seconds) # We expect a `data_pb2.ColumnFamily` response.result()
[docs] def delete(self, timeout_seconds=None): """Delete this column family. :type timeout_seconds: integer :param timeout_seconds: Number of seconds for request time-out. If not passed, defaults to value set on column family. """ request_pb = messages_pb2.DeleteColumnFamilyRequest(name=self.name) stub = make_stub(self.client, TABLE_STUB_FACTORY, TABLE_ADMIN_HOST, TABLE_ADMIN_PORT) with stub: timeout_seconds = timeout_seconds or self.timeout_seconds response = stub.DeleteColumnFamily.async(request_pb, timeout_seconds) # We expect a `._generated.empty_pb2.Empty` response.result()
def _gc_rule_from_pb(gc_rule_pb): """Convert a protobuf GC rule to a Python version. :type gc_rule_pb: :class:`data_pb2.GcRule` :param gc_rule_pb: The GC rule to convert. :rtype: :class:`GarbageCollectionRule`, :class:`GarbageCollectionRuleUnion`, :class:`GarbageCollectionRuleIntersection` or :class:`NoneType` :returns: An instance of one of the native rules defined in :module:`column_family` or ``None`` if no values were set on the protobuf passed in. :raises: :class:`ValueError` if more than one property has been set on the GC rule. """ all_fields = [field.name for field in gc_rule_pb._fields] if len(all_fields) == 0: return None elif len(all_fields) > 1: raise ValueError('At most one field can be set on a GC rule.') field_name = all_fields[0] if field_name == 'max_num_versions': return GarbageCollectionRule( max_num_versions=gc_rule_pb.max_num_versions) elif field_name == 'max_age': max_age = _duration_pb_to_timedelta(gc_rule_pb.max_age) return GarbageCollectionRule(max_age=max_age) elif field_name == 'union': all_rules = gc_rule_pb.union.rules return GarbageCollectionRuleUnion( rules=[_gc_rule_from_pb(rule) for rule in all_rules]) elif field_name == 'intersection': all_rules = gc_rule_pb.intersection.rules return GarbageCollectionRuleIntersection( rules=[_gc_rule_from_pb(rule) for rule in all_rules])