]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
working on postupdate idea, refactoring to dependency processing
authorMike Bayer <mike_mp@zzzcomputing.com>
Tue, 21 Feb 2006 02:57:38 +0000 (02:57 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Tue, 21 Feb 2006 02:57:38 +0000 (02:57 +0000)
lib/sqlalchemy/mapping/__init__.py
lib/sqlalchemy/mapping/mapper.py
lib/sqlalchemy/mapping/objectstore.py
lib/sqlalchemy/mapping/properties.py
test/cycles.py

index 64258fa6546a758400ea1569160260e830ca2c30..2de644f43bc63d624fdfc5f15a9449b5443c6e95 100644 (file)
@@ -88,21 +88,6 @@ def undefer(name, **kwargs):
     name into a non-deferred (regular column) load.  Used with mapper.options."""
     return DeferredOption(name, defer=False)
     
-def object_mapper(object):
-    """given an object, returns the primary Mapper associated with the object
-    or the object's class."""
-    return class_mapper(object.__class__)
-
-def class_mapper(class_):
-    """given a class, returns the primary Mapper associated with the class."""
-    return mapper_registry[class_]
-    try:
-        return mapper_registry[class_]
-    except KeyError:
-        pass
-    except AttributeError:
-        pass
-    raise InvalidRequestError("Class '%s' has no mapper associated with it" % class_.__name__)
 
 
 def assign_mapper(class_, *args, **params):
index 88b803b37e530c9b143e1416cf89e58e7a9ce68a..2e69a1e66188f3d6b4c7f36f0c49ab3975453d4c 100644 (file)
@@ -893,6 +893,22 @@ def hash_key(obj):
         return obj.hash_key()
     else:
         return repr(obj)
+        
+def object_mapper(object):
+    """given an object, returns the primary Mapper associated with the object
+    or the object's class."""
+    return class_mapper(object.__class__)
+
+def class_mapper(class_):
+    """given a class, returns the primary Mapper associated with the class."""
+    return mapper_registry[class_]
+    try:
+        return mapper_registry[class_]
+    except KeyError:
+        pass
+    except AttributeError:
+        pass
+    raise InvalidRequestError("Class '%s' has no mapper associated with it" % class_.__name__)
     
 
 
index 94e2f966b09856ddc9c37c22a648b7c4751008ba..e68c59e30d629a427f95b2ae440d2d2046579292 100644 (file)
@@ -454,8 +454,9 @@ class UOWTransaction(object):
         self.dependencies = {}
         self.tasks = {}
         self.saved_histories = util.HashSet()
-
-    def register_object(self, obj, isdelete = False, listonly = False, **kwargs):
+        self.__modified = False
+        
+    def register_object(self, obj, isdelete = False, listonly = False, postupdate=False, **kwargs):
         """adds an object to this UOWTransaction to be updated in the database.
 
         'isdelete' indicates whether the object is to be deleted or saved (update/inserted).
@@ -474,15 +475,19 @@ class UOWTransaction(object):
         self.mappers.append(mapper)
         task = self.get_task_by_mapper(mapper)
         
+        if postupdate:
+            mod = task.append_postupdate(obj)
+            self.__modified = self.__modified or mod
+            return
+            
         # for a cyclical task, things need to be sorted out already,
         # so this object should have already been added to the appropriate sub-task
         # can put an assertion here to make sure....
         if task.circular:
             return
             
-        if obj not in task.objects:
-            self.__modified = True
-        task.append(obj, listonly, isdelete=isdelete, **kwargs)
+        mod = task.append(obj, listonly, isdelete=isdelete, **kwargs)
+        self.__modified = self.__modified or mod
 
     def unregister_object(self, obj):
         mapper = object_mapper(obj)
@@ -665,16 +670,24 @@ class UOWTask(object):
         dependent operations at the per-object instead of per-task level. """
         try:
             rec = self.objects[obj]
+            retval = False
         except KeyError:
             rec = UOWTaskElement(obj)
             self.objects[obj] = rec
+            retval = True
         if not listonly:
             rec.listonly = False
         if childtask:
             rec.childtasks.append(childtask)
         if isdelete:
             rec.isdelete = True
-
+        return retval
+    
+    def append_postupdate(self, obj):
+        # postupdates are UPDATED immeditely (for now)
+        self.mapper.save_obj([obj], self.uowtransaction, postupdate=True)
+        return True
+            
     def delete(self, obj):
         try:
             del self.objects[obj]
@@ -974,6 +987,9 @@ class UOWTask(object):
         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")
         for element in self.todelete_elements():
             for task in element.childtasks:
                 header(buf, _indent() + "  |- Delete subelements of UOWTaskElement(%s)\n" % id(element))
index 571bfc0b577f21f2c04ef0bfc3b4493250379a1a..036dfe4400a173c4b2bbd5eb4d94780fe6f40ae3 100644 (file)
@@ -358,14 +358,20 @@ class PropertyLoader(MapperProperty):
             uowcommit.register_processor(stub, self, self.parent, True)
         elif self.direction == PropertyLoader.ONETOMANY:
             if self.post_update:
-                raise InvalidRequestError("post_update not yet supported with one-to-many relation")
-            uowcommit.register_dependency(self.parent, self.mapper)
-            uowcommit.register_processor(self.parent, self, self.parent, False)
-            uowcommit.register_processor(self.parent, self, self.parent, True)
+                stub = PropertyLoader.MapperStub(self.mapper)
+                uowcommit.register_dependency(self.mapper, stub)
+                uowcommit.register_dependency(self.parent, stub)
+                uowcommit.register_processor(stub, self, self.parent, False)
+                uowcommit.register_processor(stub, self, self.parent, True)
+            else:
+                uowcommit.register_dependency(self.parent, self.mapper)
+                uowcommit.register_processor(self.parent, self, self.parent, False)
+                uowcommit.register_processor(self.parent, self, self.parent, True)
         elif self.direction == PropertyLoader.MANYTOONE:
             if self.post_update:
                 stub = PropertyLoader.MapperStub(self.mapper)
                 uowcommit.register_dependency(self.mapper, stub)
+                uowcommit.register_dependency(self.parent, stub)
                 uowcommit.register_processor(stub, self, self.parent, False)
                 uowcommit.register_processor(stub, self, self.parent, True)
             else:
@@ -433,12 +439,12 @@ class PropertyLoader(MapperProperty):
                 statement = self.secondary.insert()
                 statement.execute(*secondary_insert)
         elif self.direction == PropertyLoader.MANYTOONE and delete:
-            # head object is being deleted, and we manage a foreign key object.
-            # dont have to do anything to it.
             if self.post_update:
+                # post_update means we have to update our row to not reference the child object
+                # before we can DELETE the row
                 for obj in deplist:
                     self._synchronize(obj, None, None, True)
-                    task.mapper.save_obj([obj], uowcommit, postupdate=True)
+                    uowcommit.register_object(obj, postupdate=True)
         elif self.direction == PropertyLoader.ONETOMANY and delete:
             # head object is being deleted, and we manage its list of child objects
             # the child objects have to have their foreign key to the parent set to NULL
@@ -450,7 +456,7 @@ class PropertyLoader(MapperProperty):
                 childlist = getlist(obj, False)
                 for child in childlist.deleted_items() + childlist.unchanged_items():
                     self._synchronize(obj, child, None, True)
-                    uowcommit.register_object(child)
+                    uowcommit.register_object(child, postupdate=self.post_update)
         elif self.association is not None:
             # manage association objects.
             for obj in deplist:
@@ -488,21 +494,16 @@ class PropertyLoader(MapperProperty):
                         #print "DELETE ASSOC OBJ", repr(child)
                         uowcommit.register_object(child, isdelete=True)
         else:
-            for obj in deplist:            
-                if self.direction == PropertyLoader.MANYTOONE:
-                    uowcommit.register_object(obj)
+            for obj in deplist:
                 childlist = getlist(obj, passive=True)
-                if childlist is None: continue
-                for child in childlist.added_items():
-                    self._synchronize(obj, child, None, False)
-                    if self.direction == PropertyLoader.ONETOMANY and child is not None:
-                        if self.post_update:
-                            task.mapper.save_obj([child],uowcommit, postupdate=True)
-                        else:
-                            uowcommit.register_object(child)
-                if self.post_update:
-                    task.mapper.save_obj([obj], uowcommit, postupdate=True)
-                if self.direction != PropertyLoader.MANYTOONE or len(childlist.added_items()) == 0:
+                if childlist is not None:
+                    for child in childlist.added_items():
+                        self._synchronize(obj, child, None, False)
+                        if self.direction == PropertyLoader.ONETOMANY and child is not None:
+                            uowcommit.register_object(child, postupdate=self.post_update)
+                if self.direction == PropertyLoader.MANYTOONE:
+                    uowcommit.register_object(obj, postupdate=self.post_update)
+                if self.direction != PropertyLoader.MANYTOONE:
                     for child in childlist.deleted_items():
                         if not self.private:
                             self._synchronize(obj, child, None, True)
index 863d30fd9505bd8986b2b75f01e8b3c25385a675..f30ac0297bfd53e4ec5d132c0e6f1f491963762f 100644 (file)
@@ -238,8 +238,8 @@ class CycleTest2(AssertMixin):
 
         Ball.mapper = mapper(Ball, ball)
         Person.mapper = mapper(Person, person, properties= dict(
-         balls = relation(Ball.mapper, primaryjoin=ball.c.person_id==person.c.id, foreignkey=ball.c.person_id),
-         favorateBall = relation(Ball.mapper, primaryjoin=person.c.favoriteBall_id==ball.c.id, foreignkey=person.c.favoriteBall_id),
+         balls = relation(Ball.mapper, primaryjoin=ball.c.person_id==person.c.id, foreignkey=ball.c.person_id, post_update=False, private=True),
+         favorateBall = relation(Ball.mapper, primaryjoin=person.c.favoriteBall_id==ball.c.id, foreignkey=person.c.favoriteBall_id, post_update=True),
          )
         )
 
@@ -248,8 +248,14 @@ class CycleTest2(AssertMixin):
         b = Ball()
         p = Person()
         p.balls.append(b)
+        p.balls.append(Ball())
+        p.balls.append(Ball())
+        p.balls.append(Ball())
         p.favorateBall = b
         objectstore.commit()
+        
+        objectstore.delete(p)
+        objectstore.commit()
 
         
 if __name__ == "__main__":