summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2014-08-26 17:23:23 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2014-08-26 17:23:23 -0400
commit00862a29c6c1494f1b55c3f93e5300f69fb4ac98 (patch)
tree0be186c1bea89154e385059a75303fa51f589002 /lib
parente346ee2c5776e21d4b37f9b495db943b21b47da2 (diff)
downloadsqlalchemy-00862a29c6c1494f1b55c3f93e5300f69fb4ac98.tar.gz
- The behavior of :paramref:`.joinedload.innerjoin` as well as
:paramref:`.relationship.innerjoin` is now to use "nested" inner joins, that is, right-nested, as the default behavior when an inner join joined eager load is chained to an outer join eager load. fixes #3008
Diffstat (limited to 'lib')
-rw-r--r--lib/sqlalchemy/orm/relationships.py16
-rw-r--r--lib/sqlalchemy/orm/strategies.py3
-rw-r--r--lib/sqlalchemy/orm/strategy_options.py49
3 files changed, 48 insertions, 20 deletions
diff --git a/lib/sqlalchemy/orm/relationships.py b/lib/sqlalchemy/orm/relationships.py
index c2debda03..2bcb3f4a1 100644
--- a/lib/sqlalchemy/orm/relationships.py
+++ b/lib/sqlalchemy/orm/relationships.py
@@ -459,22 +459,18 @@ class RelationshipProperty(StrategizedProperty):
nullable, or when the reference is one-to-one or a collection that
is guaranteed to have one or at least one entry.
- If the joined-eager load is chained onto an existing LEFT OUTER
- JOIN, ``innerjoin=True`` will be bypassed and the join will continue
- to chain as LEFT OUTER JOIN so that the results don't change. As an
- alternative, specify the value ``"nested"``. This will instead nest
- the join on the right side, e.g. using the form "a LEFT OUTER JOIN
- (b JOIN c)".
-
- .. versionadded:: 0.9.4 Added ``innerjoin="nested"`` option to
- support nesting of eager "inner" joins.
+ The option supports the same "nested" and "unnested" options as
+ that of :paramref:`.joinedload.innerjoin`. See that flag
+ for details on nested / unnested behaviors.
.. seealso::
+ :paramref:`.joinedload.innerjoin` - the option as specified by
+ loader option, including detail on nesting behavior.
+
:ref:`what_kind_of_loading` - Discussion of some details of
various loader options.
- :paramref:`.joinedload.innerjoin` - loader option version
:param join_depth:
when non-``None``, an integer value indicating how many levels
diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py
index 1e8020dd9..c3edbf6e6 100644
--- a/lib/sqlalchemy/orm/strategies.py
+++ b/lib/sqlalchemy/orm/strategies.py
@@ -1324,7 +1324,8 @@ class JoinedLoader(AbstractRelationshipLoader):
join_to_outer = innerjoin and isinstance(towrap, sql.Join) and \
towrap.isouter
- if chained_from_outerjoin and join_to_outer and innerjoin == 'nested':
+ if chained_from_outerjoin and \
+ join_to_outer and innerjoin != 'unnested':
inner = orm_util.join(
towrap.right,
clauses.aliased_class,
diff --git a/lib/sqlalchemy/orm/strategy_options.py b/lib/sqlalchemy/orm/strategy_options.py
index 392f7cec2..4f986193e 100644
--- a/lib/sqlalchemy/orm/strategy_options.py
+++ b/lib/sqlalchemy/orm/strategy_options.py
@@ -1,4 +1,3 @@
-# orm/strategy_options.py
# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
@@ -631,15 +630,47 @@ def joinedload(loadopt, attr, innerjoin=None):
query(Order).options(joinedload(Order.user, innerjoin=True))
- If the joined-eager load is chained onto an existing LEFT OUTER JOIN,
- ``innerjoin=True`` will be bypassed and the join will continue to
- chain as LEFT OUTER JOIN so that the results don't change. As an
- alternative, specify the value ``"nested"``. This will instead nest the
- join on the right side, e.g. using the form "a LEFT OUTER JOIN
- (b JOIN c)".
+ In order to chain multiple eager joins together where some may be
+ OUTER and others INNER, right-nested joins are used to link them::
- .. versionadded:: 0.9.4 Added ``innerjoin="nested"`` option to support
- nesting of eager "inner" joins.
+ query(A).options(
+ joinedload(A.bs, innerjoin=False).
+ joinedload(B.cs, innerjoin=True)
+ )
+
+ The above query, linking A.bs via "outer" join and B.cs via "inner" join
+ would render the joins as "a LEFT OUTER JOIN (b JOIN c)". When using
+ SQLite, this form of JOIN is translated to use full subqueries as this
+ syntax is otherwise not directly supported.
+
+ The ``innerjoin`` flag can also be stated with the term ``"unnested"``.
+ This will prevent joins from being right-nested, and will instead
+ link an "innerjoin" eagerload to an "outerjoin" eagerload by bypassing
+ the "inner" join. Using this form as follows::
+
+ query(A).options(
+ joinedload(A.bs, innerjoin=False).
+ joinedload(B.cs, innerjoin="unnested")
+ )
+
+ Joins will be rendered as "a LEFT OUTER JOIN b LEFT OUTER JOIN c", so that
+ all of "a" is matched rather than being incorrectly limited by a "b" that
+ does not contain a "c".
+
+ .. note:: The "unnested" flag does **not** affect the JOIN rendered
+ from a many-to-many association table, e.g. a table configured
+ as :paramref:`.relationship.secondary`, to the target table; for
+ correctness of results, these joins are always INNER and are
+ therefore right-nested if linked to an OUTER join.
+
+ .. versionadded:: 0.9.4 Added support for "nesting" of eager "inner"
+ joins. See :ref:`feature_2976`.
+
+ .. versionchanged:: 1.0.0 ``innerjoin=True`` now implies
+ ``innerjoin="nested"``, whereas in 0.9 it implied
+ ``innerjoin="unnested"``. In order to achieve the pre-1.0 "unnested"
+ inner join behavior, use the value ``innerjoin="unnested"``.
+ See :ref:`migration_3008`.
.. note::