Ejemplo n.º 1
0
    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
Ejemplo n.º 2
0
    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
Ejemplo n.º 3
0
    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
Ejemplo n.º 4
0
 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
Ejemplo n.º 5
0
 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
Ejemplo n.º 6
0
 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
Ejemplo n.º 7
0
 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
Ejemplo n.º 8
0
    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
Ejemplo n.º 9
0
 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)
Ejemplo n.º 10
0
 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)
Ejemplo n.º 11
0
    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