X Tutup
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 16 additions & 8 deletions src/main/java/graphql/GraphQL.java
Original file line number Diff line number Diff line change
Expand Up @@ -418,14 +418,13 @@ public CompletableFuture<ExecutionResult> executeAsync(UnaryOperator<ExecutionIn
* @return a promise to an {@link ExecutionResult} which can include errors
*/
public CompletableFuture<ExecutionResult> executeAsync(ExecutionInput executionInput) {
try {
if (logNotSafe.isDebugEnabled()) {
logNotSafe.debug("Executing request. operation name: '{}'. query: '{}'. variables '{}'", executionInput.getOperationName(), executionInput.getQuery(), executionInput.getVariables());
}
executionInput = ensureInputHasId(executionInput);

InstrumentationState instrumentationState = instrumentation.createState(new InstrumentationCreateStateParameters(this.graphQLSchema, executionInput));
if (logNotSafe.isDebugEnabled()) {
logNotSafe.debug("Executing request. operation name: '{}'. query: '{}'. variables '{}'", executionInput.getOperationName(), executionInput.getQuery(), executionInput.getVariables());
}
executionInput = ensureInputHasId(executionInput);

InstrumentationState instrumentationState = instrumentation.createState(new InstrumentationCreateStateParameters(this.graphQLSchema, executionInput));
try {
InstrumentationExecutionParameters inputInstrumentationParameters = new InstrumentationExecutionParameters(executionInput, this.graphQLSchema, instrumentationState);
executionInput = instrumentation.instrumentExecutionInput(executionInput, inputInstrumentationParameters, instrumentationState);

Expand All @@ -445,10 +444,19 @@ public CompletableFuture<ExecutionResult> executeAsync(ExecutionInput executionI
executionResult = executionResult.thenCompose(result -> instrumentation.instrumentExecutionResult(result, instrumentationParameters, instrumentationState));
return executionResult;
} catch (AbortExecutionException abortException) {
return CompletableFuture.completedFuture(abortException.toExecutionResult());
return handleAbortException(executionInput, instrumentationState, abortException);
}
}

private CompletableFuture<ExecutionResult> handleAbortException(ExecutionInput executionInput, InstrumentationState instrumentationState, AbortExecutionException abortException) {
CompletableFuture<ExecutionResult> executionResult = CompletableFuture.completedFuture(abortException.toExecutionResult());
InstrumentationExecutionParameters instrumentationParameters = new InstrumentationExecutionParameters(executionInput, this.graphQLSchema, instrumentationState);
//
// allow instrumentation to tweak the result
executionResult = executionResult.thenCompose(result -> instrumentation.instrumentExecutionResult(result, instrumentationParameters, instrumentationState));
return executionResult;
}

private ExecutionInput ensureInputHasId(ExecutionInput executionInput) {
if (executionInput.getExecutionId() != null) {
return executionInput;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,24 @@
package graphql.execution

import graphql.ErrorType
import graphql.ExecutionInput
import graphql.ExecutionResult
import graphql.GraphQL
import graphql.GraphQLError
import graphql.TestUtil
import graphql.execution.instrumentation.Instrumentation
import graphql.execution.instrumentation.InstrumentationContext
import graphql.execution.instrumentation.InstrumentationState
import graphql.execution.instrumentation.SimplePerformantInstrumentation
import graphql.execution.instrumentation.parameters.InstrumentationExecuteOperationParameters
import graphql.execution.instrumentation.parameters.InstrumentationExecutionParameters
import graphql.execution.instrumentation.parameters.InstrumentationValidationParameters
import graphql.language.SourceLocation
import graphql.validation.ValidationError
import spock.lang.Specification

import java.util.concurrent.CompletableFuture

class AbortExecutionExceptionTest extends Specification {

class BasicError implements GraphQLError {
Expand Down Expand Up @@ -35,10 +49,73 @@ class AbortExecutionExceptionTest extends Specification {
e.toExecutionResult().getErrors()[0].message == "No underlying errors"

when:
e = new AbortExecutionException([new BasicError(message:"UnderlyingA"), new BasicError(message:"UnderlyingB")])
e = new AbortExecutionException([new BasicError(message: "UnderlyingA"), new BasicError(message: "UnderlyingB")])
then:
e.toExecutionResult().getErrors().size() == 2
e.toExecutionResult().getErrors()[0].message == "UnderlyingA"
e.toExecutionResult().getErrors()[1].message == "UnderlyingB"
}

def "will call instrumentation.instrumentExecutionResult() at the end"() {
def sdl = """
type Query {
q : Q
}

type Q {
name : String
}
"""


def schema = TestUtil.schema(sdl)

def throwOnEarlyPhase = true
Instrumentation instrumentation = new SimplePerformantInstrumentation() {
@Override
InstrumentationContext<List<ValidationError>> beginValidation(InstrumentationValidationParameters parameters, InstrumentationState state) {
if (throwOnEarlyPhase) {
throw new AbortExecutionException("early")
}
return super.beginValidation(parameters, state)
}

@Override
InstrumentationContext<ExecutionResult> beginExecuteOperation(InstrumentationExecuteOperationParameters parameters, InstrumentationState state) {
if (!throwOnEarlyPhase) {
throw new AbortExecutionException("later")
}
return super.beginExecuteOperation(parameters, state)
}

@Override
CompletableFuture<ExecutionResult> instrumentExecutionResult(ExecutionResult executionResult, InstrumentationExecutionParameters parameters, InstrumentationState state) {
def newER = executionResult.transform { it.extensions([extra: "extensions"]) }
return CompletableFuture.completedFuture(newER)
}
}
def graphQL = GraphQL.newGraphQL(schema).instrumentation(instrumentation).build()


def executionInput = ExecutionInput.newExecutionInput("query q { q {name}}")
.root([q: [name: "nameV"]])
.build()

when:
def er = graphQL.execute(executionInput)

then:
!er.errors.isEmpty()
er.errors[0].message == "early"
er.extensions == [extra: "extensions"]

when:
throwOnEarlyPhase = false
er = graphQL.execute(executionInput)

then:
!er.errors.isEmpty()
er.errors[0].message == "later"
er.extensions == [extra: "extensions"]
}
}
X Tutup