diff --git a/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/QraphQLJpaBaseDataFetcher.java b/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/QraphQLJpaBaseDataFetcher.java index 0138aa8e7..6e9ab5bfe 100644 --- a/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/QraphQLJpaBaseDataFetcher.java +++ b/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/QraphQLJpaBaseDataFetcher.java @@ -395,7 +395,7 @@ private > R getValue(Argument argument, DataFetchingEnvironme GraphQLArgument graphQLArgument = environment.getExecutionStepInfo() .getFieldDefinition() - .getArgument(variableName); + .getArgument(argument.getName()); return (R) AstValueHelper.astFromValue(variableValue, graphQLArgument.getType()); } @@ -918,19 +918,19 @@ else if (value instanceof VariableReference) { } } else if (value instanceof ArrayValue) { Object convertedValue = environment.getArgument(argument.getName()); - + if (convertedValue != null && getJavaType(environment, argument).isEnum()) { - + Function f = (obj) -> Value.class.isInstance(obj) - ? Value.class.cast(obj) + ? Value.class.cast(obj) : new EnumValue(obj.toString()); - + // unwrap [[EnumValue{name='value'}]] if(convertedValue instanceof Collection && ((Collection) convertedValue).stream().allMatch(it->it instanceof Collection)) { convertedValue = ((Collection) convertedValue).iterator().next(); } - + if(convertedValue instanceof Collection) { return ((Collection) convertedValue).stream() .map((it) -> convertValue(environment, argument, f.apply(it))) @@ -939,7 +939,7 @@ else if (value instanceof VariableReference) { // Return real typed resolved array value return convertValue(environment, argument, f.apply(convertedValue)); } - else + else if (convertedValue != null && !getJavaType(environment, argument).isEnum()) { // unwrap [[EnumValue{name='value'}]] if(convertedValue instanceof Collection diff --git a/graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/GraphQLWhereVariableBindingsTests.java b/graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/GraphQLWhereVariableBindingsTests.java new file mode 100644 index 000000000..d2a286fb3 --- /dev/null +++ b/graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/GraphQLWhereVariableBindingsTests.java @@ -0,0 +1,296 @@ +package com.introproventures.graphql.jpa.query.schema; + +import static org.assertj.core.api.Assertions.tuple; +import static org.assertj.core.api.BDDAssertions.then; + +import static com.introproventures.graphql.jpa.query.schema.model.book.Genre.NOVEL; +import static com.introproventures.graphql.jpa.query.schema.model.book.Genre.PLAY; + +import java.io.IOException; +import java.util.Map; + +import javax.persistence.EntityManager; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.context.annotation.Bean; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaExecutor; +import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaSchemaBuilder; + +import graphql.ExecutionResult; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = WebEnvironment.NONE) +@TestPropertySource({ "classpath:hibernate.properties" }) +public class GraphQLWhereVariableBindingsTests { + + @SpringBootApplication + static class Application { + + @Bean + public GraphQLExecutor graphQLExecutor(final GraphQLSchemaBuilder graphQLSchemaBuilder) { + return new GraphQLJpaExecutor(graphQLSchemaBuilder.build()); + } + + @Bean + public GraphQLSchemaBuilder graphQLSchemaBuilder(final EntityManager entityManager) { + return new GraphQLJpaSchemaBuilder(entityManager) + .name("GraphQLBooks") + .description("Books JPA test schema"); + } + + } + + @Autowired + private GraphQLExecutor executor; + + @Test + public void queryWithSimpleEqualsVariableBinding() throws IOException { + //given + String query = "" + + "query($where: BooksCriteriaExpression) {" + + " Books(where: $where) {" + + " select {" + + " id" + + " title" + + " genre" + + " }" + + " }" + + "}"; + String variables = "" + + "{" + + " \"where\": {" + + " \"title\": {" + + " \"EQ\": \"War and Peace\"" + + " }" + + " }" + + "}"; + + //when + ExecutionResult executionResult = executor.execute(query, getVariablesMap(variables)); + + // then + then(executionResult.getErrors()).isEmpty(); + Map result = executionResult.getData(); + then(result) + .extracting("Books") + .flatExtracting("select") + .hasSize(1) + .extracting("id", "title", "genre") + .containsOnly(tuple(2L, "War and Peace", NOVEL)); + } + + @Test + public void queryWithNestedWhereClauseVariableBinding() throws IOException { + //given + String query = "" + + "query($where: BooksCriteriaExpression) {" + + " Books(where: $where) {" + + " select {" + + " author {" + + " id" + + " name" + + " }" + + " title" + + " }" + + " }" + + "}"; + String variables = "" + + "{" + + " \"where\": {" + + " \"author\": {" + + " \"name\": {" + + " \"EQ\": \"Leo Tolstoy\"" + + " }" + + " }" + + " }" + + "}"; + + //when + ExecutionResult executionResult = executor.execute(query, getVariablesMap(variables)); + + // then + then(executionResult.getErrors()).isEmpty(); + Map result = executionResult.getData(); + then(result) + .extracting("Books") + .flatExtracting("select") + .hasSize(2) + .extracting("title") + .containsOnly("War and Peace", "Anna Karenina"); + then(result) + .extracting("Books") + .flatExtracting("select") + .hasSize(2) + .extracting("author") + .extracting("id", "name") + .containsOnly(tuple(1L, "Leo Tolstoy")); + } + + @Test + public void queryWithInVariableBinding() throws IOException { + //given + String query = "" + + "query($where: BooksCriteriaExpression) {" + + " Books(where: $where) {" + + " select {" + + " id" + + " title" + + " genre" + + " }" + + " }" + + "}"; + String variables = "" + + "{" + + " \"where\": {" + + " \"genre\": {" + + " \"IN\": [\"PLAY\"]" + + " }" + + " }" + + "}"; + + //when + ExecutionResult executionResult = executor.execute(query, getVariablesMap(variables)); + + // then + then(executionResult.getErrors()).isEmpty(); + Map result = executionResult.getData(); + then(result) + .extracting("Books") + .flatExtracting("select") + .extracting("genre") + .containsOnly(PLAY); + } + + @Test + public void queryWithMultipleRestrictionForOneProperty() throws IOException { + //given + String query = "" + + "query($where: BooksCriteriaExpression) {" + + " Books(where: $where) {" + + " select {" + + " id" + + " title" + + " }" + + " }" + + "}"; + String variables = "" + + "{" + + " \"where\": {" + + " \"id\": {" + + " \"GE\": 5," + + " \"LE\": 7" + + " }" + + " }" + + "}"; + + //when + ExecutionResult executionResult = executor.execute(query, getVariablesMap(variables)); + + // then + then(executionResult.getErrors()).isEmpty(); + Map result = executionResult.getData(); + then(result) + .extracting("Books") + .flatExtracting("select") + .extracting("id", "title") + .containsOnly( + tuple(5L, "The Cherry Orchard"), + tuple(6L, "The Seagull"), + tuple(7L, "Three Sisters") + ); + } + + @Test + public void queryWithPropertyWhereVariableBinding() throws IOException { + //given + String query = "" + + "query($booksWhereClause: BooksCriteriaExpression) {" + + " Authors {" + + " select {" + + " name" + + " books(where: $booksWhereClause) {" + + " genre" + + " }" + + " }" + + " }" + + "}"; + String variables = "" + + "{" + + " \"booksWhereClause\": {" + + " \"genre\": {" + + " \"IN\": [\"NOVEL\"]" + + " }" + + " }" + + "}"; + + //when + ExecutionResult executionResult = executor.execute(query, getVariablesMap(variables)); + + // then + then(executionResult.getErrors()).isEmpty(); + Map result = executionResult.getData(); + then(result) + .extracting("Authors") + .flatExtracting("select") + .extracting("name") + .containsOnly("Leo Tolstoy"); + then(result) + .extracting("Authors") + .flatExtracting("select") + .flatExtracting("books") + .extracting("genre") + .containsOnly(NOVEL); + } + + @Test + public void queryWithRestrictionsForMultipleProperties() throws IOException { + //given + String query = "" + + "query($where: BooksCriteriaExpression) {" + + " Books(where: $where) {" + + " select {" + + " id" + + " title" + + " }" + + " }" + + "}"; + String variables = "" + + "{" + + " \"where\": {" + + " \"title\": {" + + " \"LIKE\": \"The\"" + + " }," + + " \"id\": {" + + " \"LT\": 6" + + " }" + + " }" + + "}"; + + //when + ExecutionResult executionResult = executor.execute(query, getVariablesMap(variables)); + + // then + then(executionResult.getErrors()).isEmpty(); + Map result = executionResult.getData(); + then(result) + .extracting("Books") + .flatExtracting("select") + .extracting("id", "title") + .containsOnly(tuple(5L, "The Cherry Orchard")); + } + + @SuppressWarnings("unchecked") + private Map getVariablesMap(String variables) throws IOException { + ObjectMapper mapper = new ObjectMapper(); + return (Map) mapper.readValue(variables, Map.class); + } +} \ No newline at end of file