Code

implemented multilink changes (and a unit test)
[roundup.git] / roundup / backends / back_metakit.py
index 7d173c1856b134de95d2ea647e688bdf5d3ad5f1..d78b27f9f8034f176cf7c29718d4c42938faad02 100755 (executable)
@@ -12,6 +12,12 @@ def Database(config, journaltag=None):
     if db is None or db._db is None:
         db = _Database(config, journaltag)
         _dbs[config.DATABASE] = db
+    else:
+        db.journaltag = journaltag
+        try:
+            delattr(db, 'curuserid')
+        except AttributeError:
+            pass
     return db
 
 class _Database(hyperdb.Database):
@@ -46,6 +52,8 @@ class _Database(hyperdb.Database):
             except KeyError:
                 x = 0
             return x
+        elif classname == 'transactions':
+            return self.dirty
         return self.getclass(classname)
     def getclass(self, classname):
         return self.classes[classname]
@@ -271,7 +279,7 @@ class Class:
         if not isnew:
             self.fireAuditors('set', nodeid, propvalues)
         if not propvalues:
-            return
+            return propvalues
         if propvalues.has_key('id'):
             raise KeyError, '"id" is reserved'
         if self.db.journaltag is None:
@@ -322,9 +330,14 @@ class Class:
             # do stuff based on the prop type
             if isinstance(prop, hyperdb.Link):
                 link_class = prop.classname
+                # must be a string or None
+                if value is not None and not isinstance(value, type('')):
+                    raise ValueError, 'property "%s" link value be a string'%(
+                        propname)
+                # Roundup sets to "unselected" by passing None
+                if value is None:
+                    value = 0   
                 # if it isn't a number, it's a key
-                if type(value) != _STRINGTYPE:
-                    raise ValueError, 'link value must be String'
                 try:
                     int(value)
                 except ValueError:
@@ -334,7 +347,8 @@ class Class:
                         raise IndexError, 'new property "%s": %s not a %s'%(
                             key, value, prop.classname)
 
-                if not self.db.getclass(link_class).hasnode(value):
+                if (value is not None and
+                        not self.db.getclass(link_class).hasnode(value)):
                     raise IndexError, '%s has no node %s'%(link_class, value)
 
                 setattr(row, key, int(value))
@@ -343,11 +357,13 @@ class Class:
                 if self.do_journal and prop.do_journal:
                     # register the unlink with the old linked node
                     if oldvalue:
-                        self.db.addjournal(link_class, value, _UNLINK, (self.classname, str(row.id), key))
+                        self.db.addjournal(link_class, value, _UNLINK,
+                            (self.classname, str(row.id), key))
 
                     # register the link with the newly linked node
                     if value:
-                        self.db.addjournal(link_class, value, _LINK, (self.classname, str(row.id), key))
+                        self.db.addjournal(link_class, value, _LINK,
+                            (self.classname, str(row.id), key))
 
             elif isinstance(prop, hyperdb.Multilink):
                 if type(value) != _LISTTYPE:
@@ -401,6 +417,8 @@ class Class:
                 for id in adds:
                     sv.append(fid=int(id))
                 changes[key] = oldvalue
+                if not rmvd and not adds:
+                    del propvalues[key]
                     
 
             elif isinstance(prop, hyperdb.String):
@@ -449,7 +467,7 @@ class Class:
 
         # nothing to do?
         if not propvalues:
-            return
+            return propvalues
         if not propvalues.has_key('activity'):
             row.activity = int(time.time())
         if isnew:
@@ -467,6 +485,8 @@ class Class:
                 self.db.addjournal(self.classname, nodeid, _SET, changes)
                 self.fireReactors('set', nodeid, oldnode)
 
+        return propvalues
+    
     def retire(self, nodeid):
         self.fireAuditors('retire', nodeid, None)
         view = self.getview(1)
@@ -479,10 +499,11 @@ class Class:
         row._isdel = 1
         if self.do_journal:
             self.db.addjournal(self.classname, nodeid, _RETIRE, {})
-        iv = self.getindexview(1)
-        ndx = iv.find(k=getattr(row, self.keyname),i=row.id)
-        if ndx > -1:
-            iv.delete(ndx)
+        if self.keyname:
+            iv = self.getindexview(1)
+            ndx = iv.find(k=getattr(row, self.keyname),i=row.id)
+            if ndx > -1:
+                iv.delete(ndx)
         self.db.dirty = 1
         self.fireReactors('retire', nodeid, None)
     def history(self, nodeid):
@@ -732,7 +753,24 @@ class Class:
                 try:
                     prop = getattr(v, propname)
                 except AttributeError:
+                    print "MK has no property %s" % propname
                     continue
+                propclass = self.ruprops.get(propname, None)
+                if propclass is None:
+                    propclass = self.privateprops.get(propname, None)
+                    if propclass is None:
+                        print "Schema has no property %s" % propname
+                        continue
+                if isinstance(propclass, hyperdb.Link):
+                    linkclass = self.db.getclass(propclass.classname)
+                    lv = linkclass.getview()
+                    lv = lv.rename('id', propname)
+                    v = v.join(lv, prop, 1)
+                    if linkclass.getprops().has_key('order'):
+                        propname = 'order'
+                    else:
+                        propname = linkclass.labelprop()
+                    prop = getattr(v, propname)
                 if isreversed:
                     rev.append(prop)
                 sortspec.append(prop)