Commit 3d8f2a5a authored by Vincent Pelletier's avatar Vincent Pelletier

ZSQLCatalog.SQLCatalog: Allow scriptable keys access to SearchKey API.

To avoid duplicating _processSearchValue.
parent 45a87733
...@@ -40,6 +40,7 @@ from ZODB.POSException import ConflictError ...@@ -40,6 +40,7 @@ from ZODB.POSException import ConflictError
from Products.CMFCore import permissions from Products.CMFCore import permissions
from Products.PythonScripts.Utility import allow_class from Products.PythonScripts.Utility import allow_class
from compiler.consts import CO_VARKEYWORDS
from functools import wraps from functools import wraps
import time import time
import urllib import urllib
...@@ -2564,14 +2565,47 @@ class SearchKeyWrapperForScriptableKey(SearchKey.SearchKey.SearchKey): ...@@ -2564,14 +2565,47 @@ class SearchKeyWrapperForScriptableKey(SearchKey.SearchKey.SearchKey):
This SearchKey is a simple wrapper around a ScriptableKey, so such script This SearchKey is a simple wrapper around a ScriptableKey, so such script
can be used in place of a regular SearchKey. can be used in place of a regular SearchKey.
""" """
security = ClassSecurityInfo()
def __init__(self, column, script): def __init__(self, column, script):
self.script = script self.script = script
func_code = script.func_code
self.buildQuery = self.__buildQueryWithFiveArgumentsAPI if (
# 5: search_value (under any name), "search_key", "group",
# "logical_operator", "comparison_operator". The last 4 are possible in
# any order.
func_code.co_argcount == 5 or
getattr(func_code, 'co_flags', 0) & CO_VARKEYWORDS
) else self.__buildQueryWithOldAPI
super(SearchKeyWrapperForScriptableKey, self).__init__(column) super(SearchKeyWrapperForScriptableKey, self).__init__(column)
def buildQuery(self, search_value, group=None, logical_operator=None, security.declarePublic('processSearchValue')
comparison_operator=None): def processSearchValue(self, *args, **kw):
# XXX: It would be better to extend ScriptableKey API to support other """
# parameters. Expose _processSearchValue to self.script.
Only callable from full-API scripts, as others do not get access to our
instance.
"""
return self._processSearchValue(*args, **kw)
def __buildQueryWithFiveArgumentsAPI(self, search_value, group=None,
logical_operator=None, comparison_operator=None):
"""
Becomes buildQuery if self.script supports extra parameters.
"""
assert logical_operator in (None, 'and', 'or'), repr(logical_operator)
return self.script(
search_value,
search_key=self,
group=group,
logical_operator=logical_operator,
comparison_operator=comparison_operator,
)
def __buildQueryWithOldAPI(self, search_value, group=None,
logical_operator=None, comparison_operator=None):
"""
Becomes buildQuery if self.script does not support extra parameters.
"""
if group is not None: if group is not None:
raise ValueError( raise ValueError(
'ScriptableKey cannot be used inside a group (%r given).' % (group, ), 'ScriptableKey cannot be used inside a group (%r given).' % (group, ),
...@@ -2585,6 +2619,7 @@ class SearchKeyWrapperForScriptableKey(SearchKey.SearchKey.SearchKey): ...@@ -2585,6 +2619,7 @@ class SearchKeyWrapperForScriptableKey(SearchKey.SearchKey.SearchKey):
'ScriptableKey ignores comparison operators (%r given).' % (comparison_operator, ), 'ScriptableKey ignores comparison operators (%r given).' % (comparison_operator, ),
) )
return self.script(search_value) return self.script(search_value)
InitializeClass(SearchKeyWrapperForScriptableKey)
from Operator import operator_dict from Operator import operator_dict
def getComparisonOperatorInstance(operator): def getComparisonOperatorInstance(operator):
......
...@@ -170,7 +170,10 @@ class DummyCatalog(SQLCatalog): ...@@ -170,7 +170,10 @@ class DummyCatalog(SQLCatalog):
sql_catalog_keyword_search_keys = ('keyword', ) sql_catalog_keyword_search_keys = ('keyword', )
sql_catalog_datetime_search_keys = ('date', ) sql_catalog_datetime_search_keys = ('date', )
sql_catalog_full_text_search_keys = ('old_fulltext', ) sql_catalog_full_text_search_keys = ('old_fulltext', )
sql_catalog_scriptable_keys = ('scriptable_keyword | scriptableKeyScript', ) sql_catalog_scriptable_keys = (
'scriptable_keyword | scriptableKeyScript',
'scriptable_keyword_5args | scriptableKeyScriptFiveArguments',
)
sql_catalog_search_keys = ('fulltext | MroongaFullTextKey', sql_catalog_search_keys = ('fulltext | MroongaFullTextKey',
'fulltext_boolean | MroongaBooleanFullTextKey',) 'fulltext_boolean | MroongaBooleanFullTextKey',)
...@@ -218,6 +221,39 @@ class DummyCatalog(SQLCatalog): ...@@ -218,6 +221,39 @@ class DummyCatalog(SQLCatalog):
""" """
return SimpleQuery(comparison_operator='=', keyword=value) return SimpleQuery(comparison_operator='=', keyword=value)
@staticmethod
def scriptableKeyScriptFiveArguments(
value,
search_key,
group,
logical_operator,
comparison_operator,
):
"""
Mimics a scriptable key (PythonScript) subobject, using the SearchKey API.
"""
operator_value_dict, logical_operator, _ = search_key.processSearchValue(
search_value=value,
default_logical_operator=logical_operator,
comparison_operator=comparison_operator,
)
query_list = [
SimpleQuery(
keyword=value_list[0], # XXX: Fine for tests, bad in general.
comparison_operator=comparison_operator,
group=group,
)
for comparison_operator, value_list in operator_value_dict.iteritems()
]
if len(query_list) == 1:
return query_list[0]
if query_list:
return ComplexQuery(
query_list,
logical_operator=logical_operator,
)
return SimpleQuery(uid=-1)
class TestSQLCatalog(ERP5TypeTestCase): class TestSQLCatalog(ERP5TypeTestCase):
def setUp(self): def setUp(self):
self._catalog = DummyCatalog('dummy_catalog') self._catalog = DummyCatalog('dummy_catalog')
...@@ -535,6 +571,8 @@ class TestSQLCatalog(ERP5TypeTestCase): ...@@ -535,6 +571,8 @@ class TestSQLCatalog(ERP5TypeTestCase):
{'scriptable_keyword': '%a%'}) {'scriptable_keyword': '%a%'})
self.catalog(ReferenceQuery(ReferenceQuery(operator='=', keyword='%a%'), operator='and'), self.catalog(ReferenceQuery(ReferenceQuery(operator='=', keyword='%a%'), operator='and'),
{'default': 'scriptable_keyword:%a%'}) {'default': 'scriptable_keyword:%a%'})
self.catalog(ReferenceQuery(ReferenceQuery(operator='!=', keyword='a'), operator='and'),
{'scriptable_keyword_5args': '!=a'})
def test_008_testRawKey(self): def test_008_testRawKey(self):
self.catalog(ReferenceQuery(ReferenceQuery(operator='=', default='%a%'), operator='and'), self.catalog(ReferenceQuery(ReferenceQuery(operator='=', default='%a%'), operator='and'),
......
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