diff roundup/backends/rdbms_common.py @ 1170:af104fa52746

Added some words to the installation doc about choosing backends. Added hyperdb Class.filter unit tests - gadfly currently fails substring searching, but I knew it would :( Lots of fixes to the RDBMS backend - it works a treat now! A couple of other cleanups in CGI land...
author Richard Jones <richard@users.sourceforge.net>
date Thu, 19 Sep 2002 02:37:41 +0000
parents 94620e088e3a
children 8784a11f8c2f
line wrap: on
line diff
--- a/roundup/backends/rdbms_common.py	Wed Sep 18 22:26:07 2002 +0000
+++ b/roundup/backends/rdbms_common.py	Thu Sep 19 02:37:41 2002 +0000
@@ -1,4 +1,4 @@
-# $Id: rdbms_common.py,v 1.2 2002-09-18 07:04:38 richard Exp $
+# $Id: rdbms_common.py,v 1.3 2002-09-19 02:37:41 richard Exp $
 
 # standard python modules
 import sys, os, time, re, errno, weakref, copy
@@ -53,6 +53,11 @@
         '''
         raise NotImplemented
 
+    def sql_stringquote(self, value):
+        ''' Quote the string so it's safe to put in the 'sql quotes'
+        '''
+        return re.sub("'", "''", str(value))
+
     def save_dbschema(self, cursor, schema):
         ''' Save the schema definition that the database currently implements
         '''
@@ -1588,6 +1593,10 @@
             "sort" and "group" are (dir, prop) where dir is '+', '-' or None
                                and prop is a prop name or None
             "search_matches" is {nodeid: marker}
+
+            The filter must match all properties specificed - but if the
+            property value to match is a list, any one of the values in the
+            list may match for that property to match.
         '''
         cn = self.classname
 
@@ -1599,6 +1608,7 @@
         a = self.db.arg
         for k, v in filterspec.items():
             propclass = props[k]
+            # now do other where clause stuff
             if isinstance(propclass, Multilink):
                 tn = '%s_%s'%(cn, k)
                 frum.append(tn)
@@ -1607,9 +1617,35 @@
                     where.append('id=%s.nodeid and %s.linkid in (%s)'%(tn,tn,s))
                     args = args + v
                 else:
-                    where.append('id=%s.nodeid and %s.linkid = %s'%(tn, tn,
-                        self.arg))
+                    where.append('id=%s.nodeid and %s.linkid = %s'%(tn, tn, a))
                     args.append(v)
+            elif isinstance(propclass, String):
+                if not isinstance(v, type([])):
+                    v = [v]
+
+                # Quote the bits in the string that need it and then embed
+                # in a "substring" search. Note - need to quote the '%' so
+                # they make it through the python layer happily
+                v = ['%%'+self.db.sql_stringquote(s)+'%%' for s in v]
+
+                # now add to the where clause
+                where.append(' or '.join(["_%s LIKE '%s'"%(k, s) for s in v]))
+                # note: args are embedded in the query string now
+            elif isinstance(propclass, Link):
+                if isinstance(v, type([])):
+                    if '-1' in v:
+                        v.remove('-1')
+                        xtra = ' or _%s is NULL'%k
+                    s = ','.join([a for x in v])
+                    where.append('(_%s in (%s)%s)'%(k, s, xtra))
+                    args = args + v
+                else:
+                    if v == '-1':
+                        v = None
+                        where.append('_%s is NULL'%k)
+                    else:
+                        where.append('_%s=%s'%(k, a))
+                        args.append(v)
             else:
                 if isinstance(v, type([])):
                     s = ','.join([a for x in v])
@@ -1626,9 +1662,20 @@
             where.append('id in (%s)'%s)
             args = args + v
 
-        # figure the order by clause
+        # "grouping" is just the first-order sorting in the SQL fetch
+        # can modify it...)
         orderby = []
         ordercols = []
+        if group[0] is not None and group[1] is not None:
+            if group[0] != '-':
+                orderby.append('_'+group[1])
+                ordercols.append('_'+group[1])
+            else:
+                orderby.append('_'+group[1]+' desc')
+                ordercols.append('_'+group[1])
+
+        # now add in the sorting
+        group = ''
         if sort[0] is not None and sort[1] is not None:
             direction, colname = sort
             if direction != '-':
@@ -1637,6 +1684,10 @@
                     ordercols.append('max(%s__journal.date) as activity'%cn)
                     frum.append('%s__journal'%cn)
                     where.append('%s__journal.nodeid = _%s.id'%(cn, cn))
+                    # we need to group by id
+                    group = ' group by id'
+                elif colname == 'id':
+                    orderby.append(colname)
                 else:
                     orderby.append('_'+colname)
                     ordercols.append('_'+colname)
@@ -1646,46 +1697,42 @@
                     ordercols.append('max(%s__journal.date) as activity'%cn)
                     frum.append('%s__journal'%cn)
                     where.append('%s__journal.nodeid = _%s.id'%(cn, cn))
+                    # we need to group by id
+                    group = ' group by id'
+                elif colname == 'id':
+                    orderby.append(colname+' desc')
+                    ordercols.append(colname)
                 else:
                     orderby.append('_'+colname+' desc')
                     ordercols.append('_'+colname)
 
-        # figure the group by clause
-        groupby = []
-        groupcols = []
-        if group[0] is not None and group[1] is not None:
-            if group[0] != '-':
-                groupby.append('_'+group[1])
-                groupcols.append('_'+group[1])
-            else:
-                groupby.append('_'+group[1]+' desc')
-                groupcols.append('_'+group[1])
-
         # construct the SQL
         frum = ','.join(frum)
-        where = ' and '.join(where)
+        if where:
+            where = ' where ' + (' and '.join(where))
+        else:
+            where = ''
         cols = ['id']
         if orderby:
             cols = cols + ordercols
             order = ' order by %s'%(','.join(orderby))
         else:
             order = ''
-        if 0: #groupby:
-            cols = cols + groupcols
-            group = ' group by %s'%(','.join(groupby))
-        else:
-            group = ''
         cols = ','.join(cols)
-        sql = 'select %s from %s where %s%s%s'%(cols, frum, where, order,
-            group)
+        sql = 'select %s from %s %s%s%s'%(cols, frum, where, group, order)
         args = tuple(args)
         if __debug__:
             print >>hyperdb.DEBUG, 'filter', (self, sql, args)
         cursor = self.db.conn.cursor()
+        print (sql, args)
         cursor.execute(sql, args)
+        l = cursor.fetchall()
+        print l
 
-        # return the IDs
-        return [row[0] for row in cursor.fetchall()]
+        # return the IDs (the first column)
+        # XXX The filter(None, l) bit is sqlite-specific... if there's _NO_
+        # XXX matches to a fetch, it returns NULL instead of nothing!?!
+        return filter(None, [row[0] for row in l])
 
     def count(self):
         '''Get the number of nodes in this class.

Roundup Issue Tracker: http://roundup-tracker.org/