1
+ from typing import Any , Callable , NamedTuple
2
+
1
3
from graphql_relay .utils .base64 import base64 , unbase64
2
4
3
5
from graphql .type import (
6
8
GraphQLID ,
7
9
GraphQLField ,
8
10
GraphQLInterfaceType ,
11
+ GraphQLList ,
12
+ GraphQLResolveInfo ,
13
+ GraphQLTypeResolver
9
14
)
10
15
11
16
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 :
13
27
"""
14
28
Given a function to map from an ID to an underlying object, and a function
15
29
to map from an underlying object to the concrete GraphQLObjectType it
16
30
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.
18
32
19
33
If the type_resolver is omitted, object resolution on the interface will be
20
34
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):
29
43
description = 'The id of the object.' )},
30
44
resolve_type = type_resolver ,
31
45
)
46
+
32
47
# noinspection PyShadowingBuiltins
33
48
node_field = GraphQLField (
34
49
node_interface ,
@@ -39,39 +54,59 @@ def node_definitions(id_fetcher, type_resolver=None):
39
54
description = 'The ID of an object' )},
40
55
resolve = lambda _obj , info , id : id_fetcher (id , info )
41
56
)
42
- return node_interface , node_field
43
57
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
44
74
45
- def to_global_id (type_ , id_ ):
75
+
76
+ def to_global_id (type_ : str , id_ : str ) -> str :
46
77
"""
47
78
Takes a type name and an ID specific to that type name, and returns a
48
79
"global ID" that is unique among all types.
49
80
"""
50
- return base64 (':' . join ([ type_ , str ( id_ )]) )
81
+ return base64 (f' { type_ } : { id_ } ' )
51
82
52
83
53
- def from_global_id (global_id ) :
84
+ def from_global_id (global_id : str ) -> ResolvedGlobalId :
54
85
"""
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
56
87
used to create it.
57
88
"""
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 ))
61
90
62
91
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 :
64
95
"""
65
96
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
67
98
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 .
69
100
"""
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
+
70
108
return GraphQLField (
71
109
GraphQLNonNull (GraphQLID ),
72
110
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
77
112
)
0 commit comments