[Checkins] SVN: Products.ZCatalog/trunk/ Finish support for differing sort_order values for searches using two sort indexes

Hano Schlichting cvs-admin at zope.org
Sat Apr 7 15:57:55 UTC 2012


Log message for revision 125082:
  Finish support for differing sort_order values for searches using two sort indexes
  

Changed:
  U   Products.ZCatalog/trunk/CHANGES.txt
  U   Products.ZCatalog/trunk/src/Products/ZCatalog/Catalog.py
  U   Products.ZCatalog/trunk/src/Products/ZCatalog/tests/test_catalog.py

-=-
Modified: Products.ZCatalog/trunk/CHANGES.txt
===================================================================
--- Products.ZCatalog/trunk/CHANGES.txt	2012-04-07 14:42:22 UTC (rev 125081)
+++ Products.ZCatalog/trunk/CHANGES.txt	2012-04-07 15:57:52 UTC (rev 125082)
@@ -11,12 +11,13 @@
   methods and used it for a progress handler. Also optimized some of their
   internals.
 
-- Added support for simple `sort_on` queries with two sort indexes. The
-  `sort_order` is currently single valued and applies to both of them. But a
-  query like: `{'foo': 'a', 'sort_on':['foo', 'bar']}` is supported now.
+- Added support for simple `sort_on` queries with two sort indexes and
+  differing `sort_order` values. For example:
+  `{'foo': 'a', 'sort_on': ('foo', 'bar')}`
+  `{'foo': 'a', 'sort_on': ('foo', 'bar'), 'sort_order': ('', 'reverse')}`
 
 - Change some internal wiring and let multiple sort_on values pass through.
-  `Catalog.sortResults` is now called with a list of search indexes.
+  `Catalog.sortResults` can now be called with a list of search indexes.
 
 - Added support for `not` queries in field and keyword indexes. Both
   restrictions of normal queries and range queries are supported, as well as

Modified: Products.ZCatalog/trunk/src/Products/ZCatalog/Catalog.py
===================================================================
--- Products.ZCatalog/trunk/src/Products/ZCatalog/Catalog.py	2012-04-07 14:42:22 UTC (rev 125081)
+++ Products.ZCatalog/trunk/src/Products/ZCatalog/Catalog.py	2012-04-07 15:57:52 UTC (rev 125082)
@@ -692,7 +692,10 @@
         # order and limit it, then reverse the result set again
         switched_reverse = False
         if b_size and b_start and b_start > rlen / 2:
-            reverse = not reverse
+            if isinstance(reverse, list):
+                reverse = [not r for r in reverse]
+            else:
+                reverse = not reverse
             switched_reverse = True
             b_end = b_start + b_size
             if b_end >= rlen:
@@ -708,7 +711,14 @@
             limit = b_start + b_size
 
         # determine sort_spec
-        sort_spec = [reverse and -1 or 1, reverse and -1 or 1]
+        if isinstance(reverse, list):
+            sort_spec = [r and -1 or 1 for r in reverse]
+            # limit to current maximum of two indexes
+            sort_spec = sort_spec[:2]
+            # use first sort order for choosing the algorithm
+            reverse = reverse[0]
+        else:
+            sort_spec = [reverse and -1 or 1, reverse and -1 or 1]
 
         if merge and limit is None and (
             rlen > (len(sort_index) * (rlen / 100 + 1))):
@@ -921,9 +931,16 @@
         reverse = False
         if sort_indexes is not None:
             order = self._get_sort_attr("order", args)
-            if (isinstance(order, str) and
-                order.lower() in ('reverse', 'descending')):
-                reverse = True
+            reverse = []
+            if order is None:
+                order = ['']
+            elif isinstance(order, str):
+                order = [order]
+            for o in order:
+                reverse.append(o.lower() in ('reverse', 'descending'))
+            if len(reverse) == 1:
+                # be nice and keep the old API intact for single sort_order
+                reverse = reverse[0]
         # Perform searches with indexes and sort_index
         return self.search(args, sort_indexes, reverse, sort_limit, _merge)
 
@@ -1016,12 +1033,12 @@
     list entry given via `items`.
     """
     comparers = []
-    for i in xrange(len(sort_spec)):
-        comparers.append((itemgetter(i), sort_spec[i]))
+    for i, v in enumerate(sort_spec):
+        comparers.append((itemgetter(i), v))
 
     def comparer(left, right):
         for func, order in comparers:
-            result = cmp(func(left), func(right))
+            result = cmp(func(left[0]), func(right[0]))
             if result:
                 return order * result
         return 0

Modified: Products.ZCatalog/trunk/src/Products/ZCatalog/tests/test_catalog.py
===================================================================
--- Products.ZCatalog/trunk/src/Products/ZCatalog/tests/test_catalog.py	2012-04-07 14:42:22 UTC (rev 125081)
+++ Products.ZCatalog/trunk/src/Products/ZCatalog/tests/test_catalog.py	2012-04-07 15:57:52 UTC (rev 125082)
@@ -471,6 +471,14 @@
         self.assertEqual(result.actual_result_count, 100)
         self.assertEqual([r.num for r in result], range(48, 56))
 
+    def testSortLimitViaBatchingArgsRightMiddleSortOnTwoSecond(self):
+        catalog = self._make_one()
+        query = dict(att1='att1', sort_on=('att1', 'num'),
+            sort_order=('', 'reverse'), b_start=48, b_size=8)
+        result = catalog(query)
+        self.assertEqual(result.actual_result_count, 100)
+        self.assertEqual([r.num for r in result], range(51, 43, -1))
+
     def testSortLimitViaBatchingArgsEarlySecondHalf(self):
         catalog = self._make_one()
         query = dict(att1='att1', sort_on='num', b_start=55, b_size=15)
@@ -478,6 +486,30 @@
         self.assertEqual(result.actual_result_count, 100)
         self.assertEqual([r.num for r in result], range(55, 70))
 
+    def testSortLimitViaBatchingArgsEarlySecondHalfSortOnTwoFirst(self):
+        catalog = self._make_one()
+        query = dict(att1='att1', sort_on=('att1', 'num'),
+            sort_order=('reverse', ''), b_start=55, b_size=15)
+        result = catalog(query)
+        self.assertEqual(result.actual_result_count, 100)
+        self.assertEqual([r.num for r in result], range(55, 70))
+
+    def testSortLimitViaBatchingArgsEarlySecondHalfSortOnTwoSecond(self):
+        catalog = self._make_one()
+        query = dict(att1='att1', sort_on=('att1', 'num'),
+            sort_order=('', 'reverse'), b_start=55, b_size=15)
+        result = catalog(query)
+        self.assertEqual(result.actual_result_count, 100)
+        self.assertEqual([r.num for r in result], range(44, 29, -1))
+
+    def testSortLimitViaBatchingArgsEarlySecondHalfSortOnTwoBoth(self):
+        catalog = self._make_one()
+        query = dict(att1='att1', sort_on=('att1', 'num'),
+            sort_order=('reverse', 'reverse'), b_start=55, b_size=15)
+        result = catalog(query)
+        self.assertEqual(result.actual_result_count, 100)
+        self.assertEqual([r.num for r in result], range(44, 29, -1))
+
     def testSortLimitViaBatchingArgsSecondHalf(self):
         catalog = self._make_one()
         query = dict(att1='att1', sort_on='num', b_start=70, b_size=15)
@@ -588,6 +620,51 @@
         for x in range(upper - 1):
             self.assertTrue(a[x].num > a[x + 1].num)
 
+    def test_sort_on_two_reverse_neither(self):
+        catalog = self._make_one()
+        upper = self.upper
+        a = catalog(sort_on=('att1', 'num'), att1='att1',
+            sort_order=('', ''))
+        self.assertEqual(len(a), upper)
+        for x in range(upper - 1):
+            self.assertTrue(a[x].num < a[x + 1].num)
+
+    def test_sort_on_two_reverse_first(self):
+        catalog = self._make_one()
+        upper = self.upper
+        a = catalog(sort_on=('att1', 'num'), att1='att1',
+            sort_order=('reverse', ''))
+        self.assertEqual(len(a), upper)
+        for x in range(upper - 1):
+            self.assertTrue(a[x].num < a[x + 1].num)
+
+    def test_sort_on_two_reverse_second(self):
+        catalog = self._make_one()
+        upper = self.upper
+        a = catalog(sort_on=('att1', 'num'), att1='att1',
+            sort_order=('', 'reverse'))
+        self.assertEqual(len(a), upper)
+        for x in range(upper - 1):
+            self.assertTrue(a[x].num > a[x + 1].num)
+
+    def test_sort_on_two_reverse_both(self):
+        catalog = self._make_one()
+        upper = self.upper
+        a = catalog(sort_on=('att1', 'num'), att1='att1',
+            sort_order=('reverse', 'reverse'))
+        self.assertEqual(len(a), upper)
+        for x in range(upper - 1):
+            self.assertTrue(a[x].num > a[x + 1].num)
+
+    def test_sort_on_two_reverse_too_many(self):
+        catalog = self._make_one()
+        upper = self.upper
+        a = catalog(sort_on=('att1', 'num'), att1='att1',
+            sort_order=('', '', 'reverse', ''))
+        self.assertEqual(len(a), upper)
+        for x in range(upper - 1):
+            self.assertTrue(a[x].num < a[x + 1].num)
+
     def test_sort_on_two_small_limit(self):
         catalog = self._make_one()
         a = catalog(sort_on=('att1', 'num'), att1='att1', sort_limit=10)



More information about the checkins mailing list