def save(self): """ Creates / updates a row. This is a blind insert 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 nulled_fields = set() if self.instance._has_counter or self.instance._can_update(): return self.update() else: insert = InsertStatement(self.column_family_name, ttl=self._ttl, timestamp=self._timestamp, if_not_exists=self._if_not_exists) for name, col in self.instance._columns.items(): val = getattr(self.instance, name, None) if col._val_is_null(val): if self.instance._values[name].changed: nulled_fields.add(col.db_field_name) continue insert.add_assignment_clause(AssignmentClause( col.db_field_name, col.to_database(getattr(self.instance, name, None)) )) # skip query execution if it's empty # caused by pointless update queries if not insert.is_empty: self._execute(insert) # delete any nulled columns self._delete_null_columns()
def save(self): """ Creates / updates a row. This is a blind insert 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 nulled_fields = set() if self.instance._has_counter or self.instance._can_update(): return self.update() else: insert = InsertStatement(self.column_family_name, ttl=self._ttl, timestamp=self._timestamp) for name, col in self.instance._columns.items(): val = getattr(self.instance, name, None) if col._val_is_null(val): if self.instance._values[name].changed: nulled_fields.add(col.db_field_name) continue insert.add_assignment_clause(AssignmentClause( col.db_field_name, col.to_database(getattr(self.instance, name, None)) )) # skip query execution if it's empty # caused by pointless update queries if not insert.is_empty: self._execute(insert) # delete any nulled columns self._delete_null_columns()
def test_statement(self): ist = InsertStatement('table', None) ist.add_assignment_clause(AssignmentClause('a', 'b')) ist.add_assignment_clause(AssignmentClause('c', 'd')) self.assertEqual( unicode(ist), 'INSERT INTO table ("a", "c") VALUES (%(0)s, %(1)s)' )
def test_statement(self): ist = InsertStatement('table', None) ist.add_assignment_clause(AssignmentClause('a', 'b')) ist.add_assignment_clause(AssignmentClause('c', 'd')) self.assertEqual( six.text_type(ist), 'INSERT INTO table ("a", "c") VALUES (%(0)s, %(1)s)' )
def test_context_update(self): ist = InsertStatement('table', None) ist.add_assignment_clause(AssignmentClause('a', 'b')) ist.add_assignment_clause(AssignmentClause('c', 'd')) ist.update_context_id(4) self.assertEqual( unicode(ist), 'INSERT INTO table ("a", "c") VALUES (%(4)s, %(5)s)' ) ctx = ist.get_context() self.assertEqual(ctx, {'4': 'b', '5': 'd'})
def test_context_update(self): ist = InsertStatement('table', None) ist.add_assignment_clause(AssignmentClause('a', 'b')) ist.add_assignment_clause(AssignmentClause('c', 'd')) ist.update_context_id(4) self.assertEqual( six.text_type(ist), 'INSERT INTO table ("a", "c") VALUES (%(4)s, %(5)s)' ) ctx = ist.get_context() self.assertEqual(ctx, {'4': 'b', '5': 'd'})
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): ist = InsertStatement('table', ttl=60) ist.add_assignment_clause(AssignmentClause('a', 'b')) ist.add_assignment_clause(AssignmentClause('c', 'd')) self.assertIn('USING TTL 60', unicode(ist))
def test_additional_rendering(self): ist = InsertStatement('table', ttl=60) ist.add_assignment_clause(AssignmentClause('a', 'b')) ist.add_assignment_clause(AssignmentClause('c', 'd')) self.assertIn('USING TTL 60', six.text_type(ist))