]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
this one is actually doing it. removed the cruft we don't need from the old approach.
authorMike Bayer <mike_mp@zzzcomputing.com>
Fri, 18 Jun 2010 17:31:51 +0000 (13:31 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Fri, 18 Jun 2010 17:31:51 +0000 (13:31 -0400)
not sure if one-to-many with elaborate self-refs, etc., but we appear to be
as good as we were before.

lib/sqlalchemy/orm/dependency.py
lib/sqlalchemy/orm/unitofwork.py
test/orm/test_cycles.py

index c9a0ce8ed35faa7e01bd6d8915334d464427c92c..f89291ff3fd557a4506cfd6e361184be1e761965 100644 (file)
@@ -266,19 +266,13 @@ class DependencyProcessor(object):
                             set
                         )
 
-    def _post_update(self, state, uowcommit, related, processed, immediate):
-        if processed is not None and state in processed:
-            return
+    def _post_update(self, state, uowcommit, related):
         for x in related:
             if x is not None:
                 uowcommit.issue_post_update(
                         state, 
-                        [r for l, r in self.prop.synchronize_pairs],
-                        immediate
+                        [r for l, r in self.prop.synchronize_pairs]
                 )
-                if processed is not None:
-                    processed.add(state)
-                
                 break
         
     def _pks_changed(self, uowcommit, state):
@@ -297,12 +291,19 @@ class OneToManyDP(DependencyProcessor):
                                                 before_delete,
                                                 ):
         if self.post_update:
+            child_post_updates = unitofwork.PostUpdateThing(
+                                                uow, self.mapper.primary_base_mapper, False)
+            child_pre_updates = unitofwork.PostUpdateThing(
+                                                uow, self.mapper.primary_base_mapper, True)
             
             uow.dependencies.update([
                 (child_saves, after_save),
                 (parent_saves, after_save),
-                (before_delete, parent_deletes),
-                (before_delete, child_deletes),
+                (after_save, child_post_updates),
+                
+                (before_delete, child_pre_updates),
+                (child_pre_updates, parent_deletes),
+                (child_pre_updates, child_deletes),
                 
             ])
         else:
@@ -326,30 +327,36 @@ class OneToManyDP(DependencyProcessor):
                                     isdelete, childisdelete):
         
         if self.post_update:
+
+            child_post_updates = unitofwork.PostUpdateThing(
+                                                uow, self.mapper.primary_base_mapper, False)
+            child_pre_updates = unitofwork.PostUpdateThing(
+                                                uow, self.mapper.primary_base_mapper, True)
             
             # TODO: this whole block is not covered
             # by any tests
             if not isdelete:
                 if childisdelete:
                     uow.dependencies.update([
-                        (save_parent, after_save),
-                        (after_save, child_action),
+                        (child_action, after_save),
+                        (after_save, child_post_updates),
                     ])
                 else:
                     uow.dependencies.update([
                         (save_parent, after_save),
                         (child_action, after_save),
+                        (after_save, child_post_updates),
                     ])
             else:
                 if childisdelete:
                     uow.dependencies.update([
-                        (before_delete, delete_parent),
-                        (before_delete, child_action), 
+                        (before_delete, child_pre_updates),
+                        (child_pre_updates, delete_parent),
                     ])
                 else:
                     uow.dependencies.update([
-                        (before_delete, delete_parent), 
-                        (child_action, before_delete),
+                        (before_delete, child_pre_updates),
+                        (child_pre_updates, delete_parent), 
                     ])
         elif not isdelete:
             uow.dependencies.update([
@@ -432,8 +439,6 @@ class OneToManyDP(DependencyProcessor):
         # key to the parent set to NULL this phase can be called 
         # safely for any cascade but is unnecessary if delete cascade
         # is on.
-        if self.post_update:
-            processed = self._get_reversed_processed_set(uowcommit)
         
         if self.post_update or not self.passive_deletes == 'all':
             children_added = uowcommit.memo(('children_added', self), set)
@@ -455,7 +460,7 @@ class OneToManyDP(DependencyProcessor):
                                     self._post_update(
                                             child, 
                                             uowcommit, 
-                                            [state], processed, True)
+                                            [state])
                     if self.post_update or not self.cascade.delete:
                         for child in set(history.unchanged).\
                                             difference(children_added):
@@ -468,16 +473,13 @@ class OneToManyDP(DependencyProcessor):
                                     self._post_update(
                                             child, 
                                             uowcommit, 
-                                            [state], processed, True)
+                                            [state])
                         # technically, we can even remove each child from the
                         # collection here too.  but this would be a somewhat 
                         # inconsistent behavior since it wouldn't happen if the old
                         # parent wasn't deleted but child was moved.
                             
     def process_saves(self, uowcommit, states):
-        if self.post_update:
-            processed = self._get_reversed_processed_set(uowcommit)
-            
         for state in states:
             history = uowcommit.get_attribute_history(state, self.key, passive=True)
             if history:
@@ -487,9 +489,7 @@ class OneToManyDP(DependencyProcessor):
                         self._post_update(
                                             child, 
                                             uowcommit, 
-                                            [state],
-                                            processed,
-                                            True
+                                            [state]
                                             )
 
                 for child in history.deleted:
@@ -537,20 +537,20 @@ class ManyToOneDP(DependencyProcessor):
                                         before_delete):
 
         if self.post_update:
-            child_post_updates = unitofwork.PostUpdateThing(
+            parent_post_updates = unitofwork.PostUpdateThing(
                                                 uow, self.parent.primary_base_mapper, False)
-            child_pre_updates = unitofwork.PostUpdateThing(
+            parent_pre_updates = unitofwork.PostUpdateThing(
                                                 uow, self.parent.primary_base_mapper, True)
 
             uow.dependencies.update([
                 (child_saves, after_save),
                 (parent_saves, after_save),
-                (after_save, child_post_updates),
+                (after_save, parent_post_updates),
 
-                (after_save, child_pre_updates),
-                (before_delete, child_pre_updates),
+                (after_save, parent_pre_updates),
+                (before_delete, parent_pre_updates),
 
-                (child_pre_updates, child_deletes),
+                (parent_pre_updates, child_deletes),
             ])
         else:
             uow.dependencies.update([
@@ -656,8 +656,6 @@ class ManyToOneDP(DependencyProcessor):
                 not self.cascade.delete_orphan and \
                 not self.passive_deletes == 'all':
             
-            processed = self._get_reversed_processed_set(uowcommit)
-                
             # post_update means we have to update our 
             # row to not reference the child object
             # before we can DELETE the row
@@ -672,12 +670,9 @@ class ManyToOneDP(DependencyProcessor):
                         self._post_update(
                                             state, 
                                             uowcommit, 
-                                            history.sum(), processed, False)
+                                            history.sum())
 
     def process_saves(self, uowcommit, states):
-        if self.post_update:
-            processed = self._get_reversed_processed_set(uowcommit)
-            
         for state in states:
             history = uowcommit.get_attribute_history(state, self.key, passive=True)
             if history:
@@ -687,7 +682,7 @@ class ManyToOneDP(DependencyProcessor):
                 if self.post_update:
                     self._post_update(
                                         state, 
-                                        uowcommit, history.sum(), processed, False)
+                                        uowcommit, history.sum())
 
     def _synchronize(self, state, child, associationrow, clearkeys, uowcommit):
         if state is None or (not self.post_update and uowcommit.is_deleted(state)):
index aed50f6499cfa19723a6beb39c50388d856ee57b..529a94d5dd904cce1b5ce306203587cbac5aa1ee 100644 (file)
@@ -110,7 +110,7 @@ class UOWTransaction(object):
         # or insert/updated, or just refreshed
         self.states = {}
     
-        self.post_update_states = util.defaultdict(set)
+        self.post_update_states = util.defaultdict(lambda: (set(), set()))
         
     @property
     def has_work(self):
@@ -185,14 +185,11 @@ class UOWTransaction(object):
             if not listonly and (isdelete or cancel_delete):
                 self.states[state] = (isdelete, False)
     
-    def issue_post_update(self, state, post_update_cols, immediate):
-        if immediate:
-            mapper = state.manager.mapper.base_mapper
-            mapper._save_obj([state], self, \
-                        postupdate=True, \
-                        post_update_cols=set(post_update_cols))
-        else:
-            self.post_update_states[state].update(post_update_cols)
+    def issue_post_update(self, state, post_update_cols):
+        mapper = state.manager.mapper.base_mapper
+        states, cols = self.post_update_states[mapper]
+        states.add(state)
+        cols.update(post_update_cols)
     
     @util.memoized_property
     def _mapper_for_dep(self):
@@ -426,18 +423,12 @@ class PostUpdateThing(PostSortRec):
         self.isdelete = isdelete
 
     def execute(self, uow):
-        states = []
-        update_cols = set()
-
-        for state in uow.states_for_mapper_hierarchy(self.mapper, self.isdelete, False):
-            if state not in uow.post_update_states:
-                continue
-            states.append(state)    
-            update_cols.update(uow.post_update_states[state])
-
+        states, cols = uow.post_update_states[self.mapper]
+        states = [s for s in states if uow.states[s][0] == self.isdelete]
+        
         self.mapper._save_obj(states, uow, \
                             postupdate=True, \
-                            post_update_cols=update_cols)
+                            post_update_cols=cols)
 
 class SaveUpdateAll(PostSortRec):
     def __init__(self, uow, mapper):
index b41a34aa83753d7a336edc2e344efa27cd4d9d86..e86b2c8ae0fb1747e6741a4594954ab33cb473f8 100644 (file)
@@ -1018,6 +1018,3 @@ class SelfReferentialPostUpdateTest3(_base.MappedTest):
         p1.child = None
         session.flush()
         
-        
-        
-