mirror of
https://github.com/graphql-python/graphene.git
synced 2025-02-23 15:10:48 +03:00
Allow ConnectionFields to have ObjectTypes as per relay spec
This commit is contained in:
parent
18be1daaa4
commit
b193c98e35
|
@ -6,12 +6,15 @@ from .fields import (
|
|||
|
||||
from .types import (
|
||||
Node,
|
||||
PageInfo,
|
||||
Edge,
|
||||
Connection,
|
||||
ClientIDMutation
|
||||
)
|
||||
|
||||
from .connection import (
|
||||
PageInfo,
|
||||
Connection,
|
||||
Edge,
|
||||
)
|
||||
|
||||
from .utils import is_node
|
||||
|
||||
__all__ = ['ConnectionField', 'NodeField', 'GlobalIDField', 'Node',
|
||||
|
|
85
graphene/relay/connection.py
Normal file
85
graphene/relay/connection.py
Normal file
|
@ -0,0 +1,85 @@
|
|||
from ..core.classtypes import ObjectType
|
||||
from ..core.types import Field, Boolean, String, List
|
||||
from ..utils import memoize
|
||||
|
||||
|
||||
class PageInfo(ObjectType):
|
||||
|
||||
def __init__(self, start_cursor="", end_cursor="",
|
||||
has_previous_page=False, has_next_page=False, **kwargs):
|
||||
super(PageInfo, self).__init__(**kwargs)
|
||||
self.startCursor = start_cursor
|
||||
self.endCursor = end_cursor
|
||||
self.hasPreviousPage = has_previous_page
|
||||
self.hasNextPage = has_next_page
|
||||
|
||||
hasNextPage = Boolean(
|
||||
required=True,
|
||||
description='When paginating forwards, are there more items?')
|
||||
hasPreviousPage = Boolean(
|
||||
required=True,
|
||||
description='When paginating backwards, are there more items?')
|
||||
startCursor = String(
|
||||
description='When paginating backwards, the cursor to continue.')
|
||||
endCursor = String(
|
||||
description='When paginating forwards, the cursor to continue.')
|
||||
|
||||
class Edge(ObjectType):
|
||||
'''An edge in a connection.'''
|
||||
cursor = String(
|
||||
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'
|
||||
node_field = Field(node, description='The item at the end of the edge')
|
||||
return type(
|
||||
'%s%s' % (node._meta.type_name, cls._meta.type_name),
|
||||
(cls,),
|
||||
{'node_type': node, 'node': node_field})
|
||||
|
||||
|
||||
class Connection(ObjectType):
|
||||
'''A connection to a list of items.'''
|
||||
|
||||
def __init__(self, edges, page_info, **kwargs):
|
||||
super(Connection, self).__init__(**kwargs)
|
||||
self.edges = edges
|
||||
self.pageInfo = page_info
|
||||
|
||||
class Meta:
|
||||
type_name = 'DefaultConnection'
|
||||
|
||||
pageInfo = Field(PageInfo, required=True,
|
||||
description='The Information to aid in pagination')
|
||||
|
||||
_connection_data = None
|
||||
|
||||
@classmethod
|
||||
@memoize
|
||||
def for_node(cls, node, edge_type=None):
|
||||
from graphene.relay.utils import is_node
|
||||
edge_type = edge_type or Edge.for_node(node)
|
||||
edges = List(edge_type, description='Information to aid in pagination.')
|
||||
return type(
|
||||
'%s%s' % (node._meta.type_name, cls._meta.type_name),
|
||||
(cls,),
|
||||
{'edge_type': edge_type, 'edges': edges})
|
||||
|
||||
@classmethod
|
||||
def from_list(cls, iterable, args, context, info):
|
||||
assert isinstance(
|
||||
iterable, Iterable), 'Resolved value from the connection field have to be iterable'
|
||||
connection = connection_from_list(
|
||||
iterable, args, connection_type=cls,
|
||||
edge_type=cls.edge_type, pageinfo_type=PageInfo)
|
||||
connection.set_connection_data(iterable)
|
||||
return connection
|
||||
|
||||
def set_connection_data(self, data):
|
||||
self._connection_data = data
|
||||
|
||||
def get_connection_data(self):
|
||||
return self._connection_data
|
|
@ -6,6 +6,7 @@ from ..core.fields import Field
|
|||
from ..core.types.definitions import NonNull
|
||||
from ..core.types.scalars import ID, Int, String
|
||||
from ..utils.wrap_resolver_function import has_context, with_context
|
||||
from .connection import Connection, Edge
|
||||
|
||||
|
||||
class ConnectionField(Field):
|
||||
|
@ -45,19 +46,18 @@ class ConnectionField(Field):
|
|||
return connection_type.from_list(resolved, args, context, info)
|
||||
|
||||
def get_connection_type(self, node):
|
||||
connection_type = self.connection_type or node.get_connection_type()
|
||||
connection_type = self.connection_type or Connection
|
||||
edge_type = self.get_edge_type(node)
|
||||
return connection_type.for_node(node, edge_type=edge_type)
|
||||
|
||||
def get_edge_type(self, node):
|
||||
edge_type = self.edge_type or node.get_edge_type()
|
||||
edge_type = self.edge_type or Edge
|
||||
return edge_type.for_node(node)
|
||||
|
||||
def get_type(self, schema):
|
||||
from graphene.relay.utils import is_node
|
||||
type = schema.T(self.type)
|
||||
node = schema.objecttype(type)
|
||||
assert is_node(node), 'Only nodes have connections.'
|
||||
schema.register(node)
|
||||
connection_type = self.get_connection_type(node)
|
||||
|
||||
|
|
|
@ -19,90 +19,6 @@ from ..utils.wrap_resolver_function import has_context, with_context
|
|||
from .fields import GlobalIDField
|
||||
|
||||
|
||||
class PageInfo(ObjectType):
|
||||
|
||||
def __init__(self, start_cursor="", end_cursor="",
|
||||
has_previous_page=False, has_next_page=False, **kwargs):
|
||||
super(PageInfo, self).__init__(**kwargs)
|
||||
self.startCursor = start_cursor
|
||||
self.endCursor = end_cursor
|
||||
self.hasPreviousPage = has_previous_page
|
||||
self.hasNextPage = has_next_page
|
||||
|
||||
hasNextPage = Boolean(
|
||||
required=True,
|
||||
description='When paginating forwards, are there more items?')
|
||||
hasPreviousPage = Boolean(
|
||||
required=True,
|
||||
description='When paginating backwards, are there more items?')
|
||||
startCursor = String(
|
||||
description='When paginating backwards, the cursor to continue.')
|
||||
endCursor = String(
|
||||
description='When paginating forwards, the cursor to continue.')
|
||||
|
||||
|
||||
class Edge(ObjectType):
|
||||
'''An edge in a connection.'''
|
||||
cursor = String(
|
||||
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'
|
||||
node_field = Field(node, description='The item at the end of the edge')
|
||||
return type(
|
||||
'%s%s' % (node._meta.type_name, cls._meta.type_name),
|
||||
(cls,),
|
||||
{'node_type': node, 'node': node_field})
|
||||
|
||||
|
||||
class Connection(ObjectType):
|
||||
'''A connection to a list of items.'''
|
||||
|
||||
def __init__(self, edges, page_info, **kwargs):
|
||||
super(Connection, self).__init__(**kwargs)
|
||||
self.edges = edges
|
||||
self.pageInfo = page_info
|
||||
|
||||
class Meta:
|
||||
type_name = 'DefaultConnection'
|
||||
|
||||
pageInfo = Field(PageInfo, required=True,
|
||||
description='The Information to aid in pagination')
|
||||
|
||||
_connection_data = None
|
||||
|
||||
@classmethod
|
||||
@memoize
|
||||
def for_node(cls, node, edge_type=None):
|
||||
from graphene.relay.utils import is_node
|
||||
edge_type = edge_type or Edge.for_node(node)
|
||||
assert is_node(node), 'ObjectTypes in a connection have to be Nodes'
|
||||
edges = List(edge_type, description='Information to aid in pagination.')
|
||||
return type(
|
||||
'%s%s' % (node._meta.type_name, cls._meta.type_name),
|
||||
(cls,),
|
||||
{'edge_type': edge_type, 'edges': edges})
|
||||
|
||||
@classmethod
|
||||
def from_list(cls, iterable, args, context, info):
|
||||
assert isinstance(
|
||||
iterable, Iterable), 'Resolved value from the connection field have to be iterable'
|
||||
connection = connection_from_list(
|
||||
iterable, args, connection_type=cls,
|
||||
edge_type=cls.edge_type, pageinfo_type=PageInfo)
|
||||
connection.set_connection_data(iterable)
|
||||
return connection
|
||||
|
||||
def set_connection_data(self, data):
|
||||
self._connection_data = data
|
||||
|
||||
def get_connection_data(self):
|
||||
return self._connection_data
|
||||
|
||||
|
||||
class NodeMeta(InterfaceMeta):
|
||||
|
||||
def construct_get_node(cls):
|
||||
|
@ -153,17 +69,6 @@ class Node(six.with_metaclass(NodeMeta, Interface)):
|
|||
def to_global_id(self):
|
||||
return self.global_id(self.id)
|
||||
|
||||
connection_type = Connection
|
||||
edge_type = Edge
|
||||
|
||||
@classmethod
|
||||
def get_connection_type(cls):
|
||||
return cls.connection_type
|
||||
|
||||
@classmethod
|
||||
def get_edge_type(cls):
|
||||
return cls.edge_type
|
||||
|
||||
|
||||
class MutationInputType(InputObjectType):
|
||||
clientMutationId = String(required=True)
|
||||
|
|
Loading…
Reference in New Issue
Block a user