def __create_eager_join(self, context, path, parentclauses, parentmapper, **kwargs): if parentmapper is None: localparent = context.mapper else: localparent = parentmapper if context.eager_joins: towrap = context.eager_joins else: towrap = context.from_clause # create AliasedClauses object to build up the eager query. this is cached after 1st creation. try: clauses = self.clauses[path] except KeyError: clauses = mapperutil.PropertyAliasedClauses(self.parent_property, self.parent_property.primaryjoin, self.parent_property.secondaryjoin, parentclauses) self.clauses[path] = clauses # place the "row_decorator" from the AliasedClauses into the QueryContext, where it will # be picked up in create_row_processor() when results are fetched context.attributes[("eager_row_processor", path)] = clauses.row_decorator if self.secondaryjoin is not None: context.eager_joins = sql.outerjoin(towrap, clauses.secondary, clauses.primaryjoin).outerjoin(clauses.alias, clauses.secondaryjoin) # TODO: check for "deferred" cols on parent/child tables here ? this would only be # useful if the primary/secondaryjoin are against non-PK columns on the tables (and therefore might be deferred) if self.order_by is False and self.secondary.default_order_by() is not None: context.eager_order_by += clauses.secondary.default_order_by() else: context.eager_joins = towrap.outerjoin(clauses.alias, clauses.primaryjoin) # ensure all the cols on the parent side are actually in the # columns clause (i.e. are not deferred), so that aliasing applied by the Query propagates # those columns outward. This has the effect of "undefering" those columns. for col in sql_util.find_columns(clauses.primaryjoin): if localparent.mapped_table.c.contains_column(col): context.primary_columns.append(col) if self.order_by is False and clauses.alias.default_order_by() is not None: context.eager_order_by += clauses.alias.default_order_by() if clauses.order_by: context.eager_order_by += util.to_list(clauses.order_by) return clauses
def _create_eager_join(self, context, entity, path, adapter, parentmapper, clauses): if parentmapper is None: localparent = entity.mapper else: localparent = parentmapper # whether or not the Query will wrap the selectable in a subquery, # and then attach eager load joins to that (i.e., in the case of # LIMIT/OFFSET etc.) should_nest_selectable = context.multi_row_eager_loaders and context.query._should_nest_selectable entity_key = None if entity not in context.eager_joins and not should_nest_selectable and context.from_clause: index, clause = sql_util.find_join_source(context.from_clause, entity.selectable) if clause is not None: # join to an existing FROM clause on the query. # key it to its list index in the eager_joins dict. # Query._compile_context will adapt as needed and # append to the FROM clause of the select(). entity_key, default_towrap = index, clause if entity_key is None: entity_key, default_towrap = entity, entity.selectable towrap = context.eager_joins.setdefault(entity_key, default_towrap) join_to_left = False if adapter: if getattr(adapter, "aliased_class", None): onclause = getattr(adapter.aliased_class, self.key, self.parent_property) else: onclause = getattr( mapperutil.AliasedClass(self.parent, adapter.selectable), self.key, self.parent_property ) if onclause is self.parent_property: # TODO: this is a temporary hack to # account for polymorphic eager loads where # the eagerload is referencing via of_type(). join_to_left = True else: onclause = self.parent_property innerjoin = context.attributes.get(("eager_join_type", path), self.parent_property.innerjoin) context.eager_joins[entity_key] = eagerjoin = mapperutil.join( towrap, clauses.aliased_class, onclause, join_to_left=join_to_left, isouter=not innerjoin ) # send a hint to the Query as to where it may "splice" this join eagerjoin.stop_on = entity.selectable if self.parent_property.secondary is None and not parentmapper: # for parentclause that is the non-eager end of the join, # ensure all the parent cols in the primaryjoin are actually # in the # columns clause (i.e. are not deferred), so that aliasing applied # by the Query propagates those columns outward. # This has the effect # of "undefering" those columns. for col in sql_util.find_columns(self.parent_property.primaryjoin): if localparent.mapped_table.c.contains_column(col): if adapter: col = adapter.columns[col] context.primary_columns.append(col) if self.parent_property.order_by: context.eager_order_by += eagerjoin._target_adapter.copy_and_process( util.to_list(self.parent_property.order_by) )
def _create_eager_join(self, context, entity, path, adapter, parentmapper): # check for join_depth or basic recursion, # if the current path was not explicitly stated as # a desired "loaderstrategy" (i.e. via query.options()) if ("loaderstrategy", path) not in context.attributes: if self.join_depth: if len(path) / 2 > self.join_depth: return else: if self.mapper.base_mapper in path: return if parentmapper is None: localparent = entity.mapper else: localparent = parentmapper # whether or not the Query will wrap the selectable in a subquery, # and then attach eager load joins to that (i.e., in the case of LIMIT/OFFSET etc.) should_nest_selectable = context.query._should_nest_selectable if entity in context.eager_joins: entity_key, default_towrap = entity, entity.selectable elif should_nest_selectable or not context.from_clause or not sql_util.search( context.from_clause, entity.selectable): # if no from_clause, or a from_clause we can't join to, or a subquery is going to be generated, # store eager joins per _MappedEntity; Query._compile_context will # add them as separate selectables to the select(), or splice them together # after the subquery is generated entity_key, default_towrap = entity, entity.selectable else: # otherwise, create a single eager join from the from clause. # Query._compile_context will adapt as needed and append to the # FROM clause of the select(). entity_key, default_towrap = None, context.from_clause towrap = context.eager_joins.setdefault(entity_key, default_towrap) # create AliasedClauses object to build up the eager query. clauses = mapperutil.ORMAdapter( mapperutil.AliasedClass(self.mapper), equivalents=self.mapper._equivalent_columns) join_to_left = False if adapter: if getattr(adapter, 'aliased_class', None): onclause = getattr(adapter.aliased_class, self.key, self.parent_property) else: onclause = getattr( mapperutil.AliasedClass(self.parent, adapter.selectable), self.key, self.parent_property) if onclause is self.parent_property: # TODO: this is a temporary hack to account for polymorphic eager loads where # the eagerload is referencing via of_type(). join_to_left = True else: onclause = self.parent_property context.eager_joins[entity_key] = eagerjoin = mapperutil.outerjoin( towrap, clauses.aliased_class, onclause, join_to_left=join_to_left) # send a hint to the Query as to where it may "splice" this join eagerjoin.stop_on = entity.selectable if not self.parent_property.secondary and context.query._should_nest_selectable and not parentmapper: # for parentclause that is the non-eager end of the join, # ensure all the parent cols in the primaryjoin are actually in the # columns clause (i.e. are not deferred), so that aliasing applied by the Query propagates # those columns outward. This has the effect of "undefering" those columns. for col in sql_util.find_columns(self.parent_property.primaryjoin): if localparent.mapped_table.c.contains_column(col): if adapter: col = adapter.columns[col] context.primary_columns.append(col) if self.parent_property.order_by: context.eager_order_by += eagerjoin._target_adapter.copy_and_process( util.to_list(self.parent_property.order_by)) return clauses
def setup_query(self, context, parentclauses=None, parentmapper=None, **kwargs): """Add a left outer join to the statement thats being constructed.""" path = context.path # check for join_depth or basic recursion, # if the current path was not explicitly stated as # a desired "loaderstrategy" (i.e. via query.options()) if ("loaderstrategy", path) not in context.attributes: if self.join_depth: if len(path) / 2 > self.join_depth: return else: if self.mapper.base_mapper in path: return if parentmapper is None: localparent = context.mapper else: localparent = parentmapper if context.eager_joins: towrap = context.eager_joins else: towrap = context.from_clause # create AliasedClauses object to build up the eager query. this is cached after 1st creation. try: clauses = self.clauses[path] except KeyError: clauses = mapperutil.PropertyAliasedClauses( self.parent_property, self.parent_property.primaryjoin, self.parent_property.secondaryjoin, parentclauses) self.clauses[path] = clauses # place the "row_decorator" from the AliasedClauses into the QueryContext, where it will # be picked up in create_row_processor() when results are fetched context.attributes[("eager_row_processor", path)] = clauses.row_decorator if self.secondaryjoin is not None: context.eager_joins = sql.outerjoin(towrap, clauses.secondary, clauses.primaryjoin).outerjoin( clauses.alias, clauses.secondaryjoin) # TODO: check for "deferred" cols on parent/child tables here ? this would only be # useful if the primary/secondaryjoin are against non-PK columns on the tables (and therefore might be deferred) if self.order_by is False and self.secondary.default_order_by( ) is not None: context.eager_order_by += clauses.secondary.default_order_by() else: context.eager_joins = towrap.outerjoin(clauses.alias, clauses.primaryjoin) # ensure all the cols on the parent side are actually in the # columns clause (i.e. are not deferred), so that aliasing applied by the Query propagates # those columns outward. This has the effect of "undefering" those columns. for col in sql_util.find_columns(clauses.primaryjoin): if localparent.mapped_table.c.contains_column(col): context.primary_columns.append(col) if self.order_by is False and clauses.alias.default_order_by( ) is not None: context.eager_order_by += clauses.alias.default_order_by() if clauses.order_by: context.eager_order_by += util.to_list(clauses.order_by) for value in self.mapper._iterate_polymorphic_properties(): context.exec_with_path(self.mapper, value.key, value.setup, context, parentclauses=clauses, parentmapper=self.mapper)
def setup_query(self, context, parentclauses=None, parentmapper=None, **kwargs): """Add a left outer join to the statement thats being constructed.""" path = context.path # check for join_depth or basic recursion, # if the current path was not explicitly stated as # a desired "loaderstrategy" (i.e. via query.options()) if ("loaderstrategy", path) not in context.attributes: if self.join_depth: if len(path) / 2 > self.join_depth: return else: if self.mapper.base_mapper in path: return if parentmapper is None: localparent = context.mapper else: localparent = parentmapper if context.eager_joins: towrap = context.eager_joins else: towrap = context.from_clause # create AliasedClauses object to build up the eager query. this is cached after 1st creation. try: clauses = self.clauses[path] except KeyError: clauses = mapperutil.PropertyAliasedClauses(self.parent_property, self.parent_property.primaryjoin, self.parent_property.secondaryjoin, parentclauses) self.clauses[path] = clauses # place the "row_decorator" from the AliasedClauses into the QueryContext, where it will # be picked up in create_row_processor() when results are fetched context.attributes[("eager_row_processor", path)] = clauses.row_decorator if self.secondaryjoin is not None: context.eager_joins = sql.outerjoin(towrap, clauses.secondary, clauses.primaryjoin).outerjoin(clauses.alias, clauses.secondaryjoin) # TODO: check for "deferred" cols on parent/child tables here ? this would only be # useful if the primary/secondaryjoin are against non-PK columns on the tables (and therefore might be deferred) if self.order_by is False and self.secondary.default_order_by() is not None: context.eager_order_by += clauses.secondary.default_order_by() else: context.eager_joins = towrap.outerjoin(clauses.alias, clauses.primaryjoin) # ensure all the cols on the parent side are actually in the # columns clause (i.e. are not deferred), so that aliasing applied by the Query propagates # those columns outward. This has the effect of "undefering" those columns. for col in sql_util.find_columns(clauses.primaryjoin): if localparent.mapped_table.c.contains_column(col): context.primary_columns.append(col) if self.order_by is False and clauses.alias.default_order_by() is not None: context.eager_order_by += clauses.alias.default_order_by() if clauses.order_by: context.eager_order_by += util.to_list(clauses.order_by) for value in self.mapper._iterate_polymorphic_properties(): context.exec_with_path(self.mapper, value.key, value.setup, context, parentclauses=clauses, parentmapper=self.mapper)
def _create_eager_join(self, context, entity, path, adapter, parentmapper, clauses, innerjoin): if parentmapper is None: localparent = entity.mapper else: localparent = parentmapper # whether or not the Query will wrap the selectable in a subquery, # and then attach eager load joins to that (i.e., in the case of # LIMIT/OFFSET etc.) should_nest_selectable = context.multi_row_eager_loaders and \ context.query._should_nest_selectable entity_key = None if entity not in context.eager_joins and \ not should_nest_selectable and \ context.from_clause: index, clause = \ sql_util.find_join_source( context.from_clause, entity.selectable) if clause is not None: # join to an existing FROM clause on the query. # key it to its list index in the eager_joins dict. # Query._compile_context will adapt as needed and # append to the FROM clause of the select(). entity_key, default_towrap = index, clause if entity_key is None: entity_key, default_towrap = entity, entity.selectable towrap = context.eager_joins.setdefault(entity_key, default_towrap) join_to_left = False if adapter: if getattr(adapter, 'aliased_class', None): onclause = getattr(adapter.aliased_class, self.key, self.parent_property) else: onclause = getattr( mapperutil.AliasedClass(self.parent, adapter.selectable), self.key, self.parent_property) if onclause is self.parent_property: # TODO: this is a temporary hack to # account for polymorphic eager loads where # the eagerload is referencing via of_type(). join_to_left = True else: onclause = self.parent_property context.eager_joins[entity_key] = eagerjoin = \ mapperutil.join( towrap, clauses.aliased_class, onclause, join_to_left=join_to_left, isouter=not innerjoin ) # send a hint to the Query as to where it may "splice" this join eagerjoin.stop_on = entity.selectable if self.parent_property.secondary is None and \ not parentmapper: # for parentclause that is the non-eager end of the join, # ensure all the parent cols in the primaryjoin are actually # in the # columns clause (i.e. are not deferred), so that aliasing applied # by the Query propagates those columns outward. # This has the effect # of "undefering" those columns. for col in sql_util.find_columns(self.parent_property.primaryjoin): if localparent.mapped_table.c.contains_column(col): if adapter: col = adapter.columns[col] context.primary_columns.append(col) if self.parent_property.order_by: context.eager_order_by += \ eagerjoin._target_adapter.\ copy_and_process( util.to_list( self.parent_property.order_by ) )
def _create_eager_join(self, context, entity, path, adapter, parentmapper): # check for join_depth or basic recursion, # if the current path was not explicitly stated as # a desired "loaderstrategy" (i.e. via query.options()) if ("loaderstrategy", path) not in context.attributes: if self.join_depth: if len(path) / 2 > self.join_depth: return else: if self.mapper.base_mapper in path: return if parentmapper is None: localparent = entity.mapper else: localparent = parentmapper # whether or not the Query will wrap the selectable in a subquery, # and then attach eager load joins to that (i.e., in the case of LIMIT/OFFSET etc.) should_nest_selectable = context.query._should_nest_selectable if entity in context.eager_joins: entity_key, default_towrap = entity, entity.selectable elif should_nest_selectable or not context.from_clause: # if no from_clause, or a subquery is going to be generated, # store eager joins per _MappedEntity; Query._compile_context will # add them as separate selectables to the select(), or splice them together # after the subquery is generated entity_key, default_towrap = entity, entity.selectable else: index, clause = sql_util.find_join_source(context.from_clause, entity.selectable) if clause: # join to an existing FROM clause on the query. # key it to its list index in the eager_joins dict. # Query._compile_context will adapt as needed and append to the # FROM clause of the select(). entity_key, default_towrap = index, clause else: # if no from_clause to join to, # store eager joins per _MappedEntity entity_key, default_towrap = entity, entity.selectable towrap = context.eager_joins.setdefault(entity_key, default_towrap) # create AliasedClauses object to build up the eager query. clauses = mapperutil.ORMAdapter( mapperutil.AliasedClass(self.mapper), equivalents=self.mapper._equivalent_columns ) join_to_left = False if adapter: if getattr(adapter, "aliased_class", None): onclause = getattr(adapter.aliased_class, self.key, self.parent_property) else: onclause = getattr( mapperutil.AliasedClass(self.parent, adapter.selectable), self.key, self.parent_property ) if onclause is self.parent_property: # TODO: this is a temporary hack to account for polymorphic eager loads where # the eagerload is referencing via of_type(). join_to_left = True else: onclause = self.parent_property context.eager_joins[entity_key] = eagerjoin = mapperutil.outerjoin( towrap, clauses.aliased_class, onclause, join_to_left=join_to_left ) # send a hint to the Query as to where it may "splice" this join eagerjoin.stop_on = entity.selectable if not self.parent_property.secondary and context.query._should_nest_selectable and not parentmapper: # for parentclause that is the non-eager end of the join, # ensure all the parent cols in the primaryjoin are actually in the # columns clause (i.e. are not deferred), so that aliasing applied by the Query propagates # those columns outward. This has the effect of "undefering" those columns. for col in sql_util.find_columns(self.parent_property.primaryjoin): if localparent.mapped_table.c.contains_column(col): if adapter: col = adapter.columns[col] context.primary_columns.append(col) if self.parent_property.order_by: context.eager_order_by += eagerjoin._target_adapter.copy_and_process( util.to_list(self.parent_property.order_by) ) return clauses
def _create_eager_join(self, context, entity, path, adapter, parentmapper): # check for join_depth or basic recursion, # if the current path was not explicitly stated as # a desired "loaderstrategy" (i.e. via query.options()) if ("loaderstrategy", path) not in context.attributes: if self.join_depth: if len(path) / 2 > self.join_depth: return else: if self.mapper.base_mapper in path: return if parentmapper is None: localparent = entity.mapper else: localparent = parentmapper # whether or not the Query will wrap the selectable in a subquery, # and then attach eager load joins to that (i.e., in the case of LIMIT/OFFSET etc.) should_nest_selectable = context.query._should_nest_selectable if entity in context.eager_joins: entity_key, default_towrap = entity, entity.selectable elif should_nest_selectable or not context.from_clause or not sql_util.search(context.from_clause, entity.selectable): # if no from_clause, or a from_clause we can't join to, or a subquery is going to be generated, # store eager joins per _MappedEntity; Query._compile_context will # add them as separate selectables to the select(), or splice them together # after the subquery is generated entity_key, default_towrap = entity, entity.selectable else: # otherwise, create a single eager join from the from clause. # Query._compile_context will adapt as needed and append to the # FROM clause of the select(). entity_key, default_towrap = None, context.from_clause towrap = context.eager_joins.setdefault(entity_key, default_towrap) # create AliasedClauses object to build up the eager query. this is cached after 1st creation. # this also allows ORMJoin to cache the aliased joins it produces since we pass the same # args each time in the typical case. path_key = util.WeakCompositeKey(*path) try: clauses = self.clauses[path_key] except KeyError: self.clauses[path_key] = clauses = mapperutil.ORMAdapter(mapperutil.AliasedClass(self.mapper), equivalents=self.mapper._equivalent_columns) if adapter: if getattr(adapter, 'aliased_class', None): onclause = getattr(adapter.aliased_class, self.key, self.parent_property) else: onclause = getattr(mapperutil.AliasedClass(self.parent, adapter.selectable), self.key, self.parent_property) else: onclause = self.parent_property context.eager_joins[entity_key] = eagerjoin = mapperutil.outerjoin(towrap, clauses.aliased_class, onclause) # send a hint to the Query as to where it may "splice" this join eagerjoin.stop_on = entity.selectable if not self.parent_property.secondary and context.query._should_nest_selectable and not parentmapper: # for parentclause that is the non-eager end of the join, # ensure all the parent cols in the primaryjoin are actually in the # columns clause (i.e. are not deferred), so that aliasing applied by the Query propagates # those columns outward. This has the effect of "undefering" those columns. for col in sql_util.find_columns(self.parent_property.primaryjoin): if localparent.mapped_table.c.contains_column(col): if adapter: col = adapter.columns[col] context.primary_columns.append(col) if self.parent_property.order_by: context.eager_order_by += eagerjoin._target_adapter.copy_and_process(util.to_list(self.parent_property.order_by)) return clauses