Skip to content

Commit

Permalink
feat: add search operator and fields arguments
Browse files Browse the repository at this point in the history
allow for more specific search queries by specifying the search_operator
and search_fields.
  • Loading branch information
dopry committed May 12, 2023
1 parent 4e0a512 commit 54ef10e
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 6 deletions.
50 changes: 49 additions & 1 deletion grapple/types/structures.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ class QuerySetList(graphene.List):
* ``limit``
* ``offset``
* ``search_query``
* ``search_operator``
* ``search_fields``
* ``order``
:param enable_limit: Enable limit argument.
Expand All @@ -38,6 +40,10 @@ class QuerySetList(graphene.List):
:type enable_offset: bool
:param enable_search: Enable search query argument.
:type enable_search: bool
:param enable_search_fields: Enable search fields argument, enable_search must also be True
:type enable_search_fields: bool
:param enable_search_operator: Enable search operator argument, enable_search must also be True
:type enable_search_operator: bool
:param enable_order: Enable ordering via query argument.
:type enable_order: bool
"""
Expand All @@ -46,6 +52,8 @@ def __init__(self, of_type, *args, **kwargs):
enable_limit = kwargs.pop("enable_limit", True)
enable_offset = kwargs.pop("enable_offset", True)
enable_search = kwargs.pop("enable_search", True)
enable_search_fields = kwargs.pop("enable_search_fields", True)
enable_search_operator = kwargs.pop("enable_search_operator", True)
enable_order = kwargs.pop("enable_order", True)

# Check if the type is a Django model type. Do not perform the
Expand Down Expand Up @@ -91,6 +99,22 @@ def __init__(self, of_type, *args, **kwargs):
graphene.String,
description=_("Filter the results using Wagtail's search."),
)
if enable_search_operator:
kwargs["search_operator"] = graphene.Argument(
graphene.Enum("SearchOperatorEnum", ["and", "or"]),
description=_(
"Specify search operator (and/or), see: https://docs.wagtail.org/en/stable/topics/search/searching.html#search-operator"
),
default_value="and",
)

if enable_search_fields:
kwargs["search_field"] = graphene.Argument(
graphene.List(graphene.String),
description=_(
"A list of fields to search in. see: https://docs.wagtail.org/en/stable/topics/search/searching.html#specifying-the-fields-to-search"
),
)

if "id" not in kwargs:
kwargs["id"] = graphene.Argument(graphene.ID, description=_("Filter by ID"))
Expand Down Expand Up @@ -137,21 +161,29 @@ def PaginatedQuerySet(of_type, type_class, **kwargs):
"""
Paginated QuerySet type with arguments used by Django's query sets.
This type setts the following arguments on itself:
This type sets the following arguments on itself:
* ``id``
* ``page``
* ``per_page``
* ``search_query``
* ``search_operator``
* ``search_fields``
* ``order``
:param enable_search: Enable search query argument.
:type enable_search: bool
:param enable_search_fields: Enable search fields argument, enable_search must also be True
:type enable_search_fields: bool
:param enable_search_operator: Enable search operator argument, enable_search must also be True
:type enable_search_operator: bool
:param enable_order: Enable ordering via query argument.
:type enable_order: bool
"""

enable_search = kwargs.pop("enable_search", True)
enable_search_fields = kwargs.pop("enable_search_fields", True)
enable_search_operator = kwargs.pop("enable_search_operator", True)
enable_order = kwargs.pop("enable_order", True)
required = kwargs.get("required", False)
type_name = type_class if isinstance(type_class, str) else type_class.__name__
Expand Down Expand Up @@ -198,6 +230,22 @@ def PaginatedQuerySet(of_type, type_class, **kwargs):
kwargs["search_query"] = graphene.Argument(
graphene.String, description=_("Filter the results using Wagtail's search.")
)
if enable_search_operator:
kwargs["search_operator"] = graphene.Argument(
graphene.Enum("SearchOperatorEnum", ["and", "or"]),
description=_(
"Specify search operator (and/or), see: https://docs.wagtail.org/en/stable/topics/search/searching.html#search-operator"
),
default_value="and",
)

if enable_search_fields:
kwargs["search_field"] = graphene.Argument(
graphene.List(graphene.String),
description=_(
"A list of fields to search in. see: https://docs.wagtail.org/en/stable/topics/search/searching.html#specifying-the-fields-to-search"
),
)

if "id" not in kwargs:
kwargs["id"] = graphene.Argument(graphene.ID, description=_("Filter by ID"))
Expand Down
46 changes: 41 additions & 5 deletions grapple/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from wagtail.models import Site
from wagtail.search.index import class_is_indexed
from wagtail.search.models import Query
from wagtail.search.utils import parse_query_string

from .settings import grapple_settings
from .types.structures import BasePaginatedType, PaginationType
Expand Down Expand Up @@ -62,6 +63,8 @@ def resolve_queryset(
id=None,
order=None,
collection=None,
search_operator="and",
search_fields=None,
**kwargs,
):
"""
Expand All @@ -83,6 +86,11 @@ def resolve_queryset(
:type order: str
:param collection: Use Wagtail's collection id to filter images or documents
:type collection: int
:param search_operator: The operator to use when combining search terms.
Defaults to "and".
:type search_operator: "and" | "or"
:param search_fields: A list of fields to search. Defaults to all fields.
:type search_fields: list
"""

if id is not None:
Expand Down Expand Up @@ -112,7 +120,14 @@ def resolve_queryset(
query = Query.get(search_query)
query.add_hit()

qs = qs.search(search_query, order_by_relevance=order_by_relevance)
filters, parsed_query = parse_query_string(search_query, search_operator)

qs = qs.search(
parsed_query,
order_by_relevance=order_by_relevance,
operator=search_operator,
fields=search_fields,
)
if connection.vendor != "sqlite":
qs = qs.annotate_score("search_score")

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


def resolve_paginated_queryset(
qs, info, page=None, per_page=None, search_query=None, id=None, order=None, **kwargs
qs,
info,
page=None,
per_page=None,
id=None,
order=None,
search_query=None,
search_operator="and",
search_fields=None,
**kwargs,
):
"""
Add page, per_page and search capabilities to the query. This contains
Expand All @@ -167,11 +191,16 @@ def resolve_paginated_queryset(
:type id: int
:param per_page: The maximum number of items to include on a page.
:type per_page: int
:param order: Order the query set using the Django QuerySet order_by format.
:type order: str
:param search_query: Using Wagtail search, exclude objects that do not match
the search query.
:type search_query: str
:param order: Order the query set using the Django QuerySet order_by format.
:type order: str
:param search_operator: The operator to use when combining search terms.
Defaults to "and".
:type search_operator: "and" | "or"
:param search_fields: A list of fields to search. Defaults to all fields.
:type search_fields: list
"""
page = int(page or 1)
per_page = min(
Expand Down Expand Up @@ -199,7 +228,14 @@ def resolve_paginated_queryset(
query = Query.get(search_query)
query.add_hit()

qs = qs.search(search_query, order_by_relevance=order_by_relevance)
filters, parsed_query = parse_query_string(search_query, search_operator)

qs = qs.search(
parsed_query,
order_by_relevance=order_by_relevance,
operator=search_operator,
fields=search_fields,
)
if connection.vendor != "sqlite":
qs = qs.annotate_score("search_score")

Expand Down

0 comments on commit 54ef10e

Please sign in to comment.