Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Add geometry filters #710

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions strawberry_django/__init__.py
Original file line number Diff line number Diff line change
@@ -37,6 +37,7 @@
"DjangoImageType",
"DjangoModelType",
"FilterLookup",
"GeometryFilterLookup",
"ListInput",
"ManyToManyInput",
"ManyToOneInput",
@@ -71,3 +72,13 @@
"relay",
"type",
]

from django.core.exceptions import ImproperlyConfigured

try:
from .fields.filter_types import GeometryFilterLookup

__all__.append("GeometryFilterLookup")
except ImproperlyConfigured:
# If gdal is not available, skip.
pass
60 changes: 60 additions & 0 deletions strawberry_django/fields/filter_types.py
Original file line number Diff line number Diff line change
@@ -2,19 +2,25 @@
import decimal
import uuid
from typing import (
TYPE_CHECKING,
Annotated,
Generic,
Optional,
TypeVar,
)

import strawberry
from django.core.exceptions import ImproperlyConfigured
from django.db.models import Q
from strawberry import UNSET

from strawberry_django.filters import resolve_value

from .filter_order import filter_field

if TYPE_CHECKING:
from .types import Geometry

T = TypeVar("T")

_SKIP_MSG = "Filter will be skipped on `null` value"
@@ -123,3 +129,57 @@ class DatetimeFilterLookup(DateFilterLookup[T], TimeFilterLookup[T]):
str: FilterLookup,
uuid.UUID: FilterLookup,
}


try:
pass
except ImproperlyConfigured:
# If gdal is not available, skip.
pass
else:

@strawberry.input
class GeometryFilterLookup(Generic[T]):
bbcontains: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET
bboverlaps: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET
contained: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET
contains: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET
contains_properly: Optional[
Annotated["Geometry", strawberry.lazy(".types")]
] = UNSET
coveredby: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET
covers: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET
crosses: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET
disjoint: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET
equals: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET
exacts: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET
intersects: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET
isempty: Optional[bool] = filter_field(
description=f"Test whether it's empty. {_SKIP_MSG}"
)
isvalid: Optional[bool] = filter_field(
description=f"Test whether it's valid. {_SKIP_MSG}"
)
overlaps: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET
touches: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET
within: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET
left: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET
right: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET
overlaps_left: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = (
UNSET
)
overlaps_right: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = (
UNSET
)
overlaps_above: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = (
UNSET
)
overlaps_below: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = (
UNSET
)
strictly_above: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = (
UNSET
)
strictly_below: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = (
UNSET
)
16 changes: 15 additions & 1 deletion strawberry_django/fields/types.py
Original file line number Diff line number Diff line change
@@ -24,6 +24,7 @@
from strawberry.file_uploads.scalars import Upload
from strawberry.scalars import JSON
from strawberry.types.enum import EnumValueDefinition
from strawberry.types.scalar import ScalarWrapper
from strawberry.utils.str_converters import capitalize_first, to_camel_case

from strawberry_django import filters
@@ -348,7 +349,7 @@
Geometry = strawberry.scalar(
NewType("Geometry", geos.GEOSGeometry),
serialize=lambda v: v.tuple if isinstance(v, geos.GEOSGeometry) else v, # type: ignore
parse_value=lambda v: geos.GeometryCollection,
parse_value=lambda v: geos.GEOSGeometry(v),
description=(
"An arbitrary geographical object. One of Point, "
"LineString, LinearRing, Polygon, MultiPoint, MultiLineString, MultiPolygon."
@@ -557,9 +558,22 @@
):
if using_old_filters:
field_type = filters.FilterLookup[field_type]
elif type(
field_type
) is ScalarWrapper and field_type._scalar_definition.name in (

Check failure on line 563 in strawberry_django/fields/types.py

GitHub Actions / Typing

Cannot access attribute "_scalar_definition" for class "type[bool]"   Attribute "_scalar_definition" is unknown (reportAttributeAccessIssue)
"Point",
"LineString",
"LinearRing",
"Polygon",
"MultiPoint",
"MultilineString",
"MultiPolygon",
"Geometry",
):
field_type = filter_types.GeometryFilterLookup[field_type]
else:
field_type = filter_types.type_filter_map.get( # type: ignore
field_type, filter_types.FilterLookup

Check failure on line 576 in strawberry_django/fields/types.py

GitHub Actions / Typing

Argument of type "Any | type[bool] | ScalarWrapper" cannot be assigned to parameter "key" of type "type[ID] | type[bool] | type[date] | type[datetime] | type[time] | type[Decimal] | type[float] | type[int] | type[str] | type[UUID]" in function "get"   Type "Any | type[bool] | ScalarWrapper" is not assignable to type "type[ID] | type[bool] | type[date] | type[datetime] | type[time] | type[Decimal] | type[float] | type[int] | type[str] | type[UUID]"     Type "ScalarWrapper" is not assignable to type "type[ID] | type[bool] | type[date] | type[datetime] | type[time] | type[Decimal] | type[float] | type[int] | type[str] | type[UUID]"       Type "ScalarWrapper" is not assignable to type "type[ID]"       Type "ScalarWrapper" is not assignable to type "type[bool]"       Type "ScalarWrapper" is not assignable to type "type[date]"       Type "ScalarWrapper" is not assignable to type "type[datetime]"       Type "ScalarWrapper" is not assignable to type "type[time]"       Type "ScalarWrapper" is not assignable to type "type[Decimal]" ... (reportArgumentType)
)[field_type]

return field_type