Skip to content

Commit a324759

Browse files
committed
Make the type map reducer in GraphQLSchema overridable
1 parent a6c1e56 commit a324759

File tree

1 file changed

+62
-69
lines changed

1 file changed

+62
-69
lines changed

graphql/type/schema.py

Lines changed: 62 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
from functools import partial, reduce
2-
from typing import Any, Callable, Dict, List, Optional, Sequence, Set, Tuple, cast
1+
from functools import reduce
2+
from typing import Any, Dict, List, Optional, Sequence, Set, Tuple, cast
33

44
from ..error import GraphQLError
55
from ..language import ast
@@ -145,9 +145,9 @@ def __init__(
145145
# Keep track of all types referenced within the schema.
146146
type_map: TypeMap = {}
147147
# First by deeply visiting all initial types.
148-
type_map = type_map_reduce(initial_types, type_map)
148+
type_map = reduce(self.type_map_reducer, initial_types, type_map)
149149
# Then by deeply visiting all directive types.
150-
type_map = type_map_directive_reduce(self.directives, type_map)
150+
type_map = reduce(self.type_map_directive_reducer, self.directives, type_map)
151151
# Storing the resulting map for reference by the schema
152152
self.type_map = type_map
153153

@@ -213,6 +213,64 @@ def get_directive(self, name: str) -> Optional[GraphQLDirective]:
213213
def validation_errors(self):
214214
return self._validation_errors
215215

216+
def type_map_reducer(
217+
self, map_: TypeMap, type_: GraphQLNamedType = None
218+
) -> TypeMap:
219+
"""Reducer function for creating the type map from given types."""
220+
if not type_:
221+
return map_
222+
if is_wrapping_type(type_):
223+
return self.type_map_reducer(
224+
map_, cast(GraphQLWrappingType[GraphQLNamedType], type_).of_type
225+
)
226+
name = type_.name
227+
if name in map_:
228+
if map_[name] is not type_:
229+
raise TypeError(
230+
"Schema must contain uniquely named types but contains multiple"
231+
f" types named {name!r}."
232+
)
233+
return map_
234+
map_[name] = type_
235+
236+
if is_union_type(type_):
237+
type_ = cast(GraphQLUnionType, type_)
238+
map_ = reduce(self.type_map_reducer, type_.types, map_)
239+
240+
if is_object_type(type_):
241+
type_ = cast(GraphQLObjectType, type_)
242+
map_ = reduce(self.type_map_reducer, type_.interfaces, map_)
243+
244+
if is_object_type(type_) or is_interface_type(type_):
245+
for field in cast(GraphQLInterfaceType, type_).fields.values():
246+
args = field.args
247+
if args:
248+
types = [arg.type for arg in args.values()]
249+
map_ = reduce(self.type_map_reducer, types, map_)
250+
map_ = self.type_map_reducer(map_, field.type)
251+
252+
if is_input_object_type(type_):
253+
for field in cast(GraphQLInputObjectType, type_).fields.values():
254+
map_ = self.type_map_reducer(map_, field.type)
255+
256+
return map_
257+
258+
def type_map_directive_reducer(
259+
self, map_: TypeMap, directive: GraphQLDirective = None
260+
) -> TypeMap:
261+
"""Reducer function for creating the type map from given directives."""
262+
# Directives are not validated until validate_schema() is called.
263+
if not is_directive(directive):
264+
return map_
265+
directive = cast(GraphQLDirective, directive)
266+
return reduce(
267+
lambda prev_map, arg: self.type_map_reducer(
268+
prev_map, cast(GraphQLNamedType, arg.type)
269+
),
270+
directive.args.values(),
271+
map_,
272+
)
273+
216274

217275
def is_schema(schema: Any) -> bool:
218276
"""Test if the given value is a GraphQL schema."""
@@ -223,68 +281,3 @@ def assert_schema(schema: Any) -> GraphQLSchema:
223281
if not is_schema(schema):
224282
raise TypeError(f"Expected {inspect(schema)} to be a GraphQL schema.")
225283
return cast(GraphQLSchema, schema)
226-
227-
228-
def type_map_reducer(map_: TypeMap, type_: GraphQLNamedType = None) -> TypeMap:
229-
"""Reducer function for creating the type map from given types."""
230-
if not type_:
231-
return map_
232-
if is_wrapping_type(type_):
233-
return type_map_reducer(
234-
map_, cast(GraphQLWrappingType[GraphQLNamedType], type_).of_type
235-
)
236-
name = type_.name
237-
if name in map_:
238-
if map_[name] is not type_:
239-
raise TypeError(
240-
"Schema must contain uniquely named types but contains multiple"
241-
f" types named {name!r}."
242-
)
243-
return map_
244-
map_[name] = type_
245-
246-
if is_union_type(type_):
247-
type_ = cast(GraphQLUnionType, type_)
248-
map_ = type_map_reduce(type_.types, map_)
249-
250-
if is_object_type(type_):
251-
type_ = cast(GraphQLObjectType, type_)
252-
map_ = type_map_reduce(type_.interfaces, map_)
253-
254-
if is_object_type(type_) or is_interface_type(type_):
255-
for field in cast(GraphQLInterfaceType, type_).fields.values():
256-
args = field.args
257-
if args:
258-
types = [arg.type for arg in args.values()]
259-
map_ = type_map_reduce(types, map_)
260-
map_ = type_map_reducer(map_, field.type)
261-
262-
if is_input_object_type(type_):
263-
for field in cast(GraphQLInputObjectType, type_).fields.values():
264-
map_ = type_map_reducer(map_, field.type)
265-
266-
return map_
267-
268-
269-
def type_map_directive_reducer(
270-
map_: TypeMap, directive: GraphQLDirective = None
271-
) -> TypeMap:
272-
"""Reducer function for creating the type map from given directives."""
273-
# Directives are not validated until validate_schema() is called.
274-
if not is_directive(directive):
275-
return map_
276-
directive = cast(GraphQLDirective, directive)
277-
return reduce(
278-
lambda prev_map, arg: type_map_reducer(prev_map, arg.type), # type: ignore
279-
directive.args.values(),
280-
map_,
281-
)
282-
283-
284-
# Reduce functions for type maps:
285-
type_map_reduce: Callable[ # type: ignore
286-
[Sequence[Optional[GraphQLNamedType]], TypeMap], TypeMap
287-
] = partial(reduce, type_map_reducer)
288-
type_map_directive_reduce: Callable[ # type: ignore
289-
[Sequence[Optional[GraphQLDirective]], TypeMap], TypeMap
290-
] = partial(reduce, type_map_directive_reducer)

0 commit comments

Comments
 (0)