|
18 | 18 | import graphql.language.Document; |
19 | 19 | import graphql.language.FragmentDefinition; |
20 | 20 | import graphql.language.OperationDefinition; |
21 | | -import graphql.normalized.ExecutableNormalizedOperation; |
22 | 21 | import graphql.normalized.ExecutableNormalizedOperationFactory; |
| 22 | +import graphql.normalized.GraphQlNormalizedOperation; |
| 23 | +import graphql.normalized.nf.NormalizedDocument; |
| 24 | +import graphql.normalized.nf.NormalizedDocumentFactory; |
23 | 25 | import graphql.schema.GraphQLSchema; |
24 | 26 | import graphql.util.FpKit; |
25 | 27 | import graphql.util.LockKit; |
@@ -66,7 +68,7 @@ public class ExecutionContext { |
66 | 68 | private final ResponseMapFactory responseMapFactory; |
67 | 69 |
|
68 | 70 | private final ExecutionInput executionInput; |
69 | | - private final Supplier<ExecutableNormalizedOperation> queryTree; |
| 71 | + private final Supplier<GraphQlNormalizedOperation> queryTree; |
70 | 72 | private final boolean propagateErrorsOnNonNullContractFailure; |
71 | 73 |
|
72 | 74 | private final AtomicInteger isRunning = new AtomicInteger(0); |
@@ -101,7 +103,7 @@ public class ExecutionContext { |
101 | 103 | this.localContext = builder.localContext; |
102 | 104 | this.executionInput = builder.executionInput; |
103 | 105 | this.dataLoaderDispatcherStrategy = builder.dataLoaderDispatcherStrategy; |
104 | | - this.queryTree = FpKit.interThreadMemoize(this::createExecutableNormalizedOperation); |
| 106 | + this.queryTree = FpKit.interThreadMemoize(this::createNormalizedOperation); |
105 | 107 | this.propagateErrorsOnNonNullContractFailure = builder.propagateErrorsOnNonNullContractFailure; |
106 | 108 | this.engineRunningState = builder.engineRunningState; |
107 | 109 | } |
@@ -337,7 +339,7 @@ public ExecutionStrategy getStrategy(OperationDefinition.Operation operation) { |
337 | 339 | } |
338 | 340 | } |
339 | 341 |
|
340 | | - public Supplier<ExecutableNormalizedOperation> getNormalizedQueryTree() { |
| 342 | + public Supplier<GraphQlNormalizedOperation> getNormalizedQueryTree() { |
341 | 343 | return queryTree; |
342 | 344 | } |
343 | 345 |
|
@@ -369,22 +371,52 @@ public ResultNodesInfo getResultNodesInfo() { |
369 | 371 | return resultNodesInfo; |
370 | 372 | } |
371 | 373 |
|
372 | | - private ExecutableNormalizedOperation createExecutableNormalizedOperation() { |
| 374 | + private GraphQlNormalizedOperation createNormalizedOperation() { |
373 | 375 | var parameters = new InstrumentationCreateNormalizedOperationParameters(executionInput, graphQLSchema); |
374 | 376 | var instrument = instrumentation.beginCreateNormalizedOperation(parameters, instrumentationState); |
375 | | - var result = ExecutableNormalizedOperationFactory.createExecutableNormalizedOperation(graphQLSchema, operationDefinition, fragmentsByName, coercedVariables); |
| 377 | + GraphQlNormalizedOperation result; |
| 378 | + if (hasNormalizedDocumentSupport()) { |
| 379 | + var normalizedDocument = NormalizedDocumentFactory.createNormalizedDocument(graphQLSchema, document); |
| 380 | + // Search the document for the operation that matches the operationDefinition name, |
| 381 | + // if no match then it could be anonymous query, then fallback to the first operation. |
| 382 | + var normalizedOperations = normalizedDocument.getNormalizedOperations(); |
| 383 | + result = normalizedOperations.stream() |
| 384 | + .filter(this::isExecutingOperation) |
| 385 | + .findAny() |
| 386 | + .map(NormalizedDocument.NormalizedOperationWithAssumedSkipIncludeVariables::getNormalizedOperation) |
| 387 | + .orElseGet(normalizedDocument::getSingleNormalizedOperation); |
| 388 | + } else { |
| 389 | + result = ExecutableNormalizedOperationFactory.createExecutableNormalizedOperation(graphQLSchema, operationDefinition, fragmentsByName, coercedVariables); |
| 390 | + } |
376 | 391 | if (instrument != null) { |
377 | 392 | instrument.onCompleted(result, null); |
378 | 393 | } |
379 | 394 | return result; |
380 | 395 | } |
381 | 396 |
|
| 397 | + private boolean isExecutingOperation(NormalizedDocument.NormalizedOperationWithAssumedSkipIncludeVariables op) { |
| 398 | + var operation = op.getNormalizedOperation(); |
| 399 | + var operationName = operation.getOperationName(); |
| 400 | + var operationDefinitionName = operationDefinition.getName(); |
| 401 | + if (operationName == null || operationDefinitionName == null) { |
| 402 | + return false; |
| 403 | + } |
| 404 | + |
| 405 | + return operationName.equals(operationDefinitionName); |
| 406 | + } |
| 407 | + |
382 | 408 | @Internal |
383 | 409 | public boolean hasIncrementalSupport() { |
384 | 410 | GraphQLContext graphqlContext = getGraphQLContext(); |
385 | 411 | return graphqlContext != null && graphqlContext.getBoolean(ExperimentalApi.ENABLE_INCREMENTAL_SUPPORT); |
386 | 412 | } |
387 | 413 |
|
| 414 | + @Internal |
| 415 | + public boolean hasNormalizedDocumentSupport() { |
| 416 | + GraphQLContext graphqlContext = getGraphQLContext(); |
| 417 | + return graphqlContext != null && graphqlContext.getBoolean(ExperimentalApi.ENABLE_NORMALIZED_DOCUMENT_SUPPORT); |
| 418 | + } |
| 419 | + |
388 | 420 | @Internal |
389 | 421 | public EngineRunningState getEngineRunningState() { |
390 | 422 | return engineRunningState; |
|
0 commit comments