Skip to content

Commit 5fab6be

Browse files
author
Gerit Wagner
committed
PubMed: RangeQuery
1 parent 83697d2 commit 5fab6be

File tree

6 files changed

+64
-1
lines changed

6 files changed

+64
-1
lines changed

search_query/constants.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class TokenTypes(Enum):
3131
SEARCH_TERM = "SEARCH_TERM"
3232
PARENTHESIS_OPEN = "PARENTHESIS_OPEN"
3333
PARENTHESIS_CLOSED = "PARENTHESIS_CLOSED"
34+
RANGE_OPERATOR = "RANGE_OPERATOR"
3435
UNKNOWN = "UNKNOWN"
3536

3637

@@ -72,6 +73,8 @@ def get_operator_type(self) -> str:
7273
return Operators.OR
7374
if self.value.upper() == "NOT":
7475
return Operators.NOT
76+
if self.value == ":":
77+
return Operators.RANGE
7578
raise ValueError() # pragma: no cover
7679

7780

@@ -115,6 +118,7 @@ class Operators:
115118
NOT = "NOT"
116119
NEAR = "NEAR"
117120
WITHIN = "WITHIN"
121+
RANGE = "RANGE"
118122

119123

120124
class Fields:

search_query/pubmed/linter.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,15 @@ class PubmedQueryStringLinter(QueryStringLinter):
4444
TokenTypes.FIELD: [
4545
TokenTypes.LOGIC_OPERATOR,
4646
TokenTypes.PARENTHESIS_CLOSED,
47+
TokenTypes.RANGE_OPERATOR,
4748
],
4849
TokenTypes.LOGIC_OPERATOR: [
4950
TokenTypes.SEARCH_TERM,
5051
TokenTypes.PARENTHESIS_OPEN,
5152
],
53+
TokenTypes.RANGE_OPERATOR: [
54+
TokenTypes.SEARCH_TERM,
55+
],
5256
}
5357

5458
def __init__(self, query_str: str = "") -> None:

search_query/pubmed/parser.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ def tokenize(self) -> None:
6464

6565
if value.upper() in {"AND", "OR", "NOT", "|", "&"}:
6666
token_type = TokenTypes.LOGIC_OPERATOR
67+
elif value == ":":
68+
token_type = TokenTypes.RANGE_OPERATOR
6769
elif value == "(":
6870
token_type = TokenTypes.PARENTHESIS_OPEN
6971
elif value == ")":
@@ -129,7 +131,10 @@ def _get_operator_indices(self, tokens: list) -> list:
129131
elif token.type == TokenTypes.PARENTHESIS_CLOSED:
130132
i = i - 1
131133

132-
if i == 0 and token.type == TokenTypes.LOGIC_OPERATOR:
134+
if i == 0 and token.type in [
135+
TokenTypes.LOGIC_OPERATOR,
136+
TokenTypes.RANGE_OPERATOR,
137+
]:
133138
operator = token.get_operator_type()
134139
if not first_operator_found:
135140
first_operator = operator

search_query/query.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ def value(self, v: str) -> None:
181181
Operators.NOT,
182182
Operators.NEAR,
183183
Operators.WITHIN,
184+
Operators.RANGE,
184185
]:
185186
raise ValueError(f"Invalid operator value: {v}")
186187
self._value = v

search_query/query_range.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#!/usr/bin/env python
2+
"""Range Query"""
3+
import typing
4+
5+
from search_query.constants import Operators
6+
from search_query.query import Query
7+
from search_query.query import SearchField
8+
9+
# pylint: disable=duplicate-code
10+
11+
12+
class RangeQuery(Query):
13+
"""Range Query"""
14+
15+
def __init__(
16+
self,
17+
children: typing.List[typing.Union[str, Query]],
18+
*,
19+
search_field: typing.Optional[typing.Union[SearchField, str]] = None,
20+
position: typing.Optional[tuple] = None,
21+
platform: str = "generic",
22+
) -> None:
23+
"""init method
24+
search terms: strings which you want to include in the search query
25+
nested queries: queries whose roots are appended to the query
26+
search field: search field to which the query should be applied
27+
"""
28+
assert len(children) == 2, "RangeQuery must have exactly two children"
29+
super().__init__(
30+
value=Operators.RANGE,
31+
children=children,
32+
search_field=search_field
33+
if isinstance(search_field, SearchField)
34+
else SearchField(search_field)
35+
if search_field is not None
36+
else None,
37+
position=position,
38+
platform=platform,
39+
)

test/test_pubmed.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -879,6 +879,16 @@ def test_linter_with_general_search_field(
879879
"All Fields",
880880
'OR["eHealth"[[all]], AND["digital health"[[all]], NOT["bias"[[all]], "equity"[[all]]]], "policy"[[all]]]',
881881
),
882+
(
883+
'eHealth[ti] AND ("2006/01/01"[Date - Create] : "2023/08/18"[Date - Create])',
884+
"",
885+
'AND[eHealth[[ti]], RANGE["2006/01/01"[[Date - Create]], "2023/08/18"[[Date - Create]]]]',
886+
),
887+
(
888+
'("1995/01/01"[pdat] : "3000"[pdat])',
889+
"",
890+
'RANGE["1995/01/01"[[pdat]], "3000"[[pdat]]]',
891+
),
882892
],
883893
)
884894
def test_parser(

0 commit comments

Comments
 (0)