From fe5eeef749d8df860fead6ce411fb479d3aec15a Mon Sep 17 00:00:00 2001
From: Vincent Pelletier <vincent@nexedi.com>
Date: Wed, 6 May 2009 11:58:44 +0000
Subject: [PATCH] When doing multiple FullText lookups in the same SearchText
 expression, merge all lookups into just one SQL fulltext match (per
 expression block). Add a test.

git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@26836 20353a03-c40f-0410-a6d1-a30d3c3de9de
---
 product/ZSQLCatalog/SearchKey/FullTextKey.py | 18 ++++++++++++++++++
 product/ZSQLCatalog/tests/testSQLCatalog.py  | 12 ++++++++++++
 2 files changed, 30 insertions(+)

diff --git a/product/ZSQLCatalog/SearchKey/FullTextKey.py b/product/ZSQLCatalog/SearchKey/FullTextKey.py
index 0fd98c7fdb..9664d32e59 100644
--- a/product/ZSQLCatalog/SearchKey/FullTextKey.py
+++ b/product/ZSQLCatalog/SearchKey/FullTextKey.py
@@ -29,9 +29,11 @@
 ##############################################################################
 
 from SearchKey import SearchKey
+from Products.ZSQLCatalog.Query.SimpleQuery import SimpleQuery
 from Products.ZSQLCatalog.SearchText import parse
 from Products.ZSQLCatalog.Interface.ISearchKey import ISearchKey
 from Interface.Verify import verifyClass
+from Products.ZSQLCatalog.SQLCatalog import profiler_decorator
 
 class FullTextKey(SearchKey):
   """
@@ -43,5 +45,21 @@ class FullTextKey(SearchKey):
   def parseSearchText(self, value, is_column):
     return parse(value, is_column)
 
+  @profiler_decorator
+  def _buildQuery(self, operator_value_dict, logical_operator, parsed, group):
+    """
+      Special Query builder for FullText queries: merge all values having the
+      same operator into just one query, to save SQL server from the burden to
+      do multiple fulltext lookups when one would suit the purpose.
+    """
+    column = self.getColumn()
+    query_list = []
+    append = query_list.append
+    for comparison_operator, value_list in operator_value_dict.iteritems():
+      append(SimpleQuery(search_key=self,
+                         comparison_operator=comparison_operator,
+                         group=group, **{column: ' '.join(value_list)}))
+    return query_list
+
 verifyClass(ISearchKey, FullTextKey)
 
diff --git a/product/ZSQLCatalog/tests/testSQLCatalog.py b/product/ZSQLCatalog/tests/testSQLCatalog.py
index 736645b539..aac426c31b 100644
--- a/product/ZSQLCatalog/tests/testSQLCatalog.py
+++ b/product/ZSQLCatalog/tests/testSQLCatalog.py
@@ -394,6 +394,18 @@ class TestSQLCatalog(unittest.TestCase):
     self.assertTrue(self._catalog.isAdvancedSearchText('default:a')) # "default" exists as a column
     self.assertFalse(self._catalog.isAdvancedSearchText('b:a')) # "b" doesn't exist as a column
 
+  def test_FullTextSearchMergesQueries(self):
+    """
+      FullText criterion on the same scope must be merged into one query.
+      Logical operator is ignored, as fulltext operators are expected instead.
+    """
+    self.catalog(ReferenceQuery(ReferenceQuery(operator='match', fulltext='a b'), operator='and'),
+                 {'fulltext': 'a AND b'})
+    self.catalog(ReferenceQuery(ReferenceQuery(operator='match', fulltext='a b'), operator='and'),
+                 {'fulltext': 'a OR b'})
+    self.catalog(ReferenceQuery(ReferenceQuery(ReferenceQuery(operator='match', fulltext='a b'), operator='not'), operator='and'),
+                 {'fulltext': 'NOT (a b)'})
+
 ##return catalog(title=Query(title='a', operator='not'))
 #return catalog(title={'query': 'a', 'operator': 'not'})
 #return catalog(title={'query': ['a', 'b'], 'operator': 'not'})
-- 
2.30.9