]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
merged r6383 of trunk for [ticket:1553]
authorMike Bayer <mike_mp@zzzcomputing.com>
Fri, 2 Oct 2009 22:25:51 +0000 (22:25 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Fri, 2 Oct 2009 22:25:51 +0000 (22:25 +0000)
CHANGES
lib/sqlalchemy/orm/__init__.py
lib/sqlalchemy/orm/interfaces.py
lib/sqlalchemy/orm/mapper.py
lib/sqlalchemy/orm/query.py
lib/sqlalchemy/orm/strategies.py
test/orm/test_mapper.py

diff --git a/CHANGES b/CHANGES
index 9559f6a4ad9ce050b53c1588f2da5034589ec449..49e3e2b232551903a40b1c52f16cb641f70ce728 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -16,6 +16,13 @@ CHANGES
       cartesian product.  An example is in the ticket
       description.  [ticket:1543]
 
+    - query.options() now only propagate to loaded objects
+      for potential further sub-loads only for options where
+      such behavior is relevant, keeping
+      various unserializable options like those generated
+      by contains_eager() out of individual instance states.
+      [ticket:1553]
+
 - postgresql
     - Added support for reflecting the DOUBLE PRECISION type,
       via a new postgres.PGDoublePrecision object.  
index 2a20b05ef8430f05c370ae9b637bd28337fe51c5..357859b546676caa41cc6bd39a0d32853cd13903 100644 (file)
@@ -938,7 +938,7 @@ def contains_eager(*keys, **kwargs):
     if kwargs:
         raise exceptions.ArgumentError("Invalid kwargs for contains_eager: %r" % kwargs.keys())
 
-    return (strategies.EagerLazyOption(keys, lazy=False, _only_on_lead=True), strategies.LoadEagerFromAliasOption(keys, alias=alias))
+    return (strategies.EagerLazyOption(keys, lazy=False, propagate_to_loaders=False), strategies.LoadEagerFromAliasOption(keys, alias=alias))
 
 @sa_util.accepts_a_list_as_starargs(list_deprecation='pending')
 def defer(*keys):
index 8f0db5352e2a994818b2369faded4866642b6229..a145c865dcb4b3ae8aa493527b622266e72fd8d2 100644 (file)
@@ -630,6 +630,11 @@ def deserialize_path(path):
 class MapperOption(object):
     """Describe a modification to a Query."""
 
+    propagate_to_loaders = False
+    """if True, indicate this option should be carried along 
+    Query object generated by scalar or object lazy loaders.
+    """
+    
     def process_query(self, query):
         pass
 
@@ -643,7 +648,7 @@ class MapperOption(object):
 
 class ExtensionOption(MapperOption):
     """a MapperOption that applies a MapperExtension to a query operation."""
-
+    
     def __init__(self, ext):
         self.ext = ext
 
index b8842a5f8652261ecbd4feff7880b75fd9fbe58e..1e9d0c1ab7b81b314a40b83d0a435d86ba48137a 100644 (file)
@@ -1576,8 +1576,8 @@ class Mapper(object):
 
         def populate_state(state, dict_, row, isnew, only_load_props, **flags):
             if isnew:
-                if context.options:
-                    state.load_options = context.options
+                if context.propagate_options:
+                    state.load_options = context.propagate_options
                 if state.load_options:
                     state.load_path = context.query._current_path + path
 
index db886dcb8a865af0e69b9c8c5f98c7521d77d77c..239f455622b424167ca8369825563f8d69c9707b 100644 (file)
@@ -2197,6 +2197,7 @@ class QueryContext(object):
         self.adapter = None
 
         self.options = set(query._with_options)
+        self.propagate_options = self.options.difference(o for o in self.options if not o.propagate_to_loaders)
         self.attributes = query._attributes.copy()
 
 class AliasOption(interfaces.MapperOption):
index c55d431f88b7dbfe9b31e16c4cd3d5d6817756c2..38073811b3835ba4e3a081216ea438b08db9fa01 100644 (file)
@@ -303,6 +303,8 @@ class LoadDeferredColumns(object):
         return attributes.ATTR_WAS_SET
 
 class DeferredOption(StrategizedOption):
+    propagate_to_loaders = True
+    
     def __init__(self, key, defer=False):
         super(DeferredOption, self).__init__(key)
         self.defer = defer
@@ -314,6 +316,8 @@ class DeferredOption(StrategizedOption):
             return ColumnLoader
 
 class UndeferGroupOption(MapperOption):
+    propagate_to_loaders = True
+
     def __init__(self, group):
         self.group = group
     def process_query(self, query):
@@ -794,16 +798,13 @@ class EagerLoader(AbstractRelationLoader):
 log.class_logger(EagerLoader)
 
 class EagerLazyOption(StrategizedOption):
-    def __init__(self, key, lazy=True, chained=False, mapper=None, _only_on_lead=False):
+
+    def __init__(self, key, lazy=True, chained=False, mapper=None, propagate_to_loaders=True):
         super(EagerLazyOption, self).__init__(key, mapper)
         self.lazy = lazy
         self.chained = chained
-        self._only_on_lead = _only_on_lead
+        self.propagate_to_loaders = propagate_to_loaders
         
-    def process_query_conditionally(self, query):
-        if not self._only_on_lead:
-            StrategizedOption.process_query_conditionally(self, query)
-            
     def is_chained(self):
         return not self.lazy and self.chained
         
@@ -816,6 +817,7 @@ class EagerLazyOption(StrategizedOption):
             return NoLoader
 
 class LoadEagerFromAliasOption(PropertyOption):
+    
     def __init__(self, key, alias=None):
         super(LoadEagerFromAliasOption, self).__init__(key)
         if alias:
@@ -823,10 +825,6 @@ class LoadEagerFromAliasOption(PropertyOption):
                 m, alias, is_aliased_class = mapperutil._entity_info(alias)
         self.alias = alias
 
-    def process_query_conditionally(self, query):
-        # dont run this option on a secondary load
-        pass
-        
     def process_query_property(self, query, paths, mappers):
         if self.alias:
             if isinstance(self.alias, basestring):
index 774ec47c0258b148d00beb5693a29b81e3c8d58a..5cf20beb9641b5bb0bf4fbab7dff41bbfa125e88 100644 (file)
@@ -1095,7 +1095,6 @@ class OptionsTest(_fixtures.FixtureTest):
             eq_(l, self.static.user_address_result)
         self.sql_count_(4, go)
 
-
     @testing.resolve_artifact_names
     def test_eager_degrade_deep(self):
         # test with a deeper set of eager loads.  when we first load the three
@@ -1155,6 +1154,29 @@ class OptionsTest(_fixtures.FixtureTest):
             eq_(l, self.static.user_address_result)
         self.sql_count_(4, go)
 
+    @testing.resolve_artifact_names
+    def test_option_propagate(self):
+        mapper(User, users, properties=dict(
+            orders = relation(Order)
+        ))
+        mapper(Order, orders, properties=dict(
+            items = relation(Item, secondary=order_items)
+        ))
+        mapper(Item, items)
+        
+        sess = create_session()
+        
+        oalias = aliased(Order)
+        opt1 = sa.orm.eagerload(User.orders, Order.items)
+        opt2a, opt2b = sa.orm.contains_eager(User.orders, Order.items, alias=oalias)
+        u1 = sess.query(User).join((oalias, User.orders)).options(opt1, opt2a, opt2b).first()
+        ustate = attributes.instance_state(u1)
+        assert opt1 in ustate.load_options
+        assert opt2a not in ustate.load_options
+        assert opt2b not in ustate.load_options
+        
+        import pickle
+        pickle.dumps(u1)
 
 class DeepOptionsTest(_fixtures.FixtureTest):
     @classmethod