-
Notifications
You must be signed in to change notification settings - Fork 40
Expand file tree
/
Copy pathnode.py
More file actions
130 lines (109 loc) · 3.97 KB
/
node.py
File metadata and controls
130 lines (109 loc) · 3.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
from typing import Any, Callable, NamedTuple, Optional, Union
from graphql_relay.utils.base64 import base64, unbase64
from graphql import (
GraphQLArgument,
GraphQLNonNull,
GraphQLID,
GraphQLField,
GraphQLInterfaceType,
GraphQLList,
GraphQLResolveInfo,
GraphQLTypeResolver,
)
__all__ = [
"from_global_id",
"global_id_field",
"node_definitions",
"to_global_id",
"GraphQLNodeDefinitions",
"ResolvedGlobalId",
]
class GraphQLNodeDefinitions(NamedTuple):
node_interface: GraphQLInterfaceType
node_field: GraphQLField
nodes_field: GraphQLField
def node_definitions(
fetch_by_id: Callable[[str, GraphQLResolveInfo], Any],
type_resolver: Optional[GraphQLTypeResolver] = None,
) -> GraphQLNodeDefinitions:
"""
Given a function to map from an ID to an underlying object, and a function
to map from an underlying object to the concrete GraphQLObjectType it
corresponds to, constructs a `Node` interface that objects can implement,
and a field object to be used as a `node` root field.
If the type_resolver is omitted, object resolution on the interface will be
handled with the `is_type_of` method on object types, as with any GraphQL
interface without a provided `resolve_type` method.
"""
node_interface = GraphQLInterfaceType(
"Node",
description="An object with an ID",
fields=lambda: {
"id": GraphQLField(
GraphQLNonNull(GraphQLID), description="The id of the object."
)
},
resolve_type=type_resolver,
)
# noinspection PyShadowingBuiltins
node_field = GraphQLField(
node_interface,
description="Fetches an object given its ID",
args={
"id": GraphQLArgument(
GraphQLNonNull(GraphQLID), description="The ID of an object"
)
},
resolve=lambda _obj, info, id: fetch_by_id(id, info),
)
nodes_field = GraphQLField(
GraphQLNonNull(GraphQLList(node_interface)),
description="Fetches objects given their IDs",
args={
"ids": GraphQLArgument(
GraphQLNonNull(GraphQLList(GraphQLNonNull(GraphQLID))),
description="The IDs of objects",
)
},
resolve=lambda _obj, info, ids: [fetch_by_id(id_, info) for id_ in ids],
)
return GraphQLNodeDefinitions(node_interface, node_field, nodes_field)
class ResolvedGlobalId(NamedTuple):
type: str
id: str
def to_global_id(type_: str, id_: Union[str, int]) -> str:
"""
Takes a type name and an ID specific to that type name, and returns a
"global ID" that is unique among all types.
"""
return base64(f"{type_}:{GraphQLID.serialize(id_)}")
def from_global_id(global_id: str) -> ResolvedGlobalId:
"""
Takes the "global ID" created by to_global_id, and returns the type name and ID
used to create it.
"""
global_id = unbase64(global_id)
if ":" not in global_id:
return ResolvedGlobalId("", global_id)
return ResolvedGlobalId(*global_id.split(":", 1))
def global_id_field(
type_name: Optional[str] = None,
id_fetcher: Optional[Callable[[Any, GraphQLResolveInfo], str]] = None,
) -> GraphQLField:
"""
Creates the configuration for an id field on a node, using `to_global_id` to
construct the ID from the provided typename. The type-specific ID is fetched
by calling id_fetcher on the object, or if not provided, by accessing the `id`
attribute of the object, or the `id` if the object is a dict.
"""
def resolve(obj: Any, info: GraphQLResolveInfo, **_args: Any) -> str:
type_ = type_name or info.parent_type.name
id_ = (
id_fetcher(obj, info)
if id_fetcher
else (obj["id"] if isinstance(obj, dict) else obj.id)
)
return to_global_id(type_, id_)
return GraphQLField(
GraphQLNonNull(GraphQLID), description="The ID of an object", resolve=resolve
)