anonymously aliased. Subsequent calls to :meth:`~.Query.filter`
and similar will adapt the incoming criterion to the target
alias, until :meth:`~.Query.reset_joinpoint` is called.
+ :param isouter=False: If True, the join used will be a left outer join,
+ just as if the ``outerjoin()`` method were called.
:param from_joinpoint=False: When using ``aliased=True``, a setting
of True here will cause the join to be from the most recent
joined target, rather than starting back from the original
SQLAlchemy versions was the primary ORM-level joining interface.
"""
- aliased, from_joinpoint = kwargs.pop('aliased', False),\
- kwargs.pop('from_joinpoint', False)
+ aliased, from_joinpoint, isouter = kwargs.pop('aliased', False),\
+ kwargs.pop('from_joinpoint', False),\
+ kwargs.pop('isouter', False)
if kwargs:
raise TypeError("unknown arguments: %s" %
','.join(kwargs.keys))
+ isouter = isouter
return self._join(props,
- outerjoin=False, create_aliases=aliased,
+ outerjoin=isouter, create_aliases=aliased,
from_joinpoint=from_joinpoint)
def outerjoin(self, *props, **kwargs):
self.supports_single_entity = self.bundle.single_entity
-
@property
def entity_zero(self):
for ent in self._entities:
filter_by(id=3).outerjoin('orders','address').filter_by(id=1).all()
assert [User(id=7, name='jack')] == result
+ def test_overlapping_paths_join_isouter(self):
+ User = self.classes.User
+
+ result = create_session().query(User).join('orders', 'items', isouter=True).\
+ filter_by(id=3).join('orders','address', isouter=True).filter_by(id=1).all()
+ assert [User(id=7, name='jack')] == result
+
def test_from_joinpoint(self):
Item, User, Order = (self.classes.Item,
self.classes.User,
[User(name='fred')]
)
-
def test_aliased_classes(self):
User, Address = self.classes.User, self.classes.Address
def test_joins_from_adapted_entities(self):
User = self.classes.User
-
# test for #1853
session = create_session()
'anon_2 ON anon_2.id = anon_1.users_id',
use_default_dialect=True)
+ def test_joins_from_adapted_entities_isouter(self):
+ User = self.classes.User
+
+ # test for #1853
+
+ session = create_session()
+ first = session.query(User)
+ second = session.query(User)
+ unioned = first.union(second)
+ subquery = session.query(User.id).subquery()
+ join = subquery, subquery.c.id == User.id
+ joined = unioned.join(*join, isouter=True)
+ self.assert_compile(joined,
+ 'SELECT anon_1.users_id AS '
+ 'anon_1_users_id, anon_1.users_name AS '
+ 'anon_1_users_name FROM (SELECT users.id '
+ 'AS users_id, users.name AS users_name '
+ 'FROM users UNION SELECT users.id AS '
+ 'users_id, users.name AS users_name FROM '
+ 'users) AS anon_1 LEFT OUTER JOIN (SELECT '
+ 'users.id AS id FROM users) AS anon_2 ON '
+ 'anon_2.id = anon_1.users_id',
+ use_default_dialect=True)
+
+ first = session.query(User.id)
+ second = session.query(User.id)
+ unioned = first.union(second)
+ subquery = session.query(User.id).subquery()
+ join = subquery, subquery.c.id == User.id
+ joined = unioned.join(*join, isouter=True)
+ self.assert_compile(joined,
+ 'SELECT anon_1.users_id AS anon_1_users_id '
+ 'FROM (SELECT users.id AS users_id FROM '
+ 'users UNION SELECT users.id AS users_id '
+ 'FROM users) AS anon_1 LEFT OUTER JOIN '
+ '(SELECT users.id AS id FROM users) AS '
+ 'anon_2 ON anon_2.id = anon_1.users_id',
+ use_default_dialect=True)
+
def test_reset_joinpoint(self):
User = self.classes.User
result = create_session().query(User).join('orders', 'items', aliased=aliased).filter_by(id=3).reset_joinpoint().join('orders','address', aliased=aliased).filter_by(id=1).all()
assert [User(id=7, name='jack')] == result
+ result = create_session().query(User).join('orders', 'items', aliased=aliased, isouter=True).filter_by(id=3).reset_joinpoint().join('orders','address', aliased=aliased, isouter=True).filter_by(id=1).all()
+ assert [User(id=7, name='jack')] == result
+
result = create_session().query(User).outerjoin('orders', 'items', aliased=aliased).filter_by(id=3).reset_joinpoint().outerjoin('orders','address', aliased=aliased).filter_by(id=1).all()
assert [User(id=7, name='jack')] == result