summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/sql/selectable.py
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2015-09-10 13:26:43 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2015-09-10 13:26:43 -0400
commit6fc7ef8269c6f349565b099fbf98e40fbbc43748 (patch)
tree3402a5c1b8ce9a779451d398d93f325b202667a5 /lib/sqlalchemy/sql/selectable.py
parent3fc19d53112def400566b259f716a9a3ee89b19f (diff)
downloadsqlalchemy-ticket_2857.tar.gz
- attempt number 2. just add a "correlate_from()" helper. the moreticket_2857
implicit magic we do here, the harder it will be to get the ORM to also work as expected and the more confusing it will be for everyone. I've considered making the true() in the join() implicit based on being passed a Lateral, this could be doable however again in the ORM this expectation would need to be coded all over the place.
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