summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2013-12-16 15:25:48 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2013-12-16 15:25:48 -0500
commit1d9eb4101365e2c7b8d434fae403aa876ccbef59 (patch)
treebc2d9cfc7380d9c53e76c182811ec5b5d59e81bf
parent015e804c4889cac8a0423168ec7036fb5f42fea0 (diff)
downloadsqlalchemy-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.rst10
-rw-r--r--lib/sqlalchemy/orm/mapper.py4
-rw-r--r--test/orm/inheritance/test_selects.py79
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')