1717import graphql .execution .instrumentation .ExecuteObjectInstrumentationContext ;
1818import graphql .execution .instrumentation .Instrumentation ;
1919import graphql .execution .instrumentation .InstrumentationContext ;
20+ import graphql .execution .instrumentation .dataloader .DataLoaderDispatcherInstrumentationState ;
21+ import graphql .execution .instrumentation .dataloader .FallbackDataLoaderDispatchStrategy ;
22+ import graphql .execution .instrumentation .dataloader .PerLevelDataLoaderDispatchStrategy ;
2023import graphql .execution .instrumentation .parameters .InstrumentationExecutionStrategyParameters ;
2124import graphql .execution .instrumentation .parameters .InstrumentationFieldCompleteParameters ;
2225import graphql .execution .instrumentation .parameters .InstrumentationFieldFetchParameters ;
@@ -133,7 +136,7 @@ public abstract class ExecutionStrategy {
133136 protected final DataFetcherExceptionHandler dataFetcherExceptionHandler ;
134137 private final ResolveType resolvedType = new ResolveType ();
135138
136- protected final DataLoaderDispatchStrategy dataLoaderDispatcherStrategy = DataLoaderDispatchStrategy . NO_OP ;
139+ protected DataLoaderDispatchStrategy dataLoaderDispatcherStrategy ;
137140
138141 /**
139142 * The default execution strategy constructor uses the {@link SimpleDataFetcherExceptionHandler}
@@ -143,6 +146,7 @@ protected ExecutionStrategy() {
143146 dataFetcherExceptionHandler = new SimpleDataFetcherExceptionHandler ();
144147 }
145148
149+
146150 /**
147151 * The consumers of the execution strategy can pass in a {@link DataFetcherExceptionHandler} to better
148152 * decide what do when a data fetching error happens
@@ -153,6 +157,23 @@ protected ExecutionStrategy(DataFetcherExceptionHandler dataFetcherExceptionHand
153157 this .dataFetcherExceptionHandler = dataFetcherExceptionHandler ;
154158 }
155159
160+ public void initBeforeExecution (ExecutionContext executionContext ) {
161+ initDataLoaderStrategy (executionContext );
162+ }
163+
164+ private void initDataLoaderStrategy (ExecutionContext executionContext ) {
165+ if (executionContext .getDataLoaderRegistry () == DataLoaderDispatcherInstrumentationState .EMPTY_DATALOADER_REGISTRY ) {
166+ this .dataLoaderDispatcherStrategy = DataLoaderDispatchStrategy .NO_OP ;
167+ return ;
168+ }
169+ if (this instanceof AsyncExecutionStrategy ) {
170+ this .dataLoaderDispatcherStrategy = new PerLevelDataLoaderDispatchStrategy (executionContext );
171+ } else {
172+ this .dataLoaderDispatcherStrategy = new FallbackDataLoaderDispatchStrategy (executionContext );
173+ }
174+ }
175+
176+
156177 @ Internal
157178 public static String mkNameForPath (Field currentField ) {
158179 return mkNameForPath (Collections .singletonList (currentField ));
@@ -188,6 +209,7 @@ public static String mkNameForPath(List<Field> currentField) {
188209 * @throws NonNullableFieldWasNullException in the future if a non-null field resolves to a null value
189210 */
190211 protected CompletableFuture <Map <String , Object >> executeObject (ExecutionContext executionContext , ExecutionStrategyParameters parameters ) throws NonNullableFieldWasNullException {
212+ dataLoaderDispatcherStrategy .executeObject (executionContext , parameters );
191213 Instrumentation instrumentation = executionContext .getInstrumentation ();
192214 InstrumentationExecutionStrategyParameters instrumentationParameters = new InstrumentationExecutionStrategyParameters (executionContext , parameters );
193215
@@ -211,12 +233,14 @@ protected CompletableFuture<Map<String, Object>> executeObject(ExecutionContext
211233 for (FieldValueInfo completeValueInfo : completeValueInfos ) {
212234 resultFutures .add (completeValueInfo .getFieldValueFuture ());
213235 }
236+ dataLoaderDispatcherStrategy .executeObject_onFieldValuesInfo (completeValueInfos , parameters );
214237 resolveObjectCtx .onFieldValuesInfo (completeValueInfos );
215238 resultFutures .await ().whenComplete (handleResultsConsumer );
216239 }).exceptionally ((ex ) -> {
217240 // if there are any issues with combining/handling the field results,
218241 // complete the future at all costs and bubble up any thrown exception so
219242 // the execution does not hang.
243+ dataLoaderDispatcherStrategy .executeObject_onFieldValuesException (ex , parameters );
220244 resolveObjectCtx .onFieldValuesException ();
221245 overallResult .completeExceptionally (ex );
222246 return null ;
@@ -371,9 +395,10 @@ protected CompletableFuture<FetchedValue> fetchField(ExecutionContext executionC
371395 executionContext .getInstrumentationState ())
372396 );
373397
398+ dataFetcher = dataLoaderDispatcherStrategy .modifyDataFetcher (dataFetcher );
374399 dataFetcher = instrumentation .instrumentDataFetcher (dataFetcher , instrumentationFieldFetchParams , executionContext .getInstrumentationState ());
375400 CompletableFuture <Object > fetchedValue = invokeDataFetcher (executionContext , parameters , fieldDef , dataFetchingEnvironment , dataFetcher );
376-
401+ dataLoaderDispatcherStrategy . fieldFetched ( executionContext , parameters , dataFetcher , fetchedValue );
377402 fetchCtx .onDispatched (fetchedValue );
378403 return fetchedValue
379404 .handle ((result , exception ) -> {
0 commit comments