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
37 changes: 31 additions & 6 deletions src/main/java/graphql/GraphQL.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@
import graphql.execution.ExecutionIdProvider;
import graphql.execution.ExecutionStrategy;
import graphql.execution.SimpleExecutionStrategy;
import graphql.execution.instrumentation.Instrumentation;
import graphql.execution.instrumentation.InstrumentationContext;
import graphql.execution.instrumentation.NoOpInstrumentation;
import graphql.execution.instrumentation.parameters.ExecutionParameters;
import graphql.execution.instrumentation.parameters.ValidationParameters;
import graphql.language.Document;
import graphql.language.SourceLocation;
import graphql.parser.Parser;
Expand Down Expand Up @@ -38,6 +43,7 @@ public ExecutionId provide(String query, String operationName, Object context) {
private final ExecutionStrategy queryStrategy;
private final ExecutionStrategy mutationStrategy;
private final ExecutionIdProvider idProvider;
private final Instrumentation instrumentation;


/**
Expand Down Expand Up @@ -76,14 +82,15 @@ public GraphQL(GraphQLSchema graphQLSchema, ExecutionStrategy queryStrategy) {
* @deprecated use the {@link #newGraphQL(GraphQLSchema)} builder instead. This will be removed in a future version.
*/
public GraphQL(GraphQLSchema graphQLSchema, ExecutionStrategy queryStrategy, ExecutionStrategy mutationStrategy) {
this(graphQLSchema,queryStrategy,mutationStrategy, DEFAULT_EXECUTION_ID_PROVIDER);
this(graphQLSchema,queryStrategy,mutationStrategy, DEFAULT_EXECUTION_ID_PROVIDER, NoOpInstrumentation.INSTANCE);
}

private GraphQL(GraphQLSchema graphQLSchema, ExecutionStrategy queryStrategy, ExecutionStrategy mutationStrategy, ExecutionIdProvider idProvider) {
private GraphQL(GraphQLSchema graphQLSchema, ExecutionStrategy queryStrategy, ExecutionStrategy mutationStrategy, ExecutionIdProvider idProvider, Instrumentation instrumentation) {
this.graphQLSchema = assertNotNull(graphQLSchema,"queryStrategy must be non null");
this.queryStrategy = assertNotNull(queryStrategy, "queryStrategy must be non null");
this.idProvider = assertNotNull(idProvider, "idProvider must be non null");
this.mutationStrategy = mutationStrategy;
this.instrumentation = instrumentation;
}

/**
Expand All @@ -103,6 +110,7 @@ public static class Builder {
private ExecutionStrategy queryExecutionStrategy = new SimpleExecutionStrategy();
private ExecutionStrategy mutationExecutionStrategy = new SimpleExecutionStrategy();
private ExecutionIdProvider idProvider = DEFAULT_EXECUTION_ID_PROVIDER;
private Instrumentation instrumentation = NoOpInstrumentation.INSTANCE;


public Builder(GraphQLSchema graphQLSchema) {
Expand All @@ -124,13 +132,18 @@ public Builder mutationExecutionStrategy(ExecutionStrategy executionStrategy) {
return this;
}

public Builder instrumentation(Instrumentation instrumentation) {
this.instrumentation = assertNotNull(instrumentation, "Instrumentation must be non null");
return this;
}

public Builder executionIdProvider(ExecutionIdProvider executionIdProvider) {
this.idProvider = assertNotNull(executionIdProvider, "ExecutionIdProvider must be non null");
return this;
}

public GraphQL build() {
return new GraphQL(graphQLSchema, queryExecutionStrategy, mutationExecutionStrategy, idProvider);
return new GraphQL(graphQLSchema, queryExecutionStrategy, mutationExecutionStrategy, idProvider, instrumentation);
}
}

Expand All @@ -151,29 +164,41 @@ public ExecutionResult execute(String requestString, Object context, Map<String,
}

public ExecutionResult execute(String requestString, String operationName, Object context, Map<String, Object> arguments) {
InstrumentationContext<ExecutionResult> executionCtx = instrumentation.beginExecution(new ExecutionParameters(requestString, operationName, context, arguments));

assertNotNull(arguments, "arguments can't be null");
log.debug("Executing request. operation name: {}. Request: {} ", operationName, requestString);

InstrumentationContext<Document> parseCtx = instrumentation.beginParse(new ExecutionParameters(requestString, operationName, context, arguments));
Parser parser = new Parser();
Document document;
try {
document = parser.parseDocument(requestString);
parseCtx.onEnd(document);
} catch (ParseCancellationException e) {
RecognitionException recognitionException = (RecognitionException) e.getCause();
SourceLocation sourceLocation = new SourceLocation(recognitionException.getOffendingToken().getLine(), recognitionException.getOffendingToken().getCharPositionInLine());
InvalidSyntaxError invalidSyntaxError = new InvalidSyntaxError(sourceLocation);
return new ExecutionResultImpl(Collections.singletonList(invalidSyntaxError));
}

InstrumentationContext<List<ValidationError>> validationCtx = instrumentation.beginValidation(new ValidationParameters(requestString,operationName,context,arguments,document));

Validator validator = new Validator();
List<ValidationError> validationErrors = validator.validateDocument(graphQLSchema, document);

validationCtx.onEnd(validationErrors);

if (validationErrors.size() > 0) {
return new ExecutionResultImpl(validationErrors);
}
ExecutionId executionId = idProvider.provide(requestString, operationName, context);

Execution execution = new Execution(queryStrategy, mutationStrategy);
return execution.execute(executionId, graphQLSchema, context, document, operationName, arguments);
}
Execution execution = new Execution(queryStrategy, mutationStrategy, instrumentation);
ExecutionResult result = execution.execute(executionId, graphQLSchema, context, document, operationName, arguments);

executionCtx.onEnd(result);

return result;
}
}
26 changes: 19 additions & 7 deletions src/main/java/graphql/execution/Execution.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@

import graphql.ExecutionResult;
import graphql.GraphQLException;
import graphql.execution.instrumentation.Instrumentation;
import graphql.execution.instrumentation.InstrumentationContext;
import graphql.execution.instrumentation.parameters.DataFetchParameters;
import graphql.language.Document;
import graphql.language.Field;
import graphql.language.OperationDefinition;
Expand All @@ -16,17 +19,19 @@

public class Execution {

private FieldCollector fieldCollector = new FieldCollector();
private ExecutionStrategy queryStrategy;
private ExecutionStrategy mutationStrategy;
private final FieldCollector fieldCollector = new FieldCollector();
private final ExecutionStrategy queryStrategy;
private final ExecutionStrategy mutationStrategy;
private final Instrumentation instrumentation;

public Execution(ExecutionStrategy queryStrategy, ExecutionStrategy mutationStrategy) {
public Execution(ExecutionStrategy queryStrategy, ExecutionStrategy mutationStrategy, Instrumentation instrumentation) {
this.queryStrategy = queryStrategy != null ? queryStrategy : new SimpleExecutionStrategy();
this.mutationStrategy = mutationStrategy != null ? mutationStrategy : new SimpleExecutionStrategy();
this.instrumentation = instrumentation;
}

public ExecutionResult execute(ExecutionId executionId, GraphQLSchema graphQLSchema, Object root, Document document, String operationName, Map<String, Object> args) {
ExecutionContextBuilder executionContextBuilder = new ExecutionContextBuilder(new ValuesResolver());
ExecutionContextBuilder executionContextBuilder = new ExecutionContextBuilder(new ValuesResolver(), instrumentation);
ExecutionContext executionContext = executionContextBuilder
.executionId(executionId)
.build(graphQLSchema, queryStrategy, mutationStrategy, root, document, operationName, args);
Expand All @@ -49,15 +54,22 @@ private ExecutionResult executeOperation(
ExecutionContext executionContext,
Object root,
OperationDefinition operationDefinition) {

InstrumentationContext<ExecutionResult> dataFetchCtx = instrumentation.beginDataFetch(new DataFetchParameters(executionContext));

GraphQLObjectType operationRootType = getOperationRootType(executionContext.getGraphQLSchema(), operationDefinition);

Map<String, List<Field>> fields = new LinkedHashMap<String, List<Field>>();
fieldCollector.collectFields(executionContext, operationRootType, operationDefinition.getSelectionSet(), new ArrayList<String>(), fields);

ExecutionResult result;
if (operationDefinition.getOperation() == OperationDefinition.Operation.MUTATION) {
return mutationStrategy.execute(executionContext, operationRootType, root, fields);
result = mutationStrategy.execute(executionContext, operationRootType, root, fields);
} else {
return queryStrategy.execute(executionContext, operationRootType, root, fields);
result = queryStrategy.execute(executionContext, operationRootType, root, fields);
}

dataFetchCtx.onEnd(result);
return result;
}
}
11 changes: 10 additions & 1 deletion src/main/java/graphql/execution/ExecutionContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@


import graphql.GraphQLError;
import graphql.execution.instrumentation.Instrumentation;
import graphql.execution.instrumentation.NoOpInstrumentation;
import graphql.language.FragmentDefinition;
import graphql.language.OperationDefinition;
import graphql.schema.GraphQLSchema;
Expand All @@ -21,8 +23,9 @@ public class ExecutionContext {
private final Map<String, Object> variables;
private final Object root;
private final List<GraphQLError> errors = new CopyOnWriteArrayList<GraphQLError>();
private final Instrumentation instrumentation;

public ExecutionContext(ExecutionId executionId, GraphQLSchema graphQLSchema, ExecutionStrategy queryStrategy, ExecutionStrategy mutationStrategy, Map<String, FragmentDefinition> fragmentsByName, OperationDefinition operationDefinition, Map<String, Object> variables, Object root) {
public ExecutionContext(Instrumentation instrumentation, ExecutionId executionId, GraphQLSchema graphQLSchema, ExecutionStrategy queryStrategy, ExecutionStrategy mutationStrategy, Map<String, FragmentDefinition> fragmentsByName, OperationDefinition operationDefinition, Map<String, Object> variables, Object root) {
this.graphQLSchema = graphQLSchema;
this.executionId = executionId;
this.queryStrategy = queryStrategy;
Expand All @@ -31,12 +34,18 @@ public ExecutionContext(ExecutionId executionId, GraphQLSchema graphQLSchema, Ex
this.operationDefinition = operationDefinition;
this.variables = variables;
this.root = root;
this.instrumentation = instrumentation;
}


public ExecutionId getExecutionId() {
return executionId;
}

public Instrumentation getInstrumentation() {
return instrumentation;
}

public GraphQLSchema getGraphQLSchema() {
return graphQLSchema;
}
Expand Down
10 changes: 7 additions & 3 deletions src/main/java/graphql/execution/ExecutionContextBuilder.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package graphql.execution;

import graphql.GraphQLException;
import graphql.execution.instrumentation.Instrumentation;
import graphql.language.Definition;
import graphql.language.Document;
import graphql.language.FragmentDefinition;
Expand All @@ -15,21 +16,23 @@
public class ExecutionContextBuilder {

private ValuesResolver valuesResolver;

private Instrumentation instrumentation;
private ExecutionId executionId;

public ExecutionContextBuilder(ValuesResolver valuesResolver) {
public ExecutionContextBuilder(ValuesResolver valuesResolver, Instrumentation instrumentation) {
this.valuesResolver = valuesResolver;
this.instrumentation = instrumentation;
}


public ExecutionContextBuilder executionId(ExecutionId executionId) {
this.executionId = executionId;
return this;
}

public ExecutionContext build(GraphQLSchema graphQLSchema, ExecutionStrategy queryStrategy, ExecutionStrategy mutationStrategy, Object root, Document document, String operationName, Map<String, Object> args) {
// preconditions
assertNotNull(executionId,"You must provide a query identifier");
assertNotNull(executionId, "You must provide a query identifier");

Map<String, FragmentDefinition> fragmentsByName = new LinkedHashMap<String, FragmentDefinition>();
Map<String, OperationDefinition> operationsByName = new LinkedHashMap<String, OperationDefinition>();
Expand Down Expand Up @@ -60,6 +63,7 @@ public ExecutionContext build(GraphQLSchema graphQLSchema, ExecutionStrategy que
Map<String, Object> variableValues = valuesResolver.getVariableValues(graphQLSchema, operation.getVariableDefinitions(), args);

return new ExecutionContext(
instrumentation,
executionId,
graphQLSchema,
queryStrategy,
Expand Down
41 changes: 37 additions & 4 deletions src/main/java/graphql/execution/ExecutionStrategy.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,35 @@
import graphql.ExecutionResult;

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are no code hygeine rules for the project so I let IDEA do its full import behaviour of .* imports. This is what we use here in Atlassian and I am a fan of it.

import graphql.ExecutionResultImpl;
import graphql.GraphQLException;
import graphql.execution.instrumentation.Instrumentation;
import graphql.execution.instrumentation.InstrumentationContext;
import graphql.execution.instrumentation.parameters.FieldFetchParameters;
import graphql.execution.instrumentation.parameters.FieldParameters;
import graphql.language.Field;
import graphql.schema.*;
import graphql.schema.DataFetchingEnvironment;
import graphql.schema.DataFetchingEnvironmentImpl;
import graphql.schema.GraphQLEnumType;
import graphql.schema.GraphQLFieldDefinition;
import graphql.schema.GraphQLInterfaceType;
import graphql.schema.GraphQLList;
import graphql.schema.GraphQLNonNull;
import graphql.schema.GraphQLObjectType;
import graphql.schema.GraphQLScalarType;
import graphql.schema.GraphQLSchema;
import graphql.schema.GraphQLType;
import graphql.schema.GraphQLUnionType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import static graphql.introspection.Introspection.*;
import static graphql.introspection.Introspection.SchemaMetaFieldDef;
import static graphql.introspection.Introspection.TypeMetaFieldDef;
import static graphql.introspection.Introspection.TypeNameMetaFieldDef;

public abstract class ExecutionStrategy {
private static final Logger log = LoggerFactory.getLogger(ExecutionStrategy.class);
Expand All @@ -35,15 +56,27 @@ protected ExecutionResult resolveField(ExecutionContext executionContext, GraphQ
executionContext.getGraphQLSchema()
);

Instrumentation instrumentation = executionContext.getInstrumentation();

InstrumentationContext<ExecutionResult> fieldCtx = instrumentation.beginField(new FieldParameters(executionContext, fieldDef));

InstrumentationContext<Object> fetchCtx = instrumentation.beginFieldFetch(new FieldFetchParameters(executionContext, fieldDef, environment));
Object resolvedValue = null;
try {
resolvedValue = fieldDef.getDataFetcher().get(environment);

fetchCtx.onEnd(resolvedValue);
} catch (Exception e) {
log.warn("Exception while fetching data", e);
executionContext.addError(new ExceptionWhileDataFetching(e));

fetchCtx.onEnd(e);
}

return completeValue(executionContext, fieldDef.getType(), fields, resolvedValue);
ExecutionResult result = completeValue(executionContext, fieldDef.getType(), fields, resolvedValue);

fieldCtx.onEnd(result);
return result;
}

protected ExecutionResult completeValue(ExecutionContext executionContext, GraphQLType fieldType, List<Field> fields, Object result) {
Expand Down
Loading