mirror of
https://github.com/graphql-python/graphene.git
synced 2025-02-02 12:44:15 +03:00
Improved relay integration
This commit is contained in:
parent
28d89a44f1
commit
41648b5a94
|
@ -21,7 +21,8 @@ class Field(OrderedType):
|
|||
self.name = name
|
||||
if isinstance(type, six.string_types):
|
||||
type = LazyType(type)
|
||||
if required:
|
||||
self.required = required
|
||||
if self.required:
|
||||
type = NonNull(type)
|
||||
self.type = type
|
||||
self.description = description
|
||||
|
@ -68,7 +69,7 @@ class Field(OrderedType):
|
|||
type_objecttype = schema.objecttype(type)
|
||||
if type_objecttype and type_objecttype._meta.is_mutation:
|
||||
assert len(arguments) == 0
|
||||
arguments = type_objecttype.arguments
|
||||
arguments = type_objecttype.get_arguments()
|
||||
resolver = getattr(type_objecttype, 'mutate')
|
||||
|
||||
assert type, 'Internal type for field %s is None' % str(self)
|
||||
|
|
|
@ -52,10 +52,6 @@ class ObjectTypeMeta(type):
|
|||
assert not (
|
||||
new_class._meta.is_interface and new_class._meta.is_mutation)
|
||||
|
||||
input_class = None
|
||||
if new_class._meta.is_mutation:
|
||||
input_class = attrs.pop('Input', None)
|
||||
|
||||
# Add all attributes to the class.
|
||||
for obj_name, obj in attrs.items():
|
||||
new_class.add_to_class(obj_name, obj)
|
||||
|
@ -64,14 +60,6 @@ class ObjectTypeMeta(type):
|
|||
assert hasattr(
|
||||
new_class, 'mutate'), "All mutations must implement mutate method"
|
||||
|
||||
if input_class:
|
||||
items = dict(input_class.__dict__)
|
||||
items.pop('__dict__', None)
|
||||
items.pop('__doc__', None)
|
||||
items.pop('__module__', None)
|
||||
arguments = ArgumentsGroup(**items)
|
||||
new_class.add_to_class('arguments', arguments)
|
||||
|
||||
new_class.add_extra_fields()
|
||||
|
||||
new_fields = new_class._meta.local_fields
|
||||
|
@ -215,7 +203,21 @@ class ObjectType(six.with_metaclass(ObjectTypeMeta, BaseObjectType)):
|
|||
|
||||
|
||||
class Mutation(six.with_metaclass(ObjectTypeMeta, BaseObjectType)):
|
||||
pass
|
||||
@classmethod
|
||||
def _prepare_class(cls):
|
||||
input_class = getattr(cls, 'Input', None)
|
||||
if input_class:
|
||||
items = dict(input_class.__dict__)
|
||||
items.pop('__dict__', None)
|
||||
items.pop('__doc__', None)
|
||||
items.pop('__module__', None)
|
||||
arguments = ArgumentsGroup(**items)
|
||||
cls.add_to_class('arguments', arguments)
|
||||
delattr(cls, 'Input')
|
||||
|
||||
@classmethod
|
||||
def get_arguments(cls):
|
||||
return cls.arguments
|
||||
|
||||
|
||||
class InputObjectType(ObjectType):
|
||||
|
|
|
@ -1,18 +1,21 @@
|
|||
from collections import Iterable
|
||||
|
||||
from graphene.core.fields import Field, IDField
|
||||
from graphene.core.types.scalars import String, ID
|
||||
from graphql.core.type import GraphQLArgument, GraphQLID, GraphQLNonNull
|
||||
from graphql_relay.connection.arrayconnection import connection_from_list
|
||||
from graphql_relay.connection.connection import connection_args
|
||||
from graphql_relay.node.node import from_global_id
|
||||
|
||||
|
||||
class ConnectionField(Field):
|
||||
|
||||
def __init__(self, field_type, resolve=None, description='',
|
||||
def __init__(self, field_type, resolver=None, description='',
|
||||
connection_type=None, edge_type=None, **kwargs):
|
||||
super(ConnectionField, self).__init__(field_type, resolve=resolve,
|
||||
args=connection_args,
|
||||
super(ConnectionField, self).__init__(field_type, resolver=resolver,
|
||||
before=String(),
|
||||
after=String(),
|
||||
first=String(),
|
||||
last=String(),
|
||||
description=description, **kwargs)
|
||||
self.connection_type = connection_type
|
||||
self.edge_type = edge_type
|
||||
|
@ -60,12 +63,9 @@ class NodeField(Field):
|
|||
|
||||
def __init__(self, object_type=None, *args, **kwargs):
|
||||
from graphene.relay.types import Node
|
||||
kwargs['id'] = ID(description='The ID of an object')
|
||||
super(NodeField, self).__init__(object_type or Node, *args, **kwargs)
|
||||
self.field_object_type = object_type
|
||||
self.args['id'] = GraphQLArgument(
|
||||
GraphQLNonNull(GraphQLID),
|
||||
description='The ID of an object'
|
||||
)
|
||||
|
||||
def id_fetcher(self, global_id, info):
|
||||
from graphene.relay.utils import is_node
|
||||
|
@ -88,11 +88,11 @@ class GlobalIDField(IDField):
|
|||
'''The ID of an object'''
|
||||
required = True
|
||||
|
||||
def contribute_to_class(self, cls, name, add=True):
|
||||
def contribute_to_class(self, cls, name):
|
||||
from graphene.relay.utils import is_node, is_node_type
|
||||
in_node = is_node(cls) or is_node_type(cls)
|
||||
assert in_node, 'GlobalIDField could only be inside a Node, but got %r' % cls
|
||||
super(GlobalIDField, self).contribute_to_class(cls, name, add)
|
||||
super(GlobalIDField, self).contribute_to_class(cls, name)
|
||||
|
||||
def resolve(self, instance, args, info):
|
||||
return self.object_type.to_global_id(instance, args, info)
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
from graphene.core.fields import BooleanField, Field, ListField, StringField
|
||||
from graphene.core.types import (InputObjectType, Interface, Mutation,
|
||||
ObjectType)
|
||||
from graphene.core.types.argument import ArgumentsGroup
|
||||
from graphene.core.types.definitions import NonNull
|
||||
from graphene.relay.fields import GlobalIDField
|
||||
from graphene.utils import memoize
|
||||
from graphql_relay.node.node import to_global_id
|
||||
|
@ -90,7 +92,7 @@ class BaseNode(object):
|
|||
|
||||
class Node(BaseNode, Interface):
|
||||
'''An object with an ID'''
|
||||
id = GlobalIDField()
|
||||
id = GlobalIDField(required=True)
|
||||
|
||||
|
||||
class MutationInputType(InputObjectType):
|
||||
|
@ -102,19 +104,19 @@ class ClientIDMutation(Mutation):
|
|||
|
||||
@classmethod
|
||||
def _prepare_class(cls):
|
||||
input_type = getattr(cls, 'input_type', None)
|
||||
if input_type:
|
||||
Input = getattr(cls, 'Input', None)
|
||||
if Input:
|
||||
assert hasattr(
|
||||
cls, 'mutate_and_get_payload'), 'You have to implement mutate_and_get_payload'
|
||||
new_input_inner_type = type('{}InnerInput'.format(
|
||||
cls._meta.type_name), (MutationInputType, input_type, ), {})
|
||||
items = {
|
||||
'input': Field(new_input_inner_type)
|
||||
}
|
||||
assert issubclass(new_input_inner_type, InputObjectType)
|
||||
input_type = type('{}Input'.format(
|
||||
cls._meta.type_name), (ObjectType, ), items)
|
||||
setattr(cls, 'input_type', input_type)
|
||||
|
||||
items = dict(Input.__dict__)
|
||||
items.pop('__dict__', None)
|
||||
new_input_type = type('{}Input'.format(
|
||||
cls._meta.type_name), (MutationInputType, ), items)
|
||||
cls.add_to_class('input_type', new_input_type)
|
||||
arguments = ArgumentsGroup(input=NonNull(new_input_type))
|
||||
cls.add_to_class('arguments', arguments)
|
||||
delattr(cls, 'Input')
|
||||
|
||||
@classmethod
|
||||
def mutate(cls, instance, args, info):
|
||||
|
|
|
@ -32,19 +32,19 @@ class MyResultMutation(graphene.ObjectType):
|
|||
schema = Schema(query=Query, mutation=MyResultMutation)
|
||||
|
||||
|
||||
def test_mutation_input():
|
||||
assert ChangeNumber.input_type
|
||||
assert ChangeNumber.input_type._meta.type_name == 'ChangeNumberInput'
|
||||
assert list(ChangeNumber.input_type._meta.fields_map.keys()) == ['input']
|
||||
_input = ChangeNumber.input_type._meta.fields_map['input']
|
||||
inner_type = _input.get_object_type(schema)
|
||||
client_mutation_id_field = inner_type._meta.fields_map[
|
||||
'client_mutation_id']
|
||||
assert issubclass(inner_type, InputObjectType)
|
||||
assert isinstance(client_mutation_id_field, graphene.StringField)
|
||||
assert client_mutation_id_field.object_type == inner_type
|
||||
assert isinstance(client_mutation_id_field.internal_field(
|
||||
schema), GraphQLInputObjectField)
|
||||
def test_mutation_arguments():
|
||||
assert ChangeNumber.arguments
|
||||
assert list(ChangeNumber.arguments) == ['input']
|
||||
_input = ChangeNumber.arguments['input']
|
||||
|
||||
# inner_type = _input.get_object_type(schema)
|
||||
# client_mutation_id_field = inner_type._meta.fields_map[
|
||||
# 'client_mutation_id']
|
||||
# assert issubclass(inner_type, InputObjectType)
|
||||
# assert isinstance(client_mutation_id_field, graphene.StringField)
|
||||
# assert client_mutation_id_field.object_type == inner_type
|
||||
# assert isinstance(client_mutation_id_field.internal_field(
|
||||
# schema), GraphQLInputObjectField)
|
||||
|
||||
|
||||
def test_execute_mutations():
|
||||
|
|
|
@ -21,7 +21,7 @@ class MyNode(relay.Node):
|
|||
class Query(graphene.ObjectType):
|
||||
my_node = relay.NodeField(MyNode)
|
||||
all_my_nodes = relay.ConnectionField(
|
||||
MyNode, connection_type=MyConnection, customArg=graphene.Argument(graphene.String))
|
||||
MyNode, connection_type=MyConnection, customArg=graphene.String())
|
||||
|
||||
def resolve_all_my_nodes(self, args, info):
|
||||
custom_arg = args.get('customArg')
|
||||
|
@ -73,5 +73,6 @@ def test_nodefield_query():
|
|||
|
||||
def test_nodeidfield():
|
||||
id_field = MyNode._meta.fields_map['id']
|
||||
assert isinstance(id_field.internal_field(schema).type, GraphQLNonNull)
|
||||
assert id_field.internal_field(schema).type.of_type == GraphQLID
|
||||
id_field_type = schema.T(id_field)
|
||||
assert isinstance(id_field_type.type, GraphQLNonNull)
|
||||
assert id_field_type.type.of_type == GraphQLID
|
||||
|
|
Loading…
Reference in New Issue
Block a user