changeset 2318:fa2f7ba34399

merge from maint-0-7
author Richard Jones <richard@users.sourceforge.net>
date Sun, 16 May 2004 09:35:50 +0000
parents f8a4c51e5847
children 7cf7e3bd1b31
files CHANGES.txt roundup/backends/back_anydbm.py roundup/backends/back_mysql.py roundup/backends/rdbms_common.py test/db_test_base.py
diffstat 5 files changed, 90 insertions(+), 20 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES.txt	Sun May 16 09:23:18 2004 +0000
+++ b/CHANGES.txt	Sun May 16 09:35:50 2004 +0000
@@ -16,6 +16,8 @@
 - mention DEFAULT_TIMEZONE requirement in upgrading doc (sf bug 952932)
 - fix DateHTMLProperty so local() can override user timezone (sf bug
   953678)
+- fix anydbm sort/group direction handling, and make RDBMS sort/group use
+  Link'ed "order" properties (sf bug 953148)
 
 
 2004-05-10 0.7.1
--- a/roundup/backends/back_anydbm.py	Sun May 16 09:23:18 2004 +0000
+++ b/roundup/backends/back_anydbm.py	Sun May 16 09:35:50 2004 +0000
@@ -15,7 +15,7 @@
 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 # 
-#$Id: back_anydbm.py,v 1.147 2004-05-12 22:27:17 richard Exp $
+#$Id: back_anydbm.py,v 1.148 2004-05-16 09:35:49 richard Exp $
 '''This module defines a backend that saves the hyperdatabase in a
 database chosen by anydbm. It is guaranteed to always be available in python
 versions >2.1.1 (the dumbdbm fallback in 2.1.1 and earlier has several
@@ -1800,21 +1800,27 @@
         finally:
             cldb.close()
 
+        # sort vals are inserted, but directions are appended, so reverse
+        directions.reverse()
+
         if '-' in directions:
             # one or more of the sort specs is in reverse order, so we have
             # to use this icky function to sort
             def sortfun(a, b, directions=directions, n=range(len(directions))):
                 for i in n:
-                    if a[i] == b[i]: continue
+                    if not cmp(a[i], b[i]):
+                        continue
                     if directions[i] == '+':
+                        # compare in the usual, ascending direction
                         return cmp(a[i],b[i])
                     else:
+                        # compare in the reverse, descending direction
                         return cmp(b[i],a[i])
                 # for consistency, sort by the id if the items are equal
                 return cmp(a[-2], b[-2])
             matches.sort(sortfun)
         else:
-            # sorting is in the normal direction
+            # sorting is in the normal, ascending direction
             matches.sort()
 
         # pull the id out of the individual entries
--- a/roundup/backends/back_mysql.py	Sun May 16 09:23:18 2004 +0000
+++ b/roundup/backends/back_mysql.py	Sun May 16 09:35:50 2004 +0000
@@ -638,7 +638,7 @@
                     args.append(v)
 
         # don't match retired nodes
-        where.append('__retired__ <> 1')
+        where.append('_%s.__retired__ <> 1'%cn)
 
         # add results of full text search
         if search_matches is not None:
@@ -661,6 +661,16 @@
                     # use the int column for sorting
                     o = '__'+prop+'_int__'
                     ordercols.append(o)
+                elif isinstance(props[prop], Link):
+                    # determine whether the linked Class has an order property
+                    lcn = props[prop].classname
+                    link = self.db.classes[lcn]
+                    if link.getprops().has_key('order'):
+                        tn = '_' + lcn
+                        frum.append(tn)
+                        where.append('_%s._%s = %s.id'%(cn, prop, tn))
+                        ordercols.append(tn + '._order')
+                        o = tn + '._order'
                 elif prop == 'id':
                     o = 'id'
                 else:
@@ -679,9 +689,9 @@
         if mlfilt:
             # we're joining tables on the id, so we will get dupes if we
             # don't distinct()
-            cols = ['distinct(id)']
+            cols = ['distinct(_%s.id)'%cn]
         else:
-            cols = ['id']
+            cols = ['_%s.id'%cn]
         if orderby:
             cols = cols + ordercols
             order = ' order by %s'%(','.join(orderby))
--- a/roundup/backends/rdbms_common.py	Sun May 16 09:23:18 2004 +0000
+++ b/roundup/backends/rdbms_common.py	Sun May 16 09:35:50 2004 +0000
@@ -1,4 +1,4 @@
-# $Id: rdbms_common.py,v 1.99 2004-05-10 01:30:02 richard Exp $
+# $Id: rdbms_common.py,v 1.100 2004-05-16 09:35:49 richard Exp $
 ''' Relational database (SQL) backend common code.
 
 Basics:
@@ -2123,7 +2123,7 @@
                     args.append(v)
 
         # don't match retired nodes
-        where.append('__retired__ <> 1')
+        where.append('_%s.__retired__ <> 1'%cn)
 
         # add results of full text search
         if search_matches is not None:
@@ -2146,6 +2146,16 @@
                     # use the int column for sorting
                     o = '__'+prop+'_int__'
                     ordercols.append(o)
+                elif isinstance(props[prop], Link):
+                    # determine whether the linked Class has an order property
+                    lcn = props[prop].classname
+                    link = self.db.classes[lcn]
+                    if link.getprops().has_key('order'):
+                        tn = '_' + lcn
+                        frum.append(tn)
+                        where.append('_%s._%s = %s.id'%(cn, prop, tn))
+                        ordercols.append(tn + '._order')
+                        o = tn + '._order'
                 elif prop == 'id':
                     o = 'id'
                 else:
@@ -2164,9 +2174,9 @@
         if mlfilt:
             # we're joining tables on the id, so we will get dupes if we
             # don't distinct()
-            cols = ['distinct(id)']
+            cols = ['distinct(_%s.id)'%cn]
         else:
-            cols = ['id']
+            cols = ['_%s.id'%cn]
         if orderby:
             cols = cols + ordercols
             order = ' order by %s'%(','.join(orderby))
--- a/test/db_test_base.py	Sun May 16 09:23:18 2004 +0000
+++ b/test/db_test_base.py	Sun May 16 09:35:50 2004 +0000
@@ -15,7 +15,7 @@
 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 # 
-# $Id: db_test_base.py,v 1.27 2004-05-06 01:03:01 richard Exp $ 
+# $Id: db_test_base.py,v 1.28 2004-05-16 09:35:50 richard Exp $ 
 
 import unittest, os, shutil, errno, imp, sys, time, pprint
 
@@ -27,6 +27,8 @@
 def setupSchema(db, create, module):
     status = module.Class(db, "status", name=String())
     status.setkey("name")
+    priority = module.Class(db, "priority", name=String(), order=String())
+    priority.setkey("name")
     user = module.Class(db, "user", username=String(), password=Password(),
         assignable=Boolean(), age=Number(), roles=String())
     user.setkey("username")
@@ -34,7 +36,8 @@
         comment=String(indexme="yes"), fooz=Password())
     issue = module.IssueClass(db, "issue", title=String(indexme="yes"),
         status=Link("status"), nosy=Multilink("user"), deadline=Date(),
-        foo=Interval(), files=Multilink("file"), assignedto=Link('user'))
+        foo=Interval(), files=Multilink("file"), assignedto=Link('user'),
+        priority=Link('priority'))
     stuff = module.Class(db, "stuff", stuff=String())
     session = module.Class(db, 'session', title=String())
     session.disableJournalling()
@@ -48,6 +51,9 @@
         status.create(name="in-progress")
         status.create(name="testing")
         status.create(name="resolved")
+        priority.create(name="feature", order="2")
+        priority.create(name="wish", order="3")
+        priority.create(name="bug", order="1")
     db.commit()
 
 class MyTestCase(unittest.TestCase):
@@ -814,15 +820,15 @@
         iss = self.db.issue
         for issue in (
                 {'title': 'issue one', 'status': '2', 'assignedto': '1',
-                    'foo': date.Interval('1:10'),
+                    'foo': date.Interval('1:10'), 'priority': '1',
                     'deadline': date.Date('2003-01-01.00:00')},
-                    {'title': 'issue two', 'status': '1', 'assignedto': '2',
-                    'foo': date.Interval('1d'),
+                {'title': 'issue two', 'status': '1', 'assignedto': '2',
+                    'foo': date.Interval('1d'), 'priority': '3',
                     'deadline': date.Date('2003-02-16.22:50')},
-                {'title': 'issue three', 'status': '1',
+                    {'title': 'issue three', 'status': '1', 'priority': '2',
                     'nosy': ['1','2'], 'deadline': date.Date('2003-02-18')},
                 {'title': 'non four', 'status': '3',
-                    'foo': date.Interval('0:10'),
+                    'foo': date.Interval('0:10'), 'priority': '1',
                     'nosy': ['1'], 'deadline': date.Date('2004-03-08')}):
             self.db.issue.create(**issue)
         self.db.commit()
@@ -887,6 +893,10 @@
         ae(filt(None, {'foo': 'to 0:05'}), [])
 
     def testFilteringIntervalSort(self):
+        # 1: '1:10'
+        # 2: '1d'
+        # 3: None
+        # 4: '0:10'
         ae, filt = self.filteringSetup()
         # ascending should sort None, 1:10, 1d
         ae(filt(None, {}, ('+','foo'), (None,None)), ['3', '4', '1', '2'])
@@ -894,10 +904,42 @@
         ae(filt(None, {}, ('-','foo'), (None,None)), ['2', '1', '4', '3'])
 
     def testFilteringMultilinkSort(self):
+        # 1: []
+        # 2: []
+        # 3: ['1','2']
+        # 4: ['1']
         ae, filt = self.filteringSetup()
         ae(filt(None, {}, ('+','nosy'), (None,None)), ['1', '2', '4', '3'])
         ae(filt(None, {}, ('-','nosy'), (None,None)), ['3', '4', '1', '2'])
 
+    def testFilteringDateSort(self):
+        # '1': '2003-01-01.00:00'
+        # '2': '2003-02-16.22:50'
+        # '3': '2003-02-18'
+        # '4': '2004-03-08'
+        ae, filt = self.filteringSetup()
+        # ascending
+        ae(filt(None, {}, ('+','deadline'), (None,None)), ['1', '2', '3', '4'])
+        # descending
+        ae(filt(None, {}, ('-','deadline'), (None,None)), ['4', '3', '2', '1'])
+
+    def testFilteringDateSortPriorityGroup(self):
+        # '1': '2003-01-01.00:00'  1 => 2
+        # '2': '2003-02-16.22:50'  3 => 1
+        # '3': '2003-02-18'        2 => 3
+        # '4': '2004-03-08'        1 => 2
+        ae, filt = self.filteringSetup()
+        # ascending
+        ae(filt(None, {}, ('+','deadline'), ('+','priority')),
+            ['2', '1', '4', '3'])
+        ae(filt(None, {}, ('-','deadline'), ('+','priority')),
+            ['2', '4', '1', '3'])
+        # descending
+        ae(filt(None, {}, ('+','deadline'), ('-','priority')),
+            ['3', '1', '4', '2'])
+        ae(filt(None, {}, ('-','deadline'), ('-','priority')),
+            ['3', '4', '1', '2'])
+
 # XXX add sorting tests for other types
 # XXX test auditors and reactors
 
@@ -993,7 +1035,7 @@
         keys.sort()
         self.assertEqual(keys, ['activity', 'actor', 'assignedto', 'creation',
             'creator', 'deadline', 'files', 'fixer', 'foo', 'id', 'messages',
-            'nosy', 'status', 'superseder', 'title'])
+            'nosy', 'priority', 'status', 'superseder', 'title'])
         self.assertEqual(self.db.issue.get('1', "fixer"), None)
 
     def testRemoveProperty(self):
@@ -1007,7 +1049,7 @@
         keys.sort()
         self.assertEqual(keys, ['activity', 'actor', 'assignedto', 'creation',
             'creator', 'deadline', 'files', 'foo', 'id', 'messages',
-            'nosy', 'status', 'superseder'])
+            'nosy', 'priority', 'status', 'superseder'])
         self.assertEqual(self.db.issue.list(), ['1'])
 
     def testAddRemoveProperty(self):
@@ -1022,7 +1064,7 @@
         keys.sort()
         self.assertEqual(keys, ['activity', 'actor', 'assignedto', 'creation',
             'creator', 'deadline', 'files', 'fixer', 'foo', 'id', 'messages',
-            'nosy', 'status', 'superseder'])
+            'nosy', 'priority', 'status', 'superseder'])
         self.assertEqual(self.db.issue.list(), ['1'])
 
 class ROTest(MyTestCase):

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