diff --git a/src/main/java/org/springframework/data/neo4j/core/FluentFindOperation.java b/src/main/java/org/springframework/data/neo4j/core/FluentFindOperation.java index 5aa97f0f5..2095190de 100644 --- a/src/main/java/org/springframework/data/neo4j/core/FluentFindOperation.java +++ b/src/main/java/org/springframework/data/neo4j/core/FluentFindOperation.java @@ -16,7 +16,6 @@ package org.springframework.data.neo4j.core; import java.util.Collections; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; @@ -127,12 +126,8 @@ public interface FluentFindOperation { * @throws IllegalArgumentException if statement is {@literal null}. */ default TerminatingFind matching(Statement statement, @Nullable Map parameter) { - Map mergedParameters = new HashMap<>(); - mergedParameters.putAll(statement.getParameters()); - if (parameter != null) { - mergedParameters.putAll(parameter); - } - return matching(statement.getCypher(), mergedParameters); + + return matching(statement.getCypher(), TemplateSupport.mergeParameters(statement, parameter)); } /** diff --git a/src/main/java/org/springframework/data/neo4j/core/Neo4jTemplate.java b/src/main/java/org/springframework/data/neo4j/core/Neo4jTemplate.java index a485ff296..60ac8d2a8 100644 --- a/src/main/java/org/springframework/data/neo4j/core/Neo4jTemplate.java +++ b/src/main/java/org/springframework/data/neo4j/core/Neo4jTemplate.java @@ -169,7 +169,8 @@ public final class Neo4jTemplate implements Neo4jOperations, FluentNeo4jOperatio @Override public long count(Statement statement, Map parameters) { - return count(renderer.render(statement), parameters); + + return count(renderer.render(statement), TemplateSupport.mergeParameters(statement, parameters)); } @Override @@ -194,7 +195,7 @@ public final class Neo4jTemplate implements Neo4jOperations, FluentNeo4jOperatio @Override public List findAll(Statement statement, Class domainType) { - return createExecutableQuery(domainType, renderer.render(statement)).getResults(); + return createExecutableQuery(domainType, statement, Collections.emptyMap()).getResults(); } @Override @@ -551,10 +552,9 @@ public final class Neo4jTemplate implements Neo4jOperations, FluentNeo4jOperatio return createExecutableQuery(domainType, cypherStatement, Collections.emptyMap()); } - private ExecutableQuery createExecutableQuery(Class domainType, Statement statement, - Map parameters) { + private ExecutableQuery createExecutableQuery(Class domainType, Statement statement, Map parameters) { - return createExecutableQuery(domainType, renderer.render(statement), parameters); + return createExecutableQuery(domainType, renderer.render(statement), TemplateSupport.mergeParameters(statement, parameters)); } private ExecutableQuery createExecutableQuery(Class domainType, String cypherStatement, @@ -866,8 +866,7 @@ public final class Neo4jTemplate implements Neo4jOperations, FluentNeo4jOperatio } else { Statement statement = queryFragments.toStatement(); cypherQuery = renderer.render(statement); - finalParameters = new HashMap<>(finalParameters); - finalParameters.putAll(statement.getParameters()); + finalParameters = TemplateSupport.mergeParameters(statement, finalParameters); } } diff --git a/src/main/java/org/springframework/data/neo4j/core/ReactiveFluentFindOperation.java b/src/main/java/org/springframework/data/neo4j/core/ReactiveFluentFindOperation.java index 42af73047..af2ee66c2 100644 --- a/src/main/java/org/springframework/data/neo4j/core/ReactiveFluentFindOperation.java +++ b/src/main/java/org/springframework/data/neo4j/core/ReactiveFluentFindOperation.java @@ -19,7 +19,6 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import java.util.Collections; -import java.util.HashMap; import java.util.Map; import org.apiguardian.api.API; @@ -117,12 +116,7 @@ public interface ReactiveFluentFindOperation { * @throws IllegalArgumentException if statement is {@literal null}. */ default TerminatingFind matching(Statement statement, @Nullable Map parameter) { - Map mergedParameters = new HashMap<>(); - mergedParameters.putAll(statement.getParameters()); - if (parameter != null) { - mergedParameters.putAll(parameter); - } - return matching(statement.getCypher(), mergedParameters); + return matching(statement.getCypher(), TemplateSupport.mergeParameters(statement, parameter)); } /** diff --git a/src/main/java/org/springframework/data/neo4j/core/ReactiveNeo4jTemplate.java b/src/main/java/org/springframework/data/neo4j/core/ReactiveNeo4jTemplate.java index 4197be00a..7ea8a0868 100644 --- a/src/main/java/org/springframework/data/neo4j/core/ReactiveNeo4jTemplate.java +++ b/src/main/java/org/springframework/data/neo4j/core/ReactiveNeo4jTemplate.java @@ -146,7 +146,7 @@ public final class ReactiveNeo4jTemplate implements ReactiveNeo4jOperations, Rea @Override public Mono count(Statement statement, Map parameters) { - return count(renderer.render(statement), parameters); + return count(renderer.render(statement), TemplateSupport.mergeParameters(statement, parameters)); } @Override @@ -521,7 +521,7 @@ public final class ReactiveNeo4jTemplate implements ReactiveNeo4jOperations, Rea } private Mono> createExecutableQuery(Class domainType, Statement statement) { - return createExecutableQuery(domainType, renderer.render(statement), Collections.emptyMap()); + return createExecutableQuery(domainType, statement, Collections.emptyMap()); } private Mono> createExecutableQuery(Class domainType, String cypherQuery) { @@ -531,7 +531,7 @@ public final class ReactiveNeo4jTemplate implements ReactiveNeo4jOperations, Rea private Mono> createExecutableQuery(Class domainType, Statement statement, Map parameters) { - return createExecutableQuery(domainType, renderer.render(statement), parameters); + return createExecutableQuery(domainType, renderer.render(statement), TemplateSupport.mergeParameters(statement, parameters)); } private Mono> createExecutableQuery(Class domainType, String cypherQuery, @@ -558,11 +558,7 @@ public final class ReactiveNeo4jTemplate implements ReactiveNeo4jOperations, Rea finalQueryAndParameters.getParameters())); } - Statement statement = queryFragments.toStatement(); - Map parameters = new HashMap<>(queryFragmentsAndParameters.getParameters()); - parameters.putAll(statement.getParameters()); - - return createExecutableQuery(domainType, renderer.render(statement), parameters); + return createExecutableQuery(domainType, queryFragments.toStatement(), queryFragmentsAndParameters.getParameters()); } private Mono createQueryAndParameters(Neo4jPersistentEntity entityMetaData, @@ -919,8 +915,7 @@ public final class ReactiveNeo4jTemplate implements ReactiveNeo4jOperations, Rea Statement statement = queryFragments.toStatement(); cypherQuery = renderer.render(statement); - finalParameters = new HashMap<>(finalParameters); - finalParameters.putAll(statement.getParameters()); + finalParameters = TemplateSupport.mergeParameters(statement, finalParameters); } ReactiveNeo4jClient.MappingSpec mappingSpec = this.neo4jClient.query(cypherQuery) diff --git a/src/main/java/org/springframework/data/neo4j/core/TemplateSupport.java b/src/main/java/org/springframework/data/neo4j/core/TemplateSupport.java index 473fcee36..db545041e 100644 --- a/src/main/java/org/springframework/data/neo4j/core/TemplateSupport.java +++ b/src/main/java/org/springframework/data/neo4j/core/TemplateSupport.java @@ -16,12 +16,15 @@ package org.springframework.data.neo4j.core; import java.beans.PropertyDescriptor; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.function.Predicate; import java.util.stream.Collectors; import org.apiguardian.api.API; +import org.neo4j.cypherdsl.core.Statement; import org.springframework.lang.Nullable; /** @@ -65,6 +68,21 @@ final class TemplateSupport { } } + /** + * Merges statement and explicit parameters. Statement parameters have a higher precedence + * @param statement A statement that maybe has some stored parameters + * @param parameters The original parameters + * @return Merged parameters + */ + static Map mergeParameters(Statement statement, @Nullable Map parameters) { + + Map mergedParameters = new HashMap<>(statement.getParameters()); + if (parameters != null) { + mergedParameters.putAll(parameters); + } + return mergedParameters; + } + private TemplateSupport() { } } diff --git a/src/test/java/org/springframework/data/neo4j/integration/imperative/Neo4jTemplateIT.java b/src/test/java/org/springframework/data/neo4j/integration/imperative/Neo4jTemplateIT.java index 23d9fdd3c..19f8f19dd 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/imperative/Neo4jTemplateIT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/imperative/Neo4jTemplateIT.java @@ -189,6 +189,17 @@ class Neo4jTemplateIT { assertThat(person).isPresent(); } + @Test // 2230 + void findAllWithStatementWithoutParameters() { + Node node = Cypher.node("PersonWithAllConstructor").named("n"); + Statement statement = Cypher.match(node).where(node.property("name").isEqualTo(Cypher.parameter("name").withValue(TEST_PERSON1_NAME))) + .returning(node).build(); + + List people = neo4jTemplate.findAll(statement, PersonWithAllConstructor.class); + + assertThat(people).hasSize(1); + } + @Test void findAllWithCypherQuery() { String cypherQuery = "MATCH (p:PersonWithAllConstructor) return p"; diff --git a/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveNeo4jTemplateIT.java b/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveNeo4jTemplateIT.java index f04b417ed..17e0cb756 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveNeo4jTemplateIT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveNeo4jTemplateIT.java @@ -274,6 +274,18 @@ class ReactiveNeo4jTemplateIT { } } + @Test // 2230 + void findAllWithStatementWithoutParameters() { + Node node = Cypher.node("PersonWithAllConstructor").named("n"); + Statement statement = Cypher.match(node).where(node.property("name").isEqualTo(Cypher.parameter("name").withValue(TEST_PERSON1_NAME))) + .returning(node).build(); + + neo4jTemplate.findAll(statement, PersonWithAllConstructor.class) + .as(StepVerifier::create) + .expectNextCount(1L) + .verifyComplete(); + } + @Test void deleteById() { StepVerifier.create(neo4jTemplate.deleteById(person1Id, PersonWithAllConstructor.class)).verifyComplete();