From d8d4ed8237fe659c078a37b89bdb4a900d11910c Mon Sep 17 00:00:00 2001 From: Kazuhiko Shiozaki <kazuhiko@nexedi.com> Date: Fri, 21 Nov 2014 16:57:40 +0100 Subject: [PATCH] rewrite SQLCatalog_makeSearchTextQuery without using ad-hoc Base_parseSearchString. --- .../SQLCatalog_makeSearchTextQuery.xml | 57 ++------ .../extension.erp5.SearchUtility.py | 86 ++++++++++++ .../extension.erp5.SearchUtility.xml | 123 ++++++++++++++++++ .../bt/template_extension_id_list | 1 + 4 files changed, 222 insertions(+), 45 deletions(-) create mode 100644 product/ERP5/bootstrap/erp5_mysql_innodb_catalog/ExtensionTemplateItem/portal_components/extension.erp5.SearchUtility.py create mode 100644 product/ERP5/bootstrap/erp5_mysql_innodb_catalog/ExtensionTemplateItem/portal_components/extension.erp5.SearchUtility.xml create mode 100644 product/ERP5/bootstrap/erp5_mysql_innodb_catalog/bt/template_extension_id_list diff --git a/product/ERP5/bootstrap/erp5_mysql_innodb_catalog/CatalogMethodTemplateItem/portal_catalog/erp5_mysql_innodb/SQLCatalog_makeSearchTextQuery.xml b/product/ERP5/bootstrap/erp5_mysql_innodb_catalog/CatalogMethodTemplateItem/portal_catalog/erp5_mysql_innodb/SQLCatalog_makeSearchTextQuery.xml index ada90d95f5..1d3e12e62c 100644 --- a/product/ERP5/bootstrap/erp5_mysql_innodb_catalog/CatalogMethodTemplateItem/portal_catalog/erp5_mysql_innodb/SQLCatalog_makeSearchTextQuery.xml +++ b/product/ERP5/bootstrap/erp5_mysql_innodb_catalog/CatalogMethodTemplateItem/portal_catalog/erp5_mysql_innodb/SQLCatalog_makeSearchTextQuery.xml @@ -50,9 +50,7 @@ </item> <item> <key> <string>_body</string> </key> - <value> <string encoding="cdata"><![CDATA[ - -"""\n + <value> <string>"""\n Search text query generator. Accepts a string and returns a ComplexQuery.\n For example:\n \n @@ -67,48 +65,17 @@ - are contributed by given Person\'s title\n - etc ..\n """\n -from Products.ZSQLCatalog.SQLCatalog import Query, ComplexQuery, SimpleQuery\n -\n -parsed_dict = context.Base_parseSearchString(value)\n -full_text = parsed_dict.pop(\'searchabletext\')\n -\n -#context.log(parsed_dict)\n -\n -# use full_text scriptable key!\n -query_list = [Query(**{\'full_text\': full_text})]\n -\n -# XXX: "newest" ?\n -# XXX: get known columns rather than hard-code \n -for key in (\'reference\', \'version\', \'language\', \'portal_type\', \'contributor_title\'):\n - value = parsed_dict.get(key, None)\n - if value is not None:\n - query_list.append(Query(**{key: value}))\n -\n -# user wants only his documents\n -if parsed_dict.get(\'mine\', None) is not None:\n - query_list.append(Query(**{\'owner\': str(context.portal_membership.getAuthenticatedMember())}))\n -\n -creation_from = parsed_dict.get(\'creation_from\', None)\n -creation_to = parsed_dict.get(\'creation_to\', None)\n -modification_from = parsed_dict.get(\'modification_from\', None)\n -modification_to = parsed_dict.get(\'modification_to\', None)\n -\n -if creation_from is not None:\n - query_list.append(SimpleQuery(**{\'catalog.creation_date\': creation_from, \n - \'comparison_operator\': \'>=\'}))\n -if creation_to is not None:\n - query_list.append(SimpleQuery(**{\'catalog.creation_date\': creation_to, \n - \'comparison_operator\': \'=<\'}))\n -if modification_from is not None:\n - query_list.append(SimpleQuery(**{\'catalog.modification_date\': modification_from, \n - \'comparison_operator\': \'>=\'}))\n -if modification_to is not None:\n - query_list.append(SimpleQuery(**{\'catalog.modification_date\': modification_to, \n - \'comparison_operator\': \'<=\'}))\n -return ComplexQuery(query_list, operator="AND")\n - - -]]></string> </value> +if \'full_text\' in context.sql_search_tables:\n + column = \'SearchableText\'\n +else:\n + column = \'title\'\n +node = context.Base_getAdvancedSearchSyntaxTreeNode(value, column=column)\n +if node is None:\n + from Products.ZSQLCatalog.SQLCatalog import Query\n + return Query(**{column:value})\n +else:\n + return context.getPortalObject().portal_catalog.getSQLCatalog().buildQueryFromAbstractSyntaxTreeNode(node, column)\n +</string> </value> </item> <item> <key> <string>_params</string> </key> diff --git a/product/ERP5/bootstrap/erp5_mysql_innodb_catalog/ExtensionTemplateItem/portal_components/extension.erp5.SearchUtility.py b/product/ERP5/bootstrap/erp5_mysql_innodb_catalog/ExtensionTemplateItem/portal_components/extension.erp5.SearchUtility.py new file mode 100644 index 0000000000..49d6d09869 --- /dev/null +++ b/product/ERP5/bootstrap/erp5_mysql_innodb_catalog/ExtensionTemplateItem/portal_components/extension.erp5.SearchUtility.py @@ -0,0 +1,86 @@ +############################################################################## +# +# Copyright (c) 2014 Nexedi SA and Contributors. All Rights Reserved. +# +# WARNING: This program as such is intended to be used by professional +# programmers who take the whole responsibility of assessing all potential +# consequences resulting from its eventual inadequacies and bugs +# End users who are looking for a ready-to-use solution with commercial +# garantees and support are strongly advised to contract a Free Software +# Service Company +# +# This program is Free Software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +############################################################################## + +from DateTime import DateTime +from Products.ERP5Type.DateUtils import addToDate +import re + +def render_date_range(date_range): + m = re.match(r'(\d+)([dwmy])', date_range) + if m is not None: + period_dict = { + 'd':'day', + 'w':'week', + 'm':'month', + 'y':'year', + } + num, period = m.groups() + period = period_dict[period.lower()] + return addToDate(DateTime(), **{period:-int(num)}) + +def recurseUpdateSyntaxNode(self, node): + if node.isLeaf(): + pass + elif node.isColumn(): + if node.column_name == 'mine': + node.column_name = 'owner' + node.node.value = str(self.portal_membership.getAuthenticatedMember()) + elif node.column_name == 'state' and node.node.value != 'all': + node.column_name = 'simulation_state' + elif node.column_name == 'type' and node.node.value != 'all': + node.column_name = 'portal_type' + elif node.column_name == 'file': + node.column_name = 'source_reference' + elif node.column_name == 'filetype': + node.column_name = 'source_reference' + node.node.value = '%%.%s' % node.node.value + elif node.column_name == 'created': + node.column_name = 'creation_date' + node.node.value = render_date_range(node.node.value) + node.node.comparison_operator = '>=' + elif node.column_name == 'creation_from': + node.column_name = 'creation_date' + node.node.comparison_operator = '>=' + elif node.column_name == 'creation_to': + node.column_name = 'creation_date' + node.node.comparison_operator = '<=' + elif node.column_name == 'modification_from': + node.column_name = 'modification_date' + node.node.comparison_operator = '>=' + elif node.column_name == 'modification_to': + node.column_name = 'modification_date' + node.node.comparison_operator = '<=' + else: + for subnode in node.getNodeList(): + recurseUpdateSyntaxNode(self, subnode) + +def getAdvancedSearchSyntaxTreeNode(self, search_text, column): + sql_catalog = self.getPortalObject().portal_catalog.getSQLCatalog() + node = sql_catalog.parseSearchText(search_text=search_text, column=column, is_valid=lambda x:True) + if node is not None: + recurseUpdateSyntaxNode(self, node) + return node diff --git a/product/ERP5/bootstrap/erp5_mysql_innodb_catalog/ExtensionTemplateItem/portal_components/extension.erp5.SearchUtility.xml b/product/ERP5/bootstrap/erp5_mysql_innodb_catalog/ExtensionTemplateItem/portal_components/extension.erp5.SearchUtility.xml new file mode 100644 index 0000000000..09f85216d4 --- /dev/null +++ b/product/ERP5/bootstrap/erp5_mysql_innodb_catalog/ExtensionTemplateItem/portal_components/extension.erp5.SearchUtility.xml @@ -0,0 +1,123 @@ +<?xml version="1.0"?> +<ZopeData> + <record id="1" aka="AAAAAAAAAAE="> + <pickle> + <global name="Extension Component" module="erp5.portal_type"/> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>_recorded_property_dict</string> </key> + <value> + <persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent> + </value> + </item> + <item> + <key> <string>default_reference</string> </key> + <value> <string>SearchUtility</string> </value> + </item> + <item> + <key> <string>description</string> </key> + <value> + <none/> + </value> + </item> + <item> + <key> <string>id</string> </key> + <value> <string>extension.erp5.SearchUtility</string> </value> + </item> + <item> + <key> <string>portal_type</string> </key> + <value> <string>Extension Component</string> </value> + </item> + <item> + <key> <string>sid</string> </key> + <value> + <none/> + </value> + </item> + <item> + <key> <string>text_content_error_message</string> </key> + <value> + <tuple/> + </value> + </item> + <item> + <key> <string>text_content_warning_message</string> </key> + <value> + <tuple/> + </value> + </item> + <item> + <key> <string>version</string> </key> + <value> <string>erp5</string> </value> + </item> + <item> + <key> <string>workflow_history</string> </key> + <value> + <persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent> + </value> + </item> + </dictionary> + </pickle> + </record> + <record id="2" aka="AAAAAAAAAAI="> + <pickle> + <global name="PersistentMapping" module="Persistence.mapping"/> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>data</string> </key> + <value> + <dictionary/> + </value> + </item> + </dictionary> + </pickle> + </record> + <record id="3" aka="AAAAAAAAAAM="> + <pickle> + <global name="PersistentMapping" module="Persistence.mapping"/> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>data</string> </key> + <value> + <dictionary> + <item> + <key> <string>component_validation_workflow</string> </key> + <value> + <persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent> + </value> + </item> + </dictionary> + </value> + </item> + </dictionary> + </pickle> + </record> + <record id="4" aka="AAAAAAAAAAQ="> + <pickle> + <global name="WorkflowHistoryList" module="Products.ERP5Type.patches.WorkflowTool"/> + </pickle> + <pickle> + <tuple> + <none/> + <list> + <dictionary> + <item> + <key> <string>action</string> </key> + <value> <string>validate</string> </value> + </item> + <item> + <key> <string>validation_state</string> </key> + <value> <string>validated</string> </value> + </item> + </dictionary> + </list> + </tuple> + </pickle> + </record> +</ZopeData> diff --git a/product/ERP5/bootstrap/erp5_mysql_innodb_catalog/bt/template_extension_id_list b/product/ERP5/bootstrap/erp5_mysql_innodb_catalog/bt/template_extension_id_list new file mode 100644 index 0000000000..fa6ef61e1d --- /dev/null +++ b/product/ERP5/bootstrap/erp5_mysql_innodb_catalog/bt/template_extension_id_list @@ -0,0 +1 @@ +extension.erp5.SearchUtility \ No newline at end of file -- 2.30.9