105
105
* <p>
106
106
* The first phase (data fetching) is handled by the method {@link #fetchField(ExecutionContext, ExecutionStrategyParameters)}
107
107
* <p>
108
- * The second phase (value completion) is handled by the methods {@link #completeField(ExecutionContext, ExecutionStrategyParameters, FetchedValue )}
108
+ * The second phase (value completion) is handled by the methods {@link #completeField(ExecutionContext, ExecutionStrategyParameters, Object )}
109
109
* and the other "completeXXX" methods.
110
110
* <p>
111
111
* The order of fields fetching and completion is up to the execution strategy. As the graphql specification
@@ -358,7 +358,7 @@ protected Object resolveFieldWithInfo(ExecutionContext executionContext, Executi
358
358
359
359
Object fetchedValueObj = fetchField (executionContext , parameters );
360
360
if (fetchedValueObj instanceof CompletableFuture ) {
361
- CompletableFuture <FetchedValue > fetchFieldFuture = (CompletableFuture <FetchedValue >) fetchedValueObj ;
361
+ CompletableFuture <Object > fetchFieldFuture = (CompletableFuture <Object >) fetchedValueObj ;
362
362
CompletableFuture <FieldValueInfo > result = fetchFieldFuture .thenApply ((fetchedValue ) ->
363
363
completeField (fieldDef , executionContext , parameters , fetchedValue ));
364
364
@@ -367,10 +367,9 @@ protected Object resolveFieldWithInfo(ExecutionContext executionContext, Executi
367
367
return result ;
368
368
} else {
369
369
try {
370
- FetchedValue fetchedValue = (FetchedValue ) fetchedValueObj ;
371
- FieldValueInfo fieldValueInfo = completeField (fieldDef , executionContext , parameters , fetchedValue );
370
+ FieldValueInfo fieldValueInfo = completeField (fieldDef , executionContext , parameters , fetchedValueObj );
372
371
fieldCtx .onDispatched ();
373
- fieldCtx .onCompleted (fetchedValue .getFetchedValue (), null );
372
+ fieldCtx .onCompleted (FetchedValue .getFetchedValue (fetchedValueObj ), null );
374
373
return fieldValueInfo ;
375
374
} catch (Exception e ) {
376
375
return Async .exceptionallyCompletedFuture (e );
@@ -383,29 +382,29 @@ protected Object resolveFieldWithInfo(ExecutionContext executionContext, Executi
383
382
* {@link GraphQLFieldDefinition}.
384
383
* <p>
385
384
* Graphql fragments mean that for any give logical field can have one or more {@link Field} values associated with it
386
- * in the query, hence the fieldList. However the first entry is representative of the field for most purposes.
385
+ * in the query, hence the fieldList. However, the first entry is representative of the field for most purposes.
387
386
*
388
387
* @param executionContext contains the top level execution parameters
389
388
* @param parameters contains the parameters holding the fields to be executed and source object
390
389
*
391
- * @return a promise to a {@link FetchedValue} object or the {@link FetchedValue} itself
390
+ * @return a promise to a value object or the value itself. The value maybe a raw object OR a {@link FetchedValue}
392
391
*
393
- * @throws NonNullableFieldWasNullException in the future if a non null field resolves to a null value
392
+ * @throws NonNullableFieldWasNullException in the future if a non- null field resolves to a null value
394
393
*/
395
- @ DuckTyped (shape = "CompletableFuture<FetchedValue> | FetchedValue" )
394
+ @ DuckTyped (shape = "CompletableFuture<FetchedValue|Object > | < FetchedValue|Object> " )
396
395
protected Object fetchField (ExecutionContext executionContext , ExecutionStrategyParameters parameters ) {
397
396
MergedField field = parameters .getField ();
398
397
GraphQLObjectType parentType = (GraphQLObjectType ) parameters .getExecutionStepInfo ().getUnwrappedNonNullType ();
399
398
GraphQLFieldDefinition fieldDef = getFieldDef (executionContext .getGraphQLSchema (), parentType , field .getSingleField ());
400
399
return fetchField (fieldDef , executionContext , parameters );
401
400
}
402
401
403
- @ DuckTyped (shape = "CompletableFuture<FetchedValue> | FetchedValue" )
402
+ @ DuckTyped (shape = "CompletableFuture<FetchedValue|Object > | < FetchedValue|Object> " )
404
403
private Object fetchField (GraphQLFieldDefinition fieldDef , ExecutionContext executionContext , ExecutionStrategyParameters parameters ) {
405
404
executionContext .throwIfCancelled ();
406
405
407
406
if (incrementAndCheckMaxNodesExceeded (executionContext )) {
408
- return new FetchedValue ( null , Collections . emptyList (), null ) ;
407
+ return null ;
409
408
}
410
409
411
410
MergedField field = parameters .getField ();
@@ -486,9 +485,8 @@ private Object fetchField(GraphQLFieldDefinition fieldDef, ExecutionContext exec
486
485
}
487
486
});
488
487
CompletableFuture <Object > rawResultCF = engineRunningState .compose (handleCF , Function .identity ());
489
- CompletableFuture < FetchedValue > fetchedValueCF = rawResultCF
488
+ return rawResultCF
490
489
.thenApply (result -> unboxPossibleDataFetcherResult (executionContext , parameters , result ));
491
- return fetchedValueCF ;
492
490
} else {
493
491
fetchCtx .onCompleted (fetchedObject , null );
494
492
return unboxPossibleDataFetcherResult (executionContext , parameters , fetchedObject );
@@ -520,9 +518,21 @@ protected Supplier<ExecutableNormalizedField> getNormalizedField(ExecutionContex
520
518
return () -> normalizedQuery .get ().getNormalizedField (parameters .getField (), executionStepInfo .get ().getObjectType (), executionStepInfo .get ().getPath ());
521
519
}
522
520
523
- protected FetchedValue unboxPossibleDataFetcherResult (ExecutionContext executionContext ,
524
- ExecutionStrategyParameters parameters ,
525
- Object result ) {
521
+ /**
522
+ * If the data fetching returned a {@link DataFetcherResult} then it can contain errors and new local context
523
+ * and hence it gets turned into a {@link FetchedValue} but otherwise this method returns the unboxed
524
+ * value without the wrapper. This means its more efficient overall by default.
525
+ *
526
+ * @param executionContext the execution context in play
527
+ * @param parameters the parameters in play
528
+ * @param result the fetched raw object
529
+ *
530
+ * @return an unboxed value which can be a FetchedValue or an Object
531
+ */
532
+ @ DuckTyped (shape = "FetchedValue | Object" )
533
+ protected Object unboxPossibleDataFetcherResult (ExecutionContext executionContext ,
534
+ ExecutionStrategyParameters parameters ,
535
+ Object result ) {
526
536
if (result instanceof DataFetcherResult ) {
527
537
DataFetcherResult <?> dataFetcherResult = (DataFetcherResult <?>) result ;
528
538
@@ -538,8 +548,7 @@ protected FetchedValue unboxPossibleDataFetcherResult(ExecutionContext execution
538
548
Object unBoxedValue = executionContext .getValueUnboxer ().unbox (dataFetcherResult .getData ());
539
549
return new FetchedValue (unBoxedValue , dataFetcherResult .getErrors (), localContext );
540
550
} else {
541
- Object unBoxedValue = executionContext .getValueUnboxer ().unbox (result );
542
- return new FetchedValue (unBoxedValue , ImmutableList .of (), parameters .getLocalContext ());
551
+ return executionContext .getValueUnboxer ().unbox (result );
543
552
}
544
553
}
545
554
@@ -577,29 +586,32 @@ protected <T> CompletableFuture<T> handleFetchingException(
577
586
private <T > CompletableFuture <T > asyncHandleException (DataFetcherExceptionHandler handler , DataFetcherExceptionHandlerParameters handlerParameters ) {
578
587
//noinspection unchecked
579
588
return handler .handleException (handlerParameters ).thenApply (
580
- handlerResult -> (T ) DataFetcherResult .< FetchedValue > newResult ().errors (handlerResult .getErrors ()).build ()
589
+ handlerResult -> (T ) DataFetcherResult .newResult ().errors (handlerResult .getErrors ()).build ()
581
590
);
582
591
}
583
592
584
593
/**
585
594
* Called to complete a field based on the type of the field.
586
595
* <p>
587
- * If the field is a scalar type, then it will be coerced and returned. However if the field type is an complex object type, then
596
+ * If the field is a scalar type, then it will be coerced and returned. However, if the field type is an complex object type, then
588
597
* the execution strategy will be called recursively again to execute the fields of that type before returning.
589
598
* <p>
590
599
* Graphql fragments mean that for any give logical field can have one or more {@link Field} values associated with it
591
- * in the query, hence the fieldList. However the first entry is representative of the field for most purposes.
600
+ * in the query, hence the fieldList. However, the first entry is representative of the field for most purposes.
592
601
*
593
602
* @param executionContext contains the top level execution parameters
594
603
* @param parameters contains the parameters holding the fields to be executed and source object
595
- * @param fetchedValue the fetched raw value
604
+ * @param fetchedValue the fetched raw value or perhaps a {@link FetchedValue} wrapper of that value
596
605
*
597
606
* @return a {@link FieldValueInfo}
598
607
*
599
608
* @throws NonNullableFieldWasNullException in the {@link FieldValueInfo#getFieldValueFuture()} future
600
609
* if a nonnull field resolves to a null value
601
610
*/
602
- protected FieldValueInfo completeField (ExecutionContext executionContext , ExecutionStrategyParameters parameters , FetchedValue fetchedValue ) {
611
+ protected FieldValueInfo completeField (ExecutionContext executionContext ,
612
+ ExecutionStrategyParameters parameters ,
613
+ @ DuckTyped (shape = "Object | FetchedValue" )
614
+ Object fetchedValue ) {
603
615
executionContext .throwIfCancelled ();
604
616
605
617
Field field = parameters .getField ().getSingleField ();
@@ -608,7 +620,7 @@ protected FieldValueInfo completeField(ExecutionContext executionContext, Execut
608
620
return completeField (fieldDef , executionContext , parameters , fetchedValue );
609
621
}
610
622
611
- private FieldValueInfo completeField (GraphQLFieldDefinition fieldDef , ExecutionContext executionContext , ExecutionStrategyParameters parameters , FetchedValue fetchedValue ) {
623
+ private FieldValueInfo completeField (GraphQLFieldDefinition fieldDef , ExecutionContext executionContext , ExecutionStrategyParameters parameters , Object fetchedValue ) {
612
624
GraphQLObjectType parentType = (GraphQLObjectType ) parameters .getExecutionStepInfo ().getUnwrappedNonNullType ();
613
625
ExecutionStepInfo executionStepInfo = createExecutionStepInfo (executionContext , parameters , fieldDef , parentType );
614
626
@@ -618,9 +630,11 @@ private FieldValueInfo completeField(GraphQLFieldDefinition fieldDef, ExecutionC
618
630
instrumentationParams , executionContext .getInstrumentationState ()
619
631
));
620
632
621
- ExecutionStrategyParameters newParameters = parameters .transform (executionStepInfo ,
622
- fetchedValue .getLocalContext (),
623
- fetchedValue .getFetchedValue ());
633
+ ExecutionStrategyParameters newParameters = parameters .transform (
634
+ executionStepInfo ,
635
+ FetchedValue .getLocalContext (fetchedValue , parameters .getLocalContext ()),
636
+ FetchedValue .getFetchedValue (fetchedValue )
637
+ );
624
638
625
639
FieldValueInfo fieldValueInfo = completeValue (executionContext , newParameters );
626
640
ctxCompleteField .onDispatched ();
@@ -777,12 +791,14 @@ protected FieldValueInfo completeValueForList(ExecutionContext executionContext,
777
791
778
792
ExecutionStepInfo stepInfoForListElement = executionStepInfoFactory .newExecutionStepInfoForListElement (executionStepInfo , indexedPath );
779
793
780
- FetchedValue value = unboxPossibleDataFetcherResult (executionContext , parameters , item );
794
+ Object fetchedValue = unboxPossibleDataFetcherResult (executionContext , parameters , item );
781
795
782
- ExecutionStrategyParameters newParameters = parameters .transform (stepInfoForListElement ,
796
+ ExecutionStrategyParameters newParameters = parameters .transform (
797
+ stepInfoForListElement ,
783
798
indexedPath ,
784
- value .getLocalContext (),
785
- value .getFetchedValue ());
799
+ FetchedValue .getLocalContext (fetchedValue , parameters .getLocalContext ()),
800
+ FetchedValue .getFetchedValue (fetchedValue )
801
+ );
786
802
787
803
fieldValueInfos .add (completeValue (executionContext , newParameters ));
788
804
index ++;
0 commit comments