]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
row switch works for post-cycle sorts too...just needed more data in the deps. ...
authorMike Bayer <mike_mp@zzzcomputing.com>
Sat, 3 Apr 2010 23:41:56 +0000 (19:41 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sat, 3 Apr 2010 23:41:56 +0000 (19:41 -0400)
is more data needed for each tweak.

lib/sqlalchemy/orm/dependency.py
lib/sqlalchemy/orm/mapper.py
lib/sqlalchemy/orm/unitofwork.py
test/orm/test_unitofworkv2.py

index 86cac2d8756f505ef16737e87d6d44705de53f83..398bdd91cd6f003efd0c84e0402c7403a6828fbf 100644 (file)
@@ -79,6 +79,8 @@ class DependencyProcessor(object):
                                         before_delete)
 
     def per_state_flush_actions(self, uow, state, isdelete):
+        # locate and disable the aggregate processors
+        # for this dependency
         after_save = unitofwork.ProcessAll(uow, self, False, True)
         before_delete = unitofwork.ProcessAll(uow, self, True, True)
         after_save.disabled = True
@@ -88,14 +90,20 @@ class DependencyProcessor(object):
         child_saves = unitofwork.SaveUpdateAll(uow, self.mapper.base_mapper)
         child_deletes = unitofwork.DeleteAll(uow, self.mapper.base_mapper)
         if child_saves not in uow.cycles:
+            # based on the current dependencies we use, the saves/
+            # deletes should always be in the 'cycles' collection
+            # together.   if this changes, we will have to break up
+            # this method a bit more.
             assert child_deletes not in uow.cycles
-            # its not, so we will link per-state
+            
+            # child side is not part of the cycle, so we will link per-state
             # actions to the aggregate "saves", "deletes" actions
             child_actions = [
                 (child_saves, False), (child_deletes, True)
             ]
         else:
-            # it is.  see if there's any objects.
+            # child side is part of the cycle.  create dependencies for
+            # each related object.
             sum_ = uow.get_attribute_history(state, self.key, passive=True).sum()
             if not sum_:
                 return
@@ -114,7 +122,7 @@ class DependencyProcessor(object):
                 child_actions.append(child_action)
                     
         # check if the "parent" side is part of the cycle,
-        # if so break up parent_saves
+        # if so break up parent_saves or parent_deletes
         if not isdelete:
             parent_saves = unitofwork.SaveUpdateAll(uow, self.parent.base_mapper)
             if parent_saves in uow.cycles:
index 319b06158646aa01db0754accdc3759f3791cd87..ac35ce49b7ac720844d4eb995d9a3363965ffd3f 100644 (file)
@@ -1263,11 +1263,15 @@ class Mapper(object):
             prop.per_property_flush_actions(uow)
     
     def per_state_flush_actions(self, uow, state, isdelete):
+        # keep saves before deletes -
+        # this ensures 'row switch' operations work
         if isdelete:
             action = unitofwork.DeleteState(uow, state)
+            uow.dependencies.add((unitofwork.SaveUpdateAll(uow, self.base_mapper), action))
         else:
             action = unitofwork.SaveUpdateState(uow, state)
-        
+            uow.dependencies.add((action, unitofwork.DeleteAll(uow, self.base_mapper)))
+            
         yield action
         mapper = state.manager.mapper
         for prop in mapper._props.values():
@@ -1354,7 +1358,7 @@ class Mapper(object):
                     self._log_debug(
                         "detected row switch for identity %s.  will update %s, remove %s from "
                         "transaction", instance_key, state_str(state), state_str(existing))
-                            
+                    
                     # remove the "delete" flag from the existing element
                     uowtransaction.remove_state_actions(existing)
                     row_switches[state] = existing
index a4eb00f70acf31a2c314222a4b239716d9c2cad0..c8eca67eb7ee232bc4a38a77604f77a096ece84d 100644 (file)
@@ -105,15 +105,7 @@ class UOWTransaction(object):
     def remove_state_actions(self, state):
         """remove pending actions for a state from the uowtransaction."""
         
-        if state in self.states:
-            isdelete, listonly = self.states[state]
-            self.states[state] = (False, True)
-            if isdelete:
-                self.postsort_actions.pop((DeleteState, state), None)
-            else:
-                self.postsort_actions.pop((SaveUpdateState, state), None)
-                
-        
+        self.states[state] = (False, True)
         
     def get_attribute_history(self, state, key, passive=True):
         hashkey = ("history", state, key)
@@ -223,11 +215,9 @@ class UOWTransaction(object):
         
         # execute actions
         sort = topological.sort(self.dependencies, self.postsort_actions.values())
-        print "------------------------"
-#        import pdb
-#        pdb.set_trace()
-        print self.dependencies
-        print sort
+#        print "------------------------"
+#        print self.dependencies
+#        print sort
         for rec in sort:
             rec.execute(self)
             
@@ -411,10 +401,11 @@ class DeleteState(PostSortRec):
 
     def execute(self, uow):
         mapper = self.state.manager.mapper.base_mapper
-        mapper._delete_obj(
-            [self.state],
-            uow
-        )
+        if uow.states[self.state][0]:
+            mapper._delete_obj(
+                [self.state],
+                uow
+            )
 
     def __repr__(self):
         return "%s(%s)" % (
index adc7dc79a4c6080a975ebcf7ab5aaca2823c81cf..5dd334d6e860a23f3d85abf355702fc4734aed47 100644 (file)
@@ -338,7 +338,23 @@ class SingleCycleTest(UOWTest):
                 CompiledSQL("DELETE FROM nodes WHERE nodes.id = :id", 
                         lambda ctx: {'id':n1.id})
         )
+    
+    def test_cycle_rowswitch(self):
+        mapper(Node, nodes, properties={
+            'children':relationship(Node)
+        })
+        sess = create_session()
+
+        n2, n3 = Node(data='n2', children=[]), Node(data='n3', children=[])
+        n1 = Node(data='n1', children=[n2])
 
+        sess.add(n1)
+        sess.flush()
+        sess.delete(n2)
+        n3.id = n2.id
+        n1.children.append(n3)
+        sess.flush()
+        
     def test_bidirectional_mutations_one(self):
         mapper(Node, nodes, properties={
             'children':relationship(Node, backref=backref('parent', remote_side=nodes.c.id))