# Copyright DataStax, Inc. # # 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. from cassandra.util import OrderedDict from cassandra.cqlengine import CQLEngineException from cassandra.cqlengine.columns import Column from cassandra.cqlengine.connection import get_cluster from cassandra.cqlengine.models import UsingDescriptor, BaseModel from cassandra.cqlengine.query import AbstractQueryableColumn, SimpleQuerySet from cassandra.cqlengine.query import DoesNotExist as _DoesNotExist from cassandra.cqlengine.query import MultipleObjectsReturned as _MultipleObjectsReturned class QuerySetDescriptor(object): """ returns a fresh queryset for the given model it's declared on everytime it's accessed """ def __get__(self, obj, model): """ :rtype: ModelQuerySet """ if model.__abstract__: raise CQLEngineException('cannot execute queries against abstract models') return SimpleQuerySet(obj) def __call__(self, *args, **kwargs): """ Just a hint to IDEs that it's ok to call this :rtype: ModelQuerySet """ raise NotImplementedError class NamedColumn(AbstractQueryableColumn): """ A column that is not coupled to a model class, or type """ def __init__(self, name): self.name = name def __unicode__(self): return self.name def _get_column(self): """ :rtype: NamedColumn """ return self @property def db_field_name(self): return self.name @property def cql(self): return self.get_cql() def get_cql(self): return '"{0}"'.format(self.name) def to_database(self, val): return val class NamedTable(object): """ A Table that is not coupled to a model class """ __abstract__ = False objects = QuerySetDescriptor() __partition_keys = None _partition_key_index = None __connection__ = None _connection = None using = UsingDescriptor() _get_connection = BaseModel._get_connection class DoesNotExist(_DoesNotExist): pass class MultipleObjectsReturned(_MultipleObjectsReturned): pass def __init__(self, keyspace, name): self.keyspace = keyspace self.name = name self._connection = None @property def _partition_keys(self): if not self.__partition_keys: self._get_partition_keys() return self.__partition_keys def _get_partition_keys(self): try: table_meta = get_cluster(self._get_connection()).metadata.keyspaces[self.keyspace].tables[self.name] self.__partition_keys = OrderedDict((pk.name, Column(primary_key=True, partition_key=True, db_field=pk.name)) for pk in table_meta.partition_key) except Exception as e: raise CQLEngineException("Failed inspecting partition keys for {0}." "Ensure cqlengine is connected before attempting this with NamedTable.".format(self.column_family_name())) def column(self, name): return NamedColumn(name) def column_family_name(self, include_keyspace=True): """ Returns the column family name if it's been defined otherwise, it creates it from the module and class name """ if include_keyspace: return '{0}.{1}'.format(self.keyspace, self.name) else: return self.name def _get_column(self, name): """ Returns the column matching the given name :rtype: Column """ return self.column(name) # def create(self, **kwargs): # return self.objects.create(**kwargs) def all(self): return self.objects.all() def filter(self, *args, **kwargs): return self.objects.filter(*args, **kwargs) def get(self, *args, **kwargs): return self.objects.get(*args, **kwargs) class NamedKeyspace(object): """ A keyspace """ def __init__(self, name): self.name = name def table(self, name): """ returns a table descriptor with the given name that belongs to this keyspace """ return NamedTable(self.name, name)