From 90c88abb5d8f99f43efb245e56fda7ad15040405 Mon Sep 17 00:00:00 2001 From: Markus Padourek Date: Fri, 3 Jun 2016 10:27:54 +0100 Subject: [PATCH 01/13] Added SimpleConnection to relay types Sometimes you do not want a full blown relay connection, where you have `edges[...].node.attribute` but simply `edges[...].attribute`. According to https://github.com/graphql/graphql-relay-js/issues/27#issuecomment-142421989 relay has support for this simpler use-case as well if you do not need certain functionality such as deletion. This implements such a type that can be used instead of the default connection via the `connection_type` argument on `ConnectionField` --- graphene/relay/types.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/graphene/relay/types.py b/graphene/relay/types.py index 3ab55770..ae3af0ad 100644 --- a/graphene/relay/types.py +++ b/graphene/relay/types.py @@ -103,6 +103,35 @@ class Connection(ObjectType): return self._connection_data +class SimpleConnection(Connection): + '''A connection without nodes to a list of items.''' + + class Meta: + type_name = 'SimpleConnection' + + @classmethod + @memoize + def for_node(cls, node, edge_type=None): + from graphene.relay.utils import is_node + edge_type = edge_type or 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, simple_list=True, connection_type=cls, + edge_type=cls.edge_type, pageinfo_type=PageInfo) + connection.set_connection_data(iterable) + return connection + + class NodeMeta(InterfaceMeta): def construct_get_node(cls): From 62c466addfb337043a107ddcce37bc954726f132 Mon Sep 17 00:00:00 2001 From: Markus Padourek Date: Fri, 3 Jun 2016 10:57:30 +0100 Subject: [PATCH 02/13] export SimpleConnection --- graphene/relay/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/graphene/relay/__init__.py b/graphene/relay/__init__.py index 9e169237..10a6b674 100644 --- a/graphene/relay/__init__.py +++ b/graphene/relay/__init__.py @@ -9,6 +9,7 @@ from .types import ( PageInfo, Edge, Connection, + SimpleConnection ClientIDMutation ) From 82bc8d5b9f586efd6e6d06d5b108a9e826167097 Mon Sep 17 00:00:00 2001 From: Markus Padourek Date: Fri, 3 Jun 2016 10:57:40 +0100 Subject: [PATCH 03/13] Update __init__.py --- graphene/relay/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graphene/relay/__init__.py b/graphene/relay/__init__.py index 10a6b674..3aece07a 100644 --- a/graphene/relay/__init__.py +++ b/graphene/relay/__init__.py @@ -16,4 +16,4 @@ from .types import ( from .utils import is_node __all__ = ['ConnectionField', 'NodeField', 'GlobalIDField', 'Node', - 'PageInfo', 'Edge', 'Connection', 'ClientIDMutation', 'is_node'] + 'PageInfo', 'Edge', 'Connection', 'SimpleConnection', 'ClientIDMutation', 'is_node'] From 16ae9de16bd0bdf8f11c50d783d6fd9a39d81c33 Mon Sep 17 00:00:00 2001 From: Markus Padourek Date: Mon, 6 Jun 2016 10:47:53 +0100 Subject: [PATCH 04/13] Added missing comma --- graphene/relay/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/graphene/relay/__init__.py b/graphene/relay/__init__.py index 3aece07a..8934ea58 100644 --- a/graphene/relay/__init__.py +++ b/graphene/relay/__init__.py @@ -9,8 +9,8 @@ from .types import ( PageInfo, Edge, Connection, - SimpleConnection - ClientIDMutation + SimpleConnection, + ClientIDMutation, ) from .utils import is_node From 6553d4554b7574424e383305cf2f8ae5f1364f52 Mon Sep 17 00:00:00 2001 From: Markus Padourek Date: Mon, 6 Jun 2016 16:50:49 +0100 Subject: [PATCH 05/13] Update types.py --- graphene/relay/types.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/graphene/relay/types.py b/graphene/relay/types.py index ae3af0ad..0d27c99b 100644 --- a/graphene/relay/types.py +++ b/graphene/relay/types.py @@ -113,13 +113,12 @@ class SimpleConnection(Connection): @memoize def for_node(cls, node, edge_type=None): from graphene.relay.utils import is_node - edge_type = edge_type or node assert is_node(node), 'ObjectTypes in a connection have to be Nodes' - edges = List(edge_type, description='Information to aid in pagination.') + edges = List(node, 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}) + {'edge_type': node, 'edges': edges}) @classmethod def from_list(cls, iterable, args, context, info): From 631fa23249e4244b885b303c225c8cfcf509a1f8 Mon Sep 17 00:00:00 2001 From: Markus Padourek Date: Tue, 7 Jun 2016 10:04:42 +0100 Subject: [PATCH 06/13] Get proper connection type for SimpleConnection --- graphene/relay/fields.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/graphene/relay/fields.py b/graphene/relay/fields.py index e79b9592..9bd097ec 100644 --- a/graphene/relay/fields.py +++ b/graphene/relay/fields.py @@ -46,6 +46,10 @@ class ConnectionField(Field): def get_connection_type(self, node): connection_type = self.connection_type or node.get_connection_type() + + if issubclass(connection_type, SimpleConnection): + return connection_type.for_node(node) + edge_type = self.get_edge_type(node) return connection_type.for_node(node, edge_type=edge_type) @@ -105,3 +109,5 @@ class GlobalIDField(Field): def resolver(self, instance, args, info): return instance.to_global_id() + +from .types import SimpleConnection From 226b27fc4e5870229964375f26dff78f8aaa76b5 Mon Sep 17 00:00:00 2001 From: Markus Padourek Date: Tue, 7 Jun 2016 10:07:49 +0100 Subject: [PATCH 07/13] Allow node interface to be used in ConnectionField --- graphene/relay/fields.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/graphene/relay/fields.py b/graphene/relay/fields.py index 9bd097ec..65ecb583 100644 --- a/graphene/relay/fields.py +++ b/graphene/relay/fields.py @@ -58,10 +58,10 @@ class ConnectionField(Field): return edge_type.for_node(node) def get_type(self, schema): - from graphene.relay.utils import is_node + from graphene.relay.utils import is_node, is_node_type type = schema.T(self.type) node = schema.objecttype(type) - assert is_node(node), 'Only nodes have connections.' + assert is_node(node) or is_node_type(node), 'Only nodes have connections.' schema.register(node) connection_type = self.get_connection_type(node) From cfb0b2257b74d2a5919100a84f0c28ae529dadb7 Mon Sep 17 00:00:00 2001 From: Markus Padourek Date: Tue, 7 Jun 2016 10:08:36 +0100 Subject: [PATCH 08/13] Also allow node interface in SimpleConnection --- graphene/relay/types.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/graphene/relay/types.py b/graphene/relay/types.py index 0d27c99b..25279128 100644 --- a/graphene/relay/types.py +++ b/graphene/relay/types.py @@ -112,8 +112,8 @@ class SimpleConnection(Connection): @classmethod @memoize def for_node(cls, node, edge_type=None): - from graphene.relay.utils import is_node - assert is_node(node), 'ObjectTypes in a connection have to be Nodes' + from graphene.relay.utils import is_node, is_node_type + assert is_node(node) or is_node_type(node), 'ObjectTypes in a connection have to be Nodes' edges = List(node, description='Information to aid in pagination.') return type( '%s%s' % (node._meta.type_name, cls._meta.type_name), From 5202fed41a021fd1cf4bbb83e27c5d2dc21ff0e6 Mon Sep 17 00:00:00 2001 From: Markus Padourek Date: Tue, 7 Jun 2016 15:18:27 +0100 Subject: [PATCH 09/13] Added ability to add _root values to connection --- graphene/relay/types.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/graphene/relay/types.py b/graphene/relay/types.py index 25279128..a1a3dbe9 100644 --- a/graphene/relay/types.py +++ b/graphene/relay/types.py @@ -111,14 +111,14 @@ class SimpleConnection(Connection): @classmethod @memoize - def for_node(cls, node, edge_type=None): + def for_node(cls, node, root_values=None): from graphene.relay.utils import is_node, is_node_type assert is_node(node) or is_node_type(node), 'ObjectTypes in a connection have to be Nodes' edges = List(node, description='Information to aid in pagination.') return type( '%s%s' % (node._meta.type_name, cls._meta.type_name), (cls,), - {'edge_type': node, 'edges': edges}) + {'edge_type': node, 'edges': edges, '_root': root_values}) @classmethod def from_list(cls, iterable, args, context, info): From bc4896af91bc048899a8c1fc9b6011591cf84bad Mon Sep 17 00:00:00 2001 From: Markus Padourek Date: Tue, 7 Jun 2016 15:19:38 +0100 Subject: [PATCH 10/13] fix blank lines --- graphene/relay/fields.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/graphene/relay/fields.py b/graphene/relay/fields.py index 65ecb583..4b9589d7 100644 --- a/graphene/relay/fields.py +++ b/graphene/relay/fields.py @@ -46,10 +46,10 @@ class ConnectionField(Field): def get_connection_type(self, node): connection_type = self.connection_type or node.get_connection_type() - + if issubclass(connection_type, SimpleConnection): return connection_type.for_node(node) - + edge_type = self.get_edge_type(node) return connection_type.for_node(node, edge_type=edge_type) From 87b48efbe1a3233078e84634ccfeef8e6144449f Mon Sep 17 00:00:00 2001 From: Markus Padourek Date: Tue, 7 Jun 2016 15:34:01 +0100 Subject: [PATCH 11/13] Apply improvements also to Connection class --- graphene/relay/types.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/graphene/relay/types.py b/graphene/relay/types.py index a1a3dbe9..55da8910 100644 --- a/graphene/relay/types.py +++ b/graphene/relay/types.py @@ -76,15 +76,15 @@ class Connection(ObjectType): @classmethod @memoize - def for_node(cls, node, edge_type=None): + def for_node(cls, node, edge_type=None, root_values=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' + assert is_node(node) or is_node_type(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}) + {'edge_type': edge_type, 'edges': edges, '_root': root_values}) @classmethod def from_list(cls, iterable, args, context, info): From 576c3b1092921ad07bc5c9bfeb1c82e05366fc8b Mon Sep 17 00:00:00 2001 From: Markus Padourek Date: Tue, 7 Jun 2016 17:57:06 +0100 Subject: [PATCH 12/13] Update types.py --- graphene/relay/types.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/graphene/relay/types.py b/graphene/relay/types.py index 55da8910..abb10628 100644 --- a/graphene/relay/types.py +++ b/graphene/relay/types.py @@ -49,8 +49,8 @@ class Edge(ObjectType): @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' + from graphene.relay.utils import is_node, is_node_type + assert is_node(node) or is_node_type(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), From 8749047565425ef1b3b743c3168d57ef3579b144 Mon Sep 17 00:00:00 2001 From: Markus Padourek Date: Tue, 7 Jun 2016 18:00:11 +0100 Subject: [PATCH 13/13] Update types.py --- graphene/relay/types.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graphene/relay/types.py b/graphene/relay/types.py index abb10628..a07b8f44 100644 --- a/graphene/relay/types.py +++ b/graphene/relay/types.py @@ -77,7 +77,7 @@ class Connection(ObjectType): @classmethod @memoize def for_node(cls, node, edge_type=None, root_values=None): - from graphene.relay.utils import is_node + from graphene.relay.utils import is_node, is_node_type edge_type = edge_type or Edge.for_node(node) assert is_node(node) or is_node_type(node), 'ObjectTypes in a connection have to be Nodes' edges = List(edge_type, description='Information to aid in pagination.')