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
118 changes: 103 additions & 15 deletions src/main/java/graphql/GraphQL.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.function.UnaryOperator;

import static graphql.Assert.assertNotNull;

Expand All @@ -50,6 +51,7 @@ public class GraphQL {
* A GraphQL object ready to execute queries
*
* @param graphQLSchema the schema to use
*
* @deprecated use the {@link #newGraphQL(GraphQLSchema)} builder instead. This will be removed in a future version.
*/
@Internal
Expand All @@ -63,6 +65,7 @@ public GraphQL(GraphQLSchema graphQLSchema) {
*
* @param graphQLSchema the schema to use
* @param queryStrategy the query execution strategy to use
*
* @deprecated use the {@link #newGraphQL(GraphQLSchema)} builder instead. This will be removed in a future version.
*/
@Internal
Expand All @@ -77,6 +80,7 @@ public GraphQL(GraphQLSchema graphQLSchema, ExecutionStrategy queryStrategy) {
* @param graphQLSchema the schema to use
* @param queryStrategy the query execution strategy to use
* @param mutationStrategy the mutation execution strategy to use
*
* @deprecated use the {@link #newGraphQL(GraphQLSchema)} builder instead. This will be removed in a future version.
*/
@Internal
Expand All @@ -91,6 +95,7 @@ public GraphQL(GraphQLSchema graphQLSchema, ExecutionStrategy queryStrategy, Exe
* @param queryStrategy the query execution strategy to use
* @param mutationStrategy the mutation execution strategy to use
* @param subscriptionStrategy the subscription execution strategy to use
*
* @deprecated use the {@link #newGraphQL(GraphQLSchema)} builder instead. This will be removed in a future version.
*/
@Internal
Expand All @@ -112,6 +117,7 @@ private GraphQL(GraphQLSchema graphQLSchema, ExecutionStrategy queryStrategy, Ex
* Helps you build a GraphQL object ready to execute queries
*
* @param graphQLSchema the schema to use
*
* @return a builder of GraphQL objects
*/
public static Builder newGraphQL(GraphQLSchema graphQLSchema) {
Expand Down Expand Up @@ -178,11 +184,12 @@ public GraphQL build() {
}

/**
* Executes the specified graphql query/mutation/subscription
*
* @param query the query/mutation/subscription
* @return result including errors
* @deprecated Use {@link #execute(ExecutionInput)}
*
* @return an {@link ExecutionResult} which can include errors
*/
@Deprecated
public ExecutionResult execute(String query) {
ExecutionInput executionInput = ExecutionInput.newExecutionInput()
.query(query)
Expand All @@ -195,7 +202,9 @@ public ExecutionResult execute(String query) {
*
* @param query the query/mutation/subscription
* @param context custom object provided to each {@link graphql.schema.DataFetcher}
* @return result including errors
*
* @return an {@link ExecutionResult} which can include errors
*
* @deprecated Use {@link #execute(ExecutionInput)}
*/
@Deprecated
Expand All @@ -214,7 +223,9 @@ public ExecutionResult execute(String query, Object context) {
* @param query the query/mutation/subscription
* @param operationName the name of the operation to execute
* @param context custom object provided to each {@link graphql.schema.DataFetcher}
* @return result including errors
*
* @return an {@link ExecutionResult} which can include errors
*
* @deprecated Use {@link #execute(ExecutionInput)}
*/
@Deprecated
Expand All @@ -234,7 +245,9 @@ public ExecutionResult execute(String query, String operationName, Object contex
* @param query the query/mutation/subscription
* @param context custom object provided to each {@link graphql.schema.DataFetcher}
* @param variables variable values uses as argument
* @return result including errors
*
* @return an {@link ExecutionResult} which can include errors
*
* @deprecated Use {@link #execute(ExecutionInput)}
*/
@Deprecated
Expand All @@ -255,7 +268,9 @@ public ExecutionResult execute(String query, Object context, Map<String, Object>
* @param operationName name of the operation to execute
* @param context custom object provided to each {@link graphql.schema.DataFetcher}
* @param variables variable values uses as argument
* @return result including errors
*
* @return an {@link ExecutionResult} which can include errors
*
* @deprecated Use {@link #execute(ExecutionInput)}
*/
@Deprecated
Expand All @@ -271,11 +286,91 @@ public ExecutionResult execute(String query, String operationName, Object contex
}

/**
* Executes the graphql query using the provided input object builder
*
* @param executionInputBuilder {@link ExecutionInput.Builder}
*
* @return an {@link ExecutionResult} which can include errors
*/
public ExecutionResult execute(ExecutionInput.Builder executionInputBuilder) {
return execute(executionInputBuilder.build());
}

/**
* Executes the graphql query using calling the builder function and giving it a new builder.
* <p>
* This allows a lambda style like :
*
* <pre>
* {@code
* ExecutionResult result = graphql.execute(input -> input.query("{hello}").root(startingObj).context(contextObj));
* }
* </pre>
*
* @param builderFunction a function that is given a {@link ExecutionInput.Builder}
*
* @return an {@link ExecutionResult} which can include errors
*/
public ExecutionResult execute(UnaryOperator<ExecutionInput.Builder> builderFunction) {
return execute(builderFunction.apply(ExecutionInput.newExecutionInput()).build());
}

/**
* Executes the graphql query using the provided input object
*
* @param executionInput {@link ExecutionInput}
*
* @return an {@link ExecutionResult} which can include errors
*/
public ExecutionResult execute(ExecutionInput executionInput) {
return executeAsync(executionInput).join();
}

/**
* Executes the graphql query using the provided input object builder
*
* This will return a promise (aka {@link CompletableFuture}) to provide a {@link ExecutionResult}
* which is the result of executing the provided query.
*
* @param executionInputBuilder {@link ExecutionInput.Builder}
*
* @return a promise to an {@link ExecutionResult} which can include errors
*/
public CompletableFuture<ExecutionResult> executeAsync(ExecutionInput.Builder executionInputBuilder) {
return executeAsync(executionInputBuilder.build());
}

/**
* Executes the graphql query using the provided input object builder
*
* This will return a promise (aka {@link CompletableFuture}) to provide a {@link ExecutionResult}
* which is the result of executing the provided query.
* <p>
* This allows a lambda style like :
*
* <pre>
* {@code
* ExecutionResult result = graphql.execute(input -> input.query("{hello}").root(startingObj).context(contextObj));
* }
* </pre>
*
* @param builderFunction a function that is given a {@link ExecutionInput.Builder}
*
* @return a promise to an {@link ExecutionResult} which can include errors
*/
public CompletableFuture<ExecutionResult> executeAsync(UnaryOperator<ExecutionInput.Builder> builderFunction) {
return executeAsync(builderFunction.apply(ExecutionInput.newExecutionInput()).build());
}

/**
* Executes the graphql query using the provided input object
*
* This will return a promise (aka {@link CompletableFuture}) to provide a {@link ExecutionResult}
* which is the result of executing the provided query.
*
* @param executionInput {@link ExecutionInput}
* @return a promise to an execution result
*
* @return a promise to an {@link ExecutionResult} which can include errors
*/
public CompletableFuture<ExecutionResult> executeAsync(ExecutionInput executionInput) {
log.debug("Executing request. operation name: {}. query: {}. variables {} ", executionInput.getOperationName(), executionInput.getQuery(), executionInput.getVariables());
Expand All @@ -286,13 +381,6 @@ public CompletableFuture<ExecutionResult> executeAsync(ExecutionInput executionI
return executionResult;
}

/**
* @param executionInput {@link ExecutionInput}
* @return result including errors
*/
public ExecutionResult execute(ExecutionInput executionInput) {
return executeAsync(executionInput).join();
}

private CompletableFuture<ExecutionResult> parseValidateAndExecute(ExecutionInput executionInput) {
PreparsedDocumentEntry preparsedDoc = preparsedDocumentProvider.get(executionInput.getQuery(), query -> parseAndValidate(executionInput));
Expand Down
78 changes: 70 additions & 8 deletions src/test/groovy/graphql/GraphQLTest.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ import graphql.schema.StaticDataFetcher
import graphql.validation.ValidationErrorType
import spock.lang.Specification

import java.util.function.UnaryOperator

import static graphql.ExecutionInput.Builder
import static graphql.ExecutionInput.newExecutionInput
import static graphql.Scalars.GraphQLInt
import static graphql.Scalars.GraphQLString
import static graphql.schema.GraphQLArgument.newArgument
Expand All @@ -24,9 +28,7 @@ import static graphql.schema.GraphQLSchema.newSchema

class GraphQLTest extends Specification {


def "simple query"() {
given:
GraphQLSchema simpleSchema() {
GraphQLFieldDefinition.Builder fieldDefinition = newFieldDefinition()
.name("hello")
.type(GraphQLString)
Expand All @@ -37,6 +39,12 @@ class GraphQLTest extends Specification {
.field(fieldDefinition)
.build()
).build()
schema
}

def "simple query"() {
given:
GraphQLSchema schema = simpleSchema()

when:
def result = GraphQL.newGraphQL(schema).build().execute('{ hello }').data
Expand Down Expand Up @@ -199,7 +207,8 @@ class GraphQLTest extends Specification {
def expected = [field2: 'value2']

when:
def result = GraphQL.newGraphQL(schema).build().execute(query, 'Query2', null, [:])
def executionInput = newExecutionInput().query(query).operationName('Query2').context(null).variables([:])
def result = GraphQL.newGraphQL(schema).build().execute(executionInput)

then:
result.data == expected
Expand Down Expand Up @@ -246,7 +255,6 @@ class GraphQLTest extends Specification {
}



def "query with int literal too large"() {
given:
GraphQLSchema schema = newSchema().query(
Expand All @@ -269,6 +277,7 @@ class GraphQLTest extends Specification {
result.errors[0].description.contains("has wrong type")
}

@SuppressWarnings("GroovyAssignabilityCheck")
def "query with missing argument results in arguments map with value null"() {
given:
def dataFetcher = Mock(DataFetcher)
Expand All @@ -295,6 +304,7 @@ class GraphQLTest extends Specification {
}
}

@SuppressWarnings("GroovyAssignabilityCheck")
def "query with missing key in an input object result in a empty map"() {
given:
def dataFetcher = Mock(DataFetcher)
Expand Down Expand Up @@ -336,6 +346,7 @@ class GraphQLTest extends Specification {
result.errors[0].errorType == ErrorType.InvalidSyntax
}


def "wrong argument type: array of enum instead of enum"() {
given:
GraphQLEnumType enumType = GraphQLEnumType.newEnum().name("EnumType").value("Val1").value("Val2").build()
Expand All @@ -345,19 +356,70 @@ class GraphQLTest extends Specification {
.field(newFieldDefinition()
.name("query")
.argument(newArgument().name("fooParam").type(enumType))
.type(Scalars.GraphQLInt))
.type(GraphQLInt))
.build()

GraphQLSchema schema = newSchema()
.query(queryType)
.build()
when:
final GraphQL graphQL = GraphQL.newGraphQL(schema).build();
final ExecutionResult result = graphQL.execute("{query (fooParam: [Val1,Val2])}");
final GraphQL graphQL = GraphQL.newGraphQL(schema).build()
final ExecutionResult result = graphQL.execute("{query (fooParam: [Val1,Val2])}")
then:
result.errors.size() == 1
result.errors[0].errorType == ErrorType.ValidationError

}


def "execution input passing builder"() {
given:
GraphQLSchema schema = simpleSchema()

when:
def builder = newExecutionInput().query('{ hello }')
def result = GraphQL.newGraphQL(schema).build().execute(builder).data

then:
result == [hello: 'world']
}

def "execution input using builder function"() {
given:
GraphQLSchema schema = simpleSchema()

when:

def builderFunction = { it.query('{hello}') } as UnaryOperator<Builder>
def result = GraphQL.newGraphQL(schema).build().execute(builderFunction).data

then:
result == [hello: 'world']
}

def "execution input passing builder to async"() {
given:
GraphQLSchema schema = simpleSchema()

when:
def builder = newExecutionInput().query('{ hello }')
def result = GraphQL.newGraphQL(schema).build().executeAsync(builder).join().data

then:
result == [hello: 'world']
}

def "execution input using builder function to async"() {
given:
GraphQLSchema schema = simpleSchema()

when:

def builderFunction = { it.query('{hello}') } as UnaryOperator<Builder>
def result = GraphQL.newGraphQL(schema).build().executeAsync(builderFunction).join().data

then:
result == [hello: 'world']
}

}