# HG changeset patch # User Thierry Florac # Date 1546952753 -3600 # Node ID 739f215263746b2ddadd6acbcb2e3f7ba32c5a11 # Parent fc81a5fb22250e2837d9f429458cc1d703d248b2 Don't execute query when a view params extension adapter return a null value diff -r fc81a5fb2225 -r 739f21526374 src/pyams_content_es/shared/view/__init__.py --- a/src/pyams_content_es/shared/view/__init__.py Tue Jan 08 14:04:53 2019 +0100 +++ b/src/pyams_content_es/shared/view/__init__.py Tue Jan 08 14:05:53 2019 +0100 @@ -12,7 +12,6 @@ __docformat__ = 'restructuredtext' -from collections import OrderedDict from datetime import datetime from elasticsearch_dsl import Q, Search @@ -21,7 +20,7 @@ from pyams_catalog.query import CatalogResultSet from pyams_content.features.search import ISearchFolder -from pyams_content.shared.view.interfaces import IViewInternalReferencesSettings, IViewQuery, \ +from pyams_content.shared.view.interfaces import IViewQuery, \ IViewQueryEsParamsExtension, IViewQueryFilterExtension, IViewUserQuery, IWfView, RELEVANCE_ORDER from pyams_content.shared.view.portlet import SEARCH_EXCLUDED_ITEMS from pyams_sequence.interfaces import ISequentialIntIds @@ -48,87 +47,70 @@ wf_params.extend(workflow.published_states) params &= Q('terms', **{'workflow.status': wf_params}) # check custom extensions - do_search = True for name, adapter in sorted(registry.getAdapters((view,), IViewQueryEsParamsExtension), key=lambda x: x[1].weight): for new_params in adapter.get_es_params(context, request): - if isinstance(new_params, tuple): - new_params, do_search = new_params - if new_params: + if new_params is None: + return None + else: params &= new_params - if not do_search: - break # activate search - if do_search: - params &= Q('bool', must=Q('range', **{'workflow.push_end_date': {'gte': now}})) | \ - Q('bool', must_not=Q('exists', **{'field': 'workflow.push_end_date'})) - # check content path - content_path = view.get_content_path(context) - if content_path is not None: - params &= Q('term', **{'parent_ids': content_path}) - # check content types - content_types = view.get_content_types(context) - if content_types: - params &= Q('terms', **{'content_type': content_types}) - # check data types - data_types = view.get_data_types(context) - if data_types: - params &= Q('terms', **{'data_type': data_types}) + params &= Q('bool', must=Q('range', **{'workflow.push_end_date': {'gte': now}})) | \ + Q('bool', must_not=Q('exists', **{'field': 'workflow.push_end_date'})) + # check content path + content_path = view.get_content_path(context) + if content_path is not None: + params &= Q('term', **{'parent_ids': content_path}) + # check content types + content_types = view.get_content_types(context) + if content_types: + params &= Q('terms', **{'content_type': content_types}) + # check data types + data_types = view.get_data_types(context) + if data_types: + params &= Q('terms', **{'data_type': data_types}) return params def get_results(self, context, sort_index, reverse, limit, request=None): registry = request.registry client = get_client(request) params = self.get_params(context, request) - search = Search(using=client.es, index=client.index) \ - .query(params) \ - .source(['internal_id']) - # Define sort order - sort_values = [] - settings = IViewInternalReferencesSettings(self.context) - if settings.references: - sort_values.append({ - '_script': { - 'type': 'number', - 'script': { - 'lang': 'painless', - 'source': """ - if (params.scores.containsKey(doc['reference_id'].value)) { - return params.scores[doc['reference_id'].value]; - } - return 999; - """, - 'params': { - 'scores': OrderedDict(((ref, order) for order, ref in enumerate(settings.references))) - } + if params is None: + items = CatalogResultSet([]) + total_count = 0 + else: + search = Search(using=client.es, index=client.index) \ + .query(params) \ + .source(['internal_id']) + # Define sort order + sort_values = [] + if (not sort_index) or (sort_index == RELEVANCE_ORDER): + sort_values.append({ + '_score': { + 'order': 'desc' } - } - }) - if (not sort_index) or (sort_index == RELEVANCE_ORDER): - sort_values.append({ - '_score': { - 'order': 'desc' - } - }) - else: - sort_values.append({ - 'workflow.{0}'.format(sort_index): { - 'order': 'desc' if reverse else 'asc', - 'unmapped_type': 'date' - } - }) - if sort_values: - search = search.sort(*sort_values) - # Define limits - if limit: - search = search[:limit] - else: - search = search[:999] - items = CatalogResultSet([result.internal_id for result in search]) + }) + else: + sort_values.append({ + 'workflow.{0}'.format(sort_index): { + 'order': 'desc' if reverse else 'asc', + 'unmapped_type': 'date' + } + }) + if sort_values: + search = search.sort(*sort_values) + # Define limits + if limit: + search = search[:limit] + else: + search = search[:999] + # Get query results + items = CatalogResultSet([result.internal_id for result in search]) + total_count = search.count() for name, adapter in sorted(registry.getAdapters((self.context,), IViewQueryFilterExtension), key=lambda x: x[1].weight): items = adapter.filter(context, items, request) - return unique_iter(items), search.count() + return unique_iter(items), total_count # diff -r fc81a5fb2225 -r 739f21526374 src/pyams_content_es/shared/view/reference.py --- a/src/pyams_content_es/shared/view/reference.py Tue Jan 08 14:04:53 2019 +0100 +++ b/src/pyams_content_es/shared/view/reference.py Tue Jan 08 14:05:53 2019 +0100 @@ -29,10 +29,12 @@ def get_es_params(self, context, request=None): settings = IViewInternalReferencesSettings(self.context) - # check view settings - if settings.exclude_context: - intids = get_utility(IIntIds) - yield Q('bool', must_not=Q('term', **{'internal_id': intids.register(context)})) # check view references mode if settings.references_mode == ONLY_REFERENCE_MODE: - yield Q('terms', **{'reference_id': settings.references}), False + # references are retrieved by query filter extension, so no params are required! + yield None + else: + # check view settings + if settings.exclude_context: + intids = get_utility(IIntIds) + yield Q('bool', must_not=Q('term', **{'internal_id': intids.register(context)})) diff -r fc81a5fb2225 -r 739f21526374 src/pyams_content_es/shared/view/theme.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content_es/shared/view/theme.py Tue Jan 08 14:05:53 2019 +0100 @@ -0,0 +1,101 @@ +# +# Copyright (c) 2008-2015 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + +from elasticsearch_dsl import Q +from zope.intid.interfaces import IIntIds + +from pyams_content.component.theme import ITagsManager +from pyams_content.shared.view.interfaces import IViewCollectionsSettings, IViewQueryEsParamsExtension, \ + IViewTagsSettings, IViewThemesSettings, IViewUserQuery, IWfView +from pyams_content_es.shared.view import EsSearchFolderQuery +from pyams_thesaurus.interfaces.thesaurus import IThesaurus +from pyams_utils.adapter import ContextAdapter, adapter_config +from pyams_utils.registry import query_utility + + +# +# Tags query +# + +@adapter_config(name='tags', context=IWfView, provides=IViewQueryEsParamsExtension) +class ViewTagsQueryEsParamsExtension(ContextAdapter): + """View tags query adapter """ + + weight = 60 + + def get_es_params(self, context, request=None): + settings = IViewTagsSettings(self.context) + tags = settings.get_tags_index(context) + if tags: + yield Q('terms', **{'tags': tags}) + elif settings.select_context_tags: + yield None + + +@adapter_config(name='tag', context=EsSearchFolderQuery, provides=IViewUserQuery) +class EsSearchFolderTagQuery(ContextAdapter): + """Search folder tag query for Elasticsearch""" + + @staticmethod + def get_user_params(request): + tag = request.params.get('tag') + if tag: + manager = ITagsManager(request.root, None) + if manager is None: + raise StopIteration + thesaurus = query_utility(IThesaurus, name=manager.thesaurus_name) + if thesaurus is None: + raise StopIteration + term = thesaurus.terms.get(tag) + if term is not None: + intids = query_utility(IIntIds) + yield Q('term', **{'tags': intids.queryId(term)}) + + +# +# Themes query +# + +@adapter_config(name='themes', context=IWfView, provides=IViewQueryEsParamsExtension) +class ViewThemesQueryEsParamsExtension(ContextAdapter): + """View themes query adapter """ + + weight = 62 + + def get_es_params(self, context, request=None): + settings = IViewThemesSettings(self.context) + themes = settings.get_themes_index(context) + if themes: + yield Q('terms', **{'themes.terms': themes}) + elif settings.select_context_themes: + yield None + + +# +# Collections query +# + +@adapter_config(name='collections', context=IWfView, provides=IViewQueryEsParamsExtension) +class ViewCollectionsQueryEsParamsExtension(ContextAdapter): + """View collections query adapter """ + + weight = 64 + + def get_es_params(self, context, request=None): + settings = IViewCollectionsSettings(self.context) + collections = settings.get_collections_index(context) + if collections: + yield Q('terms', **{'collections': collections}) + elif settings.select_context_collections: + yield None