is more data needed for each tweak.
before_delete)
def per_state_flush_actions(self, uow, state, isdelete):
+ # locate and disable the aggregate processors
+ # for this dependency
after_save = unitofwork.ProcessAll(uow, self, False, True)
before_delete = unitofwork.ProcessAll(uow, self, True, True)
after_save.disabled = True
child_saves = unitofwork.SaveUpdateAll(uow, self.mapper.base_mapper)
child_deletes = unitofwork.DeleteAll(uow, self.mapper.base_mapper)
if child_saves not in uow.cycles:
+ # based on the current dependencies we use, the saves/
+ # deletes should always be in the 'cycles' collection
+ # together. if this changes, we will have to break up
+ # this method a bit more.
assert child_deletes not in uow.cycles
- # its not, so we will link per-state
+
+ # child side is not part of the cycle, so we will link per-state
# actions to the aggregate "saves", "deletes" actions
child_actions = [
(child_saves, False), (child_deletes, True)
]
else:
- # it is. see if there's any objects.
+ # child side is part of the cycle. create dependencies for
+ # each related object.
sum_ = uow.get_attribute_history(state, self.key, passive=True).sum()
if not sum_:
return
child_actions.append(child_action)
# check if the "parent" side is part of the cycle,
- # if so break up parent_saves
+ # if so break up parent_saves or parent_deletes
if not isdelete:
parent_saves = unitofwork.SaveUpdateAll(uow, self.parent.base_mapper)
if parent_saves in uow.cycles:
prop.per_property_flush_actions(uow)
def per_state_flush_actions(self, uow, state, isdelete):
+ # keep saves before deletes -
+ # this ensures 'row switch' operations work
if isdelete:
action = unitofwork.DeleteState(uow, state)
+ uow.dependencies.add((unitofwork.SaveUpdateAll(uow, self.base_mapper), action))
else:
action = unitofwork.SaveUpdateState(uow, state)
-
+ uow.dependencies.add((action, unitofwork.DeleteAll(uow, self.base_mapper)))
+
yield action
mapper = state.manager.mapper
for prop in mapper._props.values():
self._log_debug(
"detected row switch for identity %s. will update %s, remove %s from "
"transaction", instance_key, state_str(state), state_str(existing))
-
+
# remove the "delete" flag from the existing element
uowtransaction.remove_state_actions(existing)
row_switches[state] = existing
def remove_state_actions(self, state):
"""remove pending actions for a state from the uowtransaction."""
- if state in self.states:
- isdelete, listonly = self.states[state]
- self.states[state] = (False, True)
- if isdelete:
- self.postsort_actions.pop((DeleteState, state), None)
- else:
- self.postsort_actions.pop((SaveUpdateState, state), None)
-
-
+ self.states[state] = (False, True)
def get_attribute_history(self, state, key, passive=True):
hashkey = ("history", state, key)
# execute actions
sort = topological.sort(self.dependencies, self.postsort_actions.values())
- print "------------------------"
-# import pdb
-# pdb.set_trace()
- print self.dependencies
- print sort
+# print "------------------------"
+# print self.dependencies
+# print sort
for rec in sort:
rec.execute(self)
def execute(self, uow):
mapper = self.state.manager.mapper.base_mapper
- mapper._delete_obj(
- [self.state],
- uow
- )
+ if uow.states[self.state][0]:
+ mapper._delete_obj(
+ [self.state],
+ uow
+ )
def __repr__(self):
return "%s(%s)" % (
CompiledSQL("DELETE FROM nodes WHERE nodes.id = :id",
lambda ctx: {'id':n1.id})
)
+
+ def test_cycle_rowswitch(self):
+ mapper(Node, nodes, properties={
+ 'children':relationship(Node)
+ })
+ sess = create_session()
+
+ n2, n3 = Node(data='n2', children=[]), Node(data='n3', children=[])
+ n1 = Node(data='n1', children=[n2])
+ sess.add(n1)
+ sess.flush()
+ sess.delete(n2)
+ n3.id = n2.id
+ n1.children.append(n3)
+ sess.flush()
+
def test_bidirectional_mutations_one(self):
mapper(Node, nodes, properties={
'children':relationship(Node, backref=backref('parent', remote_side=nodes.c.id))