From 20ce0e4227363e893d81761d725500c0d8eb34b8 Mon Sep 17 00:00:00 2001
From: Vincent Pelletier <vincent@nexedi.com>
Date: Wed, 28 Jul 2010 12:33:15 +0000
Subject: [PATCH] Fix providing a sort direction for a full-text column.

This changes SQLExpression API, but this should not be a problem, since
this API is internal to ZSQLCatalog.

git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@37338 20353a03-c40f-0410-a6d1-a30d3c3de9de
---
 product/ZSQLCatalog/Query/EntireQuery.py       |  7 ++-----
 product/ZSQLCatalog/SQLExpression.py           | 12 ++++++++++--
 .../ZSQLCatalog/interfaces/sql_expression.py   |  7 +++++--
 product/ZSQLCatalog/tests/testSQLCatalog.py    | 18 +++++++++++++++++-
 4 files changed, 34 insertions(+), 10 deletions(-)

diff --git a/product/ZSQLCatalog/Query/EntireQuery.py b/product/ZSQLCatalog/Query/EntireQuery.py
index 41ab108d72..6811b61580 100644
--- a/product/ZSQLCatalog/Query/EntireQuery.py
+++ b/product/ZSQLCatalog/Query/EntireQuery.py
@@ -141,11 +141,8 @@ class EntireQuery(object):
             LOG('SQLCatalog', 100, 'Order by %r ignored: it could not be mapped to a known column.' % (order_by, ))
             rendered = None
         if rendered is not None:
-          if len(order_by) > 1:
-            if len(order_by) > 2 and order_by[2] not in (None, ''):
-              rendered = 'CAST(%s AS %s)' % (rendered, order_by[2])
-            rendered = '%s %s' % (rendered, order_by[1])
-          append(rendered)
+          append((rendered, ) + tuple(order_by[1:]) + (
+            None, ) * (3 - len(order_by)))
       self.order_by_list = new_order_by_list
       # generate SQLExpression from query
       sql_expression_list = [self.query.asSQLExpression(sql_catalog, column_map, only_group_columns)]
diff --git a/product/ZSQLCatalog/SQLExpression.py b/product/ZSQLCatalog/SQLExpression.py
index 13850bff2e..7ee0aa1a87 100644
--- a/product/ZSQLCatalog/SQLExpression.py
+++ b/product/ZSQLCatalog/SQLExpression.py
@@ -238,9 +238,17 @@ class SQLExpression(object):
 
       Returns a rendered "order by" expression. See getOrderByList.
     """
+    result = []
+    append = result.append
     order_by_dict = self._getOrderByDict()
-    return SQL_LIST_SEPARATOR.join(conflictSafeGet(order_by_dict, x, str(x)) \
-                                   for x in self.getOrderByList())
+    for (column, direction, cast) in self.getOrderByList():
+      expression = conflictSafeGet(order_by_dict, column, str(column))
+      if cast not in (None, ''):
+        expression = 'CAST(%s AS %s)' % (expression, cast)
+      if direction is not None:
+        expression = '%s %s' % (expression, direction)
+      append(expression)
+    return SQL_LIST_SEPARATOR.join(result)
 
   @profiler_decorator
   def getWhereExpression(self):
diff --git a/product/ZSQLCatalog/interfaces/sql_expression.py b/product/ZSQLCatalog/interfaces/sql_expression.py
index dc9b4df518..4099cba2dc 100644
--- a/product/ZSQLCatalog/interfaces/sql_expression.py
+++ b/product/ZSQLCatalog/interfaces/sql_expression.py
@@ -76,8 +76,11 @@ class ISQLExpression(Interface):
         The Query instance which called this constructor.
       table_alias_dict (dict, key: string, value: string)
         Table alias dict as returned by ColumnMap.getTableAliasDict() .
-      order_by_list (list of strings)
-        List of result ordering, pre-rendered.
+      order_by_list (list of 3-tuples)
+        Result ordering.
+        - column (rendered)
+        - direction (string or None)
+        - cast (string or None)
       order_by_dict (dict, key: string, value: string)
         Column rendering replacement specific to order_by.
       group_by_list (list of strings)
diff --git a/product/ZSQLCatalog/tests/testSQLCatalog.py b/product/ZSQLCatalog/tests/testSQLCatalog.py
index 1127492b06..4e4e148ca7 100644
--- a/product/ZSQLCatalog/tests/testSQLCatalog.py
+++ b/product/ZSQLCatalog/tests/testSQLCatalog.py
@@ -583,7 +583,23 @@ class TestSQLCatalog(unittest.TestCase):
     # order_by_list on fulltext column, resulting "ORDER BY" must be non-empty.
     sql_expression = self.asSQLExpression({'fulltext': 'foo',
       'order_by_list': [('fulltext', ), ]})
-    self.assertNotEqual(sql_expression.getOrderByExpression(), '')
+    order_by_expression = sql_expression.getOrderByExpression()
+    self.assertNotEqual(order_by_expression, '')
+    # ... and must sort by relevance
+    self.assertTrue('MATCH' in order_by_expression, order_by_expression)
+    # ordering on fulltext column with sort order specified must preserve
+    # sorting by relevance.
+    for direction in ('ASC', 'DESC'):
+      sql_expression = self.asSQLExpression({'fulltext': 'foo',
+        'order_by_list': [('fulltext', direction), ]})
+      order_by_expression = sql_expression.getOrderByExpression()
+      self.assertTrue('MATCH' in order_by_expression, (order_by_expression, direction))
+    # Providing a None cast should work too
+    for direction in ('ASC', 'DESC'):
+      sql_expression = self.asSQLExpression({'fulltext': 'foo',
+        'order_by_list': [('fulltext', direction, None), ]})
+      order_by_expression = sql_expression.getOrderByExpression()
+      self.assertTrue('MATCH' in order_by_expression, (order_by_expression, direction))
 
 ##return catalog(title=Query(title='a', operator='not'))
 #return catalog(title={'query': 'a', 'operator': 'not'})
-- 
2.30.9