Skip to content

Commit 54ef10e

Browse files
committed
feat: add search operator and fields arguments
allow for more specific search queries by specifying the search_operator and search_fields.
1 parent 4e0a512 commit 54ef10e

File tree

2 files changed

+90
-6
lines changed

2 files changed

+90
-6
lines changed

grapple/types/structures.py

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ class QuerySetList(graphene.List):
3030
* ``limit``
3131
* ``offset``
3232
* ``search_query``
33+
* ``search_operator``
34+
* ``search_fields``
3335
* ``order``
3436
3537
:param enable_limit: Enable limit argument.
@@ -38,6 +40,10 @@ class QuerySetList(graphene.List):
3840
:type enable_offset: bool
3941
:param enable_search: Enable search query argument.
4042
:type enable_search: bool
43+
:param enable_search_fields: Enable search fields argument, enable_search must also be True
44+
:type enable_search_fields: bool
45+
:param enable_search_operator: Enable search operator argument, enable_search must also be True
46+
:type enable_search_operator: bool
4147
:param enable_order: Enable ordering via query argument.
4248
:type enable_order: bool
4349
"""
@@ -46,6 +52,8 @@ def __init__(self, of_type, *args, **kwargs):
4652
enable_limit = kwargs.pop("enable_limit", True)
4753
enable_offset = kwargs.pop("enable_offset", True)
4854
enable_search = kwargs.pop("enable_search", True)
55+
enable_search_fields = kwargs.pop("enable_search_fields", True)
56+
enable_search_operator = kwargs.pop("enable_search_operator", True)
4957
enable_order = kwargs.pop("enable_order", True)
5058

5159
# Check if the type is a Django model type. Do not perform the
@@ -91,6 +99,22 @@ def __init__(self, of_type, *args, **kwargs):
9199
graphene.String,
92100
description=_("Filter the results using Wagtail's search."),
93101
)
102+
if enable_search_operator:
103+
kwargs["search_operator"] = graphene.Argument(
104+
graphene.Enum("SearchOperatorEnum", ["and", "or"]),
105+
description=_(
106+
"Specify search operator (and/or), see: https://docs.wagtail.org/en/stable/topics/search/searching.html#search-operator"
107+
),
108+
default_value="and",
109+
)
110+
111+
if enable_search_fields:
112+
kwargs["search_field"] = graphene.Argument(
113+
graphene.List(graphene.String),
114+
description=_(
115+
"A list of fields to search in. see: https://docs.wagtail.org/en/stable/topics/search/searching.html#specifying-the-fields-to-search"
116+
),
117+
)
94118

95119
if "id" not in kwargs:
96120
kwargs["id"] = graphene.Argument(graphene.ID, description=_("Filter by ID"))
@@ -137,21 +161,29 @@ def PaginatedQuerySet(of_type, type_class, **kwargs):
137161
"""
138162
Paginated QuerySet type with arguments used by Django's query sets.
139163
140-
This type setts the following arguments on itself:
164+
This type sets the following arguments on itself:
141165
142166
* ``id``
143167
* ``page``
144168
* ``per_page``
145169
* ``search_query``
170+
* ``search_operator``
171+
* ``search_fields``
146172
* ``order``
147173
148174
:param enable_search: Enable search query argument.
149175
:type enable_search: bool
176+
:param enable_search_fields: Enable search fields argument, enable_search must also be True
177+
:type enable_search_fields: bool
178+
:param enable_search_operator: Enable search operator argument, enable_search must also be True
179+
:type enable_search_operator: bool
150180
:param enable_order: Enable ordering via query argument.
151181
:type enable_order: bool
152182
"""
153183

154184
enable_search = kwargs.pop("enable_search", True)
185+
enable_search_fields = kwargs.pop("enable_search_fields", True)
186+
enable_search_operator = kwargs.pop("enable_search_operator", True)
155187
enable_order = kwargs.pop("enable_order", True)
156188
required = kwargs.get("required", False)
157189
type_name = type_class if isinstance(type_class, str) else type_class.__name__
@@ -198,6 +230,22 @@ def PaginatedQuerySet(of_type, type_class, **kwargs):
198230
kwargs["search_query"] = graphene.Argument(
199231
graphene.String, description=_("Filter the results using Wagtail's search.")
200232
)
233+
if enable_search_operator:
234+
kwargs["search_operator"] = graphene.Argument(
235+
graphene.Enum("SearchOperatorEnum", ["and", "or"]),
236+
description=_(
237+
"Specify search operator (and/or), see: https://docs.wagtail.org/en/stable/topics/search/searching.html#search-operator"
238+
),
239+
default_value="and",
240+
)
241+
242+
if enable_search_fields:
243+
kwargs["search_field"] = graphene.Argument(
244+
graphene.List(graphene.String),
245+
description=_(
246+
"A list of fields to search in. see: https://docs.wagtail.org/en/stable/topics/search/searching.html#specifying-the-fields-to-search"
247+
),
248+
)
201249

202250
if "id" not in kwargs:
203251
kwargs["id"] = graphene.Argument(graphene.ID, description=_("Filter by ID"))

grapple/utils.py

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from wagtail.models import Site
55
from wagtail.search.index import class_is_indexed
66
from wagtail.search.models import Query
7+
from wagtail.search.utils import parse_query_string
78

89
from .settings import grapple_settings
910
from .types.structures import BasePaginatedType, PaginationType
@@ -62,6 +63,8 @@ def resolve_queryset(
6263
id=None,
6364
order=None,
6465
collection=None,
66+
search_operator="and",
67+
search_fields=None,
6568
**kwargs,
6669
):
6770
"""
@@ -83,6 +86,11 @@ def resolve_queryset(
8386
:type order: str
8487
:param collection: Use Wagtail's collection id to filter images or documents
8588
:type collection: int
89+
:param search_operator: The operator to use when combining search terms.
90+
Defaults to "and".
91+
:type search_operator: "and" | "or"
92+
:param search_fields: A list of fields to search. Defaults to all fields.
93+
:type search_fields: list
8694
"""
8795

8896
if id is not None:
@@ -112,7 +120,14 @@ def resolve_queryset(
112120
query = Query.get(search_query)
113121
query.add_hit()
114122

115-
qs = qs.search(search_query, order_by_relevance=order_by_relevance)
123+
filters, parsed_query = parse_query_string(search_query, search_operator)
124+
125+
qs = qs.search(
126+
parsed_query,
127+
order_by_relevance=order_by_relevance,
128+
operator=search_operator,
129+
fields=search_fields,
130+
)
116131
if connection.vendor != "sqlite":
117132
qs = qs.annotate_score("search_score")
118133

@@ -153,7 +168,16 @@ def get_paginated_result(qs, page, per_page):
153168

154169

155170
def resolve_paginated_queryset(
156-
qs, info, page=None, per_page=None, search_query=None, id=None, order=None, **kwargs
171+
qs,
172+
info,
173+
page=None,
174+
per_page=None,
175+
id=None,
176+
order=None,
177+
search_query=None,
178+
search_operator="and",
179+
search_fields=None,
180+
**kwargs,
157181
):
158182
"""
159183
Add page, per_page and search capabilities to the query. This contains
@@ -167,11 +191,16 @@ def resolve_paginated_queryset(
167191
:type id: int
168192
:param per_page: The maximum number of items to include on a page.
169193
:type per_page: int
194+
:param order: Order the query set using the Django QuerySet order_by format.
195+
:type order: str
170196
:param search_query: Using Wagtail search, exclude objects that do not match
171197
the search query.
172198
:type search_query: str
173-
:param order: Order the query set using the Django QuerySet order_by format.
174-
:type order: str
199+
:param search_operator: The operator to use when combining search terms.
200+
Defaults to "and".
201+
:type search_operator: "and" | "or"
202+
:param search_fields: A list of fields to search. Defaults to all fields.
203+
:type search_fields: list
175204
"""
176205
page = int(page or 1)
177206
per_page = min(
@@ -199,7 +228,14 @@ def resolve_paginated_queryset(
199228
query = Query.get(search_query)
200229
query.add_hit()
201230

202-
qs = qs.search(search_query, order_by_relevance=order_by_relevance)
231+
filters, parsed_query = parse_query_string(search_query, search_operator)
232+
233+
qs = qs.search(
234+
parsed_query,
235+
order_by_relevance=order_by_relevance,
236+
operator=search_operator,
237+
fields=search_fields,
238+
)
203239
if connection.vendor != "sqlite":
204240
qs = qs.annotate_score("search_score")
205241

0 commit comments

Comments
 (0)