diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2010-03-31 17:31:34 -0400 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2010-03-31 17:31:34 -0400 |
| commit | 89afcfdda4d714ccc4e361e2fb32328f816d06c9 (patch) | |
| tree | 10d3d3363b73c4986bdffa2e527b5c8b4893bb15 /lib | |
| parent | 15f4a6ef058f148045e5bd4b4ceb3fd38480f7bc (diff) | |
| download | sqlalchemy-89afcfdda4d714ccc4e361e2fb32328f816d06c9.tar.gz | |
beginning to address cycles but its not worked out yet
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/sqlalchemy/orm/dependency.py | 75 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/unitofwork.py | 32 |
2 files changed, 96 insertions, 11 deletions
diff --git a/lib/sqlalchemy/orm/dependency.py b/lib/sqlalchemy/orm/dependency.py index 8b90fbb7f..5729f553d 100644 --- a/lib/sqlalchemy/orm/dependency.py +++ b/lib/sqlalchemy/orm/dependency.py @@ -191,10 +191,73 @@ class OneToManyDP(DependencyProcessor): uow.dependencies.update([ (parent_saves, after_save), (after_save, child_saves), - (child_deletes, before_delete), - (before_delete, parent_deletes) + + (child_saves, parent_deletes), + (before_delete, child_saves), + + (child_deletes, parent_deletes) ]) + def per_saved_state_flush_actions(self, uow, state): + if True: + parent_saves = unitofwork.SaveUpdateAll(uow, self.parent) + child_saves = unitofwork.SaveUpdateAll(uow, self.mapper) + assert parent_saves in uow.cycles + assert child_saves in uow.cycles + + added, updated, deleted = uow.get_attribute_history(state, self.key, passive=True) + if not added and not unchanged and not deleted: + return + + save_parent = unitofwork.SaveUpdateState(state) + after_save = unitofwork.ProcessState(uow, self, False, state) + + for child_state in added + unchanged + deleted: + if child_state is None: + continue + + (deleted, listonly) = uow.states[child_state] + if deleted: + child_action = unitofwork.DeleteState(child_state) + else: + child_action = unitofwork.SaveUpdateState(child_state) + + uow.dependencies.update([ + (save_parent, after_save), + (after_save, child_action), + ]) + + def per_deleted_state_flush_actions(self, uow, state): + if True: + parent_deletes = unitofwork.DeleteAll(uow, self.parent) + child_deletes = unitofwork.DeleteAll(uow, self.mapper) + assert parent_deletes in uow.cycles + assert child_deletes in uow.cycles + + added, updated, deleted = uow.get_attribute_history(state, self.key, passive=True) + if not added and not unchanged and not deleted: + return + + delete_parent = unitofwork.DeleteState(state) + after_delete = unitofwork.ProcessState(uow, self, True, state) + + for child_state in added + unchanged + deleted: + if child_state is None: + continue + + (deleted, listonly) = uow.states[child_state] + if deleted: + child_action = unitofwork.DeleteState(child_state) + else: + child_action = unitofwork.SaveUpdateState(child_state) + + uow.dependencies.update([ + (child_action, ) + (save_parent, after_save), + (after_save, child_action), + ]) + + def presort_deletes(self, uowcommit, states): # head object is being deleted, and we manage its list of child objects # the child objects have to have their foreign key to the parent set to NULL @@ -318,12 +381,11 @@ class ManyToOneDP(DependencyProcessor): else: unitofwork.GetDependentObjects(uow, self, False, True) unitofwork.GetDependentObjects(uow, self, True, True) - + uow.dependencies.update([ - (after_save, parent_saves), (child_saves, after_save), - (parent_deletes, before_delete), - (before_delete, child_deletes) + (after_save, parent_saves), + (parent_saves, child_deletes) ]) def presort_deletes(self, uowcommit, states): @@ -375,6 +437,7 @@ class ManyToOneDP(DependencyProcessor): if history: for child in history.added: self._synchronize(state, child, None, False, uowcommit) + self._conditional_post_update(state, uowcommit, history.sum()) diff --git a/lib/sqlalchemy/orm/unitofwork.py b/lib/sqlalchemy/orm/unitofwork.py index 6c53586e7..65d85a37b 100644 --- a/lib/sqlalchemy/orm/unitofwork.py +++ b/lib/sqlalchemy/orm/unitofwork.py @@ -166,16 +166,23 @@ class UOWTransaction(object): if not ret: break + self.cycles = cycles = topological.find_cycles(self.dependencies, self.postsort_actions.values()) + assert not cycles + for rec in cycles: + rec.per_state_flush_actions(self) + + for edge in list(self.dependencies): + # both nodes in this edge were part of a cycle. + # remove that from our deps as it has replaced + # itself with per-state actions + if cycles.issuperset(edge): + self.dependencies.remove(edge) + sort = topological.sort(self.dependencies, self.postsort_actions.values()) print sort for rec in sort: rec.execute(self) -# if cycles: -# break up actions into finer grained actions along those cycles - -# for rec in topological.sort(self.dependencies, self.actions): -# rec.execute() def finalize_flush_changes(self): """mark processed objects as clean / deleted after a successful flush(). @@ -276,6 +283,13 @@ class ProcessAll(PropertyRecMixin, PostSortRec): else: self.dependency_processor.process_saves(uow, states) + def per_state_flush_actions(self, uow): + for state in self._elements(uow): + if self.delete: + self.dependency_processor.per_deleted_state_flush_actions(uow, self.dependency_processor, state) + else: + self.dependency_processor.per_saved_state_flush_actions(uow, self.dependency_processor, state) + class SaveUpdateAll(PostSortRec): def __init__(self, uow, mapper): self.mapper = mapper @@ -285,6 +299,10 @@ class SaveUpdateAll(PostSortRec): uow.states_for_mapper_hierarchy(self.mapper, False, False), uow ) + + def per_state_flush_actions(self, uow): + for state in uow.states_for_mapper_hierarchy(self.mapper, False, False): + SaveUpdateState(uow, state) class DeleteAll(PostSortRec): def __init__(self, uow, mapper): @@ -296,6 +314,10 @@ class DeleteAll(PostSortRec): uow ) + def per_state_flush_actions(self, uow): + for state in uow.states_for_mapper_hierarchy(self.mapper, True, False): + DeleteState(uow, state) + class ProcessState(PostSortRec): def __init__(self, uow, dependency_processor, delete, state): self.dependency_processor = dependency_processor |
