diff --git a/RELEASE.md b/RELEASE.md new file mode 100644 index 0000000000..ff1f19f011 --- /dev/null +++ b/RELEASE.md @@ -0,0 +1,3 @@ +Release type: patch + +Adds support for lazy unions. diff --git a/strawberry/schema/schema_converter.py b/strawberry/schema/schema_converter.py index 24a0857c4b..efb3ca3295 100644 --- a/strawberry/schema/schema_converter.py +++ b/strawberry/schema/schema_converter.py @@ -2,9 +2,11 @@ import dataclasses import sys +import typing from functools import partial, reduce from typing import ( TYPE_CHECKING, + Annotated, Any, Callable, Generic, @@ -862,6 +864,12 @@ def from_type(self, type_: Union[StrawberryType, type]) -> GraphQLNullableType: if compat.is_graphql_generic(type_): raise MissingTypesForGenericError(type_) + # to handle lazy unions + if typing.get_origin(type_) is Annotated: + args = typing.get_args(type_) + if len(args) >= 2 and isinstance(args[1], StrawberryUnion): + type_ = args[1] + if isinstance(type_, EnumDefinition): # TODO: Replace with StrawberryEnum return self.from_enum(type_) if compat.is_input_type(type_): # TODO: Replace with StrawberryInputObject diff --git a/tests/schema/test_lazy_types/test_lazy_unions.py b/tests/schema/test_lazy_types/test_lazy_unions.py new file mode 100644 index 0000000000..e942143430 --- /dev/null +++ b/tests/schema/test_lazy_types/test_lazy_unions.py @@ -0,0 +1,90 @@ +import textwrap +from typing import Annotated, Union + +import strawberry +from strawberry.printer import print_schema + + +@strawberry.type +class TypeA: + a: int + + +@strawberry.type +class TypeB: + b: int + + +ABUnion = Annotated[ + Union[TypeA, TypeB], strawberry.union("ABUnion", types=[TypeA, TypeB]) +] + + +TypeALazy = Annotated[ + "TypeA", strawberry.lazy("tests.schema.test_lazy_types.test_lazy_unions") +] +TypeBLazy = Annotated[ + "TypeB", strawberry.lazy("tests.schema.test_lazy_types.test_lazy_unions") +] +LazyABUnion = Annotated[ + Union[ + TypeALazy, + TypeBLazy, + ], + strawberry.union("LazyABUnion", types=[TypeALazy, TypeBLazy]), +] + + +def test_lazy_union_with_non_lazy_members(): + @strawberry.type + class Query: + ab: Annotated[ + "ABUnion", strawberry.lazy("tests.schema.test_lazy_types.test_lazy_unions") + ] + + expected = """ + union ABUnion = TypeA | TypeB + + type Query { + ab: ABUnion! + } + + type TypeA { + a: Int! + } + + type TypeB { + b: Int! + } + """ + + schema = strawberry.Schema(query=Query) + assert print_schema(schema) == textwrap.dedent(expected).strip() + + +def test_lazy_union_with_lazy_members(): + @strawberry.type + class Query: + ab: Annotated[ + "LazyABUnion", + strawberry.lazy("tests.schema.test_lazy_types.test_lazy_unions"), + ] + + expected = """ + union LazyABUnion = TypeA | TypeB + + type Query { + ab: LazyABUnion! + } + + type TypeA { + a: Int! + } + + type TypeB { + b: Int! + } + """ + + schema = strawberry.Schema(query=Query) + assert print_schema(schema) == textwrap.dedent(expected).strip()