diff --git a/src/Products/PluginIndexes/interfaces.py b/src/Products/PluginIndexes/interfaces.py index 0df5d9cd..e1aeb879 100644 --- a/src/Products/PluginIndexes/interfaces.py +++ b/src/Products/PluginIndexes/interfaces.py @@ -90,9 +90,12 @@ def clear(): class ILimitedResultIndex(IPluggableIndex): def _apply_index(request, resultset=None): - """Same as IPluggableIndex' _apply_index method. The additional - resultset argument contains the resultset, as already calculated by - ZCatalog's search method. + """Same as IPluggableIndex' _apply_index method. + + If not `None`, the additional resultset argument + indicates that the search result is relevant only on this set, + i.e. everything outside resultset is of no importance. + The index can use this information for optimizations. """ diff --git a/src/Products/PluginIndexes/tests/test_unindex.py b/src/Products/PluginIndexes/tests/test_unindex.py index 383306e3..66eeefef 100644 --- a/src/Products/PluginIndexes/tests/test_unindex.py +++ b/src/Products/PluginIndexes/tests/test_unindex.py @@ -193,3 +193,41 @@ class Dummy(object): query = IndexQuery({'counter': 42}, 'counter') res = index.query_index(query) self.assertListEqual(list(res), []) + + def test_not(self): + index = self._makeOne("idx") + index.query_options = "not", "operator" # activate `not`, `operator` + apply = index._apply_index + for i, vals in enumerate(((10, 11, 12), (11, 12, 13))): + for v in vals: + index.insertForwardIndexEntry(v, i) + query = {"query": (10, 11), "not": (10,)} + req = dict(idx=query) + # or(10,11), not(10) + self.assertEqual((1, ), tuple(apply(req)[0]), "or(10,11), not(10)") + # and(10, 11), not(10) + query["operator"] = "and" + self.assertEqual((), tuple(apply(req)[0]), "and(10, 11), not(10)") + # 11, not 10 + query["query"] = 11 + self.assertEqual((1,), tuple(apply(req)[0]), "11, not(10)") + + def test_range(self): + index = self._makeOne("idx") + index.query_options = "range", "usage" # activate `range`, `usage` + apply = index._apply_index + docs = tuple(range(10)) + for i in docs: + index.insertForwardIndexEntry(i, i) + ranges = (9, None), (None, 1), (5, 6), # fails: (None, None), + for op in ("range", "usage"): + for r in ranges: + spec = (["range"] if op == "usage" else []) \ + + (["min"] if r[0] is not None else []) \ + + (["max"] if r[1] is not None else []) + query = {"query": [v for v in r if v is not None], + op: ":".join(spec)} + self.assertEqual( + docs[r[0]: (r[1] + 1 if r[1] is not None else None)], + tuple(apply(dict(idx=query))[0]), + "%s: %s" % (op, r)) diff --git a/src/Products/PluginIndexes/unindex.py b/src/Products/PluginIndexes/unindex.py index c00fcfdc..cd199647 100644 --- a/src/Products/PluginIndexes/unindex.py +++ b/src/Products/PluginIndexes/unindex.py @@ -399,6 +399,11 @@ def _apply_index(self, request, resultset=None): If the query does not match the index, return None, otherwise return a tuple of (result, used_attributes), where used_attributes is again a tuple with the names of all used data fields. + + If not `None`, the resultset argument + indicates that the search result is relevant only on this set, + i.e. everything outside resultset is of no importance. + The index can use this information for optimizations. """ record = IndexQuery(request, self.id, self.query_options, self.operators, self.useOperator) @@ -409,18 +414,10 @@ def _apply_index(self, request, resultset=None): def query_index(self, record, resultset=None): """Search the index with the given IndexQuery object. - If the query has a key which matches the 'id' of - the index instance, one of a few things can happen: - - - if the value is a string, turn the value into - a single-element sequence, and proceed. - - - if the value is a sequence, return a union search. - - - If the value is a dict and contains a key of the form - '_operator' this overrides the default method - ('or') to combine search results. Valid values are 'or' - and 'and'. + If not `None`, the resultset argument + indicates that the search result is relevant only on this set, + i.e. everything outside resultset is of no importance. + The index can use this information for optimizations. """ index = self._index r = None