From: Mike Bayer Date: Fri, 9 Apr 2010 17:57:49 +0000 (-0400) Subject: refined system bywhich dependencyprocessor per-state actions X-Git-Tag: rel_0_6_0~34 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=27b0832ea89ce99408d4c02f2269d34cb85233da;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git refined system bywhich dependencyprocessor per-state actions are established --- diff --git a/lib/sqlalchemy/orm/dependency.py b/lib/sqlalchemy/orm/dependency.py index d94c6b43f5..dfcddacaa2 100644 --- a/lib/sqlalchemy/orm/dependency.py +++ b/lib/sqlalchemy/orm/dependency.py @@ -115,16 +115,12 @@ class DependencyProcessor(object): """ - # TODO: this check sucks. somehow get mapper to - # not even call this. - if ('has_flush_activity', self) not in uow.attributes: - return + # assertions to ensure this method isn't being + # called unnecessarily. can comment these out when + # code is stable + assert ('has_flush_activity', self) in uow.attributes + assert not self.post_update or not self._check_reverse(uow) - # TODO: why are we calling this ? shouldnt per_property - # have stopped us from getting keyhere ? - if self.post_update and self._check_reverse(uow): - # TODO: coverage here - return # locate and disable the aggregate processors # for this dependency diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py index 0ea0342c40..72bc8ee317 100644 --- a/lib/sqlalchemy/orm/mapper.py +++ b/lib/sqlalchemy/orm/mapper.py @@ -1265,31 +1265,8 @@ class Mapper(object): for prop in self._props.values(): prop.per_property_flush_actions(uow) - def _property_iterator(self, mappers): - """return an iterator of all MapperProperty objects - and a list containing all mappers which use that property, - descending through the polymorphic hierarchy of this - mapper. - - 'mappers' is a set which will limit the traversal - to just those mappers. - - """ - props = set() - for mapper in self.polymorphic_iterator(): - if mapper not in mappers: - continue - - for prop in mapper._props.values(): - if prop not in props: - props.add(prop) - yield prop, [m for m in mappers - if m._props.get(prop.key) is prop] - def _per_state_flush_actions(self, uow, states, isdelete): - mappers_to_states = util.defaultdict(set) - base_mapper = self.base_mapper save_all = unitofwork.SaveUpdateAll(uow, base_mapper) delete_all = unitofwork.DeleteAll(uow, base_mapper) @@ -1303,19 +1280,8 @@ class Mapper(object): action = unitofwork.SaveUpdateState(uow, state, base_mapper) uow.dependencies.add((action, delete_all)) - mappers_to_states[state.manager.mapper].add(state) yield action - # TODO: can't we just loop through the frigging entries - # that are already in the uow instead of this goofy - # polymorphic BS ? - for prop, mappers in self._property_iterator(set(mappers_to_states)): - states_for_prop = [] - for mapper in mappers: - states_for_prop += list(mappers_to_states[mapper]) - - prop.per_state_flush_actions(uow, states_for_prop, isdelete) - def _save_obj(self, states, uowtransaction, postupdate=False, post_update_cols=None, single=False): """Issue ``INSERT`` and/or ``UPDATE`` statements for a list of objects. diff --git a/lib/sqlalchemy/orm/unitofwork.py b/lib/sqlalchemy/orm/unitofwork.py index bdfaa008b2..c93f8af200 100644 --- a/lib/sqlalchemy/orm/unitofwork.py +++ b/lib/sqlalchemy/orm/unitofwork.py @@ -79,6 +79,7 @@ class UOWTransaction(object): # information. self.attributes = {} + self.deps = util.defaultdict(set) self.mappers = util.defaultdict(set) self.presort_actions = {} self.postsort_actions = {} @@ -146,6 +147,16 @@ class UOWTransaction(object): postupdate=True, \ post_update_cols=set(post_update_cols)) + @util.memoized_property + def _mapper_for_dep(self): + return util.PopulateDict( + lambda tup:tup[0]._props.get(tup[1].key) is tup[1].prop + ) + + def filter_states_for_dep(self, dep, states): + mapper_for_dep = self._mapper_for_dep + return [s for s in states if mapper_for_dep[(s.manager.mapper, dep)]] + def states_for_mapper(self, mapper, isdelete, listonly): checktup = (isdelete, listonly) for state in self.mappers[mapper]: @@ -341,6 +352,10 @@ class GetDependentObjects(PropertyRecMixin, PreSortRec): return False class ProcessAll(PropertyRecMixin, PostSortRec): + def __init__(self, uow, *args): + super(ProcessAll, self).__init__(uow, *args) + uow.deps[self.dependency_processor.parent.base_mapper].add(self.dependency_processor) + def execute(self, uow): states = list(self._elements(uow)) if self.delete: @@ -368,11 +383,16 @@ class SaveUpdateAll(PostSortRec): ) def per_state_flush_actions(self, uow): + states = list(uow.states_for_mapper_hierarchy(self.mapper, False, False)) for rec in self.mapper._per_state_flush_actions( uow, - uow.states_for_mapper_hierarchy(self.mapper, False, False), + states, False): yield rec + + for dep in uow.deps[self.mapper]: + states_for_prop = uow.filter_states_for_dep(dep, states) + dep.per_state_flush_actions(uow, states_for_prop, False) class DeleteAll(PostSortRec): def __init__(self, uow, mapper): @@ -386,11 +406,16 @@ class DeleteAll(PostSortRec): ) def per_state_flush_actions(self, uow): + states = list(uow.states_for_mapper_hierarchy(self.mapper, True, False)) for rec in self.mapper._per_state_flush_actions( uow, - uow.states_for_mapper_hierarchy(self.mapper, True, False), + states, True): yield rec + + for dep in uow.deps[self.mapper]: + states_for_prop = uow.filter_states_for_dep(dep, states) + dep.per_state_flush_actions(uow, states_for_prop, True) class ProcessState(PostSortRec): def __init__(self, uow, dependency_processor, delete, state): diff --git a/test/orm/test_unitofworkv2.py b/test/orm/test_unitofworkv2.py index e9183297d2..728cdfd7bb 100644 --- a/test/orm/test_unitofworkv2.py +++ b/test/orm/test_unitofworkv2.py @@ -466,7 +466,7 @@ class SingleCycleTest(UOWTest): n1.children.append(n2) - self._assert_uow_size(sess, 4) + self._assert_uow_size(sess, 3) sess.flush() @@ -476,7 +476,7 @@ class SingleCycleTest(UOWTest): self._assert_uow_size(sess, 2) n1.children - self._assert_uow_size(sess, 3) + self._assert_uow_size(sess, 2) class SingleCycleM2MTest(_base.MappedTest, testing.AssertsExecutionResults):