def __find_entity(self, query, mapper, raiseerr): from sqlalchemy.orm.util import _class_to_mapper, _is_aliased_class if _is_aliased_class(mapper): searchfor = mapper else: searchfor = _class_to_mapper(mapper).base_mapper for ent in query._mapper_entities: if ent.path_entity is searchfor: return ent else: if raiseerr: raise sa_exc.ArgumentError("Can't find entity %s in Query. Current list: %r" % (searchfor, [str(m.path_entity) for m in query._entities])) else: return None
def __find_entity(self, query, mapper, raiseerr): from sqlalchemy.orm.util import _class_to_mapper, _is_aliased_class if _is_aliased_class(mapper): searchfor = mapper isa = False else: searchfor = _class_to_mapper(mapper) isa = True for ent in query._mapper_entities: if searchfor is ent.path_entity or (isa and searchfor.common_parent(ent.path_entity)): return ent else: if raiseerr: raise sa_exc.ArgumentError("Can't find entity %s in Query. Current list: %r" % (searchfor, [str(m.path_entity) for m in query._entities])) else: return None
def __init__(self, entities, *args, **kwargs): Query.__init__(self, entities, *args, **kwargs) for entity in entities: if hasattr(entity, 'parententity'): entity = entity.parententity try: cls = _class_to_mapper(entity).class_ except AttributeError: # XXX For tables, table columns pass else: crit = getattr(cls, 'public', None) if crit is not None: if not isinstance(crit, ClauseElement): # This simplest safe way to make bare boolean column # accepted as expression. crit = cast(crit, Boolean) query = self.filter(crit) self._criterion = query._criterion
def _find_entity( self, query, mapper, raiseerr): from sqlalchemy.orm.util import _class_to_mapper, \ _is_aliased_class if _is_aliased_class(mapper): searchfor = mapper isa = False else: searchfor = _class_to_mapper(mapper) isa = True for ent in query._mapper_entities: if searchfor is ent.path_entity or isa \ and searchfor.common_parent(ent.path_entity): return ent else: if raiseerr: raise sa_exc.ArgumentError("Can't find entity %s in " "Query. Current list: %r" % (searchfor, [str(m.path_entity) for m in query._entities])) else: return None
def _entity_criterion(self, entity): #if hasattr(entity, "property"): # entity = entity.property.mapper if hasattr(entity, 'parententity'): entity = entity.parententity try: cls = _class_to_mapper(entity).class_ except AttributeError: # XXX For tables, table columns #pass raise # XXX temporal, to verify it's used else: alias = entity if isinstance(entity, AliasedClass) else cls prop = self.property_name if prop in dir(cls): crit = getattr(alias, prop) if crit is not None: if not isinstance(crit, ClauseElement): # This simplest safe way to make bare boolean column # accepted as expression. crit = cast(crit, Boolean) return crit return None
def _entity_criterion(self, entity): #if hasattr(entity, "property"): # entity = entity.property.mapper if hasattr(entity, 'parententity'): # XXX is this used? entity = entity.parententity try: cls = _class_to_mapper(entity).class_ except AttributeError: # XXX For tables, table columns #pass raise # XXX temporal, to verify it's used else: alias = entity if isinstance(entity, AliasedClass) else cls prop = self.property_name if prop in dir(cls): crit = getattr(alias, prop) if crit is not None: if not isinstance(crit, ClauseElement): # This simplest safe way to make bare boolean column # accepted as expression. crit = cast(crit, Boolean) return crit return None
def setup_query(self, context, entity, path, reduced_path, adapter, column_collection=None, parentmapper=None, **kwargs): if not context.query._enable_eagerloads: return path = path + (self.key, ) reduced_path = reduced_path + (self.key, ) # build up a path indicating the path from the leftmost # entity to the thing we're subquery loading. subq_path = context.attributes.get(('subquery_path', None), ()) subq_path = subq_path + path # join-depth / recursion check if ("loaderstrategy", reduced_path) not in context.attributes: if self.join_depth: if len(path) / 2 > self.join_depth: return else: if self.mapper.base_mapper in interfaces._reduce_path( subq_path): return orig_query = context.attributes.get(("orig_query", SubqueryLoader), context.query) subq_mapper = mapperutil._class_to_mapper(subq_path[0]) # determine attributes of the leftmost mapper if self.parent.isa(subq_mapper) and self.key == subq_path[1]: leftmost_mapper, leftmost_prop = \ self.parent, self.parent_property else: leftmost_mapper, leftmost_prop = \ subq_mapper, \ subq_mapper._props[subq_path[1]] leftmost_cols, remote_cols = self._local_remote_columns(leftmost_prop) leftmost_attr = [ leftmost_mapper._columntoproperty[c].class_attribute for c in leftmost_cols ] # reformat the original query # to look only for significant columns q = orig_query._clone() # TODO: why does polymporphic etc. require hardcoding # into _adapt_col_list ? Does query.add_columns(...) work # with polymorphic loading ? q._set_entities(q._adapt_col_list(leftmost_attr)) # don't need ORDER BY if no limit/offset if q._limit is None and q._offset is None: q._order_by = None # the original query now becomes a subquery # which we'll join onto. embed_q = q.with_labels().subquery() left_alias = mapperutil.AliasedClass(leftmost_mapper, embed_q) # q becomes a new query. basically doing a longhand # "from_self()". (from_self() itself not quite industrial # strength enough for all contingencies...but very close) q = q.session.query(self.mapper) q._attributes = { ("orig_query", SubqueryLoader): orig_query, ('subquery_path', None): subq_path } q = q._enable_single_crit(False) # figure out what's being joined. a.k.a. the fun part to_join = [(subq_path[i], subq_path[i + 1]) for i in range(0, len(subq_path), 2)] # determine the immediate parent class we are joining from, # which needs to be aliased. if len(to_join) < 2: # in the case of a one level eager load, this is the # leftmost "left_alias". parent_alias = left_alias elif subq_path[-2].isa(self.parent): # In the case of multiple levels, retrieve # it from subq_path[-2]. This is the same as self.parent # in the vast majority of cases, and [ticket:2014] # illustrates a case where sub_path[-2] is a subclass # of self.parent parent_alias = mapperutil.AliasedClass(subq_path[-2]) else: # if of_type() were used leading to this relationship, # self.parent is more specific than subq_path[-2] parent_alias = mapperutil.AliasedClass(self.parent) local_cols, remote_cols = \ self._local_remote_columns(self.parent_property) local_attr = [ getattr(parent_alias, self.parent._columntoproperty[c].key) for c in local_cols ] q = q.order_by(*local_attr) q = q.add_columns(*local_attr) for i, (mapper, key) in enumerate(to_join): # we need to use query.join() as opposed to # orm.join() here because of the # rich behavior it brings when dealing with # "with_polymorphic" mappers. "aliased" # and "from_joinpoint" take care of most of # the chaining and aliasing for us. first = i == 0 middle = i < len(to_join) - 1 second_to_last = i == len(to_join) - 2 if first: attr = getattr(left_alias, key) else: attr = key if second_to_last: q = q.join(parent_alias, attr, from_joinpoint=True) else: q = q.join(attr, aliased=middle, from_joinpoint=True) # propagate loader options etc. to the new query. # these will fire relative to subq_path. q = q._with_current_path(subq_path) q = q._conditional_options(*orig_query._with_options) if self.parent_property.order_by: # if there's an ORDER BY, alias it the same # way joinedloader does, but we have to pull out # the "eagerjoin" from the query. # this really only picks up the "secondary" table # right now. eagerjoin = q._from_obj[0] eager_order_by = \ eagerjoin._target_adapter.\ copy_and_process( util.to_list( self.parent_property.order_by ) ) q = q.order_by(*eager_order_by) # add new query to attributes to be picked up # by create_row_processor context.attributes[('subquery', reduced_path)] = q
def __init__(self, prop, mapper, of_type=None, adapter=None): self.prop = prop self.mapper = mapper self.adapter = adapter if of_type: self._of_type = _class_to_mapper(of_type)
def __init__(self, prop, mapper, of_type=None, adapter=None): self.prop = self.property = prop self.mapper = mapper self.adapter = adapter if of_type: self._of_type = _class_to_mapper(of_type)
def setup_query(self, context, entity, path, reduced_path, adapter, column_collection=None, parentmapper=None, **kwargs): if not context.query._enable_eagerloads: return path = path + (self.key, ) reduced_path = reduced_path + (self.key, ) # build up a path indicating the path from the leftmost # entity to the thing we're subquery loading. subq_path = context.attributes.get(('subquery_path', None), ()) subq_path = subq_path + path # join-depth / recursion check if ("loaderstrategy", reduced_path) not in context.attributes: if self.join_depth: if len(path) / 2 > self.join_depth: return else: if self.mapper.base_mapper in interfaces._reduce_path(subq_path): return orig_query = context.attributes.get( ("orig_query", SubqueryLoader), context.query) subq_mapper = mapperutil._class_to_mapper(subq_path[0]) # determine attributes of the leftmost mapper if self.parent.isa(subq_mapper) and self.key==subq_path[1]: leftmost_mapper, leftmost_prop = \ self.parent, self.parent_property else: leftmost_mapper, leftmost_prop = \ subq_mapper, \ subq_mapper._props[subq_path[1]] leftmost_cols, remote_cols = self._local_remote_columns(leftmost_prop) leftmost_attr = [ leftmost_mapper._columntoproperty[c].class_attribute for c in leftmost_cols ] # reformat the original query # to look only for significant columns q = orig_query._clone() # TODO: why does polymporphic etc. require hardcoding # into _adapt_col_list ? Does query.add_columns(...) work # with polymorphic loading ? q._set_entities(q._adapt_col_list(leftmost_attr)) # don't need ORDER BY if no limit/offset if q._limit is None and q._offset is None: q._order_by = None # the original query now becomes a subquery # which we'll join onto. embed_q = q.with_labels().subquery() left_alias = mapperutil.AliasedClass(leftmost_mapper, embed_q) # q becomes a new query. basically doing a longhand # "from_self()". (from_self() itself not quite industrial # strength enough for all contingencies...but very close) q = q.session.query(self.mapper) q._attributes = { ("orig_query", SubqueryLoader): orig_query, ('subquery_path', None) : subq_path } q = q._enable_single_crit(False) # figure out what's being joined. a.k.a. the fun part to_join = [ (subq_path[i], subq_path[i+1]) for i in xrange(0, len(subq_path), 2) ] # determine the immediate parent class we are joining from, # which needs to be aliased. if len(to_join) < 2: # in the case of a one level eager load, this is the # leftmost "left_alias". parent_alias = left_alias elif subq_path[-2].isa(self.parent): # In the case of multiple levels, retrieve # it from subq_path[-2]. This is the same as self.parent # in the vast majority of cases, and [ticket:2014] # illustrates a case where sub_path[-2] is a subclass # of self.parent parent_alias = mapperutil.AliasedClass(subq_path[-2]) else: # if of_type() were used leading to this relationship, # self.parent is more specific than subq_path[-2] parent_alias = mapperutil.AliasedClass(self.parent) local_cols, remote_cols = \ self._local_remote_columns(self.parent_property) local_attr = [ getattr(parent_alias, self.parent._columntoproperty[c].key) for c in local_cols ] q = q.order_by(*local_attr) q = q.add_columns(*local_attr) for i, (mapper, key) in enumerate(to_join): # we need to use query.join() as opposed to # orm.join() here because of the # rich behavior it brings when dealing with # "with_polymorphic" mappers. "aliased" # and "from_joinpoint" take care of most of # the chaining and aliasing for us. first = i == 0 middle = i < len(to_join) - 1 second_to_last = i == len(to_join) - 2 if first: attr = getattr(left_alias, key) else: attr = key if second_to_last: q = q.join(parent_alias, attr, from_joinpoint=True) else: q = q.join(attr, aliased=middle, from_joinpoint=True) # propagate loader options etc. to the new query. # these will fire relative to subq_path. q = q._with_current_path(subq_path) q = q._conditional_options(*orig_query._with_options) if self.parent_property.order_by: # if there's an ORDER BY, alias it the same # way joinedloader does, but we have to pull out # the "eagerjoin" from the query. # this really only picks up the "secondary" table # right now. eagerjoin = q._from_obj[0] eager_order_by = \ eagerjoin._target_adapter.\ copy_and_process( util.to_list( self.parent_property.order_by ) ) q = q.order_by(*eager_order_by) # add new query to attributes to be picked up # by create_row_processor context.attributes[('subquery', reduced_path)] = q