diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2013-12-16 15:25:48 -0500 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2013-12-16 15:25:48 -0500 |
commit | 1d9eb4101365e2c7b8d434fae403aa876ccbef59 (patch) | |
tree | bc2d9cfc7380d9c53e76c182811ec5b5d59e81bf | |
parent | 015e804c4889cac8a0423168ec7036fb5f42fea0 (diff) | |
download | sqlalchemy-1d9eb4101365e2c7b8d434fae403aa876ccbef59.tar.gz |
- 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.
[ticket:2885]
-rw-r--r-- | doc/build/changelog/changelog_08.rst | 10 | ||||
-rw-r--r-- | lib/sqlalchemy/orm/mapper.py | 4 | ||||
-rw-r--r-- | test/orm/inheritance/test_selects.py | 79 |
3 files changed, 78 insertions, 15 deletions
diff --git a/doc/build/changelog/changelog_08.rst b/doc/build/changelog/changelog_08.rst index 2e1bdc9ad..70999ed6a 100644 --- a/doc/build/changelog/changelog_08.rst +++ b/doc/build/changelog/changelog_08.rst @@ -14,6 +14,16 @@ .. 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 :tickets: 2889 :func:`.composite` will raise an informative error message when the diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py index b3b872f38..2d354de54 100644 --- a/lib/sqlalchemy/orm/mapper.py +++ b/lib/sqlalchemy/orm/mapper.py @@ -2488,7 +2488,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 diff --git a/test/orm/inheritance/test_selects.py b/test/orm/inheritance/test_selects.py index dd9c8c8b8..94f5faf8f 100644 --- a/test/orm/inheritance/test_selects.py +++ b/test/orm/inheritance/test_selects.py @@ -1,50 +1,101 @@ -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') |