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
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
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_
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 [])
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)
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