Don't execute query when a view params extension adapter return a null value
authorThierry Florac <thierry.florac@onf.fr>
Tue, 08 Jan 2019 14:05:53 +0100
changeset 138 739f21526374
parent 137 fc81a5fb2225
child 139 c1399609c5c0
Don't execute query when a view params extension adapter return a null value
src/pyams_content_es/shared/view/__init__.py
src/pyams_content_es/shared/view/reference.py
src/pyams_content_es/shared/view/theme.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
 
 
 #
--- 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)}))
--- /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 <tflorac AT ulthar.net>
+# 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