import testenv; testenv.configure_for_tests() from sqlalchemy import * from sqlalchemy.orm import * from sqlalchemy import exceptions from testlib.fixtures import * from testlib import * """test primary key changing capabilities and passive/non-passive cascading updates.""" class NaturalPKTest(ORMTest): def define_tables(self, metadata): global users, addresses, items, users_to_items users = Table('users', metadata, Column('username', String(50), primary_key=True), Column('fullname', String(100))) addresses = Table('addresses', metadata, Column('email', String(50), primary_key=True), Column('username', String(50), ForeignKey('users.username', onupdate="cascade"))) items = Table('items', metadata, Column('itemname', String(50), primary_key=True), Column('description', String(100))) users_to_items = Table('userstoitems', metadata, Column('username', String(50), ForeignKey('users.username', onupdate='cascade'), primary_key=True), Column('itemname', String(50), ForeignKey('items.itemname', onupdate='cascade'), primary_key=True), ) def test_entity(self): mapper(User, users) sess = create_session() u1 = User(username='jack', fullname='jack') sess.save(u1) sess.flush() assert sess.get(User, 'jack') is u1 u1.username = 'ed' sess.flush() def go(): assert sess.get(User, 'ed') is u1 self.assert_sql_count(testing.db, go, 0) assert sess.get(User, 'jack') is None sess.clear() u1 = sess.query(User).get('ed') self.assertEquals(User(username='ed', fullname='jack'), u1) def test_expiry(self): mapper(User, users) sess = create_session() u1 = User(username='jack', fullname='jack') sess.save(u1) sess.flush() assert sess.get(User, 'jack') is u1 users.update(values={u1.c.username:'jack'}).execute(username='ed') try: # expire/refresh works off of primary key. the PK is gone # in this case so theres no way to look it up. criterion- # based session invalidation could solve this [ticket:911] sess.expire(u1) u1.username assert False except exceptions.InvalidRequestError, e: assert "Could not refresh instance" in str(e) sess.clear() assert sess.get(User, 'jack') is None assert sess.get(User, 'ed').fullname == 'jack' @testing.unsupported('sqlite','mysql') def test_onetomany_passive(self): self._test_onetomany(True) def test_onetomany_nonpassive(self): self._test_onetomany(False) def _test_onetomany(self, passive_updates): mapper(User, users, properties={ 'addresses':relation(Address, passive_updates=passive_updates) }) mapper(Address, addresses) sess = create_session() u1 = User(username='jack', fullname='jack') u1.addresses.append(Address(email='jack1')) u1.addresses.append(Address(email='jack2')) sess.save(u1) sess.flush() assert sess.get(Address, 'jack1') is u1.addresses[0] u1.username = 'ed' sess.flush() assert u1.addresses[0].username == 'ed' sess.clear() self.assertEquals([Address(username='ed'), Address(username='ed')], sess.query(Address).all()) u1 = sess.get(User, 'ed') u1.username = 'jack' def go(): sess.flush() if not passive_updates: self.assert_sql_count(testing.db, go, 4) # test passive_updates=False; load addresses, update user, update 2 addresses else: self.assert_sql_count(testing.db, go, 1) # test passive_updates=True; update user sess.clear() assert User(username='jack', addresses=[Address(username='jack'), Address(username='jack')]) == sess.get(User, 'jack') u1 = sess.get(User, 'jack') u1.addresses = [] u1.username = 'fred' sess.flush() sess.clear() assert sess.get(Address, 'jack1').username is None u1 = sess.get(User, 'fred') self.assertEquals(User(username='fred', fullname='jack'), u1) @testing.unsupported('sqlite', 'mysql') def test_manytoone_passive(self): self._test_manytoone(True) def test_manytoone_nonpassive(self): self._test_manytoone(False) def _test_manytoone(self, passive_updates): mapper(User, users) mapper(Address, addresses, properties={ 'user':relation(User, passive_updates=passive_updates) }) sess = create_session() a1 = Address(email='jack1') a2 = Address(email='jack2') u1 = User(username='jack', fullname='jack') a1.user = u1 a2.user = u1 sess.save(a1) sess.save(a2) sess.flush() u1.username = 'ed' print id(a1), id(a2), id(u1) print u1._state.parents def go(): sess.flush() if passive_updates: self.assert_sql_count(testing.db, go, 1) else: self.assert_sql_count(testing.db, go, 3) def go(): sess.flush() self.assert_sql_count(testing.db, go, 0) assert a1.username == a2.username == 'ed' sess.clear() self.assertEquals([Address(username='ed'), Address(username='ed')], sess.query(Address).all()) @testing.unsupported('sqlite', 'mysql') def test_bidirectional_passive(self): self._test_bidirectional(True) def test_bidirectional_nonpassive(self): self._test_bidirectional(False) def _test_bidirectional(self, passive_updates): mapper(User, users) mapper(Address, addresses, properties={ 'user':relation(User, passive_updates=passive_updates, backref='addresses') }) sess = create_session() a1 = Address(email='jack1') a2 = Address(email='jack2') u1 = User(username='jack', fullname='jack') a1.user = u1 a2.user = u1 sess.save(a1) sess.save(a2) sess.flush() u1.username = 'ed' (ad1, ad2) = sess.query(Address).all() self.assertEquals([Address(username='jack'), Address(username='jack')], [ad1, ad2]) def go(): sess.flush() if passive_updates: self.assert_sql_count(testing.db, go, 1) else: self.assert_sql_count(testing.db, go, 3) self.assertEquals([Address(username='ed'), Address(username='ed')], [ad1, ad2]) sess.clear() self.assertEquals([Address(username='ed'), Address(username='ed')], sess.query(Address).all()) u1 = sess.get(User, 'ed') assert len(u1.addresses) == 2 # load addresses u1.username = 'fred' print "--------------------------------" def go(): sess.flush() # check that the passive_updates is on on the other side if passive_updates: self.assert_sql_count(testing.db, go, 1) else: self.assert_sql_count(testing.db, go, 3) sess.clear() self.assertEquals([Address(username='fred'), Address(username='fred')], sess.query(Address).all()) @testing.unsupported('sqlite', 'mysql') def test_manytomany_passive(self): self._test_manytomany(True) def test_manytomany_nonpassive(self): self._test_manytomany(False) def _test_manytomany(self, passive_updates): mapper(User, users, properties={ 'items':relation(Item, secondary=users_to_items, backref='users', passive_updates=passive_updates) }) mapper(Item, items) sess = create_session() u1 = User(username='jack') u2 = User(username='fred') i1 = Item(itemname='item1') i2 = Item(itemname='item2') u1.items.append(i1) u1.items.append(i2) i2.users.append(u2) sess.save(u1) sess.save(u2) sess.flush() r = sess.query(Item).all() # fixtures.Base can't handle a comparison with the backrefs involved.... self.assertEquals(Item(itemname='item1'), r[0]) self.assertEquals(['jack'], [u.username for u in r[0].users]) self.assertEquals(Item(itemname='item2'), r[1]) self.assertEquals(['jack', 'fred'], [u.username for u in r[1].users]) u2.username='ed' def go(): sess.flush() go() def go(): sess.flush() self.assert_sql_count(testing.db, go, 0) sess.clear() r = sess.query(Item).all() self.assertEquals(Item(itemname='item1'), r[0]) self.assertEquals(['jack'], [u.username for u in r[0].users]) self.assertEquals(Item(itemname='item2'), r[1]) self.assertEquals(['ed', 'jack'], sorted([u.username for u in r[1].users])) class SelfRefTest(ORMTest): def define_tables(self, metadata): global nodes, Node nodes = Table('nodes', metadata, Column('name', String(50), primary_key=True), Column('parent', String(50), ForeignKey('nodes.name', onupdate='cascade')) ) class Node(Base): pass def test_onetomany(self): mapper(Node, nodes, properties={ 'children':relation(Node, backref=backref('parentnode', remote_side=nodes.c.name, passive_updates=False), passive_updates=False) }) sess = create_session() n1 = Node(name='n1') n1.children.append(Node(name='n11')) n1.children.append(Node(name='n12')) n1.children.append(Node(name='n13')) sess.save(n1) sess.flush() n1.name = 'new n1' sess.flush() self.assertEquals(n1.children[1].parent, 'new n1') self.assertEquals(['new n1', 'new n1', 'new n1'], [n.parent for n in sess.query(Node).filter(Node.name.in_(['n11', 'n12', 'n13']))]) class NonPKCascadeTest(ORMTest): def define_tables(self, metadata): global users, addresses users = Table('users', metadata, Column('id', Integer, primary_key=True), Column('username', String(50), unique=True), Column('fullname', String(100))) addresses = Table('addresses', metadata, Column('id', Integer, primary_key=True), Column('email', String(50)), Column('username', String(50), ForeignKey('users.username', onupdate="cascade"))) @testing.unsupported('sqlite','mysql') def test_onetomany_passive(self): self._test_onetomany(True) def test_onetomany_nonpassive(self): self._test_onetomany(False) def _test_onetomany(self, passive_updates): mapper(User, users, properties={ 'addresses':relation(Address, passive_updates=passive_updates) }) mapper(Address, addresses) sess = create_session() u1 = User(username='jack', fullname='jack') u1.addresses.append(Address(email='jack1')) u1.addresses.append(Address(email='jack2')) sess.save(u1) sess.flush() a1 = u1.addresses[0] self.assertEquals(select([addresses.c.username]).execute().fetchall(), [('jack',), ('jack',)]) assert sess.get(Address, a1.id) is u1.addresses[0] u1.username = 'ed' sess.flush() assert u1.addresses[0].username == 'ed' self.assertEquals(select([addresses.c.username]).execute().fetchall(), [('ed',), ('ed',)]) sess.clear() self.assertEquals([Address(username='ed'), Address(username='ed')], sess.query(Address).all()) u1 = sess.get(User, u1.id) u1.username = 'jack' def go(): sess.flush() if not passive_updates: self.assert_sql_count(testing.db, go, 4) # test passive_updates=False; load addresses, update user, update 2 addresses else: self.assert_sql_count(testing.db, go, 1) # test passive_updates=True; update user sess.clear() assert User(username='jack', addresses=[Address(username='jack'), Address(username='jack')]) == sess.get(User, u1.id) sess.clear() u1 = sess.get(User, u1.id) u1.addresses = [] u1.username = 'fred' sess.flush() sess.clear() a1 = sess.get(Address, a1.id) self.assertEquals(a1.username, None) self.assertEquals(select([addresses.c.username]).execute().fetchall(), [(None,), (None,)]) u1 = sess.get(User, u1.id) self.assertEquals(User(username='fred', fullname='jack'), u1) if __name__ == '__main__': testenv.main()