]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- a session.expire() on a particular collection attribute
authorMike Bayer <mike_mp@zzzcomputing.com>
Wed, 11 Feb 2009 20:38:30 +0000 (20:38 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Wed, 11 Feb 2009 20:38:30 +0000 (20:38 +0000)
will clear any pending backref additions as well, so that
the next access correctly returns only what was present
in the database.  Presents some degree of a workaround for
[ticket:1315], although we are considering removing the
flush([objects]) feature altogether.

CHANGES
lib/sqlalchemy/orm/attributes.py
test/orm/expire.py

diff --git a/CHANGES b/CHANGES
index c2b32672ffe0d73a7c6bb7c95709095d9989ca52..be009b4efe1d4fd048d0681ec0d8f10add90410f 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -12,6 +12,13 @@ CHANGES
       union(query1, query2), select([foo]).select_from(query), 
       etc.
 
+    - a session.expire() on a particular collection attribute
+      will clear any pending backref additions as well, so that
+      the next access correctly returns only what was present
+      in the database.  Presents some degree of a workaround for 
+      [ticket:1315], although we are considering removing the 
+      flush([objects]) feature altogether.
+      
     - improvements to the "determine direction" logic of 
       relation() such that the direction of tricky situations 
       like mapper(A.join(B)) -> relation-> mapper(B) can be
index 657b961900c343693ee0ab403e870befc7c028a6..557a29098f944f5d4f9282424ed03c3e3453ce4d 100644 (file)
@@ -758,6 +758,7 @@ class CollectionAttributeImpl(AttributeImpl):
         state.commit([self.key])
 
         if self.key in state.pending:
+            
             # pending items exist.  issue a modified event,
             # add/remove new items.
             state.modified_event(self, True, user_data)
@@ -1027,6 +1028,7 @@ class InstanceState(object):
                 if impl.accepts_scalar_loader:
                     self.callables[key] = self
             self.dict.pop(key, None)
+            self.pending.pop(key, None)
             self.committed_state.pop(key, None)
 
     def reset(self, key):
index 4e8771347e209c403905b583e630e665f547cda7..56384f3c237c1cef55b89bc2ef5051e262a506d2 100644 (file)
@@ -293,6 +293,45 @@ class ExpireTest(_fixtures.FixtureTest):
         print attributes.instance_state(u).dict
         assert u.addresses[0].email_address == 'ed@wood.com'
 
+    @testing.resolve_artifact_names
+    def test_expired_pending(self):
+        mapper(User, users, properties={
+            'addresses':relation(Address, backref='user'),
+            })
+        mapper(Address, addresses)
+
+        sess = create_session()
+        a1 = Address(email_address='a1')
+        sess.add(a1)
+        sess.flush()
+        
+        u1 = User(name='u1')
+        a1.user = u1
+        sess.flush()
+
+        # expire 'addresses'.  backrefs
+        # which attach to u1 will expect to be "pending"
+        sess.expire(u1, ['addresses'])
+
+        # attach an Address.  now its "pending" 
+        # in user.addresses
+        a2 = Address(email_address='a2')
+        a2.user = u1
+
+        # expire u1.addresses again.  this expires
+        # "pending" as well.
+        sess.expire(u1, ['addresses'])
+        
+        # insert a new row
+        sess.execute(addresses.insert(), dict(email_address='a3', user_id=u1.id))
+        
+        # only two addresses pulled from the DB, no "pending"
+        assert len(u1.addresses) == 2
+        
+        sess.flush()
+        sess.expire_all()
+        assert len(u1.addresses) == 3
+        
     @testing.resolve_artifact_names
     def test_expired_lazy(self):
         mapper(User, users, properties={