mirror of
https://github.com/sqlalchemy/sqlalchemy.git
synced 2026-05-30 20:44:45 -04:00
- Made a small improvement to the heuristics of relationship when
determining remote side with semi-self-referential (e.g. two joined inh subclasses referring to each other), non-simple join conditions such that the parententity is taken into account and can reduce the need for using the ``remote()`` annotation; this can restore some cases that might have worked without the annotation prior to 0.9.4 via 🎫`2948`. fixes #3364
This commit is contained in:
Vendored
+12
@@ -18,6 +18,18 @@
|
||||
.. changelog::
|
||||
:version: 1.0.0
|
||||
|
||||
.. change::
|
||||
:tags: bug, orm
|
||||
:tickets: 3364
|
||||
|
||||
Made a small improvement to the heuristics of relationship when
|
||||
determining remote side with semi-self-referential (e.g. two joined
|
||||
inh subclasses referring to each other), non-simple join conditions
|
||||
such that the parententity is taken into account and can reduce the
|
||||
need for using the ``remote()`` annotation; this can restore some
|
||||
cases that might have worked without the annotation prior to 0.9.4
|
||||
via :ticket:`2948`.
|
||||
|
||||
.. change::
|
||||
:tags: bug, mssql
|
||||
:tickets: 3360
|
||||
|
||||
@@ -2329,12 +2329,21 @@ class JoinCondition(object):
|
||||
binary.right, binary.left = proc_left_right(binary.right,
|
||||
binary.left)
|
||||
|
||||
check_entities = self.prop is not None and \
|
||||
self.prop.mapper is not self.prop.parent
|
||||
|
||||
def proc_left_right(left, right):
|
||||
if isinstance(left, expression.ColumnClause) and \
|
||||
isinstance(right, expression.ColumnClause):
|
||||
if self.child_selectable.c.contains_column(right) and \
|
||||
self.parent_selectable.c.contains_column(left):
|
||||
right = right._annotate({"remote": True})
|
||||
elif check_entities and \
|
||||
right._annotations.get('parentmapper') is self.prop.mapper:
|
||||
right = right._annotate({"remote": True})
|
||||
elif check_entities and \
|
||||
left._annotations.get('parentmapper') is self.prop.mapper:
|
||||
left = left._annotate({"remote": True})
|
||||
else:
|
||||
self._warn_non_column_elements()
|
||||
|
||||
|
||||
+41
-2
@@ -3,9 +3,9 @@ from sqlalchemy.testing import assert_raises_message, eq_, \
|
||||
from sqlalchemy.testing import fixtures
|
||||
from sqlalchemy.orm import relationships, foreign, remote
|
||||
from sqlalchemy import MetaData, Table, Column, ForeignKey, Integer, \
|
||||
select, ForeignKeyConstraint, exc, func, and_, String
|
||||
select, ForeignKeyConstraint, exc, func, and_, String, Boolean
|
||||
from sqlalchemy.orm.interfaces import ONETOMANY, MANYTOONE, MANYTOMANY
|
||||
|
||||
from sqlalchemy.testing import mock
|
||||
|
||||
class _JoinFixtures(object):
|
||||
@classmethod
|
||||
@@ -71,6 +71,7 @@ class _JoinFixtures(object):
|
||||
)
|
||||
cls.base = Table('base', m,
|
||||
Column('id', Integer, primary_key=True),
|
||||
Column('flag', Boolean)
|
||||
)
|
||||
cls.sub = Table('sub', m,
|
||||
Column('id', Integer, ForeignKey('base.id'),
|
||||
@@ -504,6 +505,33 @@ class _JoinFixtures(object):
|
||||
foreign(remote(self.selfref.c.sid)))
|
||||
)
|
||||
|
||||
def _join_fixture_inh_selfref_w_entity(self, **kw):
|
||||
# MARKMARK
|
||||
|
||||
fake_logger = mock.Mock(info=lambda *arg, **kw: None)
|
||||
prop = mock.Mock(
|
||||
parent=mock.Mock(),
|
||||
mapper=mock.Mock(),
|
||||
logger=fake_logger
|
||||
)
|
||||
local_selectable = self.base.join(self.sub)
|
||||
remote_selectable = self.base.join(self.sub_w_sub_rel)
|
||||
|
||||
sub_w_sub_rel__sub_id = self.sub_w_sub_rel.c.sub_id._annotate(
|
||||
{'parentmapper': prop.mapper})
|
||||
sub__id = self.sub.c.id._annotate({'parentmapper': prop.parent})
|
||||
sub_w_sub_rel__flag = self.base.c.flag._annotate(
|
||||
{"parentmapper": prop.mapper})
|
||||
return relationships.JoinCondition(
|
||||
local_selectable, remote_selectable,
|
||||
local_selectable, remote_selectable,
|
||||
primaryjoin=and_(
|
||||
sub_w_sub_rel__sub_id == sub__id,
|
||||
sub_w_sub_rel__flag == True
|
||||
),
|
||||
prop=prop
|
||||
)
|
||||
|
||||
def _assert_non_simple_warning(self, fn):
|
||||
assert_raises_message(
|
||||
exc.SAWarning,
|
||||
@@ -904,6 +932,17 @@ class ColumnCollectionsTest(_JoinFixtures, fixtures.TestBase,
|
||||
[(self.purely_single_col.c.path, self.purely_single_col.c.path)]
|
||||
)
|
||||
|
||||
def test_determine_local_remote_pairs_inh_selfref_w_entities(self):
|
||||
joincond = self._join_fixture_inh_selfref_w_entity()
|
||||
eq_(
|
||||
joincond.local_remote_pairs,
|
||||
[(self.sub.c.id, self.sub_w_sub_rel.c.sub_id)]
|
||||
)
|
||||
eq_(
|
||||
joincond.remote_columns,
|
||||
set([self.base.c.flag, self.sub_w_sub_rel.c.sub_id])
|
||||
)
|
||||
|
||||
class DirectionTest(_JoinFixtures, fixtures.TestBase, AssertsCompiledSQL):
|
||||
def test_determine_direction_compound_2(self):
|
||||
joincond = self._join_fixture_compound_expression_2(
|
||||
|
||||
Reference in New Issue
Block a user