Add documentation to help specifying types for Unions

Also add an additional test case, update existing ones, to cover
`resolve_type` and `Meta.possible_types` more
This commit is contained in:
Ramon Wenger 2022-06-15 16:03:58 +02:00
parent 9c3e4bb7da
commit 2c92618648
3 changed files with 102 additions and 10 deletions

View File

@ -61,3 +61,63 @@ The above types have the following representation in a schema:
union SearchResult = Human | Droid | Starship
Resolving Types
~~~~~~~~~~~~~~~
When defining Unions, as with Interfaces, we need to tell the schema how to resolve the type of a returned object.
This can be achieved by:
- defining an `is_type_of`-method on each `ObjectType`
- defining the attribute `possible_types` on the Meta class
- defining a `resolve_type` on the Union
Examples:
^^^^^^^^^
An example with `is_type_of` and `Meta.possible_types`:
.. code:: python
class one_object:
one = 'one'
class two_object:
two = 'two'
class One(ObjectType):
one = String()
@classmethod
def is_type_of(cls, root, info):
return isinstance(root, one_object)
class Two(ObjectType):
class Meta:
possible_types = (two_object,)
two = String()
class MyUnion(Union):
class Meta:
types = (One, Two)
An example with `resolve_type`:
.. code:: python
class One(ObjectType):
one = String()
class Two(ObjectType):
two = String()
class MyUnion(Union):
class Meta:
types = (One, Two)
@classmethod
def resolve_type(cls, instance, info)
if hasattr(instance, 'one'):
return One
else:
return Two

View File

@ -65,12 +65,10 @@ def test_query_union():
return isinstance(root, one_object)
class Two(ObjectType):
class Meta:
possible_types = (two_object,)
two = String()
@classmethod
def is_type_of(cls, root, info):
return isinstance(root, two_object)
class MyUnion(Union):
class Meta:
types = (One, Two)
@ -111,13 +109,10 @@ def test_query_interface():
class Two(ObjectType):
class Meta:
interfaces = (MyInterface,)
possible_types = (two_object,)
two = String()
@classmethod
def is_type_of(cls, root, info):
return isinstance(root, two_object)
class Query(ObjectType):
interfaces = List(MyInterface)

View File

@ -4,14 +4,16 @@ from ..field import Field
from ..objecttype import ObjectType
from ..union import Union
from ..unmountedtype import UnmountedType
from ..schema import Schema
from ..scalars import String
class MyObjectType1(ObjectType):
pass
name = Field(String)
class MyObjectType2(ObjectType):
pass
not_name = Field(String)
def test_generate_union():
@ -56,3 +58,38 @@ def test_union_can_be_mounted():
my_union_field = my_union_instance.mount_as(Field)
assert isinstance(my_union_field, Field)
assert my_union_field.type == MyUnion
def test_resolve_type_custom():
class MyUnion(Union):
class Meta:
types = (MyObjectType1, MyObjectType2)
@classmethod
def resolve_type(cls, instance, info):
if 'name' in instance:
return MyObjectType1
else:
return MyObjectType2
class Query(ObjectType):
test = Field(MyUnion)
def resolve_test(_, info):
return {'name': 'Type 1'}
schema = Schema(query=Query)
result = schema.execute(
"""
query {
test {
__typename
...on MyObjectType1 {
name
}
}
}
"""
)
assert not result.errors
assert result.data == {"test": {"__typename": "MyObjectType1", "name": "Type 1"}}