From 200cd2770b11f5902caed4668a89348be8333827 Mon Sep 17 00:00:00 2001 From: Igor Dianov Date: Thu, 9 May 2024 20:05:22 -0700 Subject: [PATCH] Fix where query criteria with multiple associations joins --- .../schema/impl/GraphQLJpaQueryFactory.java | 23 ++++-- .../converter/GraphQLJpaConverterTests.java | 81 +++++++++++++++++++ tests/gatling/src/main/resources/data.sql | 7 ++ 3 files changed, 105 insertions(+), 6 deletions(-) diff --git a/schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/GraphQLJpaQueryFactory.java b/schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/GraphQLJpaQueryFactory.java index 6e815010a..68628eeeb 100644 --- a/schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/GraphQLJpaQueryFactory.java +++ b/schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/GraphQLJpaQueryFactory.java @@ -1108,12 +1108,23 @@ protected Predicate getObjectFieldPredicate( AbstractQuery query = environment.getRoot(); Boolean isFetch = environment.getLocalContext(); - Boolean isOptional = isOptionalAttribute(attribute); - - From context = (isSubquery(query) || isCountQuery(query) || !isFetch) - ? reuseJoin(from, objectField.getName(), isOptional) - : reuseFetch(from, objectField.getName(), isOptional); - + boolean isOptional = isOptionalAttribute(attribute); + List> logicalArguments = Optional + .ofNullable(environment.getArgument(logical.name())) + .filter(List.class::isInstance) + .map(List.class::cast) + .orElseGet(List::of); + + From context; + if (logicalArguments.stream().filter(it -> it.containsKey(objectField.getName())).count() > 1) { + context = + isOptional ? from.join(objectField.getName(), JoinType.LEFT) : from.join(objectField.getName()); + } else { + context = + (isSubquery(query) || isCountQuery(query) || !isFetch) + ? reuseJoin(from, objectField.getName(), isOptional) + : reuseFetch(from, objectField.getName(), isOptional); + } return getArgumentPredicate( cb, context, diff --git a/schema/src/test/java/com/introproventures/graphql/jpa/query/converter/GraphQLJpaConverterTests.java b/schema/src/test/java/com/introproventures/graphql/jpa/query/converter/GraphQLJpaConverterTests.java index 7dc409544..aaeaeed30 100644 --- a/schema/src/test/java/com/introproventures/graphql/jpa/query/converter/GraphQLJpaConverterTests.java +++ b/schema/src/test/java/com/introproventures/graphql/jpa/query/converter/GraphQLJpaConverterTests.java @@ -179,6 +179,42 @@ public void criteriaTester3() { assertThat(result).hasSize(1); } + @Test + @Transactional + public void criteriaTesterMultipleJoinWhereCriteria() { + CriteriaBuilder cb = entityManager.getCriteriaBuilder(); + + CriteriaQuery tasksQuery = cb.createQuery(TaskEntity.class); + Root task = tasksQuery.from(TaskEntity.class); + + Join taskVariableEntityJoin1 = task.join("variables"); + + Predicate var1 = cb.and( + cb.equal(taskVariableEntityJoin1.get("name"), "variable2"), + cb.equal(taskVariableEntityJoin1.get("value"), new VariableValue<>(Boolean.TRUE)) + ); + + taskVariableEntityJoin1.on(var1); + taskVariableEntityJoin1.alias("var1"); + + Join taskVariableEntityJoin2 = task.join("variables"); + Predicate var2 = cb.and( + cb.equal(taskVariableEntityJoin2.get("name"), "variable1"), + cb.equal(taskVariableEntityJoin2.get("value"), new VariableValue<>(new String("data"))) + ); + + taskVariableEntityJoin2.on(var2); + taskVariableEntityJoin2.alias("var2"); + + tasksQuery.select(task); + // when: + List result = entityManager.createQuery(tasksQuery).getResultList(); + + // then: + assertThat(result).isNotEmpty(); + assertThat(result).hasSize(1); + } + @Test @Transactional public void criteriaTester4() { @@ -838,6 +874,51 @@ public void queryTasksVariablesWhereWithExplicitANDEXISTSByNameAndValueCriteria( assertThat(result.toString()).isEqualTo(expected); } + @Test + public void queryTasksVariablesWhereWithExplicitANDByMultipleNameAndValueCriteria() { + //given + String query = + "query {" + + " Tasks(where: {" + + " status: {EQ: COMPLETED}" + + " AND: [" + + " {" + + " variables: {" + + " name: {EQ: \"variable1\"}" + + " value: {EQ: \"data\"} }" + + " }" + + " {" + + " variables: {" + + " name: {EQ: \"variable2\"}" + + " value: {EQ: true} }" + + " }" + + " ]" + + " }) {" + + " select {" + + " id" + + " status" + + " variables {" + + " name" + + " value" + + " }" + + " }" + + " }" + + "}"; + + String expected = + "{Tasks={select=[" + + "{id=1, status=COMPLETED, variables=[" + + "{name=variable2, value=true}, " + + "{name=variable1, value=data}]}" + + "]}}"; + + //when + Object result = executor.execute(query).getData(); + + // then + assertThat(result.toString()).isEqualTo(expected); + } + @Test public void queryTasksVariablesWhereWithEXISTSByNameAndValueCriteria() { //given diff --git a/tests/gatling/src/main/resources/data.sql b/tests/gatling/src/main/resources/data.sql index 6221618cd..9672cb6e8 100644 --- a/tests/gatling/src/main/resources/data.sql +++ b/tests/gatling/src/main/resources/data.sql @@ -1090,3 +1090,10 @@ insert into INTEGRATION_CONTEXT (id, client_id, client_name, execution_id, proce ('2', '1', 'serviceTask', '2', '1'), ('3', '1', 'serviceTask', '3', '1'); +insert into TASK_PROCESS_VARIABLE (task_id, process_variable_id) values + (1,1), + (1,2), + (1,3), + (1,4), + (1,5), + (1,6);