found = True
def delete_obj(self, objects, uow):
- pass
+ for table in self.tables:
+ delete = []
+ for obj in objects:
+ params = {}
+ if not hasattr(obj, "_instance_key"):
+ continue
+ else:
+ delete.append(params)
+ for col in table.primary_keys:
+ params[col.key] = self._getattrbycolumn(obj, col)
+ uow.register_deleted_object(obj)
+ if len(delete):
+ clause = sql.and_()
+ for col in self.primary_keys[table]:
+ clause.clauses.append(col == sql.bindparam(col.key))
+ statement = table.delete(clause)
+ c = statement.execute(*delete)
+ if c.rowcount != len(delete):
+ raise "ConcurrencyError - updated rowcount does not match number of objects updated"
def register_dependencies(self, *args, **kwargs):
for prop in self.props.values():
# if only a list changes, the parent mapper is the only mapper that
# gets added to the "todo" list
uowcommit.register_dependency(self.mapper, self.parent)
- uowcommit.register_task(self.parent, self, uowcommit.get_objects(self.parent), False)
+ uowcommit.register_task(self.parent, False, self, self.parent, False)
elif self.foreignkey.table == self.target:
uowcommit.register_dependency(self.parent, self.mapper)
- uowcommit.register_task(self.parent, self, uowcommit.get_objects(self.parent), False)
+ uowcommit.register_task(self.parent, False, self, self.parent, False)
+ uowcommit.register_task(self.parent, True, self, self.mapper, False)
+
elif self.foreignkey.table == self.parent.table:
uowcommit.register_dependency(self.mapper, self.parent)
- uowcommit.register_task(self.mapper, self, uowcommit.get_objects(self.parent), False)
+ uowcommit.register_task(self.mapper, False, self, self.parent, False)
+ #uowcommit.register_task(self.mapper, True, self, self.parent, False)
else:
raise " no foreign key ?"
def process_dependencies(self, deplist, uowcommit, delete = False):
- print self.mapper.table.name + " process_dep"
- def getlist(obj):
+ print self.mapper.table.name + " process_dep isdelete " + repr(delete)
+ def getlist(obj, passive = True):
if self.uselist:
- return uowcommit.uow.attributes.get_list_history(obj, self.key)
+ return uowcommit.uow.attributes.get_list_history(obj, self.key, passive = passive)
else:
return uowcommit.uow.attributes.get_history(obj, self.key)
- clearkeys = False
-
def sync_foreign_keys(binary):
self._sync_foreign_keys(binary, obj, child, associationrow, clearkeys)
setter = BinaryVisitor(sync_foreign_keys)
+ associationrow = {}
+
if self.secondaryjoin is not None:
secondary_delete = []
secondary_insert = []
for obj in deplist:
childlist = getlist(obj)
- if delete:
- clearkeys = True
- for child in childlist.deleted_items() + childlist.unchanged_items():
- associationrow = {}
- self.primaryjoin.accept_visitor(setter)
- self.secondaryjoin.accept_visitor(setter)
- secondary_delete.append(associationrow)
- uowcommit.register_removed_list(childlist)
- else:
- clearkeys = False
- for child in childlist.added_items():
- associationrow = {}
- self.primaryjoin.accept_visitor(setter)
- self.secondaryjoin.accept_visitor(setter)
- secondary_insert.append(associationrow)
- clearkeys = True
- for child in childlist.deleted_items():
- associationrow = {}
- self.primaryjoin.accept_visitor(setter)
- self.secondaryjoin.accept_visitor(setter)
- secondary_delete.append(associationrow)
- uowcommit.register_saved_list(childlist)
+ if childlist is None: return
+ clearkeys = False
+ for child in childlist.added_items():
+ associationrow = {}
+ self.primaryjoin.accept_visitor(setter)
+ self.secondaryjoin.accept_visitor(setter)
+ secondary_insert.append(associationrow)
+ clearkeys = True
+ for child in childlist.deleted_items():
+ associationrow = {}
+ self.primaryjoin.accept_visitor(setter)
+ self.secondaryjoin.accept_visitor(setter)
+ secondary_delete.append(associationrow)
+ uowcommit.register_saved_list(childlist)
if len(secondary_delete):
statement = self.secondary.delete(sql.and_(*[c == sql.bindparam(c.key) for c in self.secondary.c]))
statement.execute(*secondary_delete)
statement = self.secondary.insert()
statement.execute(*secondary_insert)
elif self.foreignkey.table == self.target:
- associationrow = {}
- for obj in deplist:
- childlist = getlist(obj)
- if delete:
- clearkeys = True
- for child in childlist.deleted_items() + childlist.current_items():
- self.primaryjoin.accept_visitor(setter)
- uowcommit.register_saved_list(childlist)
- else:
+ if delete:
+ updates = []
+ for obj in deplist:
+ childlist = getlist(obj, False)
+ #if len(updates):
+ # statement = self.secondary.update(sql.and_(*[c == sql.bindparam(c.key) for c in self.secondary.c]))
+ # statement.execute(*secondary_delete)
+ else:
+ for obj in deplist:
+ childlist = getlist(obj)
+ if childlist is None: return
+ uowcommit.register_saved_list(childlist)
clearkeys = False
for child in childlist.added_items():
self.primaryjoin.accept_visitor(setter)
- uowcommit.register_saved_list(childlist)
clearkeys = True
for child in childlist.deleted_items():
self.primaryjoin.accept_visitor(setter)
- uowcommit.register_saved_list(childlist)
elif self.foreignkey.table == self.parent.table:
- associationrow = {}
for child in deplist:
childlist = getlist(child)
- if delete:
- for obj in childlist.deleted_items() + childlist.current_items():
+ if childlist is None: return
+ uowcommit.register_saved_list(childlist)
+ clearkeys = False
+ added = childlist.added_items()
+ if len(added):
+ for obj in added:
self.primaryjoin.accept_visitor(setter)
- uowcommit.register_saved_list(childlist)
else:
- clearkeys = False
- for obj in childlist.added_items():
- self.primaryjoin.accept_visitor(setter)
- uowcommit.register_saved_list(childlist)
clearkeys = True
for obj in childlist.deleted_items():
self.primaryjoin.accept_visitor(setter)
- uowcommit.register_saved_list(childlist)
else:
raise " no foreign key ?"
elif colmap.has_key(self.target) and colmap.has_key(self.secondary):
associationrow[colmap[self.secondary].key] = self.mapper._getattrbycolumn(child, colmap[self.target])
- def delete(self):
- self.mapper.delete()
-
+# TODO: break out the lazywhere capability so that the main PropertyLoader can use it
+# to do child deletes
class LazyLoader(PropertyLoader):
def init(self, key, parent):
def _put(self, key, obj):
self.identity_map[key] = obj
+
+ def _remove_deleted(self, obj):
+ if hasattr(obj, "_instancekey"):
+ del self.identity_map[obj._instancekey]
+ del self.deleted[obj]
+ self.attributes.remove(obj)
def update(self, obj):
"""called to add an object to this UnitOfWork as though it were loaded from the DB, but is
class UOWTransaction(object):
def __init__(self, uow):
self.uow = uow
+ # links objects to their mappers
self.object_mappers = {}
+ # unique list of all the mappers we come across
self.mappers = util.HashSet()
self.dependencies = {}
self.tasks = {}
self.saved_objects = util.HashSet()
self.saved_lists = util.HashSet()
self.deleted_objects = util.HashSet()
+ self.deleted_lists = util.HashSet()
def append_task(self, obj):
mapper = self.object_mapper(obj)
def add_item_to_delete(self, obj):
mapper = self.object_mapper(obj)
- task = self.get_task_by_mapper(mapper)
- task.todelete.append(obj)
+ task = self.get_task_by_mapper(mapper, True)
+ task.objects.append(obj)
def get_task_by_mapper(self, mapper, isdelete = False):
try:
return task.objects
- # TODO: better interface for tasks with no object save, or multiple dependencies
def register_dependency(self, mapper, dependency):
self.dependencies[(mapper, dependency)] = True
- def register_task(self, mapper, processor, objects, isdelete):
+ def register_task(self, mapper, isdelete, processor, mapperfrom, isdeletefrom):
task = self.get_task_by_mapper(mapper, isdelete)
- task.dependencies.append((processor, objects))
+ targettask = self.get_task_by_mapper(mapperfrom, isdeletefrom)
+ task.dependencies.append((processor, targettask))
def register_saved_object(self, obj):
self.saved_objects.append(obj)
def register_saved_list(self, listobj):
self.saved_lists.append(listobj)
- def register_deleted(self, obj):
+ def register_deleted_list(self, listobj):
+ self.deleted_lists.append(listobj)
+
+ def register_deleted_object(self, obj):
self.deleted_objects.append(obj)
tasklist = self.tasks.values()
def compare(a, b):
- if self.dependencies.has_key((a.mapper, b.mapper)):
- return -1
+ if a.mapper is b.mapper:
+ return a.isdelete and 1 or -1
+ elif self.dependencies.has_key((a.mapper, b.mapper)):
+ if a.isdelete is not b.isdelete:
+ return a.isdelete and 1 or -1
+ else:
+ return -1
elif self.dependencies.has_key((b.mapper, a.mapper)):
- return 1
+ if a.isdelete is not b.isdelete:
+ return a.isdelete and 1 or -1
+ else:
+ return 1
else:
return 0
+ return c
tasklist.sort(compare)
import string
+ print string.join([str(t) for t in tasklist], ',')
+
for task in tasklist:
obj_list = task.objects
- if len(obj_list):
- print "t:" + string.join([o.__class__.__name__ for o in obj_list])
if not task.isdelete:
task.mapper.save_obj(obj_list, self)
for dep in task.dependencies:
- (processor, stuff) = dep
- processor.process_dependencies(stuff, self, delete = task.isdelete)
+ (processor, targettask) = dep
+ processor.process_dependencies(targettask.objects, self, delete = task.isdelete)
if task.isdelete:
task.mapper.delete_obj(obj_list, self)
except KeyError:
pass
+ for obj in self.deleted_objects:
+ self.uow._remove_deleted(obj)
+ for obj in self.deleted_lists:
+ try:
+ del self.uow.modified_lists[obj]
+ except KeyError:
+ pass
+
class UOWTask(object):
def __init__(self, mapper, isdelete = False):
self.mapper = mapper
self.isdelete = isdelete
self.objects = util.HashSet()
self.dependencies = []
-
+
+ def __str__(self):
+ if self.isdelete:
+ return self.mapper.table.name + " deletes"
+ else:
+ return self.mapper.table.name + " saves"
+
uow = util.ScopedRegistry(lambda: UnitOfWork(), "thread")
\ No newline at end of file