Unions
In this section, we'll cover how GraphQL Unions work in Undine.
Unions are abstract GraphQL types that represent a group of ObjectTypes
that need to be returned together, e.g. for a search result.
UnionType
In Undine, a GraphQL Union between two or more QueryTypes
is implemented using a UnionType
.
| from undine import QueryType, UnionType
from .models import Project, Task
class TaskType(QueryType[Task]): ...
class ProjectType(QueryType[Project]): ...
class SearchObjects(UnionType[TaskType, ProjectType]): ...
|
A UnionType
can be added to a schema using an Entrypoint
.
Note that UnionType
should always be added using a list Entrypoint
(e.g. many=True
).
| from undine import Entrypoint, QueryType, RootType, UnionType
from .models import Project, Task
class TaskType(QueryType[Task]): ...
class ProjectType(QueryType[Project]): ...
class SearchObjects(UnionType[TaskType, ProjectType]): ...
class Query(RootType):
search_objects = Entrypoint(SearchObjects, many=True)
|
This Entrypoint
can be queried like this:
| query {
searchObjects {
__typename
... on TaskType {
name
}
... on ProjectType {
name
}
}
}
|
Filtering
By default, the UnionType
will return all instances of the QueryTypes
it contains.
However, if those QueryTypes
implement a FilterSet
or an
OrderSet
, those will also be available on the UnionType
Entrypoint
.
| from undine import Entrypoint, FilterSet, OrderSet, QueryType, RootType, UnionType
from .models import Project, Task
class TaskFilterSet(FilterSet[Task]): ...
class TaskOrderSet(OrderSet[Task]): ...
class TaskType(QueryType[Task], filterset=TaskFilterSet, orderset=TaskOrderSet): ...
class ProjectFilterSet(FilterSet[Project]): ...
class ProjectOrderSet(OrderSet[Project]): ...
class ProjectType(QueryType[Project], filterset=ProjectFilterSet, orderset=ProjectOrderSet): ...
class SearchObjects(UnionType[TaskType, ProjectType]): ...
class Query(RootType):
search_objects = Entrypoint(SearchObjects, many=True)
|
This creates the following Entrypoint
:
| type Query {
searchObjects(
filterTask: TaskFilterSet
orderByTask: [TaskOrderSet!]
filterProject: ProjectFilterSet
orderByProject: [ProjectOrderSet!]
): [Commentable!]!
}
|
This allows filtering the different types of models in the UnionType
separately.
The UnionType
also provides a __process_results__
method that can be used to filter the
results of the union after everything has been fetched.
| from undine import GQLInfo, QueryType, UnionType
from .models import Project, Task
class TaskType(QueryType[Task]): ...
class ProjectType(QueryType[Project]): ...
class SearchObjects(UnionType[TaskType, ProjectType]):
@classmethod
def __process_results__(cls, instances: list[Task | Project], info: GQLInfo) -> list[Task | Project]:
return sorted(instances, key=lambda i: i.name)
|
By default, the number of items returned is limited per model in the UnionType
.
This is set by the ENTRYPOINT_LIMIT_PER_MODEL
setting,
but can also be changed per Entrypoint
using the limit
argument:
| from undine import Entrypoint, QueryType, RootType, UnionType
from .models import Project, Task
class TaskType(QueryType[Task]): ...
class ProjectType(QueryType[Project]): ...
class SearchObjects(UnionType[TaskType, ProjectType]): ...
class Query(RootType):
search_objects = Entrypoint(SearchObjects, many=True, limit=10)
|
What about pagination?
Pagination of UnionTypes
is not supported yet.
Schema name
By default, the name of the generated GraphQL Union
is the same as the name of the UnionType
class.
If you want to change the name, you can do so by setting the schema_name
argument:
| from undine import QueryType, UnionType
from .models import Project, Task
class TaskType(QueryType[Task]): ...
class ProjectType(QueryType[Project]): ...
class SearchObjects(UnionType[TaskType, ProjectType], schema_name="Search"): ...
|
Description
A description for a UnionType
can be provided as a docstring.
| from undine import QueryType, UnionType
from .models import Project, Task
class TaskType(QueryType[Task]): ...
class ProjectType(QueryType[Project]): ...
class SearchObjects(UnionType[TaskType, ProjectType]):
"""Description"""
|
GraphQL Extensions
You can provide custom extensions for the UnionType
by providing a
extensions
argument with a dictionary containing them.
| from undine import QueryType, UnionType
from .models import Project, Task
class TaskType(QueryType[Task]): ...
class ProjectType(QueryType[Project]): ...
class SearchObjects(UnionType[TaskType, ProjectType], extensions={"foo": "bar"}): ...
|
UnionType
extensions are made available in the GraphQL UnionType
extensions
after the schema is created. The UnionType
itself is found in the extensions
under a key defined by the QUERY_TYPE_UNION_EXTENSIONS_KEY
setting.