mirror of
https://github.com/sqlalchemy/sqlalchemy.git
synced 2026-05-29 20:14:55 -04:00
- fix annotation transfer when producing m2m backref, [ticket:2578]
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
+48
-6
@@ -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()
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user