def test_changed(self): """ You can list the columns that have changed on an object """ class Foo(object): a = Property('foo') b = Property() foo = Foo() info = objectInfo(foo) changed = info.changed() self.assertEqual(changed, [], "Nothing has changed yet") foo.a = 'something' self.assertEqual(info.changed(), [Foo.a], "Only Foo.a has changed") foo.b = 'another' self.assertEqual(set(info.changed()), set([Foo.a, Foo.b]), "Both Foo.a and Foo.b have changed") info.resetChangedList() self.assertEqual(info.changed(), [], "Nothing has changed since " "the change list was cleared") foo.b = 'hey' self.assertEqual(info.changed(), [Foo.b])
def test_changed_default(self): """ Specifying a default will be included in the changes """ class Foo(object): a = Property(default_factory=lambda:10) foo = Foo() info = objectInfo(foo) changed = info.changed() self.assertEqual(changed, [Foo.a])
def test_fromDatabase(self): """ Setting a value from the database will mark it as not changed """ class Foo(object): a = Property() b = Property() foo = Foo() foo.a = 'something' Foo.a.fromDatabase(foo, 'another') Foo.b.fromDatabase(foo, 'something') info = objectInfo(foo) self.assertEqual(info.changed(), [], "The attributes should not be " "considered changed because the value came from the " "database")
def insert(self, cursor, obj): """ Insert a row into the database. This function expects to be run in an asynchronous interaction. """ info = objectInfo(obj) cls_info = classInfo(obj) changed = info.changed() # insert insert = [] insert_args = [] if not changed: # no changes insert = ['INSERT INTO %s DEFAULT VALUES' % (cls_info.table,)] else: # changes columns = [] for prop in changed: columns.append(prop.column_name) value = toDB.convert(prop.__class__, prop.toDatabase(obj)) insert_args.append(value) value_placeholders = ['?'] * len(columns) insert = ['INSERT INTO %s (%s) VALUES (%s)' % (cls_info.table, ','.join(columns), ','.join(value_placeholders))] # returning columns = cls_info.columns.keys() returning = ['RETURNING %s' % (','.join(columns),)] sql = ' '.join(insert + returning) args = tuple(insert_args) d = cursor.execute(sql, args) d.addCallback(lambda _: cursor.fetchone()) d.addCallback(self._updateObject, obj) return d
def insert(self, cursor, obj): """ Insert a row into the database. This function expects to be run in an asynchronous interaction. """ info = objectInfo(obj) cls_info = classInfo(obj) changed = info.changed() # insert insert = '' insert_args = [] if not changed: # no changes insert = 'INSERT INTO %s DEFAULT VALUES' % (cls_info.table,) else: # changes columns = [] for prop in changed: columns.append(prop.column_name) value = self.toDB.convert(prop.__class__, prop.toDatabase(obj)) insert_args.append(value) value_placeholders = ['?'] * len(columns) insert = 'INSERT INTO %s (%s) VALUES (%s)' % (cls_info.table, ','.join(columns), ','.join(value_placeholders)) # select columns = cls_info.columns.keys() select = 'SELECT %s FROM %s WHERE rowid=?' % (','.join(columns), cls_info.table) d = cursor.execute(insert, tuple(insert_args)) d.addCallback(lambda _: cursor.lastRowId()) d.addCallback(lambda rowid: cursor.execute(select, (rowid,))) d.addCallback(lambda _: cursor.fetchone()) d.addCallback(self._updateObject, obj) return d