Commits

Mike Bayer committed 472cfef

- Fixed bug which prevented "mutable primary key" dependency
logic from functioning properly on a one-to-one
relation(). [ticket:1406]
- moved MySQL to use innodb for naturalpks tests

  • Participants
  • Parent commits 911ed16

Comments (0)

Files changed (4)

     - Fixed another location where autoflush was interfering
       with session.merge().  autoflush is disabled completely
       for the duration of merge() now. [ticket:1360]
-
+    
+    - Fixed bug which prevented "mutable primary key" dependency
+      logic from functioning properly on a one-to-one
+      relation().  [ticket:1406]
+      
     - Fixed bug in relation(), introduced in 0.5.3, 
       whereby a self referential relation
       from a base class to a joined-table subclass would 

File lib/sqlalchemy/orm/dependency.py

                     if not history:
                         history = uowcommit.get_attribute_history(state, self.key, passive=False)
                     for child in history.unchanged:
-                        uowcommit.register_object(child)
+                        if child is not None:
+                            uowcommit.register_object(child)
 
     def _synchronize(self, state, child, associationrow, clearkeys, uowcommit):
         source = state

File test/orm/naturalpks.py

     def define_tables(self, metadata):
         users = Table('users', metadata,
             Column('username', String(50), primary_key=True),
-            Column('fullname', String(100)))
+            Column('fullname', String(100)),
+            test_needs_fk=True)
 
         addresses = Table('addresses', metadata,
             Column('email', String(50), primary_key=True),
-            Column('username', String(50), ForeignKey('users.username', onupdate="cascade")))
+            Column('username', String(50), ForeignKey('users.username', onupdate="cascade")),
+            test_needs_fk=True)
 
         items = Table('items', metadata,
             Column('itemname', String(50), primary_key=True),
-            Column('description', String(100)))
+            Column('description', String(100)), 
+            test_needs_fk=True)
 
         users_to_items = Table('users_to_items', 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),
-        )
+            test_needs_fk=True)
 
     def setup_classes(self):
         class User(_base.ComparableEntity):
         assert sess.query(User).get('ed').fullname == 'jack'
         
 
-    @testing.fails_on('mysql', 'FIXME: unknown')
-    @testing.fails_on('sqlite', 'FIXME: unknown')
+    @testing.fails_on('sqlite', 'sqlite doesnt support ON UPDATE CASCADE')
     def test_onetomany_passive(self):
         self._test_onetomany(True)
 
         self.assertEquals(User(username='fred', fullname='jack'), u1)
         
 
-    @testing.fails_on('sqlite', 'FIXME: unknown')
-    @testing.fails_on('mysql', 'FIXME: unknown')
+    @testing.fails_on('sqlite', 'sqlite doesnt support ON UPDATE CASCADE')
     def test_manytoone_passive(self):
         self._test_manytoone(True)
 
 
         u1.username = 'ed'
 
-        print id(a1), id(a2), id(u1)
-        print sa.orm.attributes.instance_state(u1).parents
         def go():
             sess.flush()
         if passive_updates:
         sess.expunge_all()
         self.assertEquals([Address(username='ed'), Address(username='ed')], sess.query(Address).all())
 
-    @testing.fails_on('sqlite', 'FIXME: unknown')
-    @testing.fails_on('mysql', 'FIXME: unknown')
+    @testing.fails_on('sqlite', 'sqlite doesnt support ON UPDATE CASCADE')
+    def test_onetoone_passive(self):
+        self._test_onetoone(True)
+
+    def test_onetoone_nonpassive(self):
+        self._test_onetoone(False)
+
+    @testing.resolve_artifact_names
+    def _test_onetoone(self, passive_updates):
+        mapper(User, users, properties={
+            "address":relation(Address, passive_updates=passive_updates, uselist=False)
+        })
+        mapper(Address, addresses)
+
+        sess = create_session()
+        u1 = User(username='jack', fullname='jack')
+        sess.add(u1)
+        sess.flush()
+        
+        a1 = Address(email='jack1')
+        u1.address = a1
+        sess.add(a1)
+        sess.flush()
+        
+        u1.username = 'ed'
+
+        def go():
+            sess.flush()
+        if passive_updates:
+            self.assert_sql_count(testing.db, go, 1)
+        else:
+            self.assert_sql_count(testing.db, go, 2)
+
+        def go():
+            sess.flush()
+        self.assert_sql_count(testing.db, go, 0)
+
+        assert a1.username == 'ed'
+        sess.expunge_all()
+        self.assertEquals([Address(username='ed')], sess.query(Address).all())
+        
+    @testing.fails_on('sqlite', 'sqlite doesnt support ON UPDATE CASCADE')
     def test_bidirectional_passive(self):
         self._test_bidirectional(True)
 
         self.assertEquals([Address(username='fred'), Address(username='fred')], sess.query(Address).all())
 
 
-    @testing.fails_on('sqlite', 'FIXME: unknown')
-    @testing.fails_on('mysql', 'FIXME: unknown')
+    @testing.fails_on('sqlite', 'sqlite doesnt support ON UPDATE CASCADE')
     def test_manytomany_passive(self):
         self._test_manytomany(True)
 
+    @testing.fails_on('mysql', 'the executemany() of the association table fails to report the correct row count')
     def test_manytomany_nonpassive(self):
         self._test_manytomany(False)
 
         class Address(_base.ComparableEntity):
             pass
 
-    @testing.fails_on('sqlite', 'FIXME: unknown')
-    @testing.fails_on('mysql', 'FIXME: unknown')
+    @testing.fails_on('sqlite', 'sqlite doesnt support ON UPDATE CASCADE')
     def test_onetomany_passive(self):
         self._test_onetomany(True)
 

File test/orm/onetoone.py

 import testenv; testenv.configure_for_tests()
 from testlib import sa, testing
 from testlib.sa import Table, Column, Integer, String, ForeignKey
-from testlib.sa.orm import mapper, relation
+from testlib.sa.orm import mapper, relation, create_session
 from orm import _base
 
 
               Column('description', String(100)),
               Column('jack_id', Integer, ForeignKey("jack.id")))
 
+    @testing.resolve_artifact_names
     def setup_mappers(self):
         class Jack(_base.BasicEntity):
             pass
         class Port(_base.BasicEntity):
             pass
 
+
     @testing.resolve_artifact_names
-    def test_1(self):
-        ctx = sa.orm.scoped_session(sa.orm.create_session)
-
-        mapper(Port, port, extension=ctx.extension)
+    def test_basic(self):
+        mapper(Port, port)
         mapper(Jack, jack,
                order_by=[jack.c.number],
                properties=dict(
                    port=relation(Port, backref='jack',
-                                 uselist=False, lazy=True)),
-               extension=ctx.extension)
+                                 uselist=False,
+                                 )),
+               )
+
+        session = create_session()
 
         j = Jack(number='101')
+        session.add(j)
         p = Port(name='fa0/1')
+        session.add(p)
+        
         j.port=p
-        ctx.flush()
+        session.flush()
         jid = j.id
         pid = p.id
 
-        j=ctx.query(Jack).get(jid)
-        p=ctx.query(Port).get(pid)
+        j=session.query(Jack).get(jid)
+        p=session.query(Port).get(pid)
         assert p.jack is not None
         assert p.jack is  j
         assert j.port is not None
         p.jack = None
         assert j.port is None
 
-        ctx.expunge_all()
+        session.expunge_all()
 
-        j = ctx.query(Jack).get(jid)
-        p = ctx.query(Port).get(pid)
+        j = session.query(Jack).get(jid)
+        p = session.query(Port).get(pid)
 
         j.port=None
         self.assert_(p.jack is None)
-        ctx.flush()
+        session.flush()
 
-        ctx.delete(j)
-        ctx.flush()
+        session.delete(j)
+        session.flush()
 
 if __name__ == "__main__":
     testenv.main()