[Checkins] SVN: z3c.dobbin/trunk/src/z3c/dobbin/ Fixed issue with incorrect insertion order. Thanks to Michael Bayer for the guidance on this bug fix.

Malthe Borch mborch at gmail.com
Thu Jun 12 12:04:46 EDT 2008


Log message for revision 87336:
  Fixed issue with incorrect insertion order. Thanks to Michael Bayer for the guidance on this bug fix.

Changed:
  U   z3c.dobbin/trunk/src/z3c/dobbin/README.txt
  U   z3c.dobbin/trunk/src/z3c/dobbin/mapper.py

-=-
Modified: z3c.dobbin/trunk/src/z3c/dobbin/README.txt
===================================================================
--- z3c.dobbin/trunk/src/z3c/dobbin/README.txt	2008-06-12 16:02:52 UTC (rev 87335)
+++ z3c.dobbin/trunk/src/z3c/dobbin/README.txt	2008-06-12 16:04:46 UTC (rev 87336)
@@ -103,12 +103,12 @@
     [(2, 45)]
 
     >>> session.execute(metadata.tables[encode(IAlbum)].select()).fetchall()
-    [(1, u'The Great American Songbook', u'Diana Ross'),
+    [(1, u'Pet Sounds', u'The Beach Boys'),
      (2, u'Taking Care of Business', u'Diana Ross and The Supremes'),
-     (3, u'Pet Sounds', u'The Beach Boys')]
+     (3, u'The Great American Songbook', u'Diana Ross')]
 
     >>> session.execute(metadata.tables[encode(ICompactDisc)].select()).fetchall()
-    [(1, 2005)]
+    [(3, 2005)]
 
 Now we'll create a mapper based on a concrete class. We'll let the
 class implement the interface that describes the attributes we want to
@@ -225,7 +225,7 @@
 insert it into the database.
 
     >>> cleaner = Accessory()
-    >>> cleaner.name = "Record cleaner"
+    >>> cleaner.name = u"Record cleaner"
 
 Set up relation.
     
@@ -273,7 +273,11 @@
     ...         value_type=schema.Object(schema=IAlbum)
     ...         )
 
+    >>> __builtin__.ICollection = ICollection
+    
     >>> collection = create(ICollection)
+    >>> collection.records
+    []
 
 Add the Diana Ross record, and save the collection to the session.
 
@@ -282,8 +286,8 @@
     
 We can get our collection back.
 
-    >>> collection = session.query(ICollection.__mapper__).select_by(
-    ...     ICollection.__mapper__.c.spec==ICollection.__mapper__.__spec__)[0]
+    >>> from z3c.dobbin.relations import lookup
+    >>> collection = lookup(collection.uuid)
 
 Let's verify that we've stored the Diana Ross record.
     
@@ -292,16 +296,25 @@
     >>> record.artist, record.title
     (u'Diana Ross and The Supremes', u'Taking Care of Business')
 
-Now let's try and add another record.
+    >>> transaction.commit()
     
+When we create a new, transient object and append it to a list, it's
+automatically saved on the session.
+
+    >>> collection = lookup(collection.uuid)
+
+    >>> vinyl = create(IVinyl)
+    >>> vinyl.artist = u"Kool & the Gang"
+    >>> vinyl.album = u"Music Is the Message"
+    >>> vinyl.rpm = 33
+
     >>> collection.records.append(vinyl)
-    >>> another_record = collection.records[1]
+    >>> [record.artist for record in collection.records]
+    [u'Diana Ross and The Supremes', u'Kool & the Gang']
 
-They're different.
+    >>> transaction.commit()
+    >>> session.update(collection)
     
-    >>> record.uuid != another_record.uuid
-    True
-
 We can remove items.
 
     >>> collection.records.remove(vinyl)
@@ -382,5 +395,3 @@
 Commit session.
     
     >>> transaction.commit()
-
-    

Modified: z3c.dobbin/trunk/src/z3c/dobbin/mapper.py
===================================================================
--- z3c.dobbin/trunk/src/z3c/dobbin/mapper.py	2008-06-12 16:02:52 UTC (rev 87335)
+++ z3c.dobbin/trunk/src/z3c/dobbin/mapper.py	2008-06-12 16:04:46 UTC (rev 87336)
@@ -73,8 +73,6 @@
     def adapter(self):
         return self._sa_adapter
 
-    # orm collection support
-    
     @orm.collections.collection.appender
     def _appender(self, item):
         self.data.append(item)
@@ -87,28 +85,21 @@
     def _remover(self, item):
         self.data.remove(item)
         
-    # python list api
-    
     def append(self, item, _sa_initiator=None):
         # make sure item is mapped
         if not IMapped.providedBy(item):
             item = relations.persist(item)
 
-        # fire append event
-        self.adapter.fire_append_event(item, _sa_initiator)
-
         # set up relation
         relation = bootstrap.Relation()
         relation.target = item
         relation.order = len(self.data)
 
-        # save to session
-        session = Session()
-        session.save(relation)
-
+        self.adapter.fire_append_event(relation, _sa_initiator)
+        
         # add relation to internal list
         self.data.append(relation)
-        
+
     def remove(self, item, _sa_initiator=None):
         if IMapped.providedBy(item):
             uuid = item.uuid
@@ -117,20 +108,12 @@
 
         for relation in self.data:
             if relation.right == uuid:
-                # fire remove event on target
-                target = relations.lookup(uuid, ignore_cache=True)
-                self.adapter.fire_remove_event(target, _sa_initiator)
-
-                # remove reference to relation
+                self.adapter.fire_remove_event(relation, _sa_initiator)
                 self.data.remove(relation)
 
-                # delete from database
-                session = Session()
-                session.delete(relation)
-
                 return
-
-        return ValueError("Not in list: %s" % item)
+        else:
+            return ValueError("Not in list: %s" % item)
         
     def extend(self, items):
         map(self.append, items)
@@ -138,6 +121,9 @@
     def __iter__(self):
         return (relation.target for relation in iter(self.data))
 
+    def __repr__(self):
+        return repr(list(self))
+    
     def __len__(self):
         return len(self.data)
     
@@ -293,23 +279,29 @@
     # create joined table
     soup_table = table = metadata.tables['soup']
     properties = {}
+    table = None
     
     for (t, p) in (getTable(iface, metadata, ignore) for iface in ifaces):
-        table = rdb.join(table, t, onclause=(t.c.id==soup_table.c.id))
+        if table is None:
+            first_table = table = t
+        else:
+            table = rdb.join(table, t, onclause=(t.c.id==first_table.c.id))
         properties.update(p)
 
-    class Mapper(kls):
+    specification_path = '%s.%s' % (spec.__module__, spec.__name__)
+        
+    class Mapper(bootstrap.Soup, kls):
         interface.implements(IMapped, *ifaces)
 
-        __spec__ = '%s.%s' % (spec.__module__, spec.__name__)
-
+        __spec__ = specification_path
+        
         def __init__(self, *args, **kwargs):
             super(Mapper, self).__init__(*args, **kwargs)
-            
+
             # set soup metadata
             self.uuid = uuid()
             self.spec = self.__spec__
-            
+
     # if the specification is an interface class, try to look up a
     # security checker and define it on the mapper
     if interface.interfaces.IInterface.providedBy(spec):
@@ -342,7 +334,13 @@
             if isinstance(value, property):
                 exclude += (name,)
 
-    orm.mapper(Mapper, table, properties=properties, exclude_properties=exclude)
+    orm.mapper(
+        Mapper,
+        table,
+        properties=properties,
+        exclude_properties=exclude,
+        inherits=bootstrap.Soup,
+        inherit_condition=(first_table.c.id==soup_table.c.id))
 
     spec.__mapper__ = Mapper
     interface.alsoProvides(spec, IMapped)



More information about the Checkins mailing list