From: Mike Bayer Date: Thu, 1 Apr 2010 23:06:35 +0000 (-0400) Subject: working through cycles tests... X-Git-Tag: rel_0_6_0~70 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=367bc4a9e53889afde6966ba210ccfe11dbe57c3;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git working through cycles tests... --- diff --git a/lib/sqlalchemy/orm/dependency.py b/lib/sqlalchemy/orm/dependency.py index 973036639a..df9213d3e6 100644 --- a/lib/sqlalchemy/orm/dependency.py +++ b/lib/sqlalchemy/orm/dependency.py @@ -79,52 +79,62 @@ class DependencyProcessor(object): before_delete) def per_state_flush_actions(self, uow, state, isdelete): - if True: - if not isdelete: - 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 - else: - 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 - after_save = unitofwork.ProcessAll(uow, self, False, True) before_delete = unitofwork.ProcessAll(uow, self, True, True) after_save.disabled = True before_delete.disabled = True - sum_ = uow.get_attribute_history(state, self.key, passive=True).sum() - if not sum_: - return - + # check if the "child" side is part of the cycle + child_saves = unitofwork.SaveUpdateAll(uow, self.mapper) + child_deletes = unitofwork.DeleteAll(uow, self.mapper) + if child_saves not in uow.cycles: + assert child_deletes not in uow.cycles + # its not, so we will link per-state + # actions to the aggregate "saves", "deletes" actions + child_actions = [ + child_saves, child_deletes + ] + else: + # it is. see if there's any objects. + 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 or child_state not in uow.states: + continue + (deleted, listonly) = uow.states[child_state] + if deleted: + child_action = unitofwork.DeleteState(uow, child_state) + else: + child_action = unitofwork.SaveUpdateState(uow, child_state) + child_actions.append(child_action) + + # check if the "parent" side is part of the cycle, + # if so break up parent_saves if not isdelete: - save_parent = unitofwork.SaveUpdateState(uow, state) + parent_saves = unitofwork.SaveUpdateAll(uow, self.parent) + if parent_saves in uow.cycles: + parent_saves = unitofwork.SaveUpdateState(uow, state) + after_save = unitofwork.ProcessState(uow, self, False, state) yield after_save - delete_parent = before_delete = None + parent_deletes = before_delete = None else: - delete_parent = unitofwork.DeleteState(uow, state) + parent_deletes = unitofwork.DeleteAll(uow, self.parent) + if parent_deletes in uow.cycles: + parent_deletes = unitofwork.DeleteState(uow, state) before_delete = unitofwork.ProcessState(uow, self, True, state) yield before_delete - save_parent = after_save = None - - for child_state in sum_: - if child_state is None: - continue - - (deleted, listonly) = uow.states[child_state] - if deleted: - child_action = unitofwork.DeleteState(uow, child_state) - else: - child_action = unitofwork.SaveUpdateState(uow, child_state) - - self.per_state_dependencies(uow, save_parent, - delete_parent, + parent_saves = after_save = None + + # establish dependencies between our possibly per-state + # parent action and our possibly per-state child action. + for child_action in child_actions: + self.per_state_dependencies(uow, parent_saves, + parent_deletes, child_action, after_save, before_delete, isdelete) diff --git a/lib/sqlalchemy/orm/unitofwork.py b/lib/sqlalchemy/orm/unitofwork.py index 4dd9878d51..3118e0b9f9 100644 --- a/lib/sqlalchemy/orm/unitofwork.py +++ b/lib/sqlalchemy/orm/unitofwork.py @@ -145,15 +145,15 @@ class UOWTransaction(object): def states_for_mapper(self, mapper, isdelete, listonly): checktup = (isdelete, listonly) - for state, tup in self.states.iteritems(): - if tup == checktup: + for state in self.mappers[mapper]: + if self.states[state] == checktup: yield state def states_for_mapper_hierarchy(self, mapper, isdelete, listonly): checktup = (isdelete, listonly) for mapper in mapper.base_mapper.polymorphic_iterator(): - for state, tup in self.states.iteritems(): - if tup == checktup: + for state in self.mappers[mapper]: + if self.states[state] == checktup: yield state def execute(self): diff --git a/test/orm/test_cycles.py b/test/orm/test_cycles.py index c197cb627c..e728f876a9 100644 --- a/test/orm/test_cycles.py +++ b/test/orm/test_cycles.py @@ -41,7 +41,7 @@ class SelfReferentialTest(_base.MappedTest): self.data = data @testing.resolve_artifact_names - def testsingle(self): + def test_single(self): mapper(C1, t1, properties = { 'c1s':relationship(C1, cascade="all"), 'parent':relationship(C1, @@ -59,17 +59,12 @@ class SelfReferentialTest(_base.MappedTest): sess.flush() @testing.resolve_artifact_names - def testmanytooneonly(self): + def test_many_to_one_only(self): """ test that the circular dependency sort can assemble a many-to-one dependency processor when only the object on the "many" side is - actually in the list of modified objects. this requires that the - circular sort add the other side of the relationship into the - UOWTransaction so that the dependency operation can be tacked onto it. - - This also affects inheritance relationships since they rely upon - circular sort as well. + actually in the list of modified objects. """ mapper(C1, t1, properties={ @@ -91,7 +86,7 @@ class SelfReferentialTest(_base.MappedTest): assert c2.parent_c1==c1.c1 @testing.resolve_artifact_names - def testcycle(self): + def test_cycle(self): mapper(C1, t1, properties = { 'c1s' : relationship(C1, cascade="all"), 'c2s' : relationship(mapper(C2, t2), cascade="all, delete-orphan")})