]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- fix annotation transfer when producing m2m backref, [ticket:2578]
authorMike Bayer <mike_mp@zzzcomputing.com>
Fri, 28 Sep 2012 15:00:53 +0000 (11:00 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Fri, 28 Sep 2012 15:00:53 +0000 (11:00 -0400)
lib/sqlalchemy/orm/properties.py
lib/sqlalchemy/orm/relationships.py
lib/sqlalchemy/orm/strategies.py
lib/sqlalchemy/util/langhelpers.py
test/orm/test_rel_fn.py
test/orm/test_relationships.py

index ad48234c260bdd20d38df257071bd33661935aff..f8288f5fb369fe506bffd47a5ef3e8f7e2465944 100644 (file)
@@ -1167,8 +1167,10 @@ class RelationshipProperty(StrategizedProperty):
                 # for many to many, just switch primaryjoin/
                 # secondaryjoin.   use the annotated
                 # pj/sj on the _join_condition.
-                pj = kwargs.pop('primaryjoin', self._join_condition.secondaryjoin)
-                sj = kwargs.pop('secondaryjoin', self._join_condition.primaryjoin)
+                pj = kwargs.pop('primaryjoin',
+                                self._join_condition.secondaryjoin_minus_local)
+                sj = kwargs.pop('secondaryjoin',
+                                self._join_condition.primaryjoin_minus_local)
             else:
                 pj = kwargs.pop('primaryjoin',
                         self._join_condition.primaryjoin_reverse_remote)
index dd6f2442b3cecc159aee71d8ead8cc5957c7b429..c861edf836d4a2b7290a2d93a539816b2ed140aa 100644 (file)
@@ -170,6 +170,12 @@ class JoinCondition(object):
         log.info('%s local/remote pairs [%s]', self.prop,
                          ','.join('(%s / %s)' % (l, r) for (l, r) in
                          self.local_remote_pairs))
+        log.info('%s remote columns [%s]', self.prop,
+                        ','.join('%s' % col for col in self.remote_columns)
+            )
+        log.info('%s local columns [%s]', self.prop,
+                        ','.join('%s' % col for col in self.local_columns)
+            )
         log.info('%s relationship direction %s', self.prop,
                          self.direction)
 
@@ -266,6 +272,14 @@ class JoinCondition(object):
                         "foreign key reference to the parent table."
                         % self.prop)
 
+    @property
+    def primaryjoin_minus_local(self):
+        return _deep_deannotate(self.primaryjoin, values=("local", "remote"))
+
+    @property
+    def secondaryjoin_minus_local(self):
+        return _deep_deannotate(self.secondaryjoin, values=("local", "remote"))
+
     @util.memoized_property
     def primaryjoin_reverse_remote(self):
         """Return the primaryjoin condition suitable for the
index 0b73f9b7aff8a7eb15040284a3564d909ad0019c..8186aa507a4c034816ed695cc33fec6c52958b42 100644 (file)
@@ -737,7 +737,7 @@ class SubqueryLoader(AbstractRelationshipLoader):
         subq_mapper = orm_util._class_to_mapper(subq_path[0])
 
         # determine attributes of the leftmost mapper
-        if self.parent.isa(subq_mapper) and self.key==subq_path[1]:
+        if self.parent.isa(subq_mapper) and self.key == subq_path[1]:
             leftmost_mapper, leftmost_prop = \
                                     self.parent, self.parent_property
         else:
index e560b871abaa3a04b13164da287fbc552a204764..9761aeae9f3f66ede0d063902689b9770b289248 100644 (file)
@@ -862,6 +862,9 @@ class _symbol(int):
     def __reduce__(self):
         return symbol, (self.name, "x", int(self))
 
+    def __str__(self):
+        return repr(self)
+
     def __repr__(self):
         return "<symbol '%s>" % self.name
 
index f5fa1d4c9748a6247943006046cbaf4914d0be77..dfe0db4885c2b29017b9e879e11a80fbfef2732a 100644 (file)
@@ -135,6 +135,22 @@ class _JoinFixtures(object):
                     **kw
                 )
 
+    def _join_fixture_m2m_backref(self, **kw):
+        """return JoinCondition in the same way RelationshipProperty
+        calls it for a backref on an m2m.
+
+        """
+        j1 = self._join_fixture_m2m()
+        return j1, relationships.JoinCondition(
+                    self.m2mright,
+                    self.m2mleft,
+                    self.m2mright,
+                    self.m2mleft,
+                    secondary=self.m2msecondary,
+                    primaryjoin=j1.secondaryjoin_minus_local,
+                    secondaryjoin=j1.primaryjoin_minus_local
+                )
+
     def _join_fixture_o2m(self, **kw):
         return relationships.JoinCondition(
                     self.left,
@@ -688,16 +704,42 @@ class ColumnCollectionsTest(_JoinFixtures, fixtures.TestBase, AssertsCompiledSQL
         )
 
     def test_determine_local_remote_pairs_m2m_backref(self):
-        joincond = self._join_fixture_m2m()
-        joincond2 = self._join_fixture_m2m(
-            primaryjoin=joincond.secondaryjoin,
-            secondaryjoin=joincond.primaryjoin
-        )
+        j1, j2 = self._join_fixture_m2m_backref()
         eq_(
-            joincond.local_remote_pairs,
+            j1.local_remote_pairs,
             [(self.m2mleft.c.id, self.m2msecondary.c.lid),
             (self.m2mright.c.id, self.m2msecondary.c.rid)]
         )
+        eq_(
+            j2.local_remote_pairs,
+            [
+            (self.m2mright.c.id, self.m2msecondary.c.rid),
+            (self.m2mleft.c.id, self.m2msecondary.c.lid),
+            ]
+        )
+
+    def test_determine_local_columns_m2m_backref(self):
+        j1, j2 = self._join_fixture_m2m_backref()
+        eq_(
+            j1.local_columns,
+            set([self.m2mleft.c.id])
+        )
+        eq_(
+            j2.local_columns,
+            set([self.m2mright.c.id])
+        )
+
+    def test_determine_remote_columns_m2m_backref(self):
+        j1, j2 = self._join_fixture_m2m_backref()
+        eq_(
+            j1.remote_columns,
+            set([self.m2msecondary.c.lid, self.m2msecondary.c.rid])
+        )
+        eq_(
+            j2.remote_columns,
+            set([self.m2msecondary.c.lid, self.m2msecondary.c.rid])
+        )
+
 
     def test_determine_remote_columns_m2o_selfref(self):
         joincond = self._join_fixture_m2o_selfref()
index 394a1fe7ac44137c5fe1e8a3203a00817b977cf3..c1cbc0907e3ac1f7b47ecac6ddefaf430dfcd257 100644 (file)
@@ -2706,9 +2706,9 @@ class InvalidRelationshipEscalationTestM2M(_RelationshipErrors, fixtures.MappedT
         mapper(Foo, foos, properties={
                         'bars': relationship(Bar,
                                 secondary=foobars_with_many_columns,
-                              primaryjoin=foos.c.id==
+                              primaryjoin=foos.c.id ==
                                         foobars_with_many_columns.c.fid,
-                              secondaryjoin=foobars_with_many_columns.c.bid==
+                              secondaryjoin=foobars_with_many_columns.c.bid ==
                                         bars.c.id)})
         mapper(Bar, bars)
         sa.orm.configure_mappers()
@@ -2721,6 +2721,31 @@ class InvalidRelationshipEscalationTestM2M(_RelationshipErrors, fixtures.MappedT
             [(bars.c.id, foobars_with_many_columns.c.bid)]
         )
 
+    def test_local_col_setup(self):
+        foobars_with_fks, bars, Bar, Foo, foos = (
+                                self.tables.foobars_with_fks,
+                                self.tables.bars,
+                                self.classes.Bar,
+                                self.classes.Foo,
+                                self.tables.foos)
+
+        # ensure m2m backref is set up with correct annotations
+        # [ticket:2578]
+        mapper(Foo, foos, properties={
+            'bars': relationship(Bar, secondary=foobars_with_fks, backref="foos")
+            })
+        mapper(Bar, bars)
+        sa.orm.configure_mappers()
+        eq_(
+            Foo.bars.property._join_condition.local_columns,
+            set([foos.c.id])
+        )
+        eq_(
+            Bar.foos.property._join_condition.local_columns,
+            set([bars.c.id])
+        )
+
+
 
     def test_bad_primaryjoin(self):
         foobars_with_fks, bars, Bar, foobars, Foo, foos = (self.tables.foobars_with_fks,