Added support for UnionTypes

This commit is contained in:
Syrus Akbary 2015-11-16 19:48:51 -08:00
parent d2ca8a96a9
commit 24cd190f95
5 changed files with 49 additions and 6 deletions

View File

@ -8,7 +8,7 @@ Graphene is a Python library for building GraphQL schemas/types fast and easily.
- **Django:** Automatic *Django model* mapping to Graphene Types. Check a fully working [Django](http://github.com/graphql-python/swapi-graphene) implementation
*But, what is supported in this Python version?* **Everything**: Interfaces, ObjectTypes, Mutations and Relay (Nodes, Connections and Mutations).
*What is supported in this Python version?* **Everything**: Interfaces, ObjectTypes, Mutations, Scalars, Unions and Relay (Nodes, Connections and Mutations).
## Installation

View File

@ -12,9 +12,9 @@ easily.
`Django <http://github.com/graphql-python/swapi-graphene>`__
implementation
*But, what is supported in this Python version?* **Everything**:
Interfaces, ObjectTypes, Mutations and Relay (Nodes, Connections and
Mutations).
*What is supported in this Python version?* **Everything**: Interfaces,
ObjectTypes, Mutations, Scalars, Unions and Relay (Nodes, Connections
and Mutations).
Installation
------------

View File

@ -13,8 +13,10 @@ class Options(object):
self.local_fields = []
self.is_interface = False
self.is_mutation = False
self.is_union = False
self.interfaces = []
self.parents = []
self.types = []
self.valid_attrs = DEFAULT_NAMES
def contribute_to_class(self, cls, name):

View File

@ -7,7 +7,7 @@ import six
from graphene import signals
from graphql.core.type import (GraphQLInputObjectType, GraphQLInterfaceType,
GraphQLObjectType)
GraphQLObjectType, GraphQLUnionType)
from ..exceptions import SkipField
from ..options import Options
@ -51,10 +51,17 @@ class ObjectTypeMeta(type):
new_class._meta.is_interface = new_class.is_interface(parents)
new_class._meta.is_mutation = new_class.is_mutation(parents)
union_types = [p for p in parents if issubclass(p, BaseObjectType)]
new_class._meta.is_union = len(union_types) > 1
new_class._meta.types = union_types
assert not (
new_class._meta.is_interface and new_class._meta.is_mutation)
assert not (
new_class._meta.is_interface and new_class._meta.is_union)
# Add all attributes to the class.
for obj_name, obj in attrs.items():
new_class.add_to_class(obj_name, obj)
@ -66,6 +73,8 @@ class ObjectTypeMeta(type):
new_class.add_extra_fields()
new_fields = new_class._meta.local_fields
assert not(new_class._meta.is_union and new_fields), 'An union cannot have extra fields'
field_names = {f.name: f for f in new_fields}
for base in parents:
@ -129,6 +138,8 @@ class BaseObjectType(BaseType):
def __new__(cls, *args, **kwargs):
if cls._meta.is_interface:
raise Exception("An interface cannot be initialized")
if cls._meta.is_union:
raise Exception("An union cannot be initialized")
return super(BaseObjectType, cls).__new__(cls)
def __init__(self, *args, **kwargs):
@ -182,6 +193,12 @@ class BaseObjectType(BaseType):
resolve_type=partial(cls.resolve_type, schema),
fields=partial(cls.get_fields, schema)
)
elif cls._meta.is_union:
return GraphQLUnionType(
cls._meta.type_name,
types=cls._meta.types,
description=cls._meta.description,
)
return GraphQLObjectType(
cls._meta.type_name,
description=cls._meta.description,

View File

@ -4,7 +4,8 @@ from graphene.core.schema import Schema
from graphene.core.types import Int, Interface, String
from graphql.core.execution.middlewares.utils import (resolver_has_tag,
tag_resolver)
from graphql.core.type import GraphQLInterfaceType, GraphQLObjectType
from graphql.core.type import (GraphQLInterfaceType, GraphQLObjectType,
GraphQLUnionType)
class Character(Interface):
@ -34,6 +35,16 @@ class Human(Character):
def write_prop(self, value):
self._write_prop = value
class Droid(Character):
'''Droid description'''
pass
class CharacterType(Droid, Human):
'''Union Type'''
pass
schema = Schema()
@ -52,6 +63,19 @@ def test_interface_cannot_initialize():
assert 'An interface cannot be initialized' == str(excinfo.value)
def test_union():
object_type = schema.T(CharacterType)
assert CharacterType._meta.is_union is True
assert isinstance(object_type, GraphQLUnionType)
assert object_type.description == 'Union Type'
def test_union_cannot_initialize():
with raises(Exception) as excinfo:
CharacterType()
assert 'An union cannot be initialized' == str(excinfo.value)
def test_interface_resolve_type():
resolve_type = Character.resolve_type(schema, Human(object()))
assert isinstance(resolve_type, GraphQLObjectType)