Пример #1
0
def join_table_with_query(query, table):
    """Find a join between a query and a table, modifying the from clause in
    place."""
    # Check if the join is needed.
    _, orig_clause = sql_util.find_join_source(
                                            query._froms,
                                            table)
    if orig_clause is not None:
        # The join is already in the query
        return
    replace_clause_index = None
    found = False
    for index, _from in enumerate(query._froms):
        replacement = find_join(_from, table)
        if replacement is not None:
            query._from_obj = OrderedSet(
                query._from_obj[:index] +
                [replacement] +
                query._from_obj[index + 1:])
            found = True
            break
    if not found:
        raise ValueError('Cannot find join between %s and %s' % (table,
                                                                 query))
    return
Пример #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)
            )
Пример #3
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
                                    )
                                )
Пример #4
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,
            adapt_required=True)

        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
Пример #5
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