takes optional string "property" to isolate the desired relation.
also adds static Query.query_from_parent(instance, property)
version. [ticket:541]
+ - improved query.XXX_by(someprop=someinstance) querying to use
+ similar methodology to with_parent, i.e. using the "lazy" clause
+ which prevents adding the remote instance's table to the SQL,
+ thereby making more complex conditions possible [ticket:554]
- added generative versions of aggregates, i.e. sum(), avg(), etc.
to query. used via query.apply_max(), apply_sum(), etc.
#552
t = sql.text(text)
return self.execute(t, params=params)
- def _with_parent_criterion(cls, mapper, instance, prop):
+ def _with_lazy_criterion(cls, instance, prop, reverse=False):
"""extract query criterion from a LazyLoader strategy given a Mapper,
source persisted/detached instance and PropertyLoader.
- ."""
+ """
+
from sqlalchemy.orm import strategies
- # this could be done very slickly with prop.compare() and join_via(),
- # but we are using the less generic LazyLoader clause so that we
- # retain the ability to do a self-referential join (also the lazy
- # clause typically requires only the primary table with no JOIN)
- loader = prop._get_strategy(strategies.LazyLoader)
- criterion = loader.lazywhere.copy_container()
- bind_to_col = dict([(loader.lazybinds[col].key, col) for col in loader.lazybinds])
+ (criterion, lazybinds, rev) = strategies.LazyLoader._create_lazy_clause(prop, reverse_direction=reverse)
+ bind_to_col = dict([(lazybinds[col].key, col) for col in lazybinds])
class Visitor(sql.ClauseVisitor):
def visit_bindparam(self, bindparam):
+ mapper = reverse and prop.mapper or prop.parent
bindparam.value = mapper.get_attr_by_column(instance, bind_to_col[bindparam.key])
Visitor().traverse(criterion)
return criterion
- _with_parent_criterion = classmethod(_with_parent_criterion)
+ _with_lazy_criterion = classmethod(_with_lazy_criterion)
+
def query_from_parent(cls, instance, property, **kwargs):
"""return a newly constructed Query object, with criterion corresponding to
a relationship to the given parent instance.
mapper = object_mapper(instance)
prop = mapper.props[property]
target = prop.mapper
- criterion = cls._with_parent_criterion(mapper, instance, prop)
+ criterion = cls._with_lazy_criterion(instance, prop)
return Query(target, **kwargs).filter(criterion)
query_from_parent = classmethod(query_from_parent)
raise exceptions.InvalidRequestError("Could not locate a property which relates instances of class '%s' to instances of class '%s'" % (self.mapper.class_.__name__, instance.__class__.__name__))
else:
prop = mapper.props[property]
- return self.filter(Query._with_parent_criterion(mapper, instance, prop))
+ return self.filter(Query._with_lazy_criterion(instance, prop))
def add_entity(self, entity):
"""add a mapped entity to the list of result columns to be returned.
The criterion is constructed in the same way as the
``select_by()`` method.
"""
-
+ import properties
+
clause = None
for arg in args:
if clause is None:
for key, value in params.iteritems():
(keys, prop) = self._locate_prop(key, start=start)
- c = prop.compare(value) & self.join_via(keys)
+ if isinstance(prop, properties.PropertyLoader):
+ c = self._with_lazy_criterion(value, prop, True) & self.join_via(keys[:-1])
+ else:
+ c = prop.compare(value) & self.join_via(keys)
if clause is None:
clause = c
else:
class LazyLoader(AbstractRelationLoader):
def init(self):
super(LazyLoader, self).init()
- (self.lazywhere, self.lazybinds, self.lazyreverse) = self._create_lazy_clause(self.polymorphic_primaryjoin, self.polymorphic_secondaryjoin, self.remote_side)
+ (self.lazywhere, self.lazybinds, self.lazyreverse) = self._create_lazy_clause(self)
# determine if our "lazywhere" clause is the same as the mapper's
# get() clause. then we can just use mapper.get()
# to load data into it.
sessionlib.attribute_manager.reset_instance_attribute(instance, self.key)
- def _create_lazy_clause(self, primaryjoin, secondaryjoin, remote_side):
+ def _create_lazy_clause(cls, prop, reverse_direction=False):
+ (primaryjoin, secondaryjoin, remote_side) = (prop.polymorphic_primaryjoin, prop.polymorphic_secondaryjoin, prop.remote_side)
+
binds = {}
reverse = {}
def should_bind(targetcol, othercol):
- return othercol in remote_side
+ if reverse_direction:
+ return targetcol in remote_side
+ else:
+ return othercol in remote_side
def find_column_in_expr(expr):
if not isinstance(expr, sql.ColumnElement):
secondaryjoin = secondaryjoin.copy_container()
lazywhere = sql.and_(lazywhere, secondaryjoin)
- LazyLoader.logger.info(str(self.parent_property) + " lazy loading clause " + str(lazywhere))
+ if hasattr(cls, 'parent_property'):
+ LazyLoader.logger.info(str(cls.parent_property) + " lazy loading clause " + str(lazywhere))
return (lazywhere, binds, reverse)
-
+ _create_lazy_clause = classmethod(_create_lazy_clause)
+
LazyLoader.logger = logging.class_logger(LazyLoader)