@@ -214,6 +214,8 @@ def complete_value(self, ctx, return_type, field_asts, info, result):
214
214
If the field type is a Scalar or Enum, ensures the completed value is a legal value of the type by calling the
215
215
`serialize` method of GraphQL type definition.
216
216
217
+ If the field is an abstract type, determine the runtime type of the value and then complete based on that type.
218
+
217
219
Otherwise, the field type expects a sub-selection set, and will complete the value by evaluating all
218
220
sub-selections.
219
221
"""
@@ -251,49 +253,56 @@ def complete_value(self, ctx, return_type, field_asts, info, result):
251
253
252
254
# If field type is List, complete each item in the list with the inner type
253
255
if isinstance (return_type , GraphQLList ):
254
- assert isinstance (result , collections .Iterable ), \
255
- ('User Error: expected iterable, but did not find one' +
256
- 'for field {}.{}' ).format (info .parent_type , info .field_name )
256
+ return self .complete_list_value (ctx , return_type , field_asts , info , result )
257
257
258
- item_type = return_type .of_type
259
- completed_results = []
260
- contains_deferred = False
261
- for item in result :
262
- completed_item = self .complete_value_catching_error (ctx , item_type , field_asts , info , item )
263
- if not contains_deferred and isinstance (completed_item , Deferred ):
264
- contains_deferred = True
258
+ # If field type is Scalar or Enum, serialize to a valid value, returning null if coercion is not possible.
259
+ if isinstance (return_type , (GraphQLScalarType , GraphQLEnumType )):
260
+ return self .complete_leaf_value (ctx , return_type , field_asts , info , result )
265
261
266
- completed_results .append (completed_item )
262
+ if isinstance (return_type , GraphQLObjectType ):
263
+ return self .complete_object_value (ctx , return_type , field_asts , info , result )
267
264
268
- return DeferredList (completed_results ) if contains_deferred else completed_results
265
+ if isinstance (return_type , (GraphQLInterfaceType , GraphQLUnionType )):
266
+ return self .complete_abstract_value (ctx , return_type , field_asts , info , result )
269
267
270
- # If field type is Scalar or Enum, serialize to a valid value, returning null if coercion is not possible.
271
- if isinstance (return_type , (GraphQLScalarType , GraphQLEnumType )):
272
- serialized_result = return_type .serialize (result )
268
+ assert False , u'Cannot complete value of unexpected type "{}"' .format (return_type )
273
269
274
- if serialized_result is None :
275
- return None
270
+ def complete_list_value (self , ctx , return_type , field_asts , info , result ):
271
+ """
272
+ Complete a list value by completing each item in the list with the inner type
273
+ """
274
+ assert isinstance (result , collections .Iterable ), \
275
+ ('User Error: expected iterable, but did not find one' +
276
+ 'for field {}.{}' ).format (info .parent_type , info .field_name )
276
277
277
- return serialized_result
278
+ item_type = return_type .of_type
279
+ completed_results = []
280
+ contains_deferred = False
281
+ for item in result :
282
+ completed_item = self .complete_value_catching_error (ctx , item_type , field_asts , info , item )
283
+ if not contains_deferred and isinstance (completed_item , Deferred ):
284
+ contains_deferred = True
278
285
279
- runtime_type = None
286
+ completed_results . append ( completed_item )
280
287
281
- # Field type must be Object, Interface or Union and expect sub-selections.
282
- if isinstance (return_type , GraphQLObjectType ):
283
- runtime_type = return_type
288
+ return DeferredList (completed_results ) if contains_deferred else completed_results
284
289
285
- elif isinstance (return_type , (GraphQLInterfaceType , GraphQLUnionType )):
286
- runtime_type = return_type .resolve_type (result , info )
287
- if runtime_type and not return_type .is_possible_type (runtime_type ):
288
- raise GraphQLError (
289
- u'Runtime Object type "{}" is not a possible type for "{}".' .format (runtime_type , return_type ),
290
- field_asts
291
- )
290
+ def complete_leaf_value (self , ctx , return_type , field_asts , info , result ):
291
+ """
292
+ Complete a Scalar or Enum by serializing to a valid value, returning null if serialization is not possible.
293
+ """
294
+ serialized_result = return_type .serialize (result )
292
295
293
- if not runtime_type :
296
+ if serialized_result is None :
294
297
return None
295
298
296
- if runtime_type .is_type_of and not runtime_type .is_type_of (result , info ):
299
+ return serialized_result
300
+
301
+ def complete_object_value (self , ctx , return_type , field_asts , info , result ):
302
+ """
303
+ Complete an Object value by evaluating all sub-selections.
304
+ """
305
+ if return_type .is_type_of and not return_type .is_type_of (result , info ):
297
306
raise GraphQLError (
298
307
u'Expected value of type "{}" but got {}.' .format (return_type , type (result ).__name__ ),
299
308
field_asts
@@ -306,11 +315,32 @@ def complete_value(self, ctx, return_type, field_asts, info, result):
306
315
selection_set = field_ast .selection_set
307
316
if selection_set :
308
317
subfield_asts = collect_fields (
309
- ctx , runtime_type , selection_set ,
318
+ ctx , return_type , selection_set ,
310
319
subfield_asts , visited_fragment_names
311
320
)
312
321
313
- return self ._execute_fields (ctx , runtime_type , result , subfield_asts )
322
+ return self ._execute_fields (ctx , return_type , result , subfield_asts )
323
+
324
+ def complete_abstract_value (self , ctx , return_type , field_asts , info , result ):
325
+ """
326
+ Complete an value of an abstract type by determining the runtime type of that value, then completing based
327
+ on that type.
328
+ """
329
+ # Field type must be Object, Interface or Union and expect sub-selections.
330
+ runtime_type = None
331
+
332
+ if isinstance (return_type , (GraphQLInterfaceType , GraphQLUnionType )):
333
+ runtime_type = return_type .resolve_type (result , info )
334
+ if runtime_type and not return_type .is_possible_type (runtime_type ):
335
+ raise GraphQLError (
336
+ u'Runtime Object type "{}" is not a possible type for "{}".' .format (runtime_type , return_type ),
337
+ field_asts
338
+ )
339
+
340
+ if not runtime_type :
341
+ return None
342
+
343
+ return self .complete_object_value (ctx , runtime_type , field_asts , info , result )
314
344
315
345
def resolve_or_error (self , resolve_fn , source , args , info ):
316
346
curried_resolve_fn = functools .partial (resolve_fn , source , args , info )
0 commit comments