From 6d01d962290bb3f3973f37c61ee489ca1d94f515 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Tue, 12 Aug 2008 15:19:09 +0000 Subject: [PATCH] - Improved the behavior of query.join() when joining to joined-table inheritance subclasses, using explicit join criteria (i.e. not on a relation). --- CHANGES | 5 +++++ lib/sqlalchemy/orm/query.py | 17 +++++++++++++---- test/orm/inheritance/query.py | 19 +++++++++++++++++++ 3 files changed, 37 insertions(+), 4 deletions(-) diff --git a/CHANGES b/CHANGES index 503a9c16ee..9c88030c63 100644 --- a/CHANGES +++ b/CHANGES @@ -22,6 +22,11 @@ CHANGES should not "leak" their inner FROM objects out into the enclosing query. + - Improved the behavior of query.join() + when joining to joined-table inheritance + subclasses, using explicit join criteria + (i.e. not on a relation). + - Fixed @on_reconsitute hook for subclasses which inherit from a base class. [ticket:1129] diff --git a/lib/sqlalchemy/orm/query.py b/lib/sqlalchemy/orm/query.py index b9801370b4..ed3c2f7c38 100644 --- a/lib/sqlalchemy/orm/query.py +++ b/lib/sqlalchemy/orm/query.py @@ -829,7 +829,10 @@ class Query(object): if not clause: raise sa_exc.InvalidRequestError("Could not find a FROM clause to join from") - bogus, right_selectable, is_aliased_class = _entity_info(right_entity) + mp, right_selectable, is_aliased_class = _entity_info(right_entity) + + if not right_mapper and mp: + right_mapper = mp if right_mapper and not is_aliased_class: if right_entity is right_selectable: @@ -851,7 +854,7 @@ class Query(object): right_entity = aliased(right_mapper) alias_criterion = True aliased_entity = True - + elif prop: if prop.table in self.__currenttables: if prop.secondary is not None and prop.secondary not in self.__currenttables: @@ -867,13 +870,19 @@ class Query(object): right_entity = prop.mapper + if alias_criterion: + right_adapter = ORMAdapter(right_entity, + equivalents=right_mapper._equivalent_columns, chain_to=self._filter_aliases) + + if isinstance(onclause, sql.ClauseElement): + onclause = right_adapter.traverse(onclause) + if prop: onclause = prop clause = orm_join(clause, right_entity, onclause, isouter=outerjoin) if alias_criterion: - self._filter_aliases = ORMAdapter(right_entity, - equivalents=right_mapper._equivalent_columns, chain_to=self._filter_aliases) + self._filter_aliases = right_adapter if aliased_entity: self.__mapper_loads_polymorphically_with(right_mapper, ORMAdapter(right_entity, equivalents=right_mapper._equivalent_columns)) diff --git a/test/orm/inheritance/query.py b/test/orm/inheritance/query.py index 28659ba38a..eb40f01e56 100644 --- a/test/orm/inheritance/query.py +++ b/test/orm/inheritance/query.py @@ -455,6 +455,25 @@ def make_test(select_type): join('paperwork', from_joinpoint=True, aliased=aliased).filter(Paperwork.description.like('%#%')).all(), [c1, c2] ) + def test_explicit_polymorphic_join(self): + sess = create_session() + + # join from Company to Engineer; join condition formulated by + # ORMJoin using regular table foreign key connections. Engineer + # is expressed as "(select * people join engineers) as anon_1" + # so the join is contained. + self.assertEquals( + sess.query(Company).join(Engineer).filter(Engineer.engineer_name=='vlad').one(), + c2 + ) + + # same, using explicit join condition. Query.join() must adapt the on clause + # here to match the subquery wrapped around "people join engineers". + self.assertEquals( + sess.query(Company).join((Engineer, Company.company_id==Engineer.company_id)).filter(Engineer.engineer_name=='vlad').one(), + c2 + ) + def test_filter_on_baseclass(self): sess = create_session() -- 2.47.3