Beispiel #1
0
    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
Beispiel #2
0
    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)
            )
Beispiel #3
0
    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
Beispiel #4
0
    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)
Beispiel #6
0
    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
                                    )
                                )
Beispiel #7
0
    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
Beispiel #8
0
    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