diff options
Diffstat (limited to 'lib/sqlalchemy/orm/query.py')
| -rw-r--r-- | lib/sqlalchemy/orm/query.py | 97 |
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: |
