summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy')
-rw-r--r--lib/sqlalchemy/databases/oracle.py1
-rw-r--r--lib/sqlalchemy/ext/selectresults.py66
-rw-r--r--lib/sqlalchemy/orm/query.py19
3 files changed, 72 insertions, 14 deletions
diff --git a/lib/sqlalchemy/databases/oracle.py b/lib/sqlalchemy/databases/oracle.py
index 5db157cbb..e6d331109 100644
--- a/lib/sqlalchemy/databases/oracle.py
+++ b/lib/sqlalchemy/databases/oracle.py
@@ -298,6 +298,7 @@ class OracleCompiler(ansisql.ANSICompiler):
self.froms[join] = self.get_from_text(join.left) + ", " + self.get_from_text(join.right)
self.wheres[join] = sql.and_(self.wheres.get(join.left, None), join.onclause)
+ self.strings[join] = self.froms[join]
if join.isouter:
# if outer join, push on the right side table as the current "outertable"
diff --git a/lib/sqlalchemy/ext/selectresults.py b/lib/sqlalchemy/ext/selectresults.py
index a35cdfa7e..93698a5e0 100644
--- a/lib/sqlalchemy/ext/selectresults.py
+++ b/lib/sqlalchemy/ext/selectresults.py
@@ -18,13 +18,14 @@ class SelectResults(object):
instance with further limiting criterion added. When interpreted
in an iterator context (such as via calling list(selectresults)), executes the query."""
- def __init__(self, query, clause=None, ops={}):
+ def __init__(self, query, clause=None, ops={}, joinpoint=None):
"""constructs a new SelectResults using the given Query object and optional WHERE
clause. ops is an optional dictionary of bind parameter values."""
self._query = query
self._clause = clause
self._ops = {}
self._ops.update(ops)
+ self._joinpoint = joinpoint or (self._query.table, self._query.mapper)
def count(self):
"""executes the SQL count() function against the SelectResults criterion."""
@@ -60,7 +61,7 @@ class SelectResults(object):
def clone(self):
"""creates a copy of this SelectResults."""
- return SelectResults(self._query, self._clause, self._ops.copy())
+ return SelectResults(self._query, self._clause, self._ops.copy(), self._joinpoint)
def filter(self, clause):
"""applies an additional WHERE clause against the query."""
@@ -68,23 +69,76 @@ class SelectResults(object):
new._clause = sql.and_(self._clause, clause)
return new
+ def select(self, clause):
+ return self.filter(clause)
+
def order_by(self, order_by):
- """applies an ORDER BY to the query."""
+ """apply an ORDER BY to the query."""
new = self.clone()
new._ops['order_by'] = order_by
return new
def limit(self, limit):
- """applies a LIMIT to the query."""
+ """apply a LIMIT to the query."""
return self[:limit]
def offset(self, offset):
- """applies an OFFSET to the query."""
+ """apply an OFFSET to the query."""
return self[offset:]
def list(self):
- """returns the results represented by this SelectResults as a list. this results in an execution of the underlying query."""
+ """return the results represented by this SelectResults as a list.
+
+ this results in an execution of the underlying query."""
return list(self)
+
+ def select_from(self, from_obj):
+ """set the from_obj parameter of the query to a specific table or set of tables.
+
+ from_obj is a list."""
+ new = self.clone()
+ new._ops['from_obj'] = from_obj
+ return new
+
+ def join_to(self, prop):
+ """join the table of this SelectResults to the table located against the given property name.
+
+ subsequent calls to join_to or outerjoin_to will join against the rightmost table located from the
+ previous join_to or outerjoin_to call, searching for the property starting with the rightmost mapper
+ last located."""
+ new = self.clone()
+ (clause, mapper) = self._join_to(prop, outerjoin=False)
+ new._ops['from_obj'] = [clause]
+ new._joinpoint = (clause, mapper)
+ return new
+
+ def outerjoin_to(self, prop):
+ """outer join the table of this SelectResults to the table located against the given property name.
+
+ subsequent calls to join_to or outerjoin_to will join against the rightmost table located from the
+ previous join_to or outerjoin_to call, searching for the property starting with the rightmost mapper
+ last located."""
+ new = self.clone()
+ (clause, mapper) = self._join_to(prop, outerjoin=True)
+ new._ops['from_obj'] = [clause]
+ new._joinpoint = (clause, mapper)
+ return new
+
+ def _join_to(self, prop, outerjoin=False):
+ [keys,p] = self._query._locate_prop(prop, start=self._joinpoint[1])
+ clause = self._joinpoint[0]
+ mapper = self._joinpoint[1]
+ for key in keys:
+ prop = mapper.props[key]
+ if outerjoin:
+ clause = clause.outerjoin(prop.mapper.mapped_table, prop.get_join())
+ else:
+ clause = clause.join(prop.mapper.mapped_table, prop.get_join())
+ mapper = prop.mapper
+ return (clause, mapper)
+
+ def compile(self):
+ return self._query.compile(self._clause, **self._ops)
def __getitem__(self, item):
if isinstance(item, slice):
diff --git a/lib/sqlalchemy/orm/query.py b/lib/sqlalchemy/orm/query.py
index 0a6a05005..db497bc37 100644
--- a/lib/sqlalchemy/orm/query.py
+++ b/lib/sqlalchemy/orm/query.py
@@ -1,4 +1,4 @@
- # orm/query.py
+# orm/query.py
# Copyright (C) 2005,2006 Michael Bayer mike_mp@zzzcomputing.com
#
# This module is part of SQLAlchemy and is released under
@@ -112,7 +112,7 @@ class Query(object):
clause &= c
return clause
- def _locate_prop(self, key):
+ def _locate_prop(self, key, start=None):
import properties
keys = []
seen = util.Set()
@@ -137,7 +137,7 @@ class Query(object):
return x
else:
return None
- p = search_for_prop(self.mapper)
+ p = search_for_prop(start or self.mapper)
if p is None:
raise exceptions.InvalidRequestError("Cant locate property named '%s'" % key)
return [keys, p]
@@ -163,10 +163,9 @@ class Query(object):
else:
clause &= prop.get_join()
mapper = prop.mapper
-
+
return clause
-
-
+
def selectfirst_by(self, *args, **params):
"""works like select_by(), but only returns the first result by itself, or None if no
objects returned. Synonymous with get_by()"""
@@ -340,10 +339,15 @@ class Query(object):
if self.mapper.single and self.mapper.polymorphic_on is not None and self.mapper.polymorphic_identity is not None:
whereclause = sql.and_(whereclause, self.mapper.polymorphic_on==self.mapper.polymorphic_identity)
+
+ alltables = []
+ for l in [sql_util.TableFinder(x) for x in from_obj]:
+ alltables += l
- if self._should_nest(**kwargs):
+ if self.table not in alltables:
from_obj.append(self.table)
+ if self._should_nest(**kwargs):
# if theres an order by, add those columns to the column list
# of the "rowcount" query we're going to make
if order_by:
@@ -375,7 +379,6 @@ class Query(object):
[o.accept_visitor(aliasizer) for o in order_by]
statement.order_by(*util.to_list(order_by))
else:
- from_obj.append(self.table)
statement = sql.select([], whereclause, from_obj=from_obj, use_labels=True, for_update=for_update, **kwargs)
if order_by:
statement.order_by(*util.to_list(order_by))