@@ -66,13 +66,14 @@ class DeferredExecution
66
66
# @return [Object] the initial result, without any defers
67
67
def execute ( ast_operation , root_type , query_object )
68
68
collector = query_object . context [ CONTEXT_PATCH_TARGET ]
69
+ irep_root = query_object . internal_representation [ ast_operation . name ]
69
70
70
71
scope = ExecScope . new ( query_object )
71
72
initial_thread = ExecThread . new
72
73
initial_frame = ExecFrame . new (
73
- node : ast_operation ,
74
+ node : irep_root ,
74
75
value : query_object . root_value ,
75
- type : root_type ,
76
+ type : irep_root . return_type ,
76
77
path : [ ]
77
78
)
78
79
@@ -194,7 +195,7 @@ def initialize
194
195
195
196
# One step of execution. Each step in execution gets its own frame.
196
197
#
197
- # - {ExecFrame#node} is the AST node which is being interpreted
198
+ # - {ExecFrame#node} is the IRep node which is being interpreted
198
199
# - {ExecFrame#path} is like a stack trace, it is used for patching deferred values
199
200
# - {ExecFrame#value} is the object being exposed by GraphQL at this point
200
201
# - {ExecFrame#type} is the GraphQL type which exposes {#value} at this point
@@ -239,15 +240,13 @@ def resolve_or_defer_frame(scope, thread, frame)
239
240
# Determine this frame's result and return it
240
241
# Any subselections marked as `@defer` will be deferred.
241
242
def resolve_frame ( scope , thread , frame )
242
- ast_node = frame . node
243
+ ast_node = frame . node . ast_node
243
244
case ast_node
244
245
when Nodes ::OperationDefinition
245
246
resolve_selections ( scope , thread , frame )
246
247
when Nodes ::Field
247
248
type_defn = frame . type
248
- # Use scope because it provides dynamic fields too (like __typename)
249
- field_defn = scope . get_field ( type_defn , ast_node . name )
250
-
249
+ field_defn = scope . get_field ( type_defn , frame . node . definition . name )
251
250
field_result = resolve_field_frame ( scope , thread , frame , field_defn )
252
251
return_type_defn = field_defn . type
253
252
@@ -261,66 +260,65 @@ def resolve_frame(scope, thread, frame)
261
260
else
262
261
raise ( "No defined resolution for #{ ast_node . class . name } (#{ ast_node } )" )
263
262
end
263
+ rescue GraphQL ::InvalidNullError => err
264
+ if return_type_defn && return_type_defn . kind . non_null?
265
+ raise ( err )
266
+ else
267
+ err . parent_error? || thread . errors << err
268
+ nil
269
+ end
264
270
end
265
271
266
272
# Recursively resolve selections on `outer_frame.node`.
267
273
# Return a `Hash<String, Any>` of identifiers and results.
268
274
# Deferred fields will be absent from the result.
269
275
def resolve_selections ( scope , thread , outer_frame )
270
- merged_selections = GraphQL ::Execution ::SelectionOnType . flatten (
271
- scope ,
272
- outer_frame . value ,
273
- outer_frame . type ,
274
- outer_frame . node . selections ,
275
- )
276
+ merged_selections = outer_frame . node . children
277
+ query = scope . query
276
278
277
- resolved_selections = merged_selections . each_with_object ( { } ) do |ast_selection , memo |
278
- selection_key = if ast_selection . is_a? ( Nodes ::Field )
279
- ast_selection . alias || ast_selection . name
280
- else
281
- ast_selection . name
279
+ resolved_selections = merged_selections . each_with_object ( { } ) do |( name , irep_selection ) , memo |
280
+ field_applies_to_type = irep_selection . on_types . any? do |child_type |
281
+ GraphQL ::Execution ::Typecast . compatible? ( outer_frame . value , child_type , outer_frame . type , query . context )
282
282
end
283
+ if field_applies_to_type && !GraphQL ::Execution ::DirectiveChecks . skip? ( irep_selection , query )
284
+ selection_key = irep_selection . name
283
285
284
- inner_frame = ExecFrame . new (
285
- node : ast_selection ,
286
- path : outer_frame . path + [ selection_key ] ,
287
- type : outer_frame . type ,
288
- value : outer_frame . value ,
289
- )
286
+ inner_frame = ExecFrame . new (
287
+ node : irep_selection ,
288
+ path : outer_frame . path + [ selection_key ] ,
289
+ type : outer_frame . type ,
290
+ value : outer_frame . value ,
291
+ )
290
292
291
- inner_result = resolve_or_defer_frame ( scope , thread , inner_frame )
292
- if inner_result != DEFERRED_RESULT
293
- memo [ selection_key ] = inner_result
293
+ inner_result = resolve_or_defer_frame ( scope , thread , inner_frame )
294
+ if inner_result != DEFERRED_RESULT
295
+ memo [ selection_key ] = inner_result
296
+ end
294
297
end
295
298
end
296
299
resolved_selections
297
- rescue GraphQL ::InvalidNullError => err
298
- err . parent_error? || thread . errors << err
299
- nil
300
300
end
301
301
302
302
# Resolve `field_defn` on `frame.node`, returning the value
303
303
# of the {Field#resolve} proc.
304
304
# It might be an error or an object, not ready for serialization yet.
305
305
# @return [Object] the return value from `field_defn`'s resolve proc
306
306
def resolve_field_frame ( scope , thread , frame , field_defn )
307
- ast_node = frame . node
307
+ ast_node = frame . node . ast_node
308
308
type_defn = frame . type
309
309
value = frame . value
310
310
query = scope . query
311
311
312
312
# Build arguments according to query-string literals, default values, and query variables
313
- arguments = GraphQL ::Query ::LiteralInput . from_arguments (
314
- ast_node . arguments ,
315
- field_defn . arguments ,
316
- query . variables
317
- )
313
+ arguments = query . arguments_for ( frame . node )
318
314
319
315
# This is the last call in the middleware chain; it actually calls the user's resolve proc
320
316
field_resolve_middleware_proc = -> ( _parent_type , parent_object , field_definition , field_args , query_ctx , _next ) {
321
317
query_ctx . ast_node = ast_node
318
+ query_ctx . irep_node = frame . node
322
319
value = field_definition . resolve ( parent_object , field_args , query_ctx )
323
320
query_ctx . ast_node = nil
321
+ query_ctx . irep_node = frame . node
324
322
value
325
323
}
326
324
@@ -353,7 +351,7 @@ def resolve_field_frame(scope, thread, frame, field_defn)
353
351
def resolve_value ( scope , thread , frame , value , type_defn )
354
352
if value . nil? || value . is_a? ( GraphQL ::ExecutionError )
355
353
if type_defn . kind . non_null?
356
- raise GraphQL ::InvalidNullError . new ( frame . node . name , value )
354
+ raise GraphQL ::InvalidNullError . new ( frame . node . ast_node . name , value )
357
355
else
358
356
nil
359
357
end
0 commit comments