1- from collections import Iterable , OrderedDict , defaultdict
2- from functools import reduce
3-
4- from ..utils .type_comparators import is_equal_type , is_type_sub_type_of
5- from .definition import (GraphQLInputObjectType , GraphQLInterfaceType ,
6- GraphQLList , GraphQLNonNull , GraphQLObjectType ,
7- GraphQLUnionType , GraphQLInputObjectField , is_input_type , is_output_type , GraphQLField , GraphQLArgument )
1+ from collections import Iterable
2+ from .definition import GraphQLObjectType
83from .directives import (GraphQLDirective , GraphQLIncludeDirective ,
94 GraphQLSkipDirective )
105from .introspection import IntrospectionSchema
6+ from .typemap import GraphQLTypeMap
117
128
139class GraphQLSchema (object ):
@@ -52,22 +48,18 @@ def __init__(self, query, mutation=None, subscription=None, directives=None, typ
5248 'Schema directives must be List[GraphQLDirective] if provided but got: {}.' .format (
5349 directives
5450 )
55-
5651 self ._directives = directives
57- self ._possible_type_map = defaultdict (set )
58- self ._type_map = self ._build_type_map (types )
59- # Keep track of all implementations by interface name.
60- self ._implementations = defaultdict (list )
61- for type in self ._type_map .values ():
62- if isinstance (type , GraphQLObjectType ):
63- for interface in type .get_interfaces ():
64- self ._implementations [interface .name ].append (type )
65-
66- # Enforce correct interface implementations.
67- for type in self ._type_map .values ():
68- if isinstance (type , GraphQLObjectType ):
69- for interface in type .get_interfaces ():
70- assert_object_implements_interface (self , type , interface )
52+
53+ initial_types = [
54+ query ,
55+ mutation ,
56+ subscription ,
57+ IntrospectionSchema
58+ ]
59+ if types :
60+ initial_types += types
61+ self ._type_map = GraphQLTypeMap (initial_types )
62+
7163
7264 def get_query_type (self ):
7365 return self ._query
@@ -94,122 +86,8 @@ def get_directive(self, name):
9486
9587 return None
9688
97- def _build_type_map (self , _types ):
98- types = [
99- self .get_query_type (),
100- self .get_mutation_type (),
101- self .get_subscription_type (),
102- IntrospectionSchema
103- ]
104- if _types :
105- types += _types
106-
107- type_map = reduce (self ._type_map_reducer , types , OrderedDict ())
108- return type_map
109-
11089 def get_possible_types (self , abstract_type ):
111- if isinstance (abstract_type , GraphQLUnionType ):
112- return abstract_type .get_types ()
113- assert isinstance (abstract_type , GraphQLInterfaceType )
114- return self ._implementations [abstract_type .name ]
90+ return self ._type_map .get_possible_types (abstract_type )
11591
11692 def is_possible_type (self , abstract_type , possible_type ):
117- if not self ._possible_type_map [abstract_type .name ]:
118- possible_types = self .get_possible_types (abstract_type )
119- self ._possible_type_map [abstract_type .name ].update ([p .name for p in possible_types ])
120-
121- return possible_type .name in self ._possible_type_map [abstract_type .name ]
122-
123- def _type_map_reducer (self , map , type ):
124- if not type :
125- return map
126-
127- if isinstance (type , GraphQLList ) or isinstance (type , GraphQLNonNull ):
128- return self ._type_map_reducer (map , type .of_type )
129-
130- if type .name in map :
131- assert map [type .name ] == type , (
132- 'Schema must contain unique named types but contains multiple types named "{}".'
133- ).format (type .name )
134-
135- return map
136-
137- map [type .name ] = type
138-
139- reduced_map = map
140-
141- if isinstance (type , (GraphQLUnionType )):
142- for t in type .get_types ():
143- reduced_map = self ._type_map_reducer (reduced_map , t )
144-
145- if isinstance (type , GraphQLObjectType ):
146- for t in type .get_interfaces ():
147- reduced_map = self ._type_map_reducer (reduced_map , t )
148-
149- if isinstance (type , (GraphQLObjectType , GraphQLInterfaceType , GraphQLInputObjectType )):
150- field_map = type .get_fields ()
151- type_is_input = isinstance (type , GraphQLInputObjectType )
152- for field_name , field in field_map .items ():
153- if type_is_input :
154- assert isinstance (field , GraphQLInputObjectField ), (
155- '{}.{} must be an instance of GraphQLInputObjectField.' .format (type , field_name )
156- )
157- assert is_input_type (field .type ), (
158- '{}.{} field type must be Input Type but got: {}.' .format (type , field_name , field .type )
159- )
160- else :
161- assert isinstance (field , (GraphQLField , GraphQLField )), (
162- '{}.{} must be an instance of GraphQLField.' .format (type , field_name )
163- )
164- assert is_output_type (field .type ), (
165- '{}.{} field type must be Output Type but got: {}.' .format (type , field_name , field .type )
166- )
167- for arg_name , arg in field .args .items ():
168- assert isinstance (arg , (GraphQLArgument , GraphQLArgument )), (
169- '{}.{}({}:) argument must be an instance of GraphQLArgument.' .format (type , field_name , arg_name )
170- )
171- assert is_input_type (arg .type ), (
172- '{}.{}({}:) argument type must be Input Type but got: {}.' .format (type , field_name , arg_name ,
173- arg .type )
174- )
175- reduced_map = self ._type_map_reducer (reduced_map , arg .type )
176-
177- reduced_map = self ._type_map_reducer (reduced_map , getattr (field , 'type' , None ))
178-
179- return reduced_map
180-
181-
182- def assert_object_implements_interface (schema , object , interface ):
183- object_field_map = object .get_fields ()
184- interface_field_map = interface .get_fields ()
185-
186- for field_name , interface_field in interface_field_map .items ():
187- object_field = object_field_map .get (field_name )
188-
189- assert object_field , '"{}" expects field "{}" but "{}" does not provide it.' .format (
190- interface , field_name , object
191- )
192-
193- assert is_type_sub_type_of (schema , object_field .type , interface_field .type ), (
194- '{}.{} expects type "{}" but {}.{} provides type "{}".'
195- ).format (interface , field_name , interface_field .type , object , field_name , object_field .type )
196-
197- for arg_name , interface_arg in interface_field .args .items ():
198- object_arg = object_field .args .get (arg_name )
199-
200- assert object_arg , (
201- '{}.{} expects argument "{}" but {}.{} does not provide it.'
202- ).format (interface , field_name , arg_name , object , field_name )
203-
204- assert is_equal_type (interface_arg .type , object_arg .type ), (
205- '{}.{}({}:) expects type "{}" but {}.{}({}:) provides type "{}".'
206- ).format (interface , field_name , arg_name , interface_arg .type , object , field_name , arg_name , object_arg .type )
207-
208- for arg_name , object_arg in object_field .args .items ():
209- interface_arg = interface_field .args .get (arg_name )
210- if not interface_arg :
211- assert not isinstance (object_arg .type , GraphQLNonNull ), (
212- '{}.{}({}:) is of required type '
213- '"{}" but is not also provided by the '
214- 'interface {}.{}.'
215- ).format (object , field_name , arg_name , object_arg .type , interface , field_name )
93+ return self ._type_map .is_possible_type (abstract_type , possible_type )
0 commit comments