summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/orm/query.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy/orm/query.py')
-rw-r--r--lib/sqlalchemy/orm/query.py97
1 files changed, 52 insertions, 45 deletions
diff --git a/lib/sqlalchemy/orm/query.py b/lib/sqlalchemy/orm/query.py
index ef75efd76..609805373 100644
--- a/lib/sqlalchemy/orm/query.py
+++ b/lib/sqlalchemy/orm/query.py
@@ -162,7 +162,7 @@ class Query(object):
fa = []
for from_obj in obj:
- if isinstance(from_obj, expression._SelectBaseMixin):
+ if isinstance(from_obj, expression._SelectBase):
from_obj = from_obj.alias()
fa.append(from_obj)
@@ -270,10 +270,6 @@ class Query(object):
return self._select_from_entity or \
self._entity_zero().entity_zero
- def _extension_zero(self):
- ent = self._entity_zero()
- return getattr(ent, 'extension', ent.mapper.extension)
-
@property
def _mapper_entities(self):
# TODO: this is wrong, its hardcoded to "priamry entity" when
@@ -955,11 +951,9 @@ class Query(object):
clauses = [_entity_descriptor(self._joinpoint_zero(), key) == value
for key, value in kwargs.iteritems()]
-
return self.filter(sql.and_(*clauses))
@_generative(_no_statement_condition, _no_limit_offset)
- @util.accepts_a_list_as_starargs(list_deprecation='deprecated')
def order_by(self, *criterion):
"""apply one or more ORDER BY criterion to the query and return
the newly resulting ``Query``
@@ -992,7 +986,6 @@ class Query(object):
self._order_by = self._order_by + criterion
@_generative(_no_statement_condition, _no_limit_offset)
- @util.accepts_a_list_as_starargs(list_deprecation='deprecated')
def group_by(self, *criterion):
"""apply one or more GROUP BY criterion to the query and return
the newly resulting ``Query``"""
@@ -1117,7 +1110,6 @@ class Query(object):
expression.except_all(*([self]+ list(q)))
)
- @util.accepts_a_list_as_starargs(list_deprecation='deprecated')
def join(self, *props, **kwargs):
"""Create a join against this ``Query`` object's criterion
and apply generatively, returning the newly resulting ``Query``.
@@ -1131,9 +1123,12 @@ class Query(object):
* a class-mapped attribute, i.e. Houses.rooms. This will create a
join from "Houses" table to that of the "rooms" relationship.
- * a 2-tuple containing a target class or selectable, and an "ON"
- clause. The ON clause can be the property name/ attribute like
- above, or a SQL expression.
+ A two-element form of \*props may also be passed. In this form,
+ the first element is a target class or selectable, the second
+ is a string property name, class-mapped attribute, or clause
+ construct representing an "ON" clause. This supercedes the
+ previous "tuple" calling form - multiple join() calls should
+ be used for multiple (target, onclause) pairs.
e.g.::
@@ -1144,7 +1139,7 @@ class Query(object):
# join the Person entity to an alias of itself,
# along the "friends" relationship
PAlias = aliased(Person)
- session.query(Person).join((Palias, Person.friends))
+ session.query(Person).join(Palias, Person.friends)
# join from Houses to the "rooms" attribute on the
# "Colonials" subclass of Houses, then join to the
@@ -1155,8 +1150,8 @@ class Query(object):
# using "people JOIN engineers" as the target. Then join
# to the "computers" collection on the Engineer entity.
session.query(Company).\
- join((people.join(engineers), 'employees'),
- Engineer.computers)
+ join(people.join(engineers), 'employees').\\
+ join(Engineer.computers)
# join from Articles to Keywords, using the "keywords" attribute.
# assume this is a many-to-many relationship.
@@ -1164,11 +1159,10 @@ class Query(object):
# same thing, but spelled out entirely explicitly
# including the association table.
- session.query(Article).join(
- (article_keywords,
- Articles.id==article_keywords.c.article_id),
- (Keyword, Keyword.id==article_keywords.c.keyword_id)
- )
+ session.query(Article).join(article_keywords,
+ Articles.id==article_keywords.c.article_id).\\
+ join(Keyword,
+ Keyword.id==article_keywords.c.keyword_id)
\**kwargs include:
@@ -1177,10 +1171,19 @@ class Query(object):
same table. Consider usage of the aliased(SomeClass) construct as
a more explicit approach to this.
- from_joinpoint - when joins are specified using string property
- names, locate the property from the mapper found in the most
- recent previous join() call, instead of from the root entity.
-
+ from_joinpoint - the given join conditions will attempt
+ to join from the right endpoint of the most recent join(),
+ instead of from the query's root entity. I.e. any chain
+ of joins, such as::
+
+ query.join(a, b, c)
+
+ is equivalent to::
+
+ query.join(a).\\
+ join(b, from_joinpoint=True).\\
+ join(c, from_joinpoint=True)
+
"""
aliased, from_joinpoint = kwargs.pop('aliased', False),\
kwargs.pop('from_joinpoint', False)
@@ -1191,7 +1194,6 @@ class Query(object):
outerjoin=False, create_aliases=aliased,
from_joinpoint=from_joinpoint)
- @util.accepts_a_list_as_starargs(list_deprecation='deprecated')
def outerjoin(self, *props, **kwargs):
"""Create a left outer join against this ``Query`` object's criterion
and apply generatively, retunring the newly resulting ``Query``.
@@ -1219,16 +1221,21 @@ class Query(object):
if not from_joinpoint:
self._reset_joinpoint()
- if len(keys) >= 2 and \
- isinstance(keys[1], expression.ClauseElement) and \
- not isinstance(keys[1], expression.FromClause):
- raise sa_exc.ArgumentError(
- "You appear to be passing a clause expression as the second "
- "argument to query.join(). Did you mean to use the form "
- "query.join((target, onclause))? Note the tuple.")
-
+ if len(keys) == 2 and \
+ isinstance(keys[0], (expression.FromClause,
+ type, AliasedClass)) and \
+ isinstance(keys[1], (basestring, expression.ClauseElement,
+ interfaces.PropComparator)):
+ # detect 2-arg form of join and
+ # convert to a tuple.
+ keys = (keys,)
+
for arg1 in util.to_list(keys):
if isinstance(arg1, tuple):
+ # "tuple" form of join, multiple
+ # tuples are accepted as well. The simpler
+ # "2-arg" form is preferred. May deprecate
+ # the "tuple" usage.
arg1, arg2 = arg1
else:
arg2 = None
@@ -1597,7 +1604,7 @@ class Query(object):
if not isinstance(statement,
(expression._TextClause,
- expression._SelectBaseMixin)):
+ expression._SelectBase)):
raise sa_exc.ArgumentError(
"from_statement accepts text(), select(), "
"and union() objects only.")
@@ -1772,7 +1779,7 @@ class Query(object):
filter = None
custom_rows = single_entity and \
- 'append_result' in self._entities[0].extension
+ self._entities[0].mapper.dispatch.on_append_result
(process, labels) = \
zip(*[
@@ -2167,8 +2174,7 @@ class Query(object):
)
)
- for ext in session.extensions:
- ext.after_bulk_delete(session, self, context, result)
+ session.dispatch.on_after_bulk_delete(session, self, context, result)
return result.rowcount
@@ -2317,9 +2323,8 @@ class Query(object):
session.identity_map[identity_key],
[_attr_as_key(k) for k in values]
)
-
- for ext in session.extensions:
- ext.after_bulk_update(session, self, context, result)
+
+ session.dispatch.on_after_bulk_update(session, self, context, result)
return result.rowcount
@@ -2468,7 +2473,7 @@ class Query(object):
for hint in self._with_hints:
statement = statement.with_hint(*hint)
-
+
if self._execution_options:
statement = statement.execution_options(
**self._execution_options)
@@ -2538,7 +2543,6 @@ class _MapperEntity(_QueryEntity):
def setup_entity(self, entity, mapper, adapter,
from_obj, is_aliased_class, with_polymorphic):
self.mapper = mapper
- self.extension = self.mapper.extension
self.adapter = adapter
self.selectable = from_obj
self._with_polymorphic = with_polymorphic
@@ -2622,7 +2626,6 @@ class _MapperEntity(_QueryEntity):
context,
(self.path_entity,),
adapter,
- extension=self.extension,
only_load_props=query._only_load_props,
refresh_state=context.refresh_state,
polymorphic_discriminator=
@@ -2691,7 +2694,10 @@ class _ColumnEntity(_QueryEntity):
if isinstance(column, basestring):
column = sql.literal_column(column)
self._label_name = column.name
- elif isinstance(column, attributes.QueryableAttribute):
+ elif isinstance(column, (
+ attributes.QueryableAttribute,
+ interfaces.PropComparator
+ )):
self._label_name = column.key
column = column.__clause_element__()
else:
@@ -2752,6 +2758,7 @@ class _ColumnEntity(_QueryEntity):
def adapt_to_selectable(self, query, sel):
c = _ColumnEntity(query, sel.corresponding_column(self.column))
+ c._label_name = self._label_name
c.entity_zero = self.entity_zero
c.entities = self.entities
@@ -2803,7 +2810,7 @@ class QueryContext(object):
def __init__(self, query):
if query._statement is not None:
- if isinstance(query._statement, expression._SelectBaseMixin) and \
+ if isinstance(query._statement, expression._SelectBase) and \
not query._statement.use_labels:
self.statement = query._statement.apply_labels()
else: