]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
this approach seems to allow many-to-one post updates to occur as a single action...
authorMike Bayer <mike_mp@zzzcomputing.com>
Fri, 18 Jun 2010 15:36:35 +0000 (11:36 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Fri, 18 Jun 2010 15:36:35 +0000 (11:36 -0400)
have it working the old way still. as usual the huge job is the tests.   also I am not yet certain
that post updates can always be a "full mapper" operation, i.e. are never involved in per-state dependencies,
or even if the old approach supports that.

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

index 7a8c4cf702647f7becf4524f15ee123269a946a6..4d7a038943addce73dcdbc2a4401c91f3ba7f56c 100644 (file)
@@ -83,7 +83,8 @@ class DependencyProcessor(object):
                                         parent_deletes, 
                                         child_deletes, 
                                         after_save, 
-                                        before_delete)
+                                        before_delete
+                                        )
         
 
     def per_state_flush_actions(self, uow, states, isdelete):
@@ -95,6 +96,11 @@ class DependencyProcessor(object):
         
         """
 
+        parent_base_mapper = self.parent.primary_base_mapper
+        child_base_mapper = self.mapper.primary_base_mapper
+        child_saves = unitofwork.SaveUpdateAll(uow, child_base_mapper)
+        child_deletes = unitofwork.DeleteAll(uow, child_base_mapper)
+
         # locate and disable the aggregate processors
         # for this dependency
         
@@ -107,11 +113,6 @@ class DependencyProcessor(object):
 
         # check if the "child" side is part of the cycle
         
-        parent_base_mapper = self.parent.primary_base_mapper
-        child_base_mapper = self.mapper.primary_base_mapper
-        child_saves = unitofwork.SaveUpdateAll(uow, child_base_mapper)
-        child_deletes = unitofwork.DeleteAll(uow, child_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
@@ -196,7 +197,7 @@ class DependencyProcessor(object):
                     
             # establish dependencies between our possibly per-state
             # parent action and our possibly per-state child action.
-            for (child_action, childisdelete) in child_actions:
+            for child_action, childisdelete in child_actions:
                 self.per_state_dependencies(uow, parent_saves, 
                                                 parent_deletes, 
                                                 child_action, 
@@ -265,14 +266,15 @@ class DependencyProcessor(object):
                             set
                         )
 
-    def _post_update(self, state, uowcommit, related, processed):
+    def _post_update(self, state, uowcommit, related, processed, immediate):
         if processed is not None and state in processed:
             return
         for x in related:
             if x is not None:
                 uowcommit.issue_post_update(
                         state, 
-                        [r for l, r in self.prop.synchronize_pairs]
+                        [r for l, r in self.prop.synchronize_pairs],
+                        immediate
                 )
                 if processed is not None:
                     processed.add(state)
@@ -292,13 +294,16 @@ class OneToManyDP(DependencyProcessor):
                                                 parent_deletes, 
                                                 child_deletes, 
                                                 after_save, 
-                                                before_delete):
+                                                before_delete,
+                                                ):
         if self.post_update:
+            
             uow.dependencies.update([
                 (child_saves, after_save),
                 (parent_saves, after_save),
                 (before_delete, parent_deletes),
                 (before_delete, child_deletes),
+                
             ])
         else:
             uow.dependencies.update([
@@ -321,29 +326,30 @@ class OneToManyDP(DependencyProcessor):
                                     isdelete, childisdelete):
         
         if self.post_update:
+            
             # 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)
+                        (after_save, child_action),
                     ])
                 else:
                     uow.dependencies.update([
                         (save_parent, after_save),
-                        (child_action, after_save)
+                        (child_action, after_save),
                     ])
             else:
                 if childisdelete:
                     uow.dependencies.update([
                         (before_delete, delete_parent),
-                        (before_delete, child_action)
+                        (before_delete, child_action)
                     ])
                 else:
                     uow.dependencies.update([
-                        (before_delete, delete_parent),
-                        (child_action, before_delete)
+                        (before_delete, delete_parent), 
+                        (child_action, before_delete),
                     ])
         elif not isdelete:
             uow.dependencies.update([
@@ -449,7 +455,7 @@ class OneToManyDP(DependencyProcessor):
                                     self._post_update(
                                             child, 
                                             uowcommit, 
-                                            [state], processed)
+                                            [state], processed, True)
                     if self.post_update or not self.cascade.delete:
                         for child in set(history.unchanged).\
                                             difference(children_added):
@@ -462,7 +468,7 @@ class OneToManyDP(DependencyProcessor):
                                     self._post_update(
                                             child, 
                                             uowcommit, 
-                                            [state], processed)
+                                            [state], processed, True)
                         # 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
@@ -482,7 +488,8 @@ class OneToManyDP(DependencyProcessor):
                                             child, 
                                             uowcommit, 
                                             [state],
-                                            processed
+                                            processed,
+                                            True
                                             )
 
                 for child in history.deleted:
@@ -530,11 +537,19 @@ class ManyToOneDP(DependencyProcessor):
                                         before_delete):
 
         if self.post_update:
+            child_post_updates = unitofwork.PostUpdateThing(
+                                                uow, self.parent.primary_base_mapper, False)
+            child_pre_updates = unitofwork.PostUpdateThing(
+                                                uow, self.parent.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, child_deletes),
             ])
         else:
             uow.dependencies.update([
@@ -552,21 +567,36 @@ class ManyToOneDP(DependencyProcessor):
                                     isdelete, childisdelete):
 
         if self.post_update:
+
             if not isdelete:
+                child_post_updates = unitofwork.PostUpdateThing(
+                                                    uow, self.parent.primary_base_mapper, False)
                 if childisdelete:
                     uow.dependencies.update([
                         (save_parent, after_save),
-                        (after_save, child_action)
+                        (after_save, child_action), # can remove
+                        
+                        (after_save, child_post_updates),
+                        (child_post_updates, child_action)
                     ])
                 else:
                     uow.dependencies.update([
                         (save_parent, after_save),
-                        (child_action, after_save)
+                        (child_action, after_save),
+                        
+                        (after_save, child_post_updates)
                     ])
             else:
+                child_pre_updates = unitofwork.PostUpdateThing(
+                                                    uow, self.parent.primary_base_mapper, True)
+
                 uow.dependencies.update([
-                    (before_delete, delete_parent),
-                    (before_delete, child_action)
+                    (before_delete, delete_parent), # can remove
+                    (before_delete, child_action), # can remove
+                    
+                    (before_delete, child_pre_updates),
+                    (child_pre_updates, delete_parent),
+                    (child_pre_updates, child_action)
                 ])
                     
         elif not isdelete:
@@ -647,7 +677,7 @@ class ManyToOneDP(DependencyProcessor):
                         self._post_update(
                                             state, 
                                             uowcommit, 
-                                            history.sum(), processed)
+                                            history.sum(), processed, False)
 
     def process_saves(self, uowcommit, states):
         if self.post_update:
@@ -662,7 +692,7 @@ class ManyToOneDP(DependencyProcessor):
                 if self.post_update:
                     self._post_update(
                                         state, 
-                                        uowcommit, history.sum(), processed)
+                                        uowcommit, history.sum(), processed, False)
 
     def _synchronize(self, state, child, associationrow, clearkeys, uowcommit):
         if state is None or (not self.post_update and uowcommit.is_deleted(state)):
@@ -789,7 +819,8 @@ class ManyToManyDP(DependencyProcessor):
                                                 parent_deletes, 
                                                 child_deletes, 
                                                 after_save, 
-                                                before_delete):
+                                                before_delete
+                                                ):
 
         uow.dependencies.update([
             (parent_saves, after_save),
index cbf45039e1693500eafbd915bccfb1acede4b7c5..aed50f6499cfa19723a6beb39c50388d856ee57b 100644 (file)
@@ -110,6 +110,8 @@ class UOWTransaction(object):
         # or insert/updated, or just refreshed
         self.states = {}
     
+        self.post_update_states = util.defaultdict(set)
+        
     @property
     def has_work(self):
         return bool(self.states)
@@ -183,11 +185,14 @@ 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):
-        mapper = state.manager.mapper.base_mapper
-        mapper._save_obj([state], self, \
-                    postupdate=True, \
-                    post_update_cols=set(post_update_cols))
+    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)
     
     @util.memoized_property
     def _mapper_for_dep(self):
@@ -272,10 +277,10 @@ class UOWTransaction(object):
     def execute(self):
         postsort_actions = self._generate_actions()
         
-        #sort = topological.sort(self.dependencies, postsort_actions)
+        sort = topological.sort(self.dependencies, postsort_actions)
         #print "--------------"
         #print self.dependencies
-        #print list(sort)
+        print list(sort)
         #print "COUNT OF POSTSORT ACTIONS", len(postsort_actions)
         
         # execute
@@ -414,7 +419,26 @@ class ProcessAll(IterateMappersMixin, PostSortRec):
                 (isdelete, listonly) = uow.states[state]
                 if isdelete == self.delete and not listonly:
                     yield state
-        
+
+class PostUpdateThing(PostSortRec):
+    def __init__(self, uow, mapper, isdelete):
+        self.mapper = mapper
+        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])
+
+        self.mapper._save_obj(states, uow, \
+                            postupdate=True, \
+                            post_update_cols=update_cols)
+
 class SaveUpdateAll(PostSortRec):
     def __init__(self, uow, mapper):
         self.mapper = mapper