Commits

Mike Bayer  committed 3619188

working on postupdate idea, refactoring to dependency processing

  • Participants
  • Parent commits 477511e

Comments (0)

Files changed (5)

File lib/sqlalchemy/mapping/__init__.py

     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):

File lib/sqlalchemy/mapping/mapper.py

         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__)
     
 
 

File lib/sqlalchemy/mapping/objectstore.py

         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).
         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)
         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]
         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))

File lib/sqlalchemy/mapping/properties.py

             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:
                 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
                 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:
                         #print "DELETE ASSOC OBJ", repr(child)
                         uowcommit.register_object(child, isdelete=True)
         else:
-            for obj in deplist:            
+            for obj in deplist:
+                childlist = getlist(obj, passive=True)
+                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)
-                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:
+                    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)

File test/cycles.py

 
         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),
          )
         )
 
         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__":