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 static_update_only = True statement = UpdateStatement(self.column_family_name, ttl=self._ttl, timestamp=self._timestamp, transactions=self._transaction) #get defined fields and their column names for name, col in self.model._columns.items(): if not col.is_primary_key: val = getattr(self.instance, name, None) val_mgr = self.instance._values[name] # don't update something that is null if val is None: continue # don't update something if it hasn't changed if not val_mgr.changed and not isinstance(col, Counter): continue static_update_only = (static_update_only and col.static) if isinstance(col, (BaseContainerColumn, Counter)): # get appropriate clause if isinstance(col, List): klass = ListUpdateClause elif isinstance(col, Map): klass = MapUpdateClause elif isinstance(col, Set): klass = SetUpdateClause elif isinstance(col, Counter): klass = CounterUpdateClause else: raise RuntimeError # do the stuff 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(): if static_update_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) self._delete_null_columns()
def test_context_update(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")) us.update_context_id(3) self.assertEqual(unicode(us), 'UPDATE table SET "a" = :4, "c" = :5 WHERE "a" = :3') self.assertEqual(us.get_context(), {"4": "b", "5": "d", "3": "x"})
def test_context_update(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')) us.update_context_id(3) self.assertEqual(six.text_type(us), 'UPDATE table SET "a" = %(4)s, "c" = %(5)s WHERE "a" = %(3)s') self.assertEqual(us.get_context(), {'4': 'b', '5': 'd', '3': 'x'})
def test_rendering(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( six.text_type(us), 'UPDATE table SET "a" = %(0)s, "c" = %(1)s WHERE "a" = %(2)s', six.text_type(us))
def test_context_update(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')) us.update_context_id(3) self.assertEqual( six.text_type(us), 'UPDATE table SET "a" = %(4)s, "c" = %(5)s WHERE "a" = %(3)s') self.assertEqual(us.get_context(), {'4': 'b', '5': 'd', '3': 'x'})
def save(self, *objects): """Flush all pending changes to Cassandra. objects -- if not None, only operate on this or these object(s) """ updates = set() counter_updates = set() creates = set() counter_creates = set() for model_class, by_key in self.instances_by_class.iteritems(): for key, instance in by_key.iteritems(): if hasattr(instance, '_created') and instance._created: if model_class.id_mapped_class._has_counter: counter_creates.add(instance) else: creates.add(instance) elif hasattr(instance, '_dirties'): if model_class.id_mapped_class._has_counter: counter_updates.add(instance) else: updates.add(instance) if objects: updates = updates and objects counter_updates = counter_updates and objects creates = creates and objects counter_creates = counter_creates and objects with BatchQuery() as batch: for create in creates: # Note we skip a lot of cqlengine code and create the # insert statement directly. # (this is the non-optimized code that is replaced below) #key_names = create.id_mapped_class._columns.keys() #arg = {name: getattr(create, name) for name in key_names} #create.id_mapped_class.batch(batch).create(**arg) # (end non-optimized code) # (begin optimized) # note: it might save time to memoize column family name # note: cqlengine-session doesn't yet support 'ttl' insert = InsertStatement(create.id_mapped_class.column_family_name())#, ttl=self._ttl) for name, col in create.id_mapped_class._columns.items(): val = col.validate(getattr(create, name)) if col._val_is_null(val): continue insert.add_assignment_clause(AssignmentClause( col.db_field_name, col.to_database(val))) # skip query execution if it's empty # caused by pointless update queries if not insert.is_empty: batch.add_query(insert) # (end optimized) del create._created try: del create._dirties except AttributeError: pass for update in updates: key_names = update._primary_keys.keys() arg = {name: getattr(update, name) for name in key_names} dirties = update._dirties update.id_mapped_class.objects(**arg).batch(batch).update(**dirties) del update._dirties # It would seem that batch does not work with counter? #with BatchQuery() as batch: for create in counter_creates: primary_key_names = create.id_mapped_class._primary_keys.keys() arg = {name: getattr(create, name) for name in primary_key_names} instance = create.id_mapped_class.create(**arg) for name, col in create.id_mapped_class._columns.items(): if isinstance(col, columns.Counter): val = getattr(create, name) setattr(instance, name, val) del create._created try: del create._dirties except AttributeError: pass instance.update() for update in counter_updates: statement = UpdateStatement(update.id_mapped_class.column_family_name())#, ttl=self._ttl) for name, value in update._dirties.items(): col = update.id_mapped_class._columns[name] clause = CounterUpdateClause(col.db_field_name, value, 0, column=col) statement.add_assignment_clause(clause) for name, col in update.id_mapped_class._primary_keys.items(): statement.add_where_clause(WhereClause( col.db_field_name, EqualsOperator(), col.to_database(getattr(update, name)) )) params = statement.get_context() statement = SimpleStatement(str(statement)) cqlengine.connection.get_session().execute(statement, params) del update._dirties # for delete in self.deletes: # raise NotImplementedError for callable, args, kwargs in self.call_after_save: callable(*args, **kwargs) self.call_after_save = []
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", unicode(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"})
def test_rendering(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(unicode(us), 'UPDATE table SET "a" = :0, "c" = :1 WHERE "a" = :2', unicode(us))
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'})
def test_rendering(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(six.text_type(us), 'UPDATE table SET "a" = %(0)s, "c" = %(1)s WHERE "a" = %(2)s', six.text_type(us))
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'})