From 45dd486e0694a1dd60baa7410d2caeb00146333f Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Thu, 7 Sep 2006 20:04:10 +0000 Subject: [PATCH] - more rearrangements of unit-of-work commit scheme to better allow dependencies within circular flushes to work properly...updated task traversal/logging implementation this work is still under construction ! requires more unit tests and new dumper needs to be finished. --- CHANGES | 5 ++ lib/sqlalchemy/orm/unitofwork.py | 111 ++++++++++++++++++------------- lib/sqlalchemy/orm/uowdumper.py | 75 ++++++++++++++++++++- 3 files changed, 145 insertions(+), 46 deletions(-) diff --git a/CHANGES b/CHANGES index 8ec7f60e9f..3ce07ba9cf 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,8 @@ +0.2.9 +- more rearrangements of unit-of-work commit scheme to better allow +dependencies within circular flushes to work properly...updated +task traversal/logging implementation + 0.2.8 - cleanup on connection methods + documentation. custom DBAPI arguments specified in query string, 'connect_args' argument diff --git a/lib/sqlalchemy/orm/unitofwork.py b/lib/sqlalchemy/orm/unitofwork.py index c0bb219a32..17c77785a6 100644 --- a/lib/sqlalchemy/orm/unitofwork.py +++ b/lib/sqlalchemy/orm/unitofwork.py @@ -516,6 +516,71 @@ class UOWDependencyProcessor(object): def branch(self, task): return UOWDependencyProcessor(self.processor, task) +class UOWExecutor(object): + def execute(self, trans, task, isdelete=None): + if isdelete is not True: + self.execute_save_steps(trans, task) + if isdelete is not False: + self.execute_delete_steps(trans, task) + + def save_objects(self, trans, task): + task._save_objects(trans) + + def delete_objects(self, trans, task): + task._delete_objects(trans) + + def execute_dependency(self, trans, dep, isdelete): + dep.execute(trans, isdelete) + + def execute_save_steps(self, trans, task): + if task.circular is not None: + self.execute_save_steps(trans, task.circular) + else: + self.save_objects(trans, task) + self.execute_cyclical_dependencies(trans, task, False) + self.execute_per_element_childtasks(trans, task, False) + self.execute_dependencies(trans, task, False) + self.execute_dependencies(trans, task, True) + self.execute_childtasks(trans, task, False) + + def execute_delete_steps(self, trans, task): + if task.circular is not None: + self.execute_delete_steps(trans, task.circular) + else: + self.execute_cyclical_dependencies(trans, task, True) + self.execute_childtasks(trans, task, True) + self.execute_per_element_childtasks(trans, task, True) + self.delete_objects(trans, task) + + def execute_dependencies(self, trans, task, isdelete=None): + alltasks = list(task.polymorphic_tasks()) + if isdelete is not True: + for task in alltasks: + for dep in task.dependencies: + self.execute_dependency(trans, dep, False) + if isdelete is not False: + alltasks.reverse() + for task in alltasks: + for dep in task.dependencies: + self.execute_dependency(trans, dep, True) + + def execute_childtasks(self, trans, task, isdelete=None): + for polytask in task.polymorphic_tasks(): + for child in polytask.childtasks: + self.execute(trans, child, isdelete) + + def execute_cyclical_dependencies(self, trans, task, isdelete): + for polytask in task.polymorphic_tasks(): + for dep in polytask.cyclical_dependencies: + self.execute_dependency(trans, dep, isdelete) + + def execute_per_element_childtasks(self, trans, task, isdelete): + for polytask in task.polymorphic_tasks(): + for element in polytask.tosave_elements + polytask.todelete_elements: + for child in element.childtasks: + self.execute(trans, child, isdelete) + + class UOWTask(object): """represents the full list of objects that are to be saved/deleted by a specific Mapper.""" def __init__(self, uowtransaction, mapper, circular_parent=None): @@ -600,56 +665,12 @@ class UOWTask(object): def _delete_objects(self, trans): for task in self.polymorphic_tasks(): task.mapper.delete_obj(task.todelete_objects, trans) - def _execute_dependencies(self, trans): - alltasks = list(self.polymorphic_tasks()) - for task in alltasks: - for dep in task.dependencies: - dep.execute(trans, False) - alltasks.reverse() - for task in alltasks: - for dep in task.dependencies: - dep.execute(trans, True) - def _execute_childtasks(self, trans): - for task in self.polymorphic_tasks(): - for child in task.childtasks: - child.execute(trans) - def _execute_cyclical_dependencies(self, trans, isdelete): - for task in self.polymorphic_tasks(): - for dep in task.cyclical_dependencies: - dep.execute(trans, isdelete) - def _execute_per_element_childtasks(self, trans, isdelete): - for ptask in self.polymorphic_tasks(): - if isdelete: - for element in ptask.todelete_elements: - for task in element.childtasks: - task.execute(trans) - else: - for element in ptask.tosave_elements: - for task in element.childtasks: - task.execute(trans) def execute(self, trans): """executes this UOWTask. saves objects to be saved, processes all dependencies that have been registered, and deletes objects to be deleted. """ - # a "circular" task is a circularly-sorted collection of UOWTask/UOWTaskElements - # derived from the components of this UOWTask, which accounts for inter-row dependencies. - # if one was created for this UOWTask, it replaces the execution for this UOWTask. - if self.circular is not None: - self.circular.execute(trans) - return - - # TODO: add a visitation system to the UOW classes and have this execution called - # from a separate executor object ? (would also handle dumping) - - self._save_objects(trans) - self._execute_cyclical_dependencies(trans, False) - self._execute_per_element_childtasks(trans, False) - self._execute_dependencies(trans) - self._execute_cyclical_dependencies(trans, True) - self._execute_childtasks(trans) - self._execute_per_element_childtasks(trans, True) - self._delete_objects(trans) + UOWExecutor().execute(trans, self) def polymorphic_tasks(self): """returns an iteration consisting of this UOWTask, and all UOWTasks whose diff --git a/lib/sqlalchemy/orm/uowdumper.py b/lib/sqlalchemy/orm/uowdumper.py index ab7a1449a2..f49c35d7f0 100644 --- a/lib/sqlalchemy/orm/uowdumper.py +++ b/lib/sqlalchemy/orm/uowdumper.py @@ -1,13 +1,83 @@ +import unitofwork """dumps out a string representation of a UOWTask structure""" -class UOWDumper(object): +class UOWDumper(unitofwork.UOWExecutor): def __init__(self, task, buf, verbose=False): self.verbose = verbose self.indent = 0 self.task = task self.buf = buf + self.starttask = task + #self.execute(None, task) self._dump(task) + + # execute stuff is UNDER CONSTRUCTION + + def execute(self, trans, task, isdelete=None): + oldstarttask = self.starttask + self.starttask = task + try: + i = self._indent() + if len(i): + i = i[0:-1] + "-" + if task.circular is not None: + self.buf.write(self._indent() + "\n") + self.buf.write(i + " " + self._repr_task(task)) + self.buf.write("->circular->" + self._repr_task(task.circular)) + else: + self.buf.write(self._indent() + "\n") + self.buf.write(i + " " + self._repr_task(task)) + self.buf.write("\n") + super(UOWDumper, self).execute(trans, task, isdelete) + finally: + self.starttask = oldstarttask + + def save_objects(self, trans, task): + for rec in task.tosave_elements: + if rec.listonly: + continue + if self.verbose: + header(self.buf, self._indent() + " |- Save elements"+ self._inheritance_tag(task) + "\n") + self.buf.write(self._indent() + " |- " + self._repr_task_element(rec) + "\n") + + def delete_objects(self, trans, task): + for rec in task.todelete_elements: + if rec.listonly: + continue + if self.verbose: + header(self.buf, self._indent() + " |- Delete elements"+ self._inheritance_tag(task) + "\n") + self.buf.write(self._indent() + " |- " + self._repr_task_element(rec) + "\n") + + def _inheritance_tag(self, task): + if not self.verbose: + return "" + elif task is not self.starttask: + return (" (inheriting task %s)" % self._repr_task(task)) + else: + return "" + + def execute_dependency(self, transaction, dep, isdelete): + #self.buf.write() + pass + + def execute_save_steps(self, trans, task): + super(UOWDumper, self).execute_save_steps(trans, task) + + def execute_delete_steps(self, trans, task): + super(UOWDumper, self).execute_delete_steps(trans, task) + + def execute_dependencies(self, trans, task, isdelete=None): + super(UOWDumper, self).execute_dependencies(trans, task, isdelete) + + def execute_childtasks(self, trans, task, isdelete=None): + super(UOWDumper, self).execute_childtasks(trans, task, isdelete) + + def execute_cyclical_dependencies(self, trans, task, isdelete): + super(UOWDumper, self).execute_cyclical_dependencies(trans, task, isdelete) + + def execute_per_element_childtasks(self, trans, task, isdelete): + super(UOWDumper, self).execute_per_element_childtasks(trans, task, isdelete) def _dump_processor(self, proc, deletes): if deletes: @@ -144,6 +214,7 @@ class UOWDumper(object): self._dump(starttask.circular, indent=self.indent, circularparent=starttask) return + i = self._indent() if len(i): i = i[0:-1] + "-" @@ -185,3 +256,5 @@ class UOWDumper(object): self.buf.write(self._indent() + " |----\n") self.buf.write(self._indent() + "\n") + + -- 2.47.2