summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2010-03-31 17:31:34 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2010-03-31 17:31:34 -0400
commit89afcfdda4d714ccc4e361e2fb32328f816d06c9 (patch)
tree10d3d3363b73c4986bdffa2e527b5c8b4893bb15 /lib
parent15f4a6ef058f148045e5bd4b4ceb3fd38480f7bc (diff)
downloadsqlalchemy-89afcfdda4d714ccc4e361e2fb32328f816d06c9.tar.gz
beginning to address cycles but its not worked out yet
Diffstat (limited to 'lib')
-rw-r--r--lib/sqlalchemy/orm/dependency.py75
-rw-r--r--lib/sqlalchemy/orm/unitofwork.py32
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