From 89742be6af147bb42f2933803f2230de30ac197f Mon Sep 17 00:00:00 2001 From: James Kent Date: Tue, 12 Nov 2024 14:31:47 -0600 Subject: [PATCH 1/2] add func.to_tsquery --- store/neurostore/resources/base.py | 2 +- store/neurostore/tests/api/test_query_params.py | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/store/neurostore/resources/base.py b/store/neurostore/resources/base.py index b5ca5f72..76a0b076 100644 --- a/store/neurostore/resources/base.py +++ b/store/neurostore/resources/base.py @@ -619,7 +619,7 @@ def search(self): validate_search_query(s) except errors.SyntaxError as e: abort(400, description=e.args[0]) - tsquery = pubmed_to_tsquery(s) + tsquery = func.to_tsquery('english', pubmed_to_tsquery(s)) q = q.filter(m._ts_vector.op("@@")(tsquery)) # Alternatively (or in addition), search on individual fields. diff --git a/store/neurostore/tests/api/test_query_params.py b/store/neurostore/tests/api/test_query_params.py index ad8f2bd5..ec022137 100644 --- a/store/neurostore/tests/api/test_query_params.py +++ b/store/neurostore/tests/api/test_query_params.py @@ -97,9 +97,11 @@ def test_multiword_queries(auth_client, ingest_neurosynth, session): single_word_search = auth_client.get(f"/api/studies/?search={single_word}") assert single_word_search.status_code == 200 + assert len(single_word_search.json()["results"]) > 0 multi_word_search = auth_client.get(f"/api/studies/?search={multiple_words}") assert multi_word_search.status_code == 200 + assert len(multi_word_search.json()["results"]) > 0 @pytest.mark.parametrize("query, expected", valid_queries) From cd4a65cc3d6aaa5b904224321e82eaca6bfa464f Mon Sep 17 00:00:00 2001 From: James Kent Date: Mon, 18 Nov 2024 15:09:39 -0600 Subject: [PATCH 2/2] check for multiple operators --- store/neurostore/resources/utils.py | 13 +++++++++++++ store/neurostore/tests/conftest.py | 3 +++ 2 files changed, 16 insertions(+) diff --git a/store/neurostore/resources/utils.py b/store/neurostore/resources/utils.py index 08974e35..2733a531 100644 --- a/store/neurostore/resources/utils.py +++ b/store/neurostore/resources/utils.py @@ -65,6 +65,9 @@ def validate_search_query(query: str) -> bool: if not validate_query_end(query): raise errors.SyntaxError("Query cannot end with an operator") + if not validate_multiple_operators(query): + raise errors.SyntaxError("Consecutive operators are not allowed") + return True @@ -98,6 +101,16 @@ def validate_query_end(query: str) -> bool: return True +def validate_multiple_operators(query: str) -> bool: + """Validate that there are no consecutive operators in a query.""" + operators = ("AND", "OR", "NOT", "&", "|", "&!") + query = query.strip().split(" ") + for i in range(len(query) - 1): + if query[i] in operators and query[i + 1] in operators: + return False + return True + + def count_chars(target, query: str) -> int: """Count the number of chars in a query string. Excluding those in quoted phrases.""" diff --git a/store/neurostore/tests/conftest.py b/store/neurostore/tests/conftest.py index 1189e214..b2762793 100644 --- a/store/neurostore/tests/conftest.py +++ b/store/neurostore/tests/conftest.py @@ -602,6 +602,9 @@ def simple_neurosynth_annotation(session, ingest_neurosynth): 'OR ("ASD")) AND (("decision*" OR "Dec', "Unmatched parentheses", ), + ( + 'smoking AND NOT memory', "Consecutive operators are not allowed" + ) ] valid_queries = [