Improved relay integration and abstraction

This commit is contained in:
Syrus Akbary 2016-06-19 14:28:47 -07:00
parent 4de77c95e1
commit d3f98d75f6
2 changed files with 59 additions and 40 deletions

View File

@ -91,15 +91,11 @@ class IterableConnectionField(Field):
assert issubclass(connection_type, Connection), '{} type have to be a subclass of Connection'.format(str(self)) assert issubclass(connection_type, Connection), '{} type have to be a subclass of Connection'.format(str(self))
return connection_type return connection_type
@property def connection_resolver(self, root, args, context, info):
def resolver(self): iterable = super(ConnectionField, self).resolver(root, args, context, info)
super_resolver = super(ConnectionField, self).resolver
def resolver(root, args, context, info):
iterable = super_resolver(root, args, context, info)
# if isinstance(resolved, self.type.graphene) # if isinstance(resolved, self.type.graphene)
assert isinstance( assert isinstance(
iterable, Iterable), 'Resolved value from the connection field have to be iterable' iterable, Iterable), 'Resolved value from the connection field have to be iterable. Received "{}"'.format(iterable)
connection = connection_from_list( connection = connection_from_list(
iterable, iterable,
args, args,
@ -107,7 +103,10 @@ class IterableConnectionField(Field):
edge_type=self.connection.Edge, edge_type=self.connection.Edge,
) )
return connection return connection
return resolver
@property
def resolver(self):
return self.connection_resolver
@resolver.setter @resolver.setter
def resolver(self, resolver): def resolver(self, resolver):

View File

@ -6,41 +6,59 @@ from graphql_relay import from_global_id, node_definitions, to_global_id
from ..types.field import Field from ..types.field import Field
from ..types.interface import Interface from ..types.interface import Interface
from ..types.objecttype import ObjectType, ObjectTypeMeta from ..types.objecttype import ObjectType, ObjectTypeMeta, is_objecttype
from ..types.options import Options from ..types.options import Options
from .connection import Connection from .connection import Connection
# We inherit from ObjectTypeMeta as we want to allow
# inheriting from Node, and also ObjectType.
# Like class MyNode(Node): pass
# And class MyNodeImplementation(Node, ObjectType): pass
class NodeMeta(ObjectTypeMeta): class NodeMeta(ObjectTypeMeta):
def __new__(cls, name, bases, attrs): @staticmethod
cls = super(NodeMeta, cls).__new__(cls, name, bases, attrs) def _get_interface_options(meta):
is_object_type = cls.is_object_type() return Options(
if not is_object_type: meta,
get_node_from_global_id = getattr(cls, 'get_node_from_global_id', None)
id_resolver = getattr(cls, 'id_resolver', None)
assert get_node_from_global_id, '{}.get_node_from_global_id method is required by the Node interface.'.format(cls.__name__)
node_interface, node_field = node_definitions(
get_node_from_global_id,
id_resolver=id_resolver,
) )
cls._meta = Options(None, graphql_type=node_interface)
cls.Field = partial( def __new__(cls, name, bases, attrs):
Field.copy_and_extend,
node_field, if is_objecttype(bases):
type=node_field.type, cls = super(NodeMeta, cls).__new__(cls, name, bases, attrs)
parent=cls,
_creation_counter=None)
else:
# The interface provided by node_definitions is not an instance # The interface provided by node_definitions is not an instance
# of GrapheneInterfaceType, so it will have no graphql_type, # of GrapheneInterfaceType, so it will have no graphql_type,
# so will not trigger Node.implements # so will not trigger Node.implements
cls.implements(cls) cls.implements(cls)
return cls return cls
options = cls._get_interface_options(attrs.pop('Meta', None))
cls = type.__new__(cls, name, bases, dict(attrs, _meta=options))
get_node_from_global_id = getattr(cls, 'get_node_from_global_id', None)
id_resolver = getattr(cls, 'id_resolver', None)
assert get_node_from_global_id, '{}.get_node_from_global_id method is required by the Node interface.'.format(cls.__name__)
node_interface, node_field = node_definitions(
get_node_from_global_id,
id_resolver=id_resolver,
type_resolver=cls.resolve_type,
)
options.graphql_type = node_interface
cls.Field = partial(
Field.copy_and_extend,
node_field,
type=node_field.type,
parent=cls,
_creation_counter=None)
return cls
class Node(six.with_metaclass(NodeMeta, Interface)): class Node(six.with_metaclass(NodeMeta, Interface)):
_connection = None _connection = None
resolve_type = None
use_global_id = True
@classmethod @classmethod
def require_get_node(cls): def require_get_node(cls):
@ -48,15 +66,17 @@ class Node(six.with_metaclass(NodeMeta, Interface)):
@classmethod @classmethod
def from_global_id(cls, global_id): def from_global_id(cls, global_id):
if cls is Node:
return from_global_id(global_id) return from_global_id(global_id)
raise NotImplementedError("You need to implement {}.from_global_id".format(cls.__name__)) # if cls is Node:
# return from_global_id(global_id)
# raise NotImplementedError("You need to implement {}.from_global_id".format(cls.__name__))
@classmethod @classmethod
def to_global_id(cls, type, id): def to_global_id(cls, type, id):
if cls is Node:
return to_global_id(type, id) return to_global_id(type, id)
raise NotImplementedError("You need to implement {}.to_global_id".format(cls.__name__)) # if cls is Node:
# return to_global_id(type, id)
# raise NotImplementedError("You need to implement {}.to_global_id".format(cls.__name__))
@classmethod @classmethod
def id_resolver(cls, root, args, context, info): def id_resolver(cls, root, args, context, info):