def test_where_clause_rendering(self): """ tests that where clauses are rendered properly """ wc = WhereClause('a', EqualsOperator(), 'c') wc.set_context_id(5) self.assertEqual('"a" = %(5)s', six.text_type(wc), six.text_type(wc)) self.assertEqual('"a" = %(5)s', str(wc), type(wc))
def test_mintimeuuid_function(self): """ Tests that queries with helper functions are generated properly """ now = datetime.now() where = WhereClause('time', EqualsOperator(), functions.MinTimeUUID(now)) where.set_context_id(5) self.assertEqual(str(where), '"time" = MinTimeUUID(%(5)s)') ctx = {} where.update_context(ctx) self.assertEqual(ctx, {'5': columns.DateTime().to_database(now)})
def test_operator_check(self): """ tests that creating a where statement with a non BaseWhereOperator object fails """ with self.assertRaises(StatementException): WhereClause('a', 'b', 'c')
def contains_(self, item): """ Returns a CONTAINS operator """ return WhereClause(six.text_type(self), ContainsOperator(), item)
def __eq__(self, other): return WhereClause(six.text_type(self), EqualsOperator(), self._to_database(other))
def update(self): """ updates a row. This is a blind update call. All validation and cleaning needs to happen prior to calling this. """ if self.instance is None: raise CQLEngineException("DML Query intance attribute is None") assert type(self.instance) == self.model null_clustering_key = False if len( self.instance._clustering_keys) == 0 else True static_changed_only = True statement = UpdateStatement(self.column_family_name, ttl=self._ttl, timestamp=self._timestamp, transactions=self._transaction) for name, col in self.instance._clustering_keys.items(): null_clustering_key = null_clustering_key and col._val_is_null( getattr(self.instance, name, None)) # get defined fields and their column names for name, col in self.model._columns.items(): # if clustering key is null, don't include non static columns if null_clustering_key and not col.static and not col.partition_key: continue if not col.is_primary_key: val = getattr(self.instance, name, None) val_mgr = self.instance._values[name] if val is None: continue if not val_mgr.changed and not isinstance( col, columns.Counter): continue static_changed_only = static_changed_only and col.static if isinstance(col, (columns.BaseContainerColumn, columns.Counter)): # get appropriate clause if isinstance(col, columns.List): klass = ListUpdateClause elif isinstance(col, columns.Map): klass = MapUpdateClause elif isinstance(col, columns.Set): klass = SetUpdateClause elif isinstance(col, columns.Counter): klass = CounterUpdateClause else: raise RuntimeError clause = klass(col.db_field_name, val, previous=val_mgr.previous_value, column=col) if clause.get_context_size() > 0: statement.add_assignment_clause(clause) else: statement.add_assignment_clause( AssignmentClause(col.db_field_name, col.to_database(val))) if statement.get_context_size() > 0 or self.instance._has_counter: for name, col in self.model._primary_keys.items(): # only include clustering key if clustering key is not null, and non static columns are changed to avoid cql error if (null_clustering_key or static_changed_only) and (not col.partition_key): continue statement.add_where_clause( WhereClause(col.db_field_name, EqualsOperator(), col.to_database(getattr(self.instance, name)))) self._execute(statement) if not null_clustering_key: self._delete_null_columns()
def filter(self, *args, **kwargs): """ Adds WHERE arguments to the queryset, returning a new queryset See :ref:`retrieving-objects-with-filters` Returns a QuerySet filtered on the keyword arguments """ # add arguments to the where clause filters if len([x for x in kwargs.values() if x is None]): raise CQLEngineException("None values on filter are not allowed") clone = copy.deepcopy(self) for operator in args: if not isinstance(operator, WhereClause): raise QueryException( '{0} is not a valid query operator'.format(operator)) clone._where.append(operator) for arg, val in kwargs.items(): col_name, col_op = self._parse_filter_arg(arg) quote_field = True # resolve column and operator try: column = self.model._get_column(col_name) except KeyError: if col_name == 'pk__token': if not isinstance(val, Token): raise QueryException( "Virtual column 'pk__token' may only be compared to Token() values" ) column = columns._PartitionKeysToken(self.model) quote_field = False else: raise QueryException( "Can't resolve column name: '{0}'".format(col_name)) if isinstance(val, Token): if col_name != 'pk__token': raise QueryException( "Token() values may only be compared to the 'pk__token' virtual column" ) partition_columns = column.partition_columns if len(partition_columns) != len(val.value): raise QueryException( 'Token() received {0} arguments but model has {1} partition keys' .format(len(val.value), len(partition_columns))) val.set_columns(partition_columns) # get query operator, or use equals if not supplied operator_class = BaseWhereOperator.get_operator(col_op or 'EQ') operator = operator_class() if isinstance(operator, InOperator): if not isinstance(val, (list, tuple)): raise QueryException( 'IN queries must use a list/tuple value') query_val = [column.to_database(v) for v in val] elif isinstance(val, BaseQueryFunction): query_val = val elif (isinstance(operator, ContainsOperator) and isinstance(column, (columns.List, columns.Set, columns.Map))): # For ContainsOperator and collections, we query using the value, not the container query_val = val else: query_val = column.to_database(val) clone._where.append( WhereClause(column.db_field_name, operator, query_val, quote_field=quote_field)) return clone
def __gt__(self, other): return WhereClause(six.text_type(self), GreaterThanOperator(), self._to_database(other))
def __le__(self, other): return WhereClause(six.text_type(self), LessThanOrEqualOperator(), self._to_database(other))
def test_where_clause_rendering(self): ds = DeleteStatement('table', None) ds.add_where_clause(WhereClause('a', EqualsOperator(), 'b')) self.assertEqual(six.text_type(ds), 'DELETE FROM table WHERE "a" = %(0)s', six.text_type(ds))
def test_context(self): ds = DeleteStatement('table', None) ds.add_where_clause(WhereClause('a', EqualsOperator(), 'b')) self.assertEqual(ds.get_context(), {'0': 'b'})
def test_context(self): ss = SelectStatement('table') ss.add_where_clause(WhereClause('a', EqualsOperator(), 'b')) self.assertEqual(ss.get_context(), {'0': 'b'})
def test_count(self): ss = SelectStatement('table', count=True, limit=10, order_by='d') ss.add_where_clause(WhereClause('a', EqualsOperator(), 'b')) self.assertEqual(six.text_type(ss), 'SELECT COUNT(*) FROM table WHERE "a" = %(0)s LIMIT 10', six.text_type(ss)) self.assertIn('LIMIT', six.text_type(ss)) self.assertNotIn('ORDER', six.text_type(ss))
def test_where_clause_rendering(self): ss = SelectStatement('table') ss.add_where_clause(WhereClause('a', EqualsOperator(), 'b')) self.assertEqual(six.text_type(ss), 'SELECT * FROM table WHERE "a" = %(0)s', six.text_type(ss))
def test_additional_rendering(self): us = UpdateStatement('table', ttl=60) us.add_assignment_clause(AssignmentClause('a', 'b')) us.add_where_clause(WhereClause('a', EqualsOperator(), 'x')) self.assertIn('USING TTL 60', six.text_type(us))
def test_context(self): us = UpdateStatement('table') us.add_assignment_clause(AssignmentClause('a', 'b')) us.add_assignment_clause(AssignmentClause('c', 'd')) us.add_where_clause(WhereClause('a', EqualsOperator(), 'x')) self.assertEqual(us.get_context(), {'0': 'b', '1': 'd', '2': 'x'})