def per_property_flush_actions(self, uow):
unitofwork.GetDependentObjects(uow, self, False, True)
+ unitofwork.GetDependentObjects(uow, self, True, True)
after_save = unitofwork.ProcessAll(uow, self, False, True)
before_delete = unitofwork.ProcessAll(uow, self, True, True)
(before_delete, child_deletes),
])
else:
- unitofwork.GetDependentObjects(uow, self, True, True)
-
uow.dependencies.update([
(parent_saves, after_save),
(after_save, child_saves),
-
+ (after_save, child_deletes),
+
(child_saves, parent_deletes),
+ (child_deletes, parent_deletes),
+
(before_delete, child_saves),
+ (before_delete, child_deletes),
- (child_deletes, parent_deletes)
])
-
- def per_saved_state_flush_actions(self, uow, state):
+
+ def per_state_flush_actions(self, uow, state, isdelete):
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
+ 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
- added, unchanged, deleted = uow.get_attribute_history(state, self.key, passive=True)
- if not added and not unchanged and not deleted:
+ sum_ = uow.get_attribute_history(state, self.key, passive=True).sum()
+ if not sum_:
return
-
- save_parent = unitofwork.SaveUpdateState(uow, state)
- after_save = unitofwork.ProcessState(uow, self, False, state)
- for child_state in added + unchanged + deleted:
+ if not isdelete:
+ save_parent = unitofwork.SaveUpdateState(uow, state)
+ after_save = unitofwork.ProcessState(uow, self, False, state)
+ yield after_save
+ else:
+ delete_parent = unitofwork.DeleteState(uow, state)
+ before_delete = unitofwork.ProcessState(uow, self, True, state)
+ yield before_delete
+
+ 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)
- 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, unchanged, deleted = uow.get_attribute_history(state, self.key, passive=True)
- if not added and not unchanged and not deleted:
- return
-
- delete_parent = unitofwork.DeleteState(uow, state)
- before_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(uow, child_state)
+ if not isdelete:
+ uow.dependencies.update([
+ (save_parent, after_save),
+ (after_save, child_action),
+ (save_parent, child_action)
+ ])
else:
- child_action = unitofwork.SaveUpdateState(uow, child_state)
-
- uow.dependencies.update([
- (child_action, before_delete),
- (before_delete, delete_parent),
- ])
-
+ uow.dependencies.update([
+ (child_action, before_delete),
+ (before_delete, delete_parent),
+ (child_action, delete_parent)
+ ])
+
def presort_deletes(self, uowcommit, states):
# head object is being deleted, and we manage its list of child objects
def per_property_flush_actions(self, uow):
pass
+
+ def per_state_flush_actions(self, uow, state, isdelete):
+ return iter([])
def is_primary(self):
"""Return True if this ``MapperProperty``'s mapper is the
for prop in self._props.values():
prop.per_property_flush_actions(uow)
+
+ def per_state_flush_actions(self, uow, state, isdelete):
+ if isdelete:
+ action = unitofwork.DeleteState(uow, state)
+ else:
+ action = unitofwork.SaveUpdateState(uow, state)
+
+ yield action
+ for prop in self._props.values():
+ for rec in prop.per_state_flush_actions(uow, state, isdelete):
+ yield rec
+
def _save_obj(self, states, uowtransaction, postupdate=False,
post_update_cols=None, single=False):
if not self.viewonly and self._dependency_processor:
self._dependency_processor.per_property_flush_actions(uow)
+ def per_state_flush_actions(self, uow, state, isdelete):
+ if not self.viewonly and self._dependency_processor:
+ for rec in self._dependency_processor.per_state_flush_actions(uow, state, isdelete):
+ yield rec
+
def _create_joins(self, source_polymorphic=False,
source_selectable=None, dest_polymorphic=False,
dest_selectable=None, of_type=None):
def execute(self):
+ # execute presort_actions, until all states
+ # have been processed. a presort_action might
+ # add new states to the uow.
while True:
ret = False
for action in self.presort_actions.values():
if not ret:
break
+ # see if the graph of mapper dependencies has cycles.
self.cycles = cycles = topological.find_cycles(self.dependencies, self.postsort_actions.values())
-
+
if cycles:
- convert = {}
- for rec in cycles:
- convert[rec] = set(rec.per_state_flush_actions(self))
-
- for edge in list(self.dependencies):
- # remove old dependencies between two cycle nodes,
- # splice dependencies for dependencies from/to cycle
- # nodes from non-cycle nodes
- if cycles.issuperset(edge):
- self.dependencies.remove(edge)
- elif edge[0] in cycles:
- for dep in convert[edge[0]]:
- self.dependencies.add((dep, edge[1]))
- elif edge[1] in cycles:
- for dep in convert[edge[1]]:
- self.dependencies.add((edge[0], dep))
-
+ # if yes, break the per-mapper actions into
+ # per-state actions
+ convert = dict(
+ (rec, set(rec.per_state_flush_actions(self)))
+ for rec in cycles
+ )
+
+ # rewrite the existing dependencies to point to
+ # the per-state actions for those per-mapper actions
+ # that were broken up.
+ for edge in list(self.dependencies):
+ if cycles.issuperset(edge):
+ self.dependencies.remove(edge)
+ elif edge[0] in cycles:
+ self.dependencies.remove(edge)
+ for dep in convert[edge[0]]:
+ self.dependencies.add((dep, edge[1]))
+ elif edge[1] in cycles:
+ self.dependencies.remove(edge)
+ for dep in convert[edge[1]]:
+ self.dependencies.add((edge[0], dep))
+
+ # 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]
+
+ # execute actions
sort = topological.sort(self.dependencies, self.postsort_actions.values())
- print sort
+ #print self.dependencies
+ #print sort
for rec in sort:
- if rec in cycles:
- continue
rec.execute(self)
return ret
class PostSortRec(object):
+ disabled = False
+
def __new__(cls, uow, *args):
key = (cls, ) + args
if key in uow.postsort_actions:
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, state)
- else:
- self.dependency_processor.per_saved_state_flush_actions(uow, state)
return iter([])
class SaveUpdateAll(PostSortRec):
def per_state_flush_actions(self, uow):
for state in uow.states_for_mapper_hierarchy(self.mapper, False, False):
- yield SaveUpdateState(uow, state)
+ for rec in self.mapper.per_state_flush_actions(uow, state, False):
+ yield rec
class DeleteAll(PostSortRec):
def __init__(self, uow, mapper):
def per_state_flush_actions(self, uow):
for state in uow.states_for_mapper_hierarchy(self.mapper, True, False):
- yield DeleteState(uow, state)
+ for rec in self.mapper.per_state_flush_actions(uow, state, True):
+ yield rec
class ProcessState(PostSortRec):
def __init__(self, uow, dependency_processor, delete, state):
uow
)
+ def __repr__(self):
+ return "%s(%s)" % (
+ self.__class__.__name__,
+ mapperutil.state_str(self.state)
+ )
+
class DeleteState(PostSortRec):
def __init__(self, uow, state):
self.state = state
uow
)
+ def __repr__(self):
+ return "%s(%s)" % (
+ self.__class__.__name__,
+ mapperutil.state_str(self.state)
+ )
+
sess.flush,
CompiledSQL(
"UPDATE addresses SET user_id=:user_id WHERE addresses.id = :addresses_id",
- [{u'addresses_id': 1, 'user_id': None}]
+ lambda ctx: [{u'addresses_id': a1.id, 'user_id': None}]
),
CompiledSQL(
"UPDATE addresses SET user_id=:user_id WHERE addresses.id = :addresses_id",
- [{u'addresses_id': 2, 'user_id': None}]
+ lambda ctx: [{u'addresses_id': a2.id, 'user_id': None}]
),
CompiledSQL(
"DELETE FROM users WHERE users.id = :id",
sess.flush,
CompiledSQL(
"UPDATE addresses SET user_id=:user_id WHERE addresses.id = :addresses_id",
- [{u'addresses_id': 1, 'user_id': None}]
+ lambda ctx: [{u'addresses_id': a1.id, 'user_id': None}]
),
CompiledSQL(
"UPDATE addresses SET user_id=:user_id WHERE addresses.id = :addresses_id",
- [{u'addresses_id': 2, 'user_id': None}]
+ lambda ctx: [{u'addresses_id': a2.id, 'user_id': None}]
),
CompiledSQL(
"DELETE FROM users WHERE users.id = :id",