summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/sql/selectable.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy/sql/selectable.py')
-rw-r--r--lib/sqlalchemy/sql/selectable.py100
1 files changed, 13 insertions, 87 deletions
diff --git a/lib/sqlalchemy/sql/selectable.py b/lib/sqlalchemy/sql/selectable.py
index 9d8ea8a8e..a27ff8d53 100644
--- a/lib/sqlalchemy/sql/selectable.py
+++ b/lib/sqlalchemy/sql/selectable.py
@@ -427,96 +427,9 @@ class FromClause(Selectable):
.. versionadded:: 1.1
- .. seealso::
-
- :meth:`.FromClause.join_lateral`
-
"""
return Lateral(self, name)
- def join_lateral(self, right, onclause=None, name=None):
- """Return a JOIN of this FromClause to a :class:`.Table`
- or :class:`.Select`, using a correlated SELECT in conjunction with
- LATERAL.
-
- E.g.::
-
-
- subq = select([addresses.c.id])
-
- stmt = select([users]).select_from(
- users.join_lateral(subq)
- )
-
- Would produce the statement::
-
- SELECT users.id, users.name, users.fullname
- FROM users JOIN LATERAL (SELECT addresses.id AS id
- FROM addresses
- WHERE users.id = addresses.user_id) AS anon_1 ON true
-
- If ``right`` is an existing :class:`.Select` object, this
- call is equivalent to::
-
- left.join(
- right.where(onclause).correlate(self).lateral(name),
- true()
- )
-
- If ``right`` is a :class:`.Table`, the call is equivalent to::
-
- left.join(
- select([right]).where(onclause).correlate(self).lateral(name),
- true()
- )
-
- If ``right`` is a :class:`.Alias`, the "element" of the :class:`.Alias`
- is extracted and used as the right side; since we are generating
- a subquery, there is never a need for the "right" side to itself
- be an "alias"; the :func:`.lateral` construct provides this.
-
- The "onclause", if not specified, will be automatically
- generated from foreign key constraints in the same way as
- :meth:`.FromClause.join` if omitted; the difference between
- this an a plain JOIN is that this criteria is used as the
- WHERE clause of the correlated select. To use this feature,
- the right side must refer to an unambiguous FROM clause to
- join to; if the right side contains multiple FROM clauses besides
- this one, an exception is raised and the "onclause" should be
- passed explicitly.
-
-
- .. versionadded:: 1.1
-
- .. seealso::
-
- :meth:`.FromClause.lateral`
-
- """
-
- if isinstance(right, Alias):
- right = right.original
-
- if isinstance(right, Select):
- to_select = right
- else:
- to_select = Select([right])
-
- if onclause is None:
- froms = [
- f for f in to_select._froms if not f.is_derived_from(self)]
- if len(froms) != 1:
- raise exc.ArgumentError(
- "select() passed to join_lateral has mulitple "
- "FROM clauses; specify the ON clause of this "
- "JOIN LATERAL explicitly.")
- to_onclause = froms[0]
- onclause = self.join(to_onclause).onclause
-
- return self.join(to_select.
- where(onclause).correlate(self).lateral(name),
- True_())
-
def is_derived_from(self, fromclause):
"""Return True if this FromClause is 'derived' from the given
FromClause.
@@ -3099,6 +3012,19 @@ class Select(HasPrefixes, HasSuffixes, GenerativeSelect):
"""
self.append_from(fromclause)
+ def correlate_from(self, destination, onclause=None):
+ if onclause is None:
+ froms = [
+ f for f in self._froms if f is not destination]
+ if len(froms) != 1:
+ raise exc.ArgumentError(
+ "select() has mulitple "
+ "FROM clauses; specify the ON clause of this "
+ "correlation explicitly.")
+ to_onclause = froms[0]
+ onclause = destination.join(to_onclause).onclause
+ return self.where(onclause).correlate(destination)
+
@_generative
def correlate(self, *fromclauses):
"""return a new :class:`.Select` which will correlate the given FROM