Example #1
0
 def _aliasize_orderby(self, orderby, copy=True):
     if copy:
         orderby = [o.copy_container() for o in util.to_list(orderby)]
     else:
         orderby = util.to_list(orderby)
     for i in range(0, len(orderby)):
         if isinstance(orderby[i], schema.Column):
             orderby[i] = self.eagertarget.corresponding_column(
                 orderby[i])
         else:
             orderby[i].accept_visitor(self.aliasizer)
     return orderby
Example #2
0
    def _get(self, key, ident=None, reload=False, lockmode=None):
        lockmode = lockmode or self.lockmode
        if not reload and not self.always_refresh and lockmode is None:
            try:
                return self.session._get(key)
            except KeyError:
                pass

        if ident is None:
            ident = key[1]
        else:
            ident = util.to_list(ident)
        i = 0
        params = {}
        for primary_key in self.mapper.pks_by_table[self.table]:
            params[primary_key._label] = ident[i]
            # if there are not enough elements in the given identifier, then
            # use the previous identifier repeatedly.  this is a workaround for the issue
            # in [ticket:185], where a mapper that uses joined table inheritance needs to specify
            # all primary keys of the joined relationship, which includes even if the join is joining
            # two primary key (and therefore synonymous) columns together, the usual case for joined table inheritance.
            if len(ident) > i + 1:
                i += 1
        try:
            statement = self.compile(self._get_clause, lockmode=lockmode)
            return self._select_statement(statement,
                                          params=params,
                                          populate_existing=reload,
                                          version_check=(lockmode
                                                         is not None))[0]
        except IndexError:
            return None
Example #3
0
 def __init__(self,
              manager,
              class_,
              key,
              uselist,
              callable_,
              typecallable,
              cascade=None,
              extension=None,
              **kwargs):
     extension = util.to_list(extension or [])
     extension.insert(0, UOWEventHandler(key, class_, cascade=cascade))
     super(UOWProperty, self).__init__(manager,
                                       key,
                                       uselist,
                                       callable_,
                                       typecallable,
                                       extension=extension,
                                       **kwargs)
     self.class_ = class_
Example #4
0
 def __init__(self, manager, key, uselist, callable_, typecallable, trackparent=False, extension=None, copy_function=None, compare_function=None, mutable_scalars=False, **kwargs):
     self.manager = manager
     self.key = key
     self.uselist = uselist
     self.callable_ = callable_
     self.typecallable= typecallable
     self.trackparent = trackparent
     self.mutable_scalars = mutable_scalars
     if copy_function is None:
         if uselist:
             self.copy = lambda x:[y for y in x]
         else:
             # scalar values are assumed to be immutable unless a copy function
             # is passed
             self.copy = lambda x:x
     else:
         self.copy = lambda x:copy_function(x)
     if compare_function is None:
         self.is_equal = lambda x,y: x == y
     else:
         self.is_equal = compare_function
     self.extensions = util.to_list(extension or [])
Example #5
0
    def setup_query(self,
                    context,
                    eagertable=None,
                    parentclauses=None,
                    parentmapper=None,
                    **kwargs):
        """add a left outer join to the statement thats being constructed"""
        if parentmapper is None:
            localparent = context.mapper
        else:
            localparent = parentmapper

        if self.mapper in context.recursion_stack:
            return
        else:
            context.recursion_stack.add(self.parent)

        statement = context.statement

        if hasattr(statement, '_outerjoin'):
            towrap = statement._outerjoin
        elif isinstance(localparent.mapped_table, schema.Table):
            # if the mapper is against a plain Table, look in the from_obj of the select statement
            # to join against whats already there.
            for (fromclause, finder) in [(x, sql_util.TableFinder(x))
                                         for x in statement.froms]:
                # dont join against an Alias'ed Select.  we are really looking either for the
                # table itself or a Join that contains the table.  this logic still might need
                # adjustments for scenarios not thought of yet.
                if not isinstance(
                        fromclause,
                        sql.Alias) and localparent.mapped_table in finder:
                    towrap = fromclause
                    break
            else:
                raise exceptions.InvalidRequestError(
                    "EagerLoader cannot locate a clause with which to outer join to, in query '%s' %s"
                    % (str(statement), self.localparent.mapped_table))
        else:
            # if the mapper is against a select statement or something, we cant handle that at the
            # same time as a custom FROM clause right now.
            towrap = localparent.mapped_table

        try:
            clauses = self.clauses[parentclauses]
        except KeyError:
            clauses = EagerLoader.AliasedClauses(self, parentclauses)
            self.clauses[parentclauses] = clauses
            self.clauses_by_lead_mapper[context.mapper] = clauses

        if self.secondaryjoin is not None:
            statement._outerjoin = sql.outerjoin(
                towrap, clauses.eagersecondary,
                clauses.eagerprimary).outerjoin(clauses.eagertarget,
                                                clauses.eagersecondaryjoin)
            if self.order_by is False and self.secondary.default_order_by(
            ) is not None:
                statement.order_by(*clauses.eagersecondary.default_order_by())
        else:
            statement._outerjoin = towrap.outerjoin(clauses.eagertarget,
                                                    clauses.eagerprimary)
            if self.order_by is False and clauses.eagertarget.default_order_by(
            ) is not None:
                statement.order_by(*clauses.eagertarget.default_order_by())

        if clauses.eager_order_by:
            statement.order_by(*util.to_list(clauses.eager_order_by))
        elif getattr(statement, 'order_by_clause', None):
            clauses._aliasize_orderby(statement.order_by_clause, False)

        statement.append_from(statement._outerjoin)
        for value in self.select_mapper.props.values():
            value.setup(context,
                        eagertable=clauses.eagertarget,
                        parentclauses=clauses,
                        parentmapper=self.select_mapper)
Example #6
0
    def compile(self, whereclause=None, **kwargs):
        """given a WHERE criterion, produce a ClauseElement-based statement suitable for usage in the execute() method."""
        context = kwargs.pop('query_context', None)
        if context is None:
            context = QueryContext(self, kwargs)
        order_by = context.order_by
        from_obj = context.from_obj
        lockmode = context.lockmode
        distinct = context.distinct
        limit = context.limit
        offset = context.offset
        if order_by is False:
            order_by = self.order_by
        if order_by is False:
            if self.table.default_order_by() is not None:
                order_by = self.table.default_order_by()

        try:
            for_update = {
                'read': 'read',
                'update': True,
                'update_nowait': 'nowait',
                None: False
            }[lockmode]
        except KeyError:
            raise exceptions.ArgumentError("Unknown lockmode '%s'" % lockmode)

        if self.mapper.single and self.mapper.polymorphic_on is not None and self.mapper.polymorphic_identity is not None:
            whereclause = sql.and_(
                whereclause,
                self.mapper.polymorphic_on.in_(*[
                    m.polymorphic_identity
                    for m in self.mapper.polymorphic_iterator()
                ]))

        alltables = []
        for l in [sql_util.TableFinder(x) for x in from_obj]:
            alltables += l

        if self.table not in alltables:
            from_obj.append(self.table)

        if self._should_nest(context):
            # if theres an order by, add those columns to the column list
            # of the "rowcount" query we're going to make
            if order_by:
                order_by = util.to_list(order_by) or []
                cf = sql_util.ColumnFinder()
                [o.accept_visitor(cf) for o in order_by]
            else:
                cf = []

            s2 = sql.select(self.table.primary_key + list(cf),
                            whereclause,
                            use_labels=True,
                            from_obj=from_obj,
                            **context.select_args())
            if not distinct and order_by:
                s2.order_by(*util.to_list(order_by))
            s3 = s2.alias('tbl_row_count')
            crit = s3.primary_key == self.table.primary_key
            statement = sql.select([],
                                   crit,
                                   from_obj=[self.table],
                                   use_labels=True,
                                   for_update=for_update)
            # now for the order by, convert the columns to their corresponding columns
            # in the "rowcount" query, and tack that new order by onto the "rowcount" query
            if order_by:

                class Aliasizer(sql_util.Aliasizer):
                    def get_alias(self, table):
                        return s3

                order_by = [o.copy_container() for o in order_by]
                aliasizer = Aliasizer(*[t for t in sql_util.TableFinder(s3)])
                [o.accept_visitor(aliasizer) for o in order_by]
                statement.order_by(*util.to_list(order_by))
        else:
            statement = sql.select([],
                                   whereclause,
                                   from_obj=from_obj,
                                   use_labels=True,
                                   for_update=for_update,
                                   **context.select_args())
            if order_by:
                statement.order_by(*util.to_list(order_by))
            # for a DISTINCT query, you need the columns explicitly specified in order
            # to use it in "order_by".  ensure they are in the column criterion (particularly oid).
            # TODO: this should be done at the SQL level not the mapper level
            if kwargs.get('distinct', False) and order_by:
                [statement.append_column(c) for c in util.to_list(order_by)]

        context.statement = statement
        # give all the attached properties a chance to modify the query
        for value in self.mapper.props.values():
            value.setup(context)

        return statement