diff options
Diffstat (limited to 'lib/sqlalchemy')
-rw-r--r-- | lib/sqlalchemy/databases/oracle.py | 1 | ||||
-rw-r--r-- | lib/sqlalchemy/ext/selectresults.py | 66 | ||||
-rw-r--r-- | lib/sqlalchemy/orm/query.py | 19 |
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)) |