From 74f333d16cd8b79994e69ce00446177e69c3685a Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 8 Jun 2019 20:47:20 -0400 Subject: [PATCH] Improve search negation logic Only dashes at the start of terms and outside of quotes are now interpreted as negation. Signed-off-by: Roberto Rosario --- HISTORY.rst | 2 +- docs/releases/3.2.rst | 2 + mayan/apps/dynamic_search/classes.py | 85 ++++++++++++------- .../apps/dynamic_search/tests/test_models.py | 19 +++++ 4 files changed, 74 insertions(+), 34 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index d4a220b1cf..463a8e4b82 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -283,7 +283,7 @@ * Add support for Google Fonts dependencies. * Add support for patchin dependency files using rewriting rules. * Allow searching documents by UUID. - +* Improve search negation logic. 3.1.11 (2019-04-XX) =================== diff --git a/docs/releases/3.2.rst b/docs/releases/3.2.rst index d73a7776d1..24858814d3 100644 --- a/docs/releases/3.2.rst +++ b/docs/releases/3.2.rst @@ -711,6 +711,8 @@ Other changes - Add support for Google Fonts dependencies. - Add support for patchin dependency files using rewriting rules. - Allow searching documents by UUID. +- Improve search negation logic. Only dashes at the start of terms and + outside of quotes are now interpreted as negation. Removals diff --git a/mayan/apps/dynamic_search/classes.py b/mayan/apps/dynamic_search/classes.py index 74f4ee51c5..caa019bb4e 100644 --- a/mayan/apps/dynamic_search/classes.py +++ b/mayan/apps/dynamic_search/classes.py @@ -255,47 +255,66 @@ class SearchTermCollection(object): self.terms = [] for letter in text: - if not inside_quotes and letter == TERM_NEGATION_CHARACTER: - negated = True + if letter in TERM_QUOTES: + if inside_quotes: + if term_letters: + term_string = ''.join(term_letters) + negated = False + if term_string.startswith(TERM_NEGATION_CHARACTER): + term_string = term_string[1:] + negated = True + + self.terms.append( + SearchTerm( + is_meta=False, negated=negated, + string=term_string + ) + ) + negated = False + term_letters = [] + + inside_quotes = not inside_quotes else: - if letter in TERM_QUOTES: - if inside_quotes: - if term_letters: - self.terms.append( - SearchTerm( - is_meta=False, negated=negated, - string=''.join(term_letters) - ) - ) - negated = False - term_letters = [] + if not inside_quotes and letter == TERM_SPACE_CHARACTER: + if term_letters: + term_string = ''.join(term_letters) + if term_string in TERM_OPERATIONS: + is_meta = True + else: + is_meta = False - inside_quotes = not inside_quotes + print("NEW TERM", ''.join(term_letters)) + + if is_meta: + negated = False + else: + negated = False + if term_string.startswith(TERM_NEGATION_CHARACTER): + term_string = term_string[1:] + negated = True + + self.terms.append( + SearchTerm( + is_meta=is_meta, negated=negated, + string=term_string + ) + ) + negated = False + term_letters = [] else: - if not inside_quotes and letter == TERM_SPACE_CHARACTER: - if term_letters: - term_string = ''.join(term_letters) - if term_string in TERM_OPERATIONS: - is_meta = True - else: - is_meta = False - - self.terms.append( - SearchTerm( - is_meta=is_meta, negated=negated, - string=term_string - ) - ) - negated = False - term_letters = [] - else: - term_letters.append(letter) + term_letters.append(letter) if term_letters: + term_string = ''.join(term_letters) + negated = False + if term_string.startswith(TERM_NEGATION_CHARACTER): + term_string = term_string[1:] + negated = True + self.terms.append( SearchTerm( is_meta=False, negated=negated, - string=''.join(term_letters) + string=term_string ) ) diff --git a/mayan/apps/dynamic_search/tests/test_models.py b/mayan/apps/dynamic_search/tests/test_models.py index e3bfaf7d29..83114a8b9a 100644 --- a/mayan/apps/dynamic_search/tests/test_models.py +++ b/mayan/apps/dynamic_search/tests/test_models.py @@ -1,5 +1,7 @@ from __future__ import unicode_literals +from django.utils.encoding import force_text + from mayan.apps.common.tests import BaseTestCase from mayan.apps.documents.permissions import permission_document_view from mayan.apps.documents.search import document_search @@ -139,3 +141,20 @@ class DocumentSearchTestCase(DocumentTestMixin, BaseTestCase): {'label': '-non_valid -second'}, user=self._test_case_user ) self.assertEqual(queryset.count(), 0) + + def test_search_with_dashed_content(self): + self.upload_document(label='second-document') + + self.grant_access( + obj=self.test_document, permission=permission_document_view + ) + + queryset = document_search.search( + {'label': '-second-document'}, user=self._test_case_user + ) + self.assertEqual(queryset.count(), 0) + + queryset = document_search.search( + {'label': '-"second-document"'}, user=self._test_case_user + ) + self.assertEqual(queryset.count(), 0)