diff options
| -rw-r--r-- | lib/sqlalchemy/orm/dependency.py | 110 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/unitofwork.py | 12 |
2 files changed, 70 insertions, 52 deletions
diff --git a/lib/sqlalchemy/orm/dependency.py b/lib/sqlalchemy/orm/dependency.py index 7359d8558..a34c45233 100644 --- a/lib/sqlalchemy/orm/dependency.py +++ b/lib/sqlalchemy/orm/dependency.py @@ -58,6 +58,12 @@ class DependencyProcessor(object): return self._get_instrumented_attribute().hasparent(state) def per_property_flush_actions(self, uow): + """establish actions and dependencies related to a flush. + + These actions will operate on all relevant states in + the aggreagte. + + """ unitofwork.GetDependentObjects(uow, self, False, True) unitofwork.GetDependentObjects(uow, self, True, True) @@ -79,11 +85,13 @@ class DependencyProcessor(object): before_delete) def per_state_flush_actions(self, uow, states, isdelete): - for state in states: - for rec in self._per_state_flush_actions(uow, state, isdelete): - yield rec - - def _per_state_flush_actions(self, uow, state, isdelete): + """establish actions and dependencies related to a flush. + + These actions will operate on all relevant states + individually. This occurs only if there are cycles + in the 'aggregated' version of events. + + """ # locate and disable the aggregate processors # for this dependency after_save = unitofwork.ProcessAll(uow, self, False, True) @@ -94,6 +102,7 @@ class DependencyProcessor(object): # check if the "child" side is part of the cycle 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 @@ -106,54 +115,65 @@ class DependencyProcessor(object): child_actions = [ (child_saves, False), (child_deletes, True) ] + child_in_cycles = False else: - # 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 - child_actions = [] - for child_state in sum_: - if child_state is None: - continue - if child_state not in uow.states: - child_action = (None, None) - else: - (deleted, listonly) = uow.states[child_state] - if deleted: - child_action = (unitofwork.DeleteState(uow, child_state), True) - else: - child_action = (unitofwork.SaveUpdateState(uow, child_state), False) - child_actions.append(child_action) - - # check if the "parent" side is part of the cycle, - # if so break up parent_saves or parent_deletes + child_in_cycles = True + + # check if the "parent" side is part of the cycle if not isdelete: parent_saves = unitofwork.SaveUpdateAll(uow, self.parent.base_mapper) + parent_deletes = before_delte = None if parent_saves in uow.cycles: - parent_saves = unitofwork.SaveUpdateState(uow, state) - - after_save = unitofwork.ProcessState(uow, self, False, state) - yield after_save - - parent_deletes = before_delete = None + parent_in_cycles = True else: parent_deletes = unitofwork.DeleteAll(uow, self.parent.base_mapper) - if parent_deletes in uow.cycles: - parent_deletes = unitofwork.DeleteState(uow, state) - before_delete = unitofwork.ProcessState(uow, self, True, state) - yield before_delete - parent_saves = after_save = None + if parent_deletes in uow.cycles: + parent_in_cycles = True - # establish dependencies between our possibly per-state - # parent action and our possibly per-state child action. - for (child_action, childisdelete) in child_actions: - self.per_state_dependencies(uow, parent_saves, - parent_deletes, - child_action, - after_save, before_delete, - isdelete, childisdelete) + # now create actions /dependencies for each state. + for state in states: + if isdelete: + before_delete = unitofwork.ProcessState(uow, self, True, state) + yield before_delete + else: + after_save = unitofwork.ProcessState(uow, self, False, state) + yield after_save + + if parent_in_cycles: + if isdelete: + parent_deletes = unitofwork.DeleteState(uow, state) + else: + parent_saves = unitofwork.SaveUpdateState(uow, state) + + if child_in_cycles: + # locate each child state associated with the parent action, + # create dependencies for each. + child_actions = [] + sum_ = uow.get_attribute_history(state, self.key, passive=True).sum() + if not sum_: + continue + for child_state in sum_: + if child_state is None: + continue + if child_state not in uow.states: + child_action = (None, None) + else: + (deleted, listonly) = uow.states[child_state] + if deleted: + child_action = (unitofwork.DeleteState(uow, child_state), True) + else: + child_action = (unitofwork.SaveUpdateState(uow, child_state), False) + child_actions.append(child_action) + + # establish dependencies between our possibly per-state + # parent action and our possibly per-state child action. + for (child_action, childisdelete) in child_actions: + self.per_state_dependencies(uow, parent_saves, + parent_deletes, + child_action, + after_save, before_delete, + isdelete, childisdelete) def presort_deletes(self, uowcommit, states): pass diff --git a/lib/sqlalchemy/orm/unitofwork.py b/lib/sqlalchemy/orm/unitofwork.py index 359e1008b..b8373ff63 100644 --- a/lib/sqlalchemy/orm/unitofwork.py +++ b/lib/sqlalchemy/orm/unitofwork.py @@ -206,15 +206,13 @@ class UOWTransaction(object): elif edge[0].disabled or edge[1].disabled: self.dependencies.remove(edge) - # remove actions that were part of the cycles, - # or have been marked as "disabled" by the "breaking up" - # process - for k, v in list(self.postsort_actions.items()): - if v.disabled or v in cycles: - del self.postsort_actions[k] + postsort_actions = set( + [a for a in self.postsort_actions.values() + if not a.disabled] + ).difference(cycles) # execute actions - sort = topological.sort(self.dependencies, self.postsort_actions.values()) + sort = topological.sort(self.dependencies, postsort_actions) # print "------------------------" # print self.dependencies # print sort |
