Commit 9ca41cc3 authored by Kazuhiko Shiozaki's avatar Kazuhiko Shiozaki

full text: keep quote in full text search keys.

parent d01de179
...@@ -172,7 +172,7 @@ class MroongaComparisonOperator(MatchComparisonOperator): ...@@ -172,7 +172,7 @@ class MroongaComparisonOperator(MatchComparisonOperator):
# Always use BOOLEAN MODE to combine similarity search and boolean search. # Always use BOOLEAN MODE to combine similarity search and boolean search.
fulltext_query = '*D+' fulltext_query = '*D+'
if match_query_list: if match_query_list:
fulltext_query += ' *S"%s"' % ' '.join(x.replace('"', '\\"') for x in match_query_list) fulltext_query += ' *S"%s"' % ' '.join(match_query_list)
if match_boolean_query_list: if match_boolean_query_list:
fulltext_query += ' %s' % ' '.join(match_boolean_query_list) fulltext_query += ' %s' % ' '.join(match_boolean_query_list)
return self._renderValue(fulltext_query) return self._renderValue(fulltext_query)
......
...@@ -30,9 +30,10 @@ ...@@ -30,9 +30,10 @@
from DefaultKey import DefaultKey from DefaultKey import DefaultKey
from SearchKey import SearchKey from SearchKey import SearchKey
from Products.ZSQLCatalog.Query.SimpleQuery import SimpleQuery from Products.ZSQLCatalog.Query.SimpleQuery import SimpleQuery
from Products.ZSQLCatalog.SearchText import parse
from Products.ZSQLCatalog.interfaces.search_key import ISearchKey from Products.ZSQLCatalog.interfaces.search_key import ISearchKey
from Products.ZSQLCatalog.SearchText import dequote
from zope.interface.verify import verifyClass from zope.interface.verify import verifyClass
import re import re
...@@ -49,7 +50,7 @@ class FullTextKey(DefaultKey): ...@@ -49,7 +50,7 @@ class FullTextKey(DefaultKey):
return False return False
def _renderValueAsSearchText(self, value, operator): def _renderValueAsSearchText(self, value, operator):
return '(%s)' % (value, ) return '"%s"' % value.replace('"', '\\"')
def _processSearchValue(self, search_value, logical_operator, def _processSearchValue(self, search_value, logical_operator,
comparison_operator): comparison_operator):
...@@ -75,6 +76,13 @@ class FullTextKey(DefaultKey): ...@@ -75,6 +76,13 @@ class FullTextKey(DefaultKey):
operator_value_dict['match_boolean'].extend(new_value_list) operator_value_dict['match_boolean'].extend(new_value_list)
else: else:
operator_value_dict['match'] = new_value_list operator_value_dict['match'] = new_value_list
# Dequote for non full-text queries.
for comparison_operator, value_list in operator_value_dict.iteritems():
if comparison_operator not in ('match', 'match_boolean'):
operator_value_dict[comparison_operator] = [
isinstance(value, basestring) and dequote(value) or value
for value in value_list
]
return operator_value_dict, logical_operator, parsed return operator_value_dict, logical_operator, parsed
def _buildQuery(self, operator_value_dict, logical_operator, parsed, group): def _buildQuery(self, operator_value_dict, logical_operator, parsed, group):
...@@ -86,10 +94,26 @@ class FullTextKey(DefaultKey): ...@@ -86,10 +94,26 @@ class FullTextKey(DefaultKey):
column = self.getColumn() column = self.getColumn()
query_list = [] query_list = []
append = query_list.append append = query_list.append
for comparison_operator, value_list in operator_value_dict.iteritems(): for comparison_operator in ('match', 'match_boolean'):
value_list = operator_value_dict.pop(comparison_operator, [])
if not value_list:
continue
if logical_operator == 'or':
joined_value = ' '.join(value_list)
append(SimpleQuery(search_key=self,
comparison_operator=comparison_operator,
group=group, **{column:joined_value}))
else:
# In MySQL FTS, no operator implies OR so that we cannot merge
# AND queries into one.
for value in value_list:
append(SimpleQuery(search_key=self, append(SimpleQuery(search_key=self,
comparison_operator=comparison_operator, comparison_operator=comparison_operator,
group=group, **{column: ' '.join(value_list)})) group=group, **{column:value}))
# Other comparison operators are handled by the super class.
if operator_value_dict:
query_list += super(FullTextKey, self)._buildQuery(
operator_value_dict, logical_operator, parsed, group)
return query_list return query_list
verifyClass(ISearchKey, FullTextKey) verifyClass(ISearchKey, FullTextKey)
......
...@@ -29,11 +29,32 @@ ...@@ -29,11 +29,32 @@
from DefaultKey import DefaultKey from DefaultKey import DefaultKey
from Products.ZSQLCatalog.Query.SimpleQuery import SimpleQuery from Products.ZSQLCatalog.Query.SimpleQuery import SimpleQuery
from Products.ZSQLCatalog.interfaces.search_key import ISearchKey from Products.ZSQLCatalog.interfaces.search_key import ISearchKey
from Products.ZSQLCatalog.SearchText import dequote
from zope.interface.verify import verifyClass from zope.interface.verify import verifyClass
class MroongaFullTextKey(DefaultKey): class MroongaFullTextKey(DefaultKey):
default_comparison_operator = 'mroonga' default_comparison_operator = 'mroonga'
def dequoteParsedText(self):
return False
def _renderValueAsSearchText(self, value, operator):
return '"%s"' % value.replace('"', '\\"')
def _processSearchValue(self, search_value, logical_operator,
comparison_operator):
operator_value_dict, logical_operator, parsed = \
super(MroongaFullTextKey, self)._processSearchValue(
search_value, logical_operator, comparison_operator)
# Dequote for non full-text queries.
for comparison_operator, value_list in operator_value_dict.iteritems():
if comparison_operator not in ('mroonga', 'mroonga_boolean'):
operator_value_dict[comparison_operator] = [
isinstance(value, basestring) and dequote(value) or value
for value in value_list
]
return operator_value_dict, logical_operator, parsed
def _buildQuery(self, operator_value_dict, logical_operator, parsed, group): def _buildQuery(self, operator_value_dict, logical_operator, parsed, group):
""" """
Special Query builder for FullText queries: merge all values having the Special Query builder for FullText queries: merge all values having the
...@@ -43,18 +64,12 @@ class MroongaFullTextKey(DefaultKey): ...@@ -43,18 +64,12 @@ class MroongaFullTextKey(DefaultKey):
column = self.getColumn() column = self.getColumn()
query_list = [] query_list = []
append = query_list.append append = query_list.append
def escape(x):
# We need to escape once here for Mroonga, and it will be
# escaped once more in OperatorBase._renderValue().
return (not parsed and '"%s"' % x.replace('"', '\\"') or x).replace(
'(', '\\(').replace(
')', '\\)')
for comparison_operator in ('mroonga', 'mroonga_boolean'): for comparison_operator in ('mroonga', 'mroonga_boolean'):
value_list = operator_value_dict.pop(comparison_operator, []) value_list = operator_value_dict.pop(comparison_operator, [])
if not value_list: if not value_list:
continue continue
if logical_operator == 'and': if logical_operator == 'and':
joined_value = ' '.join(escape(value) for value in value_list) joined_value = ' '.join(value_list)
append(SimpleQuery(search_key=self, append(SimpleQuery(search_key=self,
comparison_operator=comparison_operator, comparison_operator=comparison_operator,
group=group, **{column:joined_value})) group=group, **{column:joined_value}))
...@@ -63,7 +78,7 @@ class MroongaFullTextKey(DefaultKey): ...@@ -63,7 +78,7 @@ class MroongaFullTextKey(DefaultKey):
for value in value_list: for value in value_list:
append(SimpleQuery(search_key=self, append(SimpleQuery(search_key=self,
comparison_operator=comparison_operator, comparison_operator=comparison_operator,
group=group, **{column:escape(value)})) group=group, **{column:value}))
# Other comparison operators are handled by the super class. # Other comparison operators are handled by the super class.
if operator_value_dict: if operator_value_dict:
query_list += super(MroongaFullTextKey, self)._buildQuery( query_list += super(MroongaFullTextKey, self)._buildQuery(
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment