Skip to content

Commit fe3a31b

Browse files
committed
Implement build_ast_schema utility #5
1 parent 9873cd0 commit fe3a31b

File tree

2 files changed

+520
-0
lines changed

2 files changed

+520
-0
lines changed
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
from collections import OrderedDict
2+
3+
from ..language import ast
4+
from ..type import (
5+
GraphQLArgument,
6+
GraphQLBoolean,
7+
GraphQLEnumType,
8+
GraphQLEnumValue,
9+
GraphQLField,
10+
GraphQLFloat,
11+
GraphQLID,
12+
GraphQLInputObjectField,
13+
GraphQLInputObjectType,
14+
GraphQLInt,
15+
GraphQLInterfaceType,
16+
GraphQLList,
17+
GraphQLNonNull,
18+
GraphQLObjectType,
19+
GraphQLScalarType,
20+
GraphQLSchema,
21+
GraphQLString,
22+
GraphQLUnionType,
23+
)
24+
from ..utils.value_from_ast import value_from_ast
25+
26+
27+
def _build_wrapped_type(inner_type, input_type_ast):
28+
if isinstance(input_type_ast, ast.ListType):
29+
return GraphQLList(_build_wrapped_type(inner_type, input_type_ast.type))
30+
31+
if isinstance(input_type_ast, ast.NonNullType):
32+
return GraphQLNonNull(_build_wrapped_type(inner_type, input_type_ast.type))
33+
34+
return inner_type
35+
36+
37+
def _get_inner_type_name(type_ast):
38+
if isinstance(type_ast, (ast.ListType, ast.NonNullType)):
39+
return _get_inner_type_name(type_ast.type)
40+
41+
return type_ast.name.value
42+
43+
44+
_false = lambda *_: False
45+
_none = lambda *_: None
46+
47+
48+
def build_ast_schema(document, query_type_name, mutation_type_name=None):
49+
assert isinstance(document, ast.Document), 'must pass in Document ast.'
50+
assert query_type_name, 'must pass in query type'
51+
52+
type_defs = [d for d in document.definitions if isinstance(d, ast.TypeDefinition)]
53+
ast_map = {d.name.value: d for d in type_defs}
54+
55+
if query_type_name not in ast_map:
56+
raise Exception('Specified query type {} not found in document.'.format(query_type_name))
57+
58+
if mutation_type_name and mutation_type_name not in ast_map:
59+
raise Exception('Specified mutation type {} not found in document.'.format(mutation_type_name))
60+
61+
inner_type_map = {
62+
'String': GraphQLString,
63+
'Int': GraphQLInt,
64+
'Float': GraphQLFloat,
65+
'Boolean': GraphQLBoolean,
66+
'ID': GraphQLID
67+
}
68+
69+
def produce_type_def(type_ast):
70+
type_name = _get_inner_type_name(type_ast)
71+
print('ptd', type_name)
72+
if type_name in inner_type_map:
73+
return _build_wrapped_type(inner_type_map[type_name], type_ast)
74+
75+
if type_name not in ast_map:
76+
raise Exception('Type {} not found in document.'.format(type_name))
77+
78+
inner_type_def = make_schema_def(ast_map[type_name])
79+
if not inner_type_def:
80+
raise Exception('Nothing constructed for {}.'.format(type_name))
81+
82+
inner_type_map[type_name] = inner_type_def
83+
return _build_wrapped_type(inner_type_def, type_ast)
84+
85+
def make_type_def(definition):
86+
return GraphQLObjectType(
87+
name=definition.name.value,
88+
fields=lambda: make_field_def_map(definition),
89+
interfaces=make_implemented_interfaces(definition)
90+
)
91+
92+
def make_field_def_map(definition):
93+
return OrderedDict(
94+
(f.name.value, GraphQLField(
95+
type=produce_type_def(f.type),
96+
args=make_input_values(f.arguments, GraphQLArgument)
97+
))
98+
for f in definition.fields
99+
)
100+
101+
def make_implemented_interfaces(definition):
102+
return [produce_type_def(i) for i in definition.interfaces]
103+
104+
def make_input_values(values, cls):
105+
return OrderedDict(
106+
(value.name.value, cls(
107+
type=produce_type_def(value.type),
108+
default_value=value_from_ast(value.default_value, produce_type_def(value.type))
109+
))
110+
for value in values
111+
)
112+
113+
def make_interface_def(definition):
114+
return GraphQLInterfaceType(
115+
name=definition.name.value,
116+
resolve_type=_none,
117+
fields=lambda: make_field_def_map(definition)
118+
)
119+
120+
def make_enum_def(definition):
121+
return GraphQLEnumType(
122+
name=definition.name.value,
123+
values=OrderedDict(
124+
(v.name.value, GraphQLEnumValue()) for v in definition.values
125+
)
126+
)
127+
128+
def make_union_def(definition):
129+
return GraphQLUnionType(
130+
name=definition.name.value,
131+
resolve_type=_none,
132+
types=[produce_type_def(t) for t in definition.types]
133+
)
134+
135+
def make_scalar_def(definition):
136+
return GraphQLScalarType(
137+
name=definition.name.value,
138+
serialize=_none,
139+
# Validation calls the parse functions to determine if a literal value is correct.
140+
# Returning none, however would cause the scalar to fail validation. Returning false,
141+
# will cause them to pass.
142+
parse_literal=_false,
143+
parse_value=_false
144+
)
145+
146+
def make_input_object_def(definition):
147+
return GraphQLInputObjectType(
148+
name=definition.name.value,
149+
fields=make_input_values(definition.fields, GraphQLInputObjectField)
150+
)
151+
152+
_schema_def_handlers = {
153+
ast.ObjectTypeDefinition: make_type_def,
154+
ast.InterfaceTypeDefinition: make_interface_def,
155+
ast.EnumTypeDefinition: make_enum_def,
156+
ast.UnionTypeDefinition: make_union_def,
157+
ast.ScalarTypeDefinition: make_scalar_def,
158+
ast.InputObjectTypeDefinition: make_input_object_def
159+
}
160+
161+
def make_schema_def(definition):
162+
if not definition:
163+
raise Exception('definition must be defined.')
164+
165+
handler = _schema_def_handlers.get(type(definition))
166+
if not handler:
167+
raise Exception('{} not supported.'.format(type(definition).__name__))
168+
169+
return handler(definition)
170+
171+
for definition in document.definitions:
172+
produce_type_def(definition)
173+
174+
schema_kwargs = {'query': produce_type_def(ast_map[query_type_name])}
175+
176+
if mutation_type_name:
177+
schema_kwargs['mutation'] = produce_type_def(ast_map[mutation_type_name])
178+
179+
return GraphQLSchema(**schema_kwargs)

0 commit comments

Comments
 (0)