]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- Fixed bug where determination of "self referential"
authorMike Bayer <mike_mp@zzzcomputing.com>
Sat, 7 May 2011 15:30:24 +0000 (11:30 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sat, 7 May 2011 15:30:24 +0000 (11:30 -0400)
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]

CHANGES
lib/sqlalchemy/orm/properties.py
test/orm/inheritance/test_polymorph2.py

diff --git a/CHANGES b/CHANGES
index a63656245f7ba76f702e32f52482b6c78d636b0b..25da1e7d89e61cc1c812799c6e485a5c0129be33 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -30,6 +30,13 @@ CHANGES
     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
@@ -94,12 +101,6 @@ CHANGES
     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]
index 9bb8f1a6356d1eddf3363c869f1d5a5e221034b8..a3f70935c45f1aab65f9848b4be5dcc8f8c35f9a 100644 (file)
@@ -1392,8 +1392,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
index abfbf6243f8c058a31c4d16791b263eb426d445c..2f12493797f4d5ae0354a851368004613109fbad 100644 (file)
@@ -12,6 +12,7 @@ from sqlalchemy.util import function_named
 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):
@@ -1121,3 +1122,116 @@ class MissingPolymorphicOnTest(_base.MappedTest):
         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()