Commits

Mike Bayer  committed 2483356

- got rollback to work with dynamic attributes
- dont put persistent objects in transaction._new by mistake (ouch!)
- removed ProxyAttributeFactory

  • Participants
  • Parent commits c1c8a68
  • Branches user_defined_state

Comments (0)

Files changed (4)

File lib/sqlalchemy/orm/attributes.py

             return self
         return self.impl.get(instance_state(instance))
 
-class ProxiedAttribute(InstrumentedAttribute):
-    """Adds InstrumentedAttribute class-level behavior to a regular descriptor.
-
-    Obsoleted by proxied_attribute_factory.
-    """
-
-    class ProxyImpl(object):
-        accepts_scalar_loader = False
-
-        def __init__(self, key):
-            self.key = key
-        
-        def rollback_to_savepoint(self, state, savepoint):
-            pass
-            
-    def __init__(self, key, user_prop, comparator=None):
-        self.key = key
-        self.user_prop = user_prop
-        self._comparator = comparator
-        self.impl = ProxiedAttribute.ProxyImpl(key)
-
-    def comparator(self):
-        if callable(self._comparator):
-            self._comparator = self._comparator()
-        return self._comparator
-    comparator = property(comparator)
-
-    def __get__(self, instance, owner):
-        if instance is None:
-            self.user_prop.__get__(instance, owner)
-            return self
-        return self.user_prop.__get__(instance, owner)
-
-    def __set__(self, instance, value):
-        return self.user_prop.__set__(instance, value)
-
-    def __delete__(self, instance):
-        return self.user_prop.__delete__(instance)
-
 def proxied_attribute_factory(descriptor):
     """Create an InstrumentedAttribute / user descriptor hybrid.
 
         if a value was not populated in state.dict.
         """
 
-        class_manager = manager_of_class(self.class_)
+        class_manager = self.manager
         for key in keys:
-            if key in self.dict and hasattr(class_manager[key].impl, 'commit_to_state'):
+            if key in self.dict and key in class_manager.mutable_attributes:
                 class_manager[key].impl.commit_to_state(self, self.committed_state)
             else:
                 self.committed_state.pop(key, None)
         for cls in self.class_.__subclasses__():
             manager = manager_of_class(cls)
             if manager is None:
-                try:
-                    manager = create_manager_for_cls(cls, instance_state_factory=self.instance_state_factory)
-                except TypeError:
-                    import pdb
-                    pdb.set_trace()
+                manager = create_manager_for_cls(cls, instance_state_factory=self.instance_state_factory)
             manager.uninstrument_attribute(key, True)
 
     def unregister(self):

File lib/sqlalchemy/orm/dynamic.py

         self.order_by = order_by
         self.query_class = AppenderQuery
 
+    def rollback_to_savepoint(self, state, savepoint):
+        pass
+        
     def get(self, state, passive=False):
         if passive:
             return self._get_collection_history(state, passive=True).added_items

File lib/sqlalchemy/orm/session.py

             del state.session_id
 
     def _register_newly_persistent(self, state):
-        if self.transaction:
-            self.transaction._new[state] = True
-            
         mapper = _state_mapper(state)
         instance_key = mapper._identity_key_from_state(state)
 
             state.commit_all()
 
         # remove from new last, might be the last strong ref
-        self._new.pop(state, None)
+        if state in self._new:
+            if self.transaction:
+                self.transaction._new[state] = True
+            self._new.pop(state)
         
     def _remove_newly_deleted(self, state):
         if self.transaction:

File test/orm/dynamic.py

             User(name='jack', addresses=[Address(email_address='lala@hoho.com')]),
             User(name='ed', addresses=[Address(email_address='foo@bar.com')])
         ] == sess.query(User).all()
+    
+    def test_rollback(self):
+        class Fixture(Base):
+            pass
 
+        mapper(User, users, properties={
+            'addresses':dynamic_loader(mapper(Address, addresses))
+        })
+        sess = create_session(autoexpire=False, autocommit=False, autoflush=True)
+        u1 = User(name='jack')
+        u1.addresses.append(Address(email_address='lala@hoho.com'))
+        sess.save(u1)
+        sess.flush()
+        sess.commit()
+        u1.addresses.append(Address(email_address='foo@bar.com'))
+        self.assertEquals(u1.addresses.all(), [Address(email_address='lala@hoho.com'), Address(email_address='foo@bar.com')])
+        sess.rollback()
+        self.assertEquals(u1.addresses.all(), [Address(email_address='lala@hoho.com')])
+        
     @testing.fails_on('maxdb')
     def test_delete_nocascade(self):
         mapper(User, users, properties={