1515import graphql .execution .instrumentation .Instrumentation ;
1616import graphql .execution .instrumentation .InstrumentationState ;
1717import graphql .execution .instrumentation .parameters .InstrumentationCreateExecutableNormalizedOperationParameters ;
18+ import graphql .execution .instrumentation .parameters .InstrumentationCreateNormalizedDocumentParameters ;
19+ import graphql .execution .instrumentation .parameters .InstrumentationExecutionParameters ;
1820import graphql .language .Document ;
1921import graphql .language .FragmentDefinition ;
2022import graphql .language .OperationDefinition ;
2123import graphql .normalized .ExecutableNormalizedOperation ;
2224import graphql .normalized .ExecutableNormalizedOperationFactory ;
25+ import graphql .normalized .GraphQlNormalizedOperation ;
26+ import graphql .normalized .nf .NormalizedDocument ;
27+ import graphql .normalized .nf .NormalizedDocumentFactory ;
28+ import graphql .normalized .nf .NormalizedOperation ;
2329import graphql .schema .GraphQLSchema ;
2430import graphql .util .FpKit ;
2531import graphql .util .LockKit ;
@@ -66,7 +72,7 @@ public class ExecutionContext {
6672 private final ResponseMapFactory responseMapFactory ;
6773
6874 private final ExecutionInput executionInput ;
69- private final Supplier <ExecutableNormalizedOperation > queryTree ;
75+ private final Supplier <GraphQlNormalizedOperation > queryTree ;
7076 private final boolean propagateErrorsOnNonNullContractFailure ;
7177
7278 private final AtomicInteger isRunning = new AtomicInteger (0 );
@@ -101,7 +107,7 @@ public class ExecutionContext {
101107 this .localContext = builder .localContext ;
102108 this .executionInput = builder .executionInput ;
103109 this .dataLoaderDispatcherStrategy = builder .dataLoaderDispatcherStrategy ;
104- this .queryTree = FpKit .interThreadMemoize (this ::createExecutableNormalizedOperation );
110+ this .queryTree = FpKit .interThreadMemoize (this ::createGraphQLNormalizedOperation );
105111 this .propagateErrorsOnNonNullContractFailure = builder .propagateErrorsOnNonNullContractFailure ;
106112 this .engineRunningState = builder .engineRunningState ;
107113 }
@@ -337,7 +343,7 @@ public ExecutionStrategy getStrategy(OperationDefinition.Operation operation) {
337343 }
338344 }
339345
340- public Supplier <ExecutableNormalizedOperation > getNormalizedQueryTree () {
346+ public Supplier <GraphQlNormalizedOperation > getNormalizedQueryTree () {
341347 return queryTree ;
342348 }
343349
@@ -369,14 +375,57 @@ public ResultNodesInfo getResultNodesInfo() {
369375 return resultNodesInfo ;
370376 }
371377
378+ private GraphQlNormalizedOperation createGraphQLNormalizedOperation () {
379+ // Check for experimental support for normalized documents
380+ if (hasNormalizedDocumentSupport ()) {
381+ return createNormalizedOperation ();
382+ }
383+
384+ return createExecutableNormalizedOperation ();
385+ }
386+
387+ @ ExperimentalApi
388+ private NormalizedOperation createNormalizedOperation () {
389+ var parameters = new InstrumentationCreateNormalizedDocumentParameters (executionInput , graphQLSchema );
390+ var instrument = instrumentation .beginCreateNormalizedDocument (parameters , instrumentationState );
391+ var normalizedDocument = NormalizedDocumentFactory .createNormalizedDocument (graphQLSchema , document );
392+
393+ // Search the document for the operation that matches the operationDefinition name,
394+ // if no match then it could be anonymous query, then fallback to the first operation.
395+ var normalizedOperations = normalizedDocument .getNormalizedOperations ();
396+ var normalizedOperation = normalizedOperations .stream ()
397+ .filter (this ::isExecutingOperation )
398+ .findAny ()
399+ .map (NormalizedDocument .NormalizedOperationWithAssumedSkipIncludeVariables ::getNormalizedOperation )
400+ .orElseGet (normalizedDocument ::getSingleNormalizedOperation );
401+
402+ if (instrument != null ) {
403+ instrument .onCompleted (normalizedDocument , null );
404+ }
405+
406+ return normalizedOperation ;
407+ }
408+
372409 private ExecutableNormalizedOperation createExecutableNormalizedOperation () {
373410 var parameters = new InstrumentationCreateExecutableNormalizedOperationParameters (executionInput , graphQLSchema );
374411 var instrument = instrumentation .beginCreateExecutableNormalizedOperation (parameters , instrumentationState );
375- var result = ExecutableNormalizedOperationFactory .createExecutableNormalizedOperation (graphQLSchema , operationDefinition , fragmentsByName , coercedVariables );
412+ var executableNormalizedOperation = ExecutableNormalizedOperationFactory .createExecutableNormalizedOperation (graphQLSchema , operationDefinition , fragmentsByName , coercedVariables );
376413 if (instrument != null ) {
377- instrument .onCompleted (result , null );
414+ instrument .onCompleted (executableNormalizedOperation , null );
415+ }
416+
417+ return executableNormalizedOperation ;
418+ }
419+
420+ private boolean isExecutingOperation (NormalizedDocument .NormalizedOperationWithAssumedSkipIncludeVariables op ) {
421+ var operation = op .getNormalizedOperation ();
422+ var operationName = operation .getOperationName ();
423+ var operationDefinitionName = operationDefinition .getName ();
424+ if (operationName == null || operationDefinitionName == null ) {
425+ return false ;
378426 }
379- return result ;
427+
428+ return operationName .equals (operationDefinitionName );
380429 }
381430
382431 @ Internal
@@ -385,6 +434,12 @@ public boolean hasIncrementalSupport() {
385434 return graphqlContext != null && graphqlContext .getBoolean (ExperimentalApi .ENABLE_INCREMENTAL_SUPPORT );
386435 }
387436
437+ @ Internal
438+ private boolean hasNormalizedDocumentSupport () {
439+ GraphQLContext graphqlContext = getGraphQLContext ();
440+ return graphqlContext != null && graphqlContext .getBoolean (ExperimentalApi .ENABLE_NORMALIZED_DOCUMENT_SUPPORT );
441+ }
442+
388443 @ Internal
389444 public EngineRunningState getEngineRunningState () {
390445 return engineRunningState ;
0 commit comments