]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
pretty major change to inheritance topological sorting - mapper dependencies are...
authorMike Bayer <mike_mp@zzzcomputing.com>
Thu, 25 May 2006 17:53:06 +0000 (17:53 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Thu, 25 May 2006 17:53:06 +0000 (17:53 +0000)
based on their ultimate "base inherited" mapper, UOWTasks organized into recursive inheritance structures based on the inheritance of the mappers.  this allows tasks across a class/mapper inheritance hierarchy to properly interact with other dependency processors and sub-tasks.

lib/sqlalchemy/orm/dependency.py
lib/sqlalchemy/orm/mapper.py
lib/sqlalchemy/orm/unitofwork.py

index f805207fa9159aa5ff70f3e8e5e3eac43f10c590..8cc302bfd1a09378fc01ee8b2c97762b3e6dfa76 100644 (file)
@@ -203,7 +203,7 @@ class ManyToOneDP(DependencyProcessor):
                     uowcommit.register_object(obj, postupdate=True)
             
     def preprocess_dependencies(self, task, deplist, uowcommit, delete = False):
-        #print self.mapper.table.name + " " + self.key + " " + repr(len(deplist)) + " process_dep isdelete " + repr(delete) + " direction " + repr(self.direction)
+        #print self.mapper.mapped_table.name + " " + self.key + " " + repr(len(deplist)) + " PRE process_dep isdelete " + repr(delete) + " direction " + repr(self.direction)
         # TODO: post_update instructions should be established in this step as well
         # (and executed in the regular traversal)
         if self.post_update:
@@ -359,6 +359,7 @@ class MapperStub(object):
     for the many-to-many update task."""
     def __init__(self, mapper):
         self.mapper = mapper
+        self._inheriting_mappers = []
     def register_dependencies(self, uowcommit):
         pass
     def save_obj(self, *args, **kwargs):
@@ -367,3 +368,5 @@ class MapperStub(object):
         pass
     def _primary_mapper(self):
         return self
+    def base_mapper(self):
+        return self
\ No newline at end of file
index 21daafad8f7548ee7189a091a4646d04ac28644e..4f1309fdfbb30043b1d938a2d9ca44cf04018032 100644 (file)
@@ -282,6 +282,13 @@ class Mapper(object):
                     elif (isinstance(column, list) and sql.is_column(column[0])):
                         props[key] = [self.select_table.corresponding_column(c) for c in prop]
             self.__surrogate_mapper = Mapper(self.class_, self.select_table, non_primary=True, properties=props, polymorphic_map=self.polymorphic_map, polymorphic_on=self.polymorphic_on)
+    
+    def base_mapper(self):
+        """returns the ultimate base mapper in an inheritance chain"""
+        if self.inherits is not None:
+            return self.inherits.base_mapper()
+        else:
+            return self
             
     def add_polymorphic_mapping(self, key, class_or_mapper, entity_name=None):
         if isinstance(class_or_mapper, type):
@@ -640,7 +647,6 @@ class Mapper(object):
                     if primary_key is not None:
                         i = 0
                         for col in self.pks_by_table[table]:
-                            #print "col: " + table.name + "." + col.key + " val: " + repr(self._getattrbycolumn(obj, col))
                             if self._getattrbycolumn(obj, col) is None:
                                 self._setattrbycolumn(obj, col, primary_key[i])
                             i+=1
@@ -722,8 +728,6 @@ class Mapper(object):
         objects which will process lists of objects in between saves and deletes."""
         for prop in self.props.values():
             prop.register_dependencies(uowcommit, *args, **kwargs)
-        if self.inherits is not None:
-            uowcommit.register_dependency(self.inherits, self)
     
     def cascade_iterator(self, type, object, recursive=None):
         if recursive is None:
index 3a2750edb6a0bf3d4ab93a872fccae08d4e066f5..7d05678dd72c1ccc6bcd59ebb4639d20074bc4d9 100644 (file)
@@ -333,7 +333,10 @@ class UOWTransaction(object):
         """called by mapper.PropertyLoader to register the objects handled by
         one mapper being dependent on the objects handled by another."""
         # correct for primary mapper (the mapper offcially associated with the class)
-        self.dependencies[(mapper._primary_mapper(), dependency._primary_mapper())] = True
+        mapper = mapper._primary_mapper().base_mapper()
+        dependency = dependency._primary_mapper().base_mapper()
+        
+        self.dependencies[(mapper, dependency)] = True
         self._mark_modified()
 
     def register_processor(self, mapper, processor, mapperfrom):
@@ -349,6 +352,7 @@ class UOWTransaction(object):
         # correct for primary mapper (the mapper offcially associated with the class)
         mapper = mapper._primary_mapper()
         mapperfrom = mapperfrom._primary_mapper()
+        
         task = self.get_task_by_mapper(mapper)
         targettask = self.get_task_by_mapper(mapperfrom)
         up = UOWDependencyProcessor(processor, targettask)
@@ -422,7 +426,21 @@ class UOWTransaction(object):
         mappers = util.HashSet()
         for task in self.tasks.values():
             mappers.append(task.mapper)
-    
+
+        def inheriting_tasks(task):
+            if task.mapper not in mappers:
+                return
+            for mapper in task.mapper._inheriting_mappers:
+                inherit_task = self.tasks.get(mapper, None)
+                if inherit_task is None:
+                    continue
+                inheriting_tasks(inherit_task)
+                task.inheriting_tasks.append(inherit_task)
+                del mappers[mapper]
+                
+        for task in self.tasks.values():
+            inheriting_tasks(task)
+                
         head = DependencySorter(self.dependencies, mappers).sort(allow_all_cycles=True)
         #print str(head)
         task = sort_hier(head)
@@ -525,6 +543,7 @@ class UOWTask(object):
         self.cyclical_dependencies = []
         self.circular = None
         self.childtasks = []
+        self.inheriting_tasks = []
         
     def is_empty(self):
         return len(self.objects) == 0 and len(self.dependencies) == 0 and len(self.childtasks) == 0
@@ -563,7 +582,28 @@ class UOWTask(object):
             del self.objects[obj]
         except KeyError:
             pass
-        
+
+    def _save_objects(self, trans):
+        self.mapper.save_obj(self.tosave_objects, trans)
+        for task in self.inheriting_tasks:
+            task._save_objects(trans)
+    def _delete_objects(self, trans):
+        self.mapper.delete_obj(self.todelete_objects, trans)
+        for task in self.inheriting_tasks:
+            task._delete_objects(trans)
+    def _execute_dependencies(self, trans):
+        for dep in self.dependencies:
+            dep.execute(trans, False)
+        for task in self.inheriting_tasks:
+            task._execute_dependencies(trans)
+        for dep in self.dependencies:
+            dep.execute(trans, True)
+    def _execute_childtasks(self, trans):
+        for child in self.childtasks:
+            child.execute(trans)
+        for task in self.inheriting_tasks:
+            task._execute_childtasks(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. """
@@ -571,24 +611,20 @@ class UOWTask(object):
             self.circular.execute(trans)
             return
 
-        self.mapper.save_obj(self.tosave_objects, trans)
+        self._save_objects(trans)
         for dep in self.cyclical_dependencies:
             dep.execute(trans, False)
         for element in self.tosave_elements:
             for task in element.childtasks:
                 task.execute(trans)
-        for dep in self.dependencies:
-            dep.execute(trans, False)
-        for dep in self.dependencies:
-            dep.execute(trans, True)
+        self._execute_dependencies(trans)
         for dep in self.cyclical_dependencies:
             dep.execute(trans, True)
-        for child in self.childtasks:
-            child.execute(trans)
+        self._execute_childtasks(trans)
         for element in self.todelete_elements:
             for task in element.childtasks:
                 task.execute(trans)
-        self.mapper.delete_obj(self.todelete_objects, trans)
+        self._delete_objects(trans)
 
     tosave_elements = property(lambda self: [rec for rec in self.objects.values() if not rec.isdelete])
     todelete_elements = property(lambda self:[rec for rec in self.objects.values() if rec.isdelete])
@@ -808,6 +844,47 @@ class UOWTask(object):
         def _repr(obj):
             return "%s(%d)" % (obj.__class__.__name__, id(obj))
 
+        def _inheritance_tag(task):
+            if task is not self:
+                return (" (inheriting task %s)" % _repr_task(task))
+            else:
+                return ""
+
+        def _dump_saveelements(task):
+            for rec in task.tosave_elements:
+                if rec.listonly:
+                    continue
+                header(buf, _indent() + "  |- Save elements"+ _inheritance_tag(task) + "\n")
+                buf.write(_indent() + "  |- " + _repr_task_element(rec)  + "\n")
+            for t in task.inheriting_tasks:
+                _dump_saveelements(t)
+
+        def _dump_deleteelements(task):
+            for rec in task.todelete_elements:
+                if rec.listonly:
+                    continue
+                header(buf, _indent() + "  |- Delete elements"+ _inheritance_tag(task) + "\n")
+                buf.write(_indent() + "  |- " + _repr_task_element(rec) + "\n")
+            for t in task.inheriting_tasks:
+                _dump_deleteelements(t)
+
+        def _dump_dependencies(task):
+            for dep in task.dependencies:
+                header(buf, _indent() + "  |- Save dependencies" + _inheritance_tag(task) + "\n")
+                _dump_processor(dep, False)
+            for t in task.inheriting_tasks:
+                _dump_dependencies(t)
+            for dep in task.dependencies:
+                header(buf, _indent() + "  |- Delete dependencies" + _inheritance_tag(task) + "\n")
+                _dump_processor(dep, True)
+        
+        def _dump_childtasks(task):
+            for child in task.childtasks:
+                header(buf, _indent() + "  |- Child tasks" + _inheritance_tag(task) + "\n")
+                child._dump(buf, indent + 1)
+            for t in task.inheriting_tasks:
+                _dump_childtasks(t)
+            
         if self.circular is not None:
             self.circular._dump(buf, indent, self)
             return
@@ -822,11 +899,7 @@ class UOWTask(object):
             buf.write(i + " " + _repr_task(self))
             
         buf.write("\n")
-        for rec in self.tosave_elements:
-            if rec.listonly:
-                continue
-            header(buf, _indent() + "  |- Save elements\n")
-            buf.write(_indent() + "  |- " + _repr_task_element(rec) + "\n")
+        _dump_saveelements(self)
         for dep in self.cyclical_dependencies:
             header(buf, _indent() + "  |- Cyclical Save dependencies\n")
             _dump_processor(dep, False)
@@ -834,31 +907,16 @@ class UOWTask(object):
             for task in element.childtasks:
                 header(buf, _indent() + "  |- Save subelements of UOWTaskElement(%s)\n" % id(element))
                 task._dump(buf, indent + 1)
-        for dep in self.dependencies:
-            header(buf, _indent() + "  |- Save dependencies\n")
-            _dump_processor(dep, False)
-        for dep in self.dependencies:
-            header(buf, _indent() + "  |- Delete dependencies\n")
-            _dump_processor(dep, True)
+        _dump_dependencies(self)
         for dep in self.cyclical_dependencies:
             header(buf, _indent() + "  |- Cyclical Delete dependencies\n")
             _dump_processor(dep, True)
-        for child in self.childtasks:
-            header(buf, _indent() + "  |- Child tasks\n")
-            child._dump(buf, indent + 1)
-#        for obj in self.postupdate:
-#            header(buf, _indent() + "  |- Post Update objects\n")
-#            buf.write(_repr(obj) + "\n")
+        _dump_childtasks(self)
         for element in self.todelete_elements:
             for task in element.childtasks:
                 header(buf, _indent() + "  |- Delete subelements of UOWTaskElement(%s)\n" % id(element))
                 task._dump(buf, indent + 1)
-
-        for rec in self.todelete_elements:
-            if rec.listonly:
-                continue
-            header(buf, _indent() + "  |- Delete elements\n")
-            buf.write(_indent() + "  |- " + _repr_task_element(rec) + "\n")
+        _dump_deleteelements(self)
 
         if self.is_empty():   
             buf.write(_indent() + "  |- (empty task)\n")