GH-2230 - Use Cypher-DSL statement parameters in all template methods.

This closes #2230.
This commit is contained in:
Michael Simons
2021-04-15 14:56:21 +02:00
parent a466c4ad2d
commit 4f5f5fd4e6
7 changed files with 55 additions and 31 deletions

View File

@@ -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<T> matching(Statement statement, @Nullable Map<String, Object> parameter) {
Map<String, Object> 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));
}
/**

View File

@@ -169,7 +169,8 @@ public final class Neo4jTemplate implements Neo4jOperations, FluentNeo4jOperatio
@Override
public long count(Statement statement, Map<String, Object> 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 <T> List<T> findAll(Statement statement, Class<T> 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 <T> ExecutableQuery<T> createExecutableQuery(Class<T> domainType, Statement statement,
Map<String, Object> parameters) {
private <T> ExecutableQuery<T> createExecutableQuery(Class<T> domainType, Statement statement, Map<String, Object> parameters) {
return createExecutableQuery(domainType, renderer.render(statement), parameters);
return createExecutableQuery(domainType, renderer.render(statement), TemplateSupport.mergeParameters(statement, parameters));
}
private <T> ExecutableQuery<T> createExecutableQuery(Class<T> 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);
}
}

View File

@@ -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<T> matching(Statement statement, @Nullable Map<String, Object> parameter) {
Map<String, Object> 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));
}
/**

View File

@@ -146,7 +146,7 @@ public final class ReactiveNeo4jTemplate implements ReactiveNeo4jOperations, Rea
@Override
public Mono<Long> count(Statement statement, Map<String, Object> 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 <T> Mono<ExecutableQuery<T>> createExecutableQuery(Class<T> domainType, Statement statement) {
return createExecutableQuery(domainType, renderer.render(statement), Collections.emptyMap());
return createExecutableQuery(domainType, statement, Collections.emptyMap());
}
private <T> Mono<ExecutableQuery<T>> createExecutableQuery(Class<T> domainType, String cypherQuery) {
@@ -531,7 +531,7 @@ public final class ReactiveNeo4jTemplate implements ReactiveNeo4jOperations, Rea
private <T> Mono<ExecutableQuery<T>> createExecutableQuery(Class<T> domainType, Statement statement,
Map<String, Object> parameters) {
return createExecutableQuery(domainType, renderer.render(statement), parameters);
return createExecutableQuery(domainType, renderer.render(statement), TemplateSupport.mergeParameters(statement, parameters));
}
private <T> Mono<ExecutableQuery<T>> createExecutableQuery(Class<T> domainType, String cypherQuery,
@@ -558,11 +558,7 @@ public final class ReactiveNeo4jTemplate implements ReactiveNeo4jOperations, Rea
finalQueryAndParameters.getParameters()));
}
Statement statement = queryFragments.toStatement();
Map<String, Object> 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<GenericQueryAndParameters> 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<T> mappingSpec = this.neo4jClient.query(cypherQuery)

View File

@@ -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<String, Object> mergeParameters(Statement statement, @Nullable Map<String, Object> parameters) {
Map<String, Object> mergedParameters = new HashMap<>(statement.getParameters());
if (parameters != null) {
mergedParameters.putAll(parameters);
}
return mergedParameters;
}
private TemplateSupport() {
}
}

View File

@@ -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<PersonWithAllConstructor> people = neo4jTemplate.findAll(statement, PersonWithAllConstructor.class);
assertThat(people).hasSize(1);
}
@Test
void findAllWithCypherQuery() {
String cypherQuery = "MATCH (p:PersonWithAllConstructor) return p";

View File

@@ -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();