From 16b8f5f5b00cb7ee1d8137574e71851602206a66 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Tue, 31 Oct 2006 20:40:22 +0000 Subject: [PATCH] - fixed bug where eagerload() (nor lazyload()) option didn't properly instruct the Query whether or not to use "nesting" when producing a LIMIT query. --- CHANGES | 3 +++ lib/sqlalchemy/orm/mapper.py | 3 ++- lib/sqlalchemy/orm/query.py | 3 ++- lib/sqlalchemy/orm/strategies.py | 9 ++++++++- test/orm/mapper.py | 24 ++++++++++++++++++++++++ 5 files changed, 39 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index a6021ca927..f1cdb1e011 100644 --- a/CHANGES +++ b/CHANGES @@ -9,6 +9,9 @@ passive_deletes=True on a relation(). - further fixes to sqlite booleans, weren't working as defaults - fix to postgres sequence quoting when using schemas - fixed direct execution of Compiled objects +- fixed bug where eagerload() (nor lazyload()) option didn't properly +instruct the Query whether or not to use "nesting" when producing a +LIMIT query. 0.3.0 - General: diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py index 4fcc7d14c7..abfe18db35 100644 --- a/lib/sqlalchemy/orm/mapper.py +++ b/lib/sqlalchemy/orm/mapper.py @@ -160,6 +160,7 @@ class Mapper(object): # "polymorphic identity" of the row, which indicates which Mapper should be used # to construct a new object instance from that row. self.polymorphic_on = polymorphic_on + self._eager_loaders = util.Set() # our 'polymorphic identity', a string name that when located in a result set row # indicates this Mapper should be used to construct the object instance for that row. @@ -711,7 +712,7 @@ class Mapper(object): def has_eager(self): """return True if one of the properties attached to this Mapper is eager loading""" - return getattr(self, '_has_eager', False) + return len(self._eager_loaders) > 0 def instances(self, cursor, session, *mappers, **kwargs): """return a list of mapped instances corresponding to the rows in a given ResultProxy.""" diff --git a/lib/sqlalchemy/orm/query.py b/lib/sqlalchemy/orm/query.py index a2c6624821..9c76c6a176 100644 --- a/lib/sqlalchemy/orm/query.py +++ b/lib/sqlalchemy/orm/query.py @@ -374,7 +374,7 @@ class Query(object): generated query as a subquery inside of a larger eager-loading query. this is used with keywords like distinct, limit and offset and the mapper defines eager loads.""" return ( - self.mapper.has_eager() + len(querycontext.eager_loaders) > 0 and self._nestable(**querycontext.select_args()) ) @@ -473,6 +473,7 @@ class QueryContext(OperationContext): self.distinct = kwargs.pop('distinct', False) self.limit = kwargs.pop('limit', None) self.offset = kwargs.pop('offset', None) + self.eager_loaders = util.Set([x for x in query.mapper._eager_loaders]) self.statement = None super(QueryContext, self).__init__(query.mapper, query.with_options, **kwargs) def select_args(self): diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py index bfcc377c05..6e5590bb00 100644 --- a/lib/sqlalchemy/orm/strategies.py +++ b/lib/sqlalchemy/orm/strategies.py @@ -289,7 +289,7 @@ class EagerLoader(AbstractRelationLoader): super(EagerLoader, self).init() if self.parent.isa(self.mapper): raise exceptions.ArgumentError("Error creating eager relationship '%s' on parent class '%s' to child class '%s': Cant use eager loading on a self referential relationship." % (self.key, repr(self.parent.class_), repr(self.mapper.class_))) - self.parent._has_eager = True + self.parent._eager_loaders.add(self.parent_property) self.clauses = {} self.clauses_by_lead_mapper = {} @@ -518,6 +518,13 @@ class EagerLazyOption(StrategizedOption): def __init__(self, key, lazy=True): super(EagerLazyOption, self).__init__(key) self.lazy = lazy + def process_query_property(self, context, prop): + if self.lazy: + if prop in context.eager_loaders: + context.eager_loaders.remove(prop) + else: + context.eager_loaders.add(prop) + super(EagerLazyOption, self).process_query_property(context, prop) def get_strategy_class(self): if self.lazy: return LazyLoader diff --git a/test/orm/mapper.py b/test/orm/mapper.py index 6c54a5bfbe..3a56ff6619 100644 --- a/test/orm/mapper.py +++ b/test/orm/mapper.py @@ -382,6 +382,30 @@ class MapperTest(MapperSuperTest): self.assert_result(l, User, *user_address_result) self.assert_sql_count(db, go, 0) + def testeageroptionswithlimit(self): + sess = create_session() + mapper(User, users, properties = dict( + addresses = relation(mapper(Address, addresses), lazy = True) + )) + u = sess.query(User).options(eagerload('addresses')).get_by(user_id=8) + + def go(): + assert u.user_id == 8 + assert len(u.addresses) == 3 + self.assert_sql_count(db, go, 0) + + def testlazyoptionswithlimit(self): + sess = create_session() + mapper(User, users, properties = dict( + addresses = relation(mapper(Address, addresses), lazy = False) + )) + u = sess.query(User).options(lazyload('addresses')).get_by(user_id=8) + + def go(): + assert u.user_id == 8 + assert len(u.addresses) == 3 + self.assert_sql_count(db, go, 1) + def testeagerdegrade(self): """tests that an eager relation automatically degrades to a lazy relation if eager columns are not available""" sess = create_session() -- 2.47.2