]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- Fixed bug when using joined table inheritance from a table to a
authorMike Bayer <mike_mp@zzzcomputing.com>
Mon, 16 Dec 2013 20:25:48 +0000 (15:25 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Mon, 16 Dec 2013 20:26:19 +0000 (15:26 -0500)
select/alias on the base, where the PK columns were also not same
named; the persistence system would fail to copy primary key values
from the base table to the inherited table upon INSERT.
[ticket:2885]

doc/build/changelog/changelog_08.rst
lib/sqlalchemy/orm/mapper.py
test/orm/inheritance/test_selects.py

index 6ca5a6e6980cf3a779b53ac71cc4f3875c970425..3b30333f2821ba3e23eecf0e709ba41a65e65b93 100644 (file)
 .. changelog::
     :version: 0.8.5
 
+    .. change::
+        :tags: bug, orm
+        :versions: 0.9.0b2
+        :tickets: 2885
+
+        Fixed bug when using joined table inheritance from a table to a
+        select/alias on the base, where the PK columns were also not same
+        named; the persistence system would fail to copy primary key values
+        from the base table to the inherited table upon INSERT.
+
     .. change::
         :tags: bug, orm
         :versions: 0.9.0b2
index 177e31651a223a354f798d91488c16b26446b5c9..e908054fdb0e7f5e961d849d354ada57114d7bab 100644 (file)
@@ -2116,7 +2116,9 @@ class Mapper(_InspectionAttr):
             for m in self.iterate_to_root():
                 if m._inherits_equated_pairs and \
                     cols.intersection(
-                        [l for l, r in m._inherits_equated_pairs]):
+                      util.reduce(set.union,
+                          [l.proxy_set for l, r in m._inherits_equated_pairs])
+                      ):
                     result[table].append((m, m._inherits_equated_pairs))
 
         return result
index dd9c8c8b81ad7af74bf54cb0a9af09dba5a796e2..94f5faf8fa267429551668ecbacae7ed303dd9a7 100644 (file)
-from sqlalchemy import *
-from sqlalchemy.orm import *
+from sqlalchemy import String, Integer, ForeignKey, select
+from sqlalchemy.orm import mapper, Session
 
 from sqlalchemy import testing
 
-from sqlalchemy.testing import fixtures
+from sqlalchemy.testing import fixtures, eq_
+from sqlalchemy.testing.schema import Table, Column
 
 class InheritingSelectablesTest(fixtures.MappedTest):
     @classmethod
     def define_tables(cls, metadata):
-        global foo, bar, baz
         foo = Table('foo', metadata,
                     Column('a', String(30), primary_key=1),
                     Column('b', String(30), nullable=0))
 
-        bar = foo.select(foo.c.b == 'bar').alias('bar')
-        baz = foo.select(foo.c.b == 'baz').alias('baz')
+        cls.tables.bar = foo.select(foo.c.b == 'bar').alias('bar')
+        cls.tables.baz = foo.select(foo.c.b == 'baz').alias('baz')
 
     def test_load(self):
+        foo, bar, baz = self.tables.foo, self.tables.bar, self.tables.baz
         # TODO: add persistence test also
         testing.db.execute(foo.insert(), a='not bar', b='baz')
         testing.db.execute(foo.insert(), a='also not bar', b='baz')
         testing.db.execute(foo.insert(), a='i am bar', b='bar')
         testing.db.execute(foo.insert(), a='also bar', b='bar')
 
-        class Foo(fixtures.ComparableEntity): pass
-        class Bar(Foo): pass
-        class Baz(Foo): pass
+        class Foo(fixtures.ComparableEntity):
+            pass
+        class Bar(Foo):
+            pass
+        class Baz(Foo):
+            pass
 
         mapper(Foo, foo, polymorphic_on=foo.c.b)
 
         mapper(Baz, baz,
-                    with_polymorphic=('*', foo.join(baz, foo.c.b=='baz').alias('baz')),
+                    with_polymorphic=('*', foo.join(baz, foo.c.b == 'baz').alias('baz')),
                     inherits=Foo,
-                    inherit_condition=(foo.c.a==baz.c.a),
+                    inherit_condition=(foo.c.a == baz.c.a),
                     inherit_foreign_keys=[baz.c.a],
                     polymorphic_identity='baz')
 
         mapper(Bar, bar,
-                    with_polymorphic=('*', foo.join(bar, foo.c.b=='bar').alias('bar')),
+                    with_polymorphic=('*', foo.join(bar, foo.c.b == 'bar').alias('bar')),
                     inherits=Foo,
-                    inherit_condition=(foo.c.a==bar.c.a),
+                    inherit_condition=(foo.c.a == bar.c.a),
                     inherit_foreign_keys=[bar.c.a],
                     polymorphic_identity='bar')
 
-        s = sessionmaker(bind=testing.db)()
+        s = Session()
 
         assert [Baz(), Baz(), Bar(), Bar()] == s.query(Foo).order_by(Foo.b.desc()).all()
         assert [Bar(), Bar()] == s.query(Bar).all()
 
+
+class JoinFromSelectPersistenceTest(fixtures.MappedTest):
+    """test for [ticket:2885]"""
+
+    @classmethod
+    def define_tables(cls, metadata):
+        Table('base', metadata,
+                Column('id', Integer, primary_key=True,
+                        test_needs_autoincrement=True),
+                Column('type', String(50))
+            )
+        Table('child', metadata,
+                # 1. name of column must be different, so that we rely on
+                # mapper._table_to_equated to link the two cols
+                Column('child_id', Integer, ForeignKey('base.id'), primary_key=True),
+                Column('name', String(50))
+            )
+
+    @classmethod
+    def setup_classes(cls):
+        class Base(cls.Comparable):
+            pass
+        class Child(Base):
+            pass
+
+    def test_map_to_select(self):
+        Base, Child = self.classes.Base, self.classes.Child
+        base, child = self.tables.base, self.tables.child
+
+        base_select = select([base]).alias()
+        mapper(Base, base_select, polymorphic_on=base_select.c.type,
+                        polymorphic_identity='base')
+        mapper(Child, child, inherits=Base,
+                        polymorphic_identity='child')
+
+        sess = Session()
+
+        # 2. use an id other than "1" here so can't rely on
+        # the two inserts having the same id
+        c1 = Child(id=12, name='c1')
+        sess.add(c1)
+
+        sess.commit()
+        sess.close()
+
+        c1 = sess.query(Child).one()
+        eq_(c1.name, 'c1')