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
8
3
from .directives import (GraphQLDirective , GraphQLIncludeDirective ,
9
4
GraphQLSkipDirective )
10
5
from .introspection import IntrospectionSchema
6
+ from .typemap import GraphQLTypeMap
11
7
12
8
13
9
class GraphQLSchema (object ):
@@ -52,22 +48,18 @@ def __init__(self, query, mutation=None, subscription=None, directives=None, typ
52
48
'Schema directives must be List[GraphQLDirective] if provided but got: {}.' .format (
53
49
directives
54
50
)
55
-
56
51
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
+
71
63
72
64
def get_query_type (self ):
73
65
return self ._query
@@ -94,122 +86,8 @@ def get_directive(self, name):
94
86
95
87
return None
96
88
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
-
110
89
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 )
115
91
116
92
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