Improved Relay Connection

This commit is contained in:
Syrus Akbary 2016-08-15 23:24:03 -07:00
parent fd0b9223cf
commit 5cb5d9d65a
2 changed files with 70 additions and 39 deletions

View File

@ -6,7 +6,7 @@ import six
from graphql_relay import connection_from_list from graphql_relay import connection_from_list
from ..types import Boolean, Int, List, String from ..types import Boolean, Int, List, String, AbstractType
from ..types.field import Field from ..types.field import Field
from ..types.objecttype import ObjectType, ObjectTypeMeta from ..types.objecttype import ObjectType, ObjectTypeMeta
from ..types.options import Options from ..types.options import Options
@ -55,6 +55,7 @@ class ConnectionMeta(ObjectTypeMeta):
node=None, node=None,
) )
options.interfaces = () options.interfaces = ()
options.local_fields = OrderedDict()
assert options.node, 'You have to provide a node in {}.Meta'.format(cls.__name__) assert options.node, 'You have to provide a node in {}.Meta'.format(cls.__name__)
assert issubclass(options.node, (Node, ObjectType)), ( assert issubclass(options.node, (Node, ObjectType)), (
@ -66,30 +67,25 @@ class ConnectionMeta(ObjectTypeMeta):
options.name = '{}Connection'.format(base_name) options.name = '{}Connection'.format(base_name)
edge_class = attrs.pop('Edge', None) edge_class = attrs.pop('Edge', None)
edge_fields = OrderedDict([
('node', Field(options.node, description='The item at the end of the edge')),
('cursor', Field(String, required=True, description='A cursor for use in pagination'))
])
edge_attrs = props(edge_class) if edge_class else OrderedDict()
extended_edge_fields = get_fields_in_type(ObjectType, edge_attrs)
edge_fields.update(extended_edge_fields)
edge_meta = type('Meta', (object, ), {
'fields': edge_fields,
'name': '{}Edge'.format(base_name)
})
yank_fields_from_attrs(edge_attrs, extended_edge_fields)
edge = type('Edge', (ObjectType,), dict(edge_attrs, Meta=edge_meta))
options.local_fields = OrderedDict([ class EdgeBase(AbstractType):
node = Field(options.node, description='The item at the end of the edge')
cursor = String(required=True, description='A cursor for use in pagination')
edge_name = '{}Edge'.format(base_name)
if edge_class and issubclass(edge_class, AbstractType):
edge = type(edge_name, (EdgeBase, edge_class, ObjectType, ), {})
else:
edge = type(edge_name, (EdgeBase, ObjectType, ), props(edge_class) if edge_class else {})
cls = ObjectTypeMeta.__new__(cls, name, bases, dict(attrs, _meta=options, Edge=edge))
base_fields = OrderedDict([
('page_info', Field(PageInfo, name='pageInfo', required=True)), ('page_info', Field(PageInfo, name='pageInfo', required=True)),
('edges', Field(List(edge))) ('edges', Field(List(edge)))
]) ])
typed_fields = get_fields_in_type(ObjectType, attrs) base_fields.update(cls._meta.fields)
options.local_fields.update(typed_fields) cls._meta.fields = base_fields
options.fields = options.local_fields return cls
yank_fields_from_attrs(attrs, typed_fields)
return type.__new__(cls, name, bases, dict(attrs, _meta=options, Edge=edge))
class Connection(six.with_metaclass(ConnectionMeta, ObjectType)): class Connection(six.with_metaclass(ConnectionMeta, ObjectType)):

View File

@ -1,5 +1,5 @@
from ...types import Field, List, NonNull, ObjectType, Schema, String from ...types import Field, List, NonNull, ObjectType, String, AbstractType
from ..connection import Connection, PageInfo from ..connection import Connection, PageInfo
from ..node import Node from ..node import Node
@ -15,24 +15,16 @@ class MyObject(ObjectType):
pass pass
class MyObjectConnection(Connection):
extra = String()
class Meta:
node = MyObject
class Edge:
other = String()
class RootQuery(ObjectType):
my_connection = Field(MyObjectConnection)
schema = Schema(query=RootQuery)
def test_connection(): def test_connection():
class MyObjectConnection(Connection):
extra = String()
class Meta:
node = MyObject
class Edge:
other = String()
assert MyObjectConnection._meta.name == 'MyObjectConnection' assert MyObjectConnection._meta.name == 'MyObjectConnection'
fields = MyObjectConnection._meta.fields fields = MyObjectConnection._meta.fields
assert list(fields.keys()) == ['page_info', 'edges', 'extra'] assert list(fields.keys()) == ['page_info', 'edges', 'extra']
@ -48,7 +40,27 @@ def test_connection():
assert pageinfo_field.type.of_type == PageInfo assert pageinfo_field.type.of_type == PageInfo
def test_connection_inherit_abstracttype():
class BaseConnection(AbstractType):
extra = String()
class MyObjectConnection(BaseConnection, Connection):
class Meta:
node = MyObject
assert MyObjectConnection._meta.name == 'MyObjectConnection'
fields = MyObjectConnection._meta.fields
assert list(fields.keys()) == ['page_info', 'edges', 'extra']
def test_edge(): def test_edge():
class MyObjectConnection(Connection):
class Meta:
node = MyObject
class Edge:
other = String()
Edge = MyObjectConnection.Edge Edge = MyObjectConnection.Edge
assert Edge._meta.name == 'MyObjectEdge' assert Edge._meta.name == 'MyObjectEdge'
edge_fields = Edge._meta.fields edge_fields = Edge._meta.fields
@ -61,6 +73,29 @@ def test_edge():
assert edge_fields['other'].type == String assert edge_fields['other'].type == String
def test_edge_with_bases():
class BaseEdge(AbstractType):
extra = String()
class MyObjectConnection(Connection):
class Meta:
node = MyObject
class Edge(BaseEdge):
other = String()
Edge = MyObjectConnection.Edge
assert Edge._meta.name == 'MyObjectEdge'
edge_fields = Edge._meta.fields
assert list(edge_fields.keys()) == ['node', 'cursor', 'extra', 'other']
assert isinstance(edge_fields['node'], Field)
assert edge_fields['node'].type == MyObject
assert isinstance(edge_fields['other'], Field)
assert edge_fields['other'].type == String
def test_pageinfo(): def test_pageinfo():
assert PageInfo._meta.name == 'PageInfo' assert PageInfo._meta.name == 'PageInfo'
fields = PageInfo._meta.fields fields = PageInfo._meta.fields