1. Marc Abramowitz
  2. sqlalchemy

Commits

Mike Bayer  committed ee4d0d5

- 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]

  • Participants
  • Parent commits 96ac631
  • Branches rel_0_6

Comments (0)

Files changed (3)

File CHANGES

View file
  • Ignore whitespace
     mapper 'X' does not map this column" to 
     reference the correct mapper.  [ticket:2163].
 
+  - 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]
+
 - sql
   - Fixed bug whereby if FetchedValue was passed
     to column server_onupdate, it would not
     inside to the outside query if from_self()
     were used. [ticket:2130].
 
-  - 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
-    a deprecation warning in 0.6.8.  
-    [ticket:2144]
-
 - sql
   - Column.copy(), as used in table.tometadata(), copies the 
     'doc' attribute.  [ticket:2028]

File lib/sqlalchemy/orm/properties.py

View file
  • Ignore whitespace
         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

File test/orm/inheritance/test_polymorph2.py

View file
  • Ignore whitespace
 from test.orm import _base, _fixtures
 from sqlalchemy.test.testing import eq_
 from sqlalchemy.test.schema import Table, Column
+from sqlalchemy.orm.interfaces import MANYTOONE
 
 class AttrSettable(object):
     def __init__(self, **kwargs):
         sess.expunge_all()
         eq_(sess.query(A).all(), [C(cdata='c1', adata='a1'), D(cdata='c2', adata='a2', ddata='d2')])
 
+class JoinedInhAdjacencyTest(_base.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(_base.ComparableEntity):
+            pass
+
+        class User(Person):
+            pass
+
+        class Dude(User):
+            pass
+
+    @testing.resolve_artifact_names
+    def _roundtrip(self):
+        sess = Session()
+        u1 = User()
+        u2 = User()
+        u2.supervisor = u1
+        sess.add_all([u1, u2])
+        sess.commit()
+
+        assert u2.supervisor is u1
+
+    @testing.resolve_artifact_names
+    def _dude_roundtrip(self):
+        sess = Session()
+        u1 = User()
+        d1 = Dude()
+        d1.supervisor = u1
+        sess.add_all([u1, d1])
+        sess.commit()
+
+        assert d1.supervisor is u1
+
+    @testing.resolve_artifact_names
+    def test_joined_to_base(self):
+        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()
+
+    @testing.resolve_artifact_names
+    def test_joined_to_same_subclass(self):
+        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()
+
+    @testing.resolve_artifact_names
+    def test_joined_subclass_to_superclass(self):
+        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()