From 9acd3ab4529224aeda9219b80895b9d897ce6f25 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Sat, 17 Sep 2005 06:27:29 +0000 Subject: [PATCH] --- lib/sqlalchemy/mapper.py | 19 ++++-- lib/sqlalchemy/objectstore.py | 117 +++++++++++++++++++--------------- 2 files changed, 79 insertions(+), 57 deletions(-) diff --git a/lib/sqlalchemy/mapper.py b/lib/sqlalchemy/mapper.py index d3baa387ab..fd6d50f211 100644 --- a/lib/sqlalchemy/mapper.py +++ b/lib/sqlalchemy/mapper.py @@ -153,7 +153,7 @@ class Mapper(object): def instances(self, cursor, db = None): result = util.HistoryArraySet() - cursor = engine.ResultProxy(cursor, echo = db.echo) + cursor = engine.ResultProxy(cursor, echo = db and db.echo) imap = {} while True: row = cursor.fetchone() @@ -307,7 +307,7 @@ class Mapper(object): def _identity_key(self, row): return objectstore.get_row_key(row, self.class_, self.table, self.primary_keys[self.selectable]) - def _instance(self, row, imap, result = None): + def _instance(self, row, imap, result = None, populate_existing = False): """pulls an object instance from the given row and appends it to the given result list. if the instance already exists in the given identity map, its not added. in either case, executes all the property loaders on the instance to also process extra information @@ -321,9 +321,16 @@ class Mapper(object): instance = objectstore.get(identitykey) if result is not None: result.append_nohistory(instance) - - return instance + if populate_existing: + isnew = not imap.has_key(identitykey) + if isnew: + imap[identitykey] = instance + for key, prop in self.props.iteritems(): + prop.execute(instance, row, identitykey, imap, isnew) + + return instance + # look in result-local identitymap for it. exists = imap.has_key(identitykey) if not exists: @@ -465,11 +472,11 @@ class PropertyLoader(MapperProperty): self.dependent = None def visit_binary(self, binary): if binary.operator == '=': - if binary.left.primary_key: + if isinstance(binary.left, schema.Column) and binary.left.primary_key: if self.dependent is binary.left: raise "bidirectional dependency not supported...specify foreignkey" self.dependent = binary.right - elif binary.right.primary_key: + elif isinstance(binary.right, schema.Column) and binary.right.primary_key: if self.dependent is binary.right: raise "bidirectional dependency not supported...specify foreignkey" self.dependent = binary.left diff --git a/lib/sqlalchemy/objectstore.py b/lib/sqlalchemy/objectstore.py index b4d2ccff92..f446d1b4c1 100644 --- a/lib/sqlalchemy/objectstore.py +++ b/lib/sqlalchemy/objectstore.py @@ -220,26 +220,78 @@ class UnitOfWork(object): def commit(self, *objects): import sqlalchemy.mapper - self.commit_context = UOWTransaction() + commit_context = UOWTransaction(self) if len(objects): for obj in objects: - self.commit_context.append_task(obj) + commit_context.append_task(obj) else: for obj in [n for n in self.new] + [d for d in self.dirty]: - self.commit_context.append_task(obj) + commit_context.append_task(obj) for item in self.modified_lists: obj = item.obj() - self.commit_context.append_task(obj) + commit_context.append_task(obj) + + commit_context.execute() + + # TODO: deleted stuff + + if self.parent: + uow.set(self.parent) + + + +class UOWTransaction(object): + def __init__(self, uow): + self.uow = uow + self.mappers = {} + self.dependencies = {} + self.tasks = {} + self.saved_objects = util.HashSet() + self.saved_lists = util.HashSet() + + def append_task(self, obj): + mapper = self.object_mapper(obj) + task = self.get_task_by_mapper(mapper) + task.objects.append(obj) + + def get_task_by_mapper(self, mapper): + try: + return self.tasks[mapper] + except KeyError: + return self.tasks.setdefault(mapper, UOWTask(mapper)) + + # TODO: better interface for tasks with no object save, or multiple dependencies + def register_dependency(self, mapper, dependency, processor, stuff_to_process): + self.dependencies[(mapper, dependency)] = True + task = self.get_task_by_mapper(mapper) + if processor is not None: + task.dependencies.append((processor, stuff_to_process)) + + def register_saved_object(self, obj): + self.saved_objects.append(obj) + + def register_saved_list(self, listobj): + self.saved_lists.append(listobj) + + def object_mapper(self, obj): + import sqlalchemy.mapper + try: + return self.mappers[obj] + except KeyError: + mapper = sqlalchemy.mapper.object_mapper(obj) + self.mappers[obj] = mapper + return mapper - for task in self.commit_context.tasks.values(): + def execute(self): + for task in self.tasks.values(): task.mapper.register_dependencies(task.objects, self) - mapperlist = self.commit_context.tasks.values() + mapperlist = self.tasks.values() def compare(a, b): - if self.commit_context.dependencies.has_key((a.mapper, b.mapper)): + if self.dependencies.has_key((a.mapper, b.mapper)): return -1 - elif self.commit_context.dependencies.has_key((b.mapper, a.mapper)): + elif self.dependencies.has_key((b.mapper, a.mapper)): return 1 else: return 0 @@ -255,55 +307,18 @@ class UnitOfWork(object): processor.process_dependencies(stuff_to_process, self) except: raise - - for obj in self.commit_context.saved_objects: - mapper = sqlalchemy.mapper.object_mapper(obj) + + for obj in self.saved_objects: + mapper = self.object_mapper(obj) obj._instance_key = mapper.identity_key(obj) - self.register_clean(obj) + self.uow.register_clean(obj) - for obj in self.commit_context.saved_lists: + for obj in self.saved_lists: try: - del self.modified_lists[obj] + del self.uow.modified_lists[obj] except KeyError: pass - self.commit_context = None - # TODO: deleted stuff - - if self.parent: - uow.set(self.parent) - - def register_saved_object(self, obj): - self.commit_context.saved_objects.append(obj) - - def register_saved_list(self, listobj): - self.commit_context.saved_lists.append(listobj) - - # TODO: better interface for tasks with no object save, or multiple dependencies - def register_dependency(self, mapper, dependency, processor, stuff_to_process): - self.commit_context.dependencies[(mapper, dependency)] = True - task = self.commit_context.get_task_by_mapper(mapper) - if processor is not None: - task.dependencies.append((processor, stuff_to_process)) - -class UOWTransaction(object): - def __init__(self): - self.dependencies = {} - self.tasks = {} - self.saved_objects = util.HashSet() - self.saved_lists = util.HashSet() - - def append_task(self, obj): - import sqlalchemy.mapper - mapper = sqlalchemy.mapper.object_mapper(obj) - task = self.get_task_by_mapper(mapper) - task.objects.append(obj) - - def get_task_by_mapper(self, mapper): - try: - return self.tasks[mapper] - except KeyError: - return self.tasks.setdefault(mapper, UOWTask(mapper)) class UOWTask(object): def __init__(self, mapper): -- 2.47.2