Code

- Fixed retirement of items in rdbms imports (sf bug 841355)
[roundup.git] / roundup / backends / back_metakit.py
index 8eae6946c454d0ad967735273f7a349ef859a049..53035262a8680d71847f6d43090373e667b30d6e 100755 (executable)
@@ -1,4 +1,4 @@
-# $Id: back_metakit.py,v 1.42 2003-03-16 22:24:54 kedder Exp $
+# $Id: back_metakit.py,v 1.53 2003-11-14 00:11:18 richard Exp $
 '''
    Metakit backend for Roundup, originally by Gordon McMillan.
 
@@ -17,7 +17,7 @@
       Interval  ''    convert to None
       Number    0     ambiguious :( - do nothing
       Boolean   0     ambiguious :( - do nothing
-      Link      ''    convert to None
+      Link          convert to None
       Multilink []    actually, mk can handle this one ;)
       Passowrd  ''    convert to None
       ========= ===== ====================================================
@@ -48,10 +48,6 @@ def Database(config, journaltag=None):
         _dbs[config.DATABASE] = db
     else:
         db.journaltag = journaltag
-        try:
-            delattr(db, 'curuserid')
-        except AttributeError:
-            pass
     return db
 
 class _Database(hyperdb.Database, roundupdb.Database):
@@ -73,6 +69,10 @@ class _Database(hyperdb.Database, roundupdb.Database):
         if self.indexer.should_reindex():
             self.reindex()
 
+    def refresh_database(self):
+        # XXX handle refresh
+        self.reindex()
+
     def reindex(self):
         for klass in self.classes.values():
             for nodeid in klass.list():
@@ -81,21 +81,7 @@ class _Database(hyperdb.Database, roundupdb.Database):
 
     # --- defined in ping's spec
     def __getattr__(self, classname):
-        if classname == 'curuserid':
-            if self.journaltag is None:
-                return None
-
-            # try to set the curuserid from the journaltag
-            try:
-                x = int(self.classes['user'].lookup(self.journaltag))
-                self.curuserid = x
-            except KeyError:
-                if self.journaltag == 'admin':
-                    self.curuserid = x = 1
-                else:
-                    x = 0
-            return x
-        elif classname == 'transactions':
+        if classname == 'transactions':
             return self.dirty
         # fall back on the classes
         return self.getclass(classname)
@@ -154,7 +140,7 @@ class _Database(hyperdb.Database, roundupdb.Database):
         if tblid == -1:
             tblid = self.tables.append(name=tablenm)
         if creator is None:
-            creator = self.curuserid
+            creator = int(self.getuid())
         else:
             try:
                 creator = int(creator)
@@ -373,8 +359,9 @@ class Class:
         return str(newid)
     
     def get(self, nodeid, propname, default=_marker, cache=1):
-        # default and cache aren't in the spec
-        # cache=0 means "original value"
+        '''
+            'cache' exists for backwards compatibility, and is not used.
+        '''
 
         view = self.getview()        
         id = int(nodeid)
@@ -603,10 +590,11 @@ class Class:
                 if value is None:
                     setattr(row, key, '')
                 else:
-                    setattr(row, key, str(value))
+                    # kedder: we should store interval values serialized
+                    setattr(row, key, value.serialise())
                 changes[key] = str(oldvalue)
                 propvalues[key] = str(value)
-                
             elif isinstance(prop, hyperdb.Number):
                 if value is None:
                     value = 0
@@ -640,7 +628,7 @@ class Class:
             if not row.creation:
                 row.creation = int(time.time())
             if not row.creator:
-                row.creator = self.db.curuserid
+                row.creator = int(self.db.getuid())
 
         self.db.dirty = 1
         if self.do_journal:
@@ -684,6 +672,18 @@ class Class:
         '''
         if self.db.journaltag is None:
             raise hyperdb.DatabaseError, 'Database open read-only'
+
+        # check if key property was overrided
+        key = self.getkey()
+        keyvalue = self.get(nodeid, key)
+        try:
+            id = self.lookup(keyvalue)
+        except KeyError:
+            pass
+        else:
+            raise KeyError, "Key property (%s) of retired node clashes with \
+                existing one (%s)" % (key, keyvalue)
+        # Now we can safely restore node
         self.fireAuditors('restore', nodeid, None)
         view = self.getview(1)
         ndx = view.find(id=int(nodeid))
@@ -734,6 +734,11 @@ class Class:
         if not isinstance(prop, hyperdb.String):
             raise TypeError, "%s is not a String" % propname
 
+        # TODO: metakit needs to be able to cope with the key property
+        # *changing*, which it can't do at present. At the moment, it
+        # creates the key prop index once, with no record of the name of
+        # the property for the index.
+
         # first setkey for this run
         self.keyname = propname
         iv = self.db._db.view('_%s' % self.classname)
@@ -809,10 +814,15 @@ class Class:
         for propname, ids in propspec:
             if type(ids) is _STRINGTYPE:
                 ids = {int(ids):1}
+            elif ids is None:
+                ids = {0:1}
             else:
                 d = {}
                 for id in ids.keys():
-                    d[int(id)] = 1
+                    if id is None:
+                        d[0] = 1
+                    else:
+                        d[int(id)] = 1
                 ids = d
             prop = self.ruprops[propname]
             view = self.getview()
@@ -896,7 +906,9 @@ class Class:
             if prop is None:
                 prop = self.privateprops[propname]
             if isinstance(prop, hyperdb.Multilink):
-                if type(value) is not _LISTTYPE:
+                if value in ('-1', ['-1']):
+                    value = []
+                elif type(value) is not _LISTTYPE:
                     value = [value]
                 # transform keys to ids
                 u = []
@@ -927,11 +939,16 @@ class Class:
                 else:
                     orcriteria[propname] = u
             elif isinstance(prop, hyperdb.String):
-                # simple glob searching
-                v = re.sub(r'([\|\{\}\\\.\+\[\]\(\)])', r'\\\1', value)
-                v = v.replace('?', '.')
-                v = v.replace('*', '.*?')
-                regexes[propname] = re.compile(v, re.I)
+                if type(value) is not type([]):
+                    value = [value]
+                m = []
+                for v in value:
+                    # simple glob searching
+                    v = re.sub(r'([\|\{\}\\\.\+\[\]\(\)])', r'\\\1', v)
+                    v = v.replace('?', '.')
+                    v = v.replace('*', '.*?')
+                    m.append(v)
+                regexes[propname] = re.compile('(%s)'%('|'.join(m)), re.I)
             elif propname == 'id':
                 where[propname] = int(value)
             elif isinstance(prop, hyperdb.Boolean):
@@ -947,6 +964,10 @@ class Class:
                     if date_rng.from_value:
                         t = date_rng.from_value.get_tuple()
                         where[propname] = int(calendar.timegm(t))
+                    else:
+                        # use minimum possible value to exclude items without
+                        # 'prop' property
+                        where[propname] = 0
                     if date_rng.to_value:
                         t = date_rng.to_value.get_tuple()
                         wherehigh[propname] = int(calendar.timegm(t))
@@ -956,7 +977,24 @@ class Class:
                     # If range creation fails - ignore that search parameter
                     pass                        
             elif isinstance(prop, hyperdb.Interval):
-                where[propname] = str(date.Interval(value))
+                try:
+                    # Try to filter on range of intervals
+                    date_rng = Range(value, date.Interval)
+                    if date_rng.from_value:
+                        #t = date_rng.from_value.get_tuple()
+                        where[propname] = date_rng.from_value.serialise()
+                    else:
+                        # use minimum possible value to exclude items without
+                        # 'prop' property
+                        where[propname] = '-99999999999999'
+                    if date_rng.to_value:
+                        #t = date_rng.to_value.get_tuple()
+                        wherehigh[propname] = date_rng.to_value.serialise()
+                    else:
+                        wherehigh[propname] = None
+                except ValueError:
+                    # If range creation fails - ignore that search parameter
+                    pass                        
             elif isinstance(prop, hyperdb.Number):
                 where[propname] = int(value)
             else:
@@ -975,6 +1013,8 @@ class Class:
             def ff(row, ml=mlcriteria):
                 for propname, values in ml.items():
                     sv = getattr(row, propname)
+                    if not values and sv:
+                        return 0
                     for id in values:
                         if sv.find(fid=id) == -1:
                             return 0
@@ -1133,7 +1173,7 @@ class Class:
             l.append(repr(value))
 
         # append retired flag
-        l.append(self.is_retired(nodeid))
+        l.append(repr(self.is_retired(nodeid)))
 
         return l
         
@@ -1164,12 +1204,15 @@ class Class:
                 if int(value):
                     d['_isdel'] = 1
                 continue
+            elif value is None:
+                d[propname] = None
+                continue
 
             prop = properties[propname]
             if isinstance(prop, hyperdb.Date):
                 value = int(calendar.timegm(value))
             elif isinstance(prop, hyperdb.Interval):
-                value = str(date.Interval(value))
+                value = date.Interval(value).serialise()
             elif isinstance(prop, hyperdb.Number):
                 value = int(value)
             elif isinstance(prop, hyperdb.Boolean):
@@ -1359,7 +1402,7 @@ class FileClass(Class, hyperdb.FileClass):
         Class.__init__(self, db, classname, **properties)
 
     def get(self, nodeid, propname, default=_marker, cache=1):
-        x = Class.get(self, nodeid, propname, default, cache)
+        x = Class.get(self, nodeid, propname, default)
         poss_msg = 'Possibly an access right configuration problem.'
         if propname == 'content':
             if x.startswith('file:'):