diff --git a/strawberry_django/filters.py b/strawberry_django/filters.py index 60d193a0..a5a343d2 100644 --- a/strawberry_django/filters.py +++ b/strawberry_django/filters.py @@ -26,6 +26,13 @@ from strawberry.types.unset import UnsetType from typing_extensions import Self, assert_never, dataclass_transform, deprecated +# Try to import Maybe at module level for performance +try: + from strawberry import Maybe +except ImportError: + # Maybe type not available in this version of strawberry + Maybe = None # type: ignore[assignment, misc] + from strawberry_django.fields.filter_order import ( RESOLVE_VALUE_META, WITH_NONE_META, @@ -122,6 +129,12 @@ def resolve_value(value: Any) -> Any: if isinstance(value, list): return [resolve_value(v) for v in value] + # Handle strawberry.Maybe type if available + if Maybe is not None and isinstance(value, Maybe): + # Extract .value from Maybe and recursively resolve it + # resolve_value(None) already returns None, so no need for explicit check + return resolve_value(getattr(value, "value", None)) + if isinstance(value, relay.GlobalID): return value.node_id diff --git a/tests/filters/test_filters_v2.py b/tests/filters/test_filters_v2.py index 2c509cef..791f3762 100644 --- a/tests/filters/test_filters_v2.py +++ b/tests/filters/test_filters_v2.py @@ -142,6 +142,55 @@ def test_resolve_value(value, resolved): assert resolve_value(value) == resolved +def test_resolve_value_maybe(): + """Test that strawberry.Maybe type is properly handled in resolve_value.""" + try: + from strawberry import Maybe + except ImportError: + pytest.skip("strawberry.Maybe is not available in this version") + + # Test Maybe with a value + maybe_with_value = Maybe(value="test_string") + assert resolve_value(maybe_with_value) == "test_string" + + # Test Maybe with None + maybe_none = Maybe(value=None) + assert resolve_value(maybe_none) is None + + # Test Maybe with nested types + maybe_enum = Maybe(value=Version.TWO) + assert resolve_value(maybe_enum) == Version.TWO.value + + maybe_gid = Maybe(value=GlobalID("FruitNode", "42")) + assert resolve_value(maybe_gid) == "42" + + # Test Maybe with deeply nested None value + maybe_deep_none = Maybe(value=Maybe(value=None)) + assert resolve_value(maybe_deep_none) is None + + # Test Maybe in a list + maybe_list = [ + Maybe(value=1), + Maybe(value="test"), + Maybe(value=None), + Maybe(value=Version.ONE), + ] + resolved_list = resolve_value(maybe_list) + assert resolved_list == [1, "test", None, Version.ONE.value] + + # Test nested Maybe + nested_maybe = Maybe(value=Maybe(value="nested")) + assert resolve_value(nested_maybe) == "nested" + + # Test list containing nested Maybes + nested_maybe_list = [ + Maybe(value=Maybe(value="foo")), + Maybe(value=None), + ] + resolved_nested_list = resolve_value(nested_maybe_list) + assert resolved_nested_list == ["foo", None] + + def test_filter_field_missing_prefix(): with pytest.raises( MissingFieldArgumentError, match=r".*\"prefix\".*\"field_method\".*"