Used Graphene types for relay Connection and Edges

This commit is contained in:
Syrus Akbary 2015-10-19 22:52:35 -07:00
parent 752cd77652
commit 84fcb3eac9
5 changed files with 89 additions and 8 deletions

View File

@ -30,7 +30,7 @@ class ObjectTypeMeta(type):
# If this isn't a subclass of Model, don't do anything special. # If this isn't a subclass of Model, don't do anything special.
return super_new(cls, name, bases, attrs) return super_new(cls, name, bases, attrs)
module = attrs.pop('__module__') module = attrs.pop('__module__', None)
doc = attrs.pop('__doc__', None) doc = attrs.pop('__doc__', None)
new_class = super_new(cls, name, bases, { new_class = super_new(cls, name, bases, {
'__module__': module, '__module__': module,

View File

@ -4,6 +4,11 @@ from graphene.relay.fields import (
GlobalIDField, GlobalIDField,
) )
from graphene.relay.types import Node from graphene.relay.types import (
Node,
PageInfo,
Edge,
Connection
)
from graphene.relay.utils import is_node from graphene.relay.utils import is_node

View File

@ -21,9 +21,14 @@ from graphene.utils import memoize
class ConnectionField(Field): class ConnectionField(Field):
def __init__(self, field_type, resolve=None, description=''): def __init__(self, field_type, resolve=None, description='', connection_type=None, edge_type=None, **kwargs):
from graphene.relay.types import Connection, Edge
super(ConnectionField, self).__init__(field_type, resolve=resolve, super(ConnectionField, self).__init__(field_type, resolve=resolve,
args=connectionArgs, description=description) args=connectionArgs, description=description, **kwargs)
self.connection_type = connection_type or Connection
self.edge_type = edge_type or Edge
assert issubclass(self.connection_type, Connection), 'connection_type in %r must be a subclass of Connection' % self
assert issubclass(self.edge_type, Edge), 'edge_type in %r must be a subclass of Edge' % self
def wrap_resolved(self, value, instance, args, info): def wrap_resolved(self, value, instance, args, info):
return value return value
@ -39,9 +44,12 @@ class ConnectionField(Field):
@memoize @memoize
def internal_type(self, schema): def internal_type(self, schema):
from graphene.relay.utils import is_node from graphene.relay.utils import is_node
object_type = self.get_object_type(schema) node = self.get_object_type(schema)
assert is_node(object_type), 'Only nodes have connections.' assert is_node(node), 'Only nodes have connections.'
return object_type.get_connection(schema) schema.register(node)
edge_node_type = self.edge_type.for_node(node)
connection_node_type = self.connection_type.for_node(node, edge_type=edge_node_type)
return connection_node_type.internal_type(schema)
class NodeField(Field): class NodeField(Field):

View File

@ -5,7 +5,8 @@ from graphql_relay.connection.connection import (
connection_definitions connection_definitions
) )
from graphene.core.types import Interface from graphene.core.types import Interface, ObjectType
from graphene.core.fields import BooleanField, StringField, ListField, Field
from graphene.relay.fields import GlobalIDField from graphene.relay.fields import GlobalIDField
from graphene.utils import memoize from graphene.utils import memoize
@ -35,3 +36,37 @@ class BaseNode(object):
class Node(BaseNode, Interface): class Node(BaseNode, Interface):
'''An object with an ID''' '''An object with an ID'''
id = GlobalIDField() id = GlobalIDField()
class PageInfo(ObjectType):
has_next_page = BooleanField(required=True, description='When paginating forwards, are there more items?')
has_previous_page = BooleanField(required=True, description='When paginating backwards, are there more items?')
start_cursor = StringField(description='When paginating backwards, the cursor to continue.')
end_cursor = StringField(description='When paginating forwards, the cursor to continue.')
class Edge(ObjectType):
'''An edge in a connection.'''
node = Field(lambda field: field.object_type.node_type, description='The item at the end of the edge')
end_cursor = StringField(required=True, description='A cursor for use in pagination')
@classmethod
@memoize
def for_node(cls, node):
from graphene.relay.utils import is_node
assert is_node(node), 'ObjectTypes in a edge have to be Nodes'
return type('%sEdge' % node._meta.type_name, (cls, ), {'node_type': node})
class Connection(ObjectType):
'''A connection to a list of items.'''
page_info = Field(PageInfo, required=True, description='The Information to aid in pagination')
edges = ListField(lambda field: field.object_type.edge_type, description='Information to aid in pagination.')
@classmethod
@memoize
def for_node(cls, node, edge_type=None):
from graphene.relay.utils import is_node
edge_type = edge_type or Edge
assert is_node(node), 'ObjectTypes in a connection have to be Nodes'
return type('%sConnection' % node._meta.type_name, (cls, ), {'edge_type': edge_type.for_node(node)})

View File

@ -12,6 +12,11 @@ schema = graphene.Schema()
class MyType(object): class MyType(object):
name = 'my' name = 'my'
arg = None
class MyConnection(relay.Connection):
my_custom_field = graphene.StringField(resolve=lambda instance, *_: 'Custom')
class MyNode(relay.Node): class MyNode(relay.Node):
@ -24,7 +29,13 @@ class MyNode(relay.Node):
class Query(graphene.ObjectType): class Query(graphene.ObjectType):
my_node = relay.NodeField(MyNode) my_node = relay.NodeField(MyNode)
all_my_nodes = relay.ConnectionField(MyNode, connection_type=MyConnection, customArg=graphene.Argument(graphene.String))
def resolve_all_my_nodes(self, args, info):
t = MyType()
custom_arg = args.get('customArg')
assert custom_arg == "1"
return [MyNode(t)]
schema.query = Query schema.query = Query
@ -34,12 +45,34 @@ def test_nodefield_query():
query RebelsShipsQuery { query RebelsShipsQuery {
myNode(id:"TXlOb2RlOjE=") { myNode(id:"TXlOb2RlOjE=") {
name name
},
allMyNodes (customArg:"1") {
edges {
node {
name
}
},
myCustomField
pageInfo {
hasNextPage
}
} }
} }
''' '''
expected = { expected = {
'myNode': { 'myNode': {
'name': 'my' 'name': 'my'
},
'allMyNodes': {
'edges': [{
'node': {
'name': 'my'
}
}],
'myCustomField': 'Custom',
'pageInfo': {
'hasNextPage': False,
}
} }
} }
result = schema.execute(query) result = schema.execute(query)