1+ from typing import Any , Callable , NamedTuple
2+
13from graphql_relay .utils .base64 import base64 , unbase64
24
35from graphql .type import (
68 GraphQLID ,
79 GraphQLField ,
810 GraphQLInterfaceType ,
11+ GraphQLList ,
12+ GraphQLResolveInfo ,
13+ GraphQLTypeResolver
914)
1015
1116
12- def node_definitions (id_fetcher , type_resolver = None ):
17+ class GraphQLNodeDefinitions (NamedTuple ):
18+
19+ node_interface : GraphQLInterfaceType
20+ node_field : GraphQLField
21+ nodes_field : GraphQLField
22+
23+
24+ def node_definitions (
25+ id_fetcher : Callable [[str , GraphQLResolveInfo ], Any ],
26+ type_resolver : GraphQLTypeResolver = None ) -> GraphQLNodeDefinitions :
1327 """
1428 Given a function to map from an ID to an underlying object, and a function
1529 to map from an underlying object to the concrete GraphQLObjectType it
1630 corresponds to, constructs a `Node` interface that objects can implement,
17- and a field config for a `node` root field.
31+ and a field object to be used as a `node` root field.
1832
1933 If the type_resolver is omitted, object resolution on the interface will be
2034 handled with the `is_type_of` method on object types, as with any GraphQL
@@ -29,6 +43,7 @@ def node_definitions(id_fetcher, type_resolver=None):
2943 description = 'The id of the object.' )},
3044 resolve_type = type_resolver ,
3145 )
46+
3247 # noinspection PyShadowingBuiltins
3348 node_field = GraphQLField (
3449 node_interface ,
@@ -39,39 +54,59 @@ def node_definitions(id_fetcher, type_resolver=None):
3954 description = 'The ID of an object' )},
4055 resolve = lambda _obj , info , id : id_fetcher (id , info )
4156 )
42- return node_interface , node_field
4357
58+ nodes_field = GraphQLField (
59+ GraphQLNonNull (GraphQLList (node_interface )),
60+ args = {
61+ 'ids' : GraphQLArgument (
62+ GraphQLNonNull (GraphQLList (GraphQLNonNull (GraphQLID ))),
63+ description = 'The IDs of objects' )},
64+ resolve = lambda _obj , info , ids : [id_fetcher (id_ , info ) for id_ in ids ]
65+ )
66+
67+ return GraphQLNodeDefinitions (node_interface , node_field , nodes_field )
68+
69+
70+ class ResolvedGlobalId (NamedTuple ):
71+
72+ type : str
73+ id : str
4474
45- def to_global_id (type_ , id_ ):
75+
76+ def to_global_id (type_ : str , id_ : str ) -> str :
4677 """
4778 Takes a type name and an ID specific to that type name, and returns a
4879 "global ID" that is unique among all types.
4980 """
50- return base64 (':' . join ([ type_ , str ( id_ )]) )
81+ return base64 (f' { type_ } : { id_ } ' )
5182
5283
53- def from_global_id (global_id ) :
84+ def from_global_id (global_id : str ) -> ResolvedGlobalId :
5485 """
55- Takes the "global ID" created by toGlobalID , and retuns the type name and ID
86+ Takes the "global ID" created by to_global_id , and returns the type name and ID
5687 used to create it.
5788 """
58- unbased_global_id = unbase64 (global_id )
59- _type , _id = unbased_global_id .split (':' , 1 )
60- return _type , _id
89+ return ResolvedGlobalId (* unbase64 (global_id ).split (':' , 1 ))
6190
6291
63- def global_id_field (type_name , id_fetcher = None ):
92+ def global_id_field (
93+ type_name : str = None ,
94+ id_fetcher : Callable [[Any , GraphQLResolveInfo ], str ] = None ) -> GraphQLField :
6495 """
6596 Creates the configuration for an id field on a node, using `to_global_id` to
66- construct the ID from the provided typename. The type-specific ID is fetcher
97+ construct the ID from the provided typename. The type-specific ID is fetched
6798 by calling id_fetcher on the object, or if not provided, by accessing the `id`
68- property on the object.
99+ attribute of the object, or the `id` if the object is a dict .
69100 """
101+
102+ def resolve (obj : Any , info : GraphQLResolveInfo , ** _args : Any ) -> str :
103+ type_ = type_name or info .parent_type .name
104+ id_ = id_fetcher (obj , info ) if id_fetcher else (
105+ obj ['id' ] if isinstance (obj , dict ) else obj .id )
106+ return to_global_id (type_ , id_ )
107+
70108 return GraphQLField (
71109 GraphQLNonNull (GraphQLID ),
72110 description = 'The ID of an object' ,
73- resolve = lambda obj , info , ** args : to_global_id (
74- type_name or info .parent_type .name ,
75- id_fetcher (obj , info ) if id_fetcher else obj .id
76- )
111+ resolve = resolve
77112 )
0 commit comments