From: Mike Bayer Date: Sat, 7 May 2011 15:26:00 +0000 (-0400) Subject: - Fixed bug where determination of "self referential" X-Git-Tag: rel_0_7_0~19 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4292c5621973c70b7856a9e32f7173da88572613;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - Fixed bug where determination of "self referential" relationship would fail with no workaround for joined-inh subclass related to itself, or joined-inh subclass related to a subclass of that with no cols in the sub-sub class in the join condition. [ticket:2149] Also in 0.6.8. --- diff --git a/CHANGES b/CHANGES index 11ad730da0..ebdca81b11 100644 --- a/CHANGES +++ b/CHANGES @@ -25,6 +25,14 @@ CHANGES elements are otherwise not easily accessible. [ticket:2155] + - Fixed bug where determination of "self referential" + relationship would fail with no workaround + for joined-inh subclass related to itself, + or joined-inh subclass related to a subclass + of that with no cols in the sub-sub class + in the join condition. [ticket:2149] + Also in 0.6.8. + - It is an error to call query.get() when the given entity is not a single, full class entity or mapper (i.e. a column). This is diff --git a/lib/sqlalchemy/orm/properties.py b/lib/sqlalchemy/orm/properties.py index c73aaeb00a..cf059513f1 100644 --- a/lib/sqlalchemy/orm/properties.py +++ b/lib/sqlalchemy/orm/properties.py @@ -1132,8 +1132,15 @@ class RelationshipProperty(StrategizedProperty): return strategy.use_get def _refers_to_parent_table(self): + pt = self.parent.mapped_table + mt = self.mapper.mapped_table for c, f in self.synchronize_pairs: - if c.table is f.table: + if ( + pt.is_derived_from(c.table) and \ + pt.is_derived_from(f.table) and \ + mt.is_derived_from(c.table) and \ + mt.is_derived_from(f.table) + ): return True else: return False diff --git a/test/orm/inheritance/test_polymorph2.py b/test/orm/inheritance/test_polymorph2.py index 0f1a160a50..b7ed5668ed 100644 --- a/test/orm/inheritance/test_polymorph2.py +++ b/test/orm/inheritance/test_polymorph2.py @@ -1145,3 +1145,122 @@ class MissingPolymorphicOnTest(fixtures.MappedTest): ] ) +class JoinedInhAdjacencyTest(fixtures.MappedTest): + @classmethod + def define_tables(cls, metadata): + Table('people', metadata, + Column('id', Integer, primary_key=True, + test_needs_autoincrement=True), + Column('type', String(30)), + ) + Table('users', metadata, + Column('id', Integer, ForeignKey('people.id'), + primary_key=True), + Column('supervisor_id', Integer, ForeignKey('people.id')), + ) + Table('dudes', metadata, + Column('id', Integer, ForeignKey('users.id'), + primary_key=True), + ) + + @classmethod + def setup_classes(cls): + class Person(cls.Comparable): + pass + + class User(Person): + pass + + class Dude(User): + pass + + def _roundtrip(self): + Person, User = self.classes.Person, self.classes.User + sess = Session() + u1 = User() + u2 = User() + u2.supervisor = u1 + sess.add_all([u1, u2]) + sess.commit() + + assert u2.supervisor is u1 + + def _dude_roundtrip(self): + Dude, User = self.classes.Dude, self.classes.User + sess = Session() + u1 = User() + d1 = Dude() + d1.supervisor = u1 + sess.add_all([u1, d1]) + sess.commit() + + assert d1.supervisor is u1 + + def test_joined_to_base(self): + people, users = self.tables.people, self.tables.users + Person, User = self.classes.Person, self.classes.User + + mapper(Person, people, + polymorphic_on=people.c.type, + polymorphic_identity='person', + ) + mapper(User, users, inherits=Person, + polymorphic_identity='user', + inherit_condition=(users.c.id == people.c.id), + properties = { + 'supervisor': relationship(Person, + primaryjoin=users.c.supervisor_id==people.c.id, + ), + } + ) + + assert User.supervisor.property.direction is MANYTOONE + self._roundtrip() + + def test_joined_to_same_subclass(self): + people, users = self.tables.people, self.tables.users + Person, User = self.classes.Person, self.classes.User + + mapper(Person, people, + polymorphic_on=people.c.type, + polymorphic_identity='person', + ) + mapper(User, users, inherits=Person, + polymorphic_identity='user', + inherit_condition=(users.c.id == people.c.id), + properties = { + 'supervisor': relationship(User, + primaryjoin=users.c.supervisor_id==people.c.id, + remote_side=people.c.id, + foreign_keys=[users.c.supervisor_id] + ), + } + ) + assert User.supervisor.property.direction is MANYTOONE + self._roundtrip() + + def test_joined_subclass_to_superclass(self): + people, users, dudes = self.tables.people, self.tables.users, self.tables.dudes + Person, User, Dude = self.classes.Person, self.classes.User, self.classes.Dude + + mapper(Person, people, + polymorphic_on=people.c.type, + polymorphic_identity='person', + ) + mapper(User, users, inherits=Person, + polymorphic_identity='user', + inherit_condition=(users.c.id == people.c.id), + ) + mapper(Dude, dudes, inherits=User, + polymorphic_identity='dude', + inherit_condition=(dudes.c.id==users.c.id), + properties={ + 'supervisor': relationship(User, + primaryjoin=users.c.supervisor_id==people.c.id, + remote_side=people.c.id, + foreign_keys=[users.c.supervisor_id] + ), + } + ) + assert Dude.supervisor.property.direction is MANYTOONE + self._dude_roundtrip() \ No newline at end of file