]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- session.expire() and related methods will not expire() unloaded
authorMike Bayer <mike_mp@zzzcomputing.com>
Sat, 24 Jan 2009 00:22:49 +0000 (00:22 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sat, 24 Jan 2009 00:22:49 +0000 (00:22 +0000)
deferred attributes.  This prevents them from being needlessly
loaded when the instance is refreshed.

CHANGES
lib/sqlalchemy/orm/mapper.py
lib/sqlalchemy/orm/session.py
test/orm/expire.py

diff --git a/CHANGES b/CHANGES
index dc931ad478460966833f78450a92fec45313eaf5..9a95d3b2b5647202aa2db69bca4a6037adb7d2f4 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -35,6 +35,10 @@ CHANGES
       loading would prevent other eager loads, self referential or not,
       from joining to the parent JOIN properly.  Thanks to Alex K
       for creating a great test case.
+    
+    - session.expire() and related methods will not expire() unloaded
+      deferred attributes.  This prevents them from being needlessly
+      loaded when the instance is refreshed.
       
 - sql
     - Further fixes to the "percent signs and spaces in column/table
index 7cc6bad1253b9f452ad34f6456dbc46fdc772627..6f125bc8413116d6e36449039fad5b222ba50ce6 100644 (file)
@@ -775,7 +775,12 @@ class Mapper(object):
         if prop is None and raiseerr:
             raise sa_exc.InvalidRequestError("Mapper '%s' has no property '%s'" % (str(self), key))
         return prop
-
+    
+    @util.memoized_property
+    def _deferred_props(self):
+        return [p.key for p in self._props.values() if 
+                isinstance(p, ColumnProperty) and getattr(p, 'deferred', False)]
+        
     @property
     def iterate_properties(self):
         """return an iterator of all MapperProperty objects."""
index 690286e9b9b91bed269dbf59f4d54cd54d044e4f..ea8174726ac7b2f674b7086bd7b1884e7caff2b3 100644 (file)
@@ -1518,7 +1518,15 @@ class Session(object):
 
         return util.IdentitySet(self._new.values())
 
-_expire_state = attributes.InstanceState.expire_attributes
+def _expire_state(state, attribute_names):
+    if attribute_names is None:
+        state.expired = True
+        state.modified= False
+        # dont add unloaded deferred attributes to the list of attrs
+        attribute_names = set(state.manager.keys()).\
+                difference([k for k in state.manager.mapper._deferred_props if k not in state.dict])
+    state.expire_attributes(attribute_names)
+    
 UOWEventHandler = unitofwork.UOWEventHandler
 
 _sessions = weakref.WeakValueDictionary()
index b18e1ef25258dd8747b0bfc23d505f592be71c1e..4e8771347e209c403905b583e630e665f547cda7 100644 (file)
@@ -4,7 +4,7 @@ import testenv; testenv.configure_for_tests()
 import gc
 from testlib import sa, testing
 from testlib.sa import Table, Column, Integer, String, ForeignKey, exc as sa_exc
-from testlib.sa.orm import mapper, relation, create_session, attributes
+from testlib.sa.orm import mapper, relation, create_session, attributes, deferred
 from orm import _base, _fixtures
 
 
@@ -98,7 +98,21 @@ class ExpireTest(_fixtures.FixtureTest):
         # but now its back, rollback has occured, the _remove_newly_deleted
         # is reverted
         self.assertEquals(u.name, 'chuck')
-    
+
+    @testing.resolve_artifact_names
+    def test_deferred(self):
+        """test that unloaded, deferred attributes aren't included in the expiry list."""
+        
+        mapper(Order, orders, properties={'description':deferred(orders.c.description)})
+        
+        s = create_session()
+        o1 = s.query(Order).first()
+        assert 'description' not in o1.__dict__
+        s.expire(o1)
+        assert o1.isopen is not None
+        assert 'description' not in o1.__dict__
+        assert o1.description
+        
     @testing.resolve_artifact_names
     def test_lazyload_autoflushes(self):
         mapper(User, users, properties={