GH-2296 - Convert Ids before determining dynamic labels.

Fixes #2296.
This commit is contained in:
Michael Simons
2021-06-21 13:09:16 +02:00
parent 39d99da8d2
commit fa43d68e36
5 changed files with 119 additions and 2 deletions

View File

@@ -217,6 +217,10 @@ public final class Neo4jTemplate implements Neo4jOperations, BeanFactoryAware {
private Object convertIdValues(@Nullable Neo4jPersistentProperty idProperty, Object idValues) {
if (((Neo4jPersistentEntity<?>) idProperty.getOwner()).isUsingInternalIds()) {
return idValues;
}
return neo4jMappingContext.getConversionService().writeValue(idValues,
ClassTypeInformation.from(idValues.getClass()),
idProperty == null ? null : idProperty.getOptionalWritingConverter());
@@ -269,9 +273,10 @@ public final class Neo4jTemplate implements Neo4jOperations, BeanFactoryAware {
return entityMetaData.getDynamicLabelsProperty().map(p -> {
PersistentPropertyAccessor propertyAccessor = entityMetaData.getPropertyAccessor(entityToBeSaved);
Neo4jPersistentProperty idProperty = entityMetaData.getRequiredIdProperty();
Neo4jClient.RunnableSpecTightToDatabase runnableQuery = neo4jClient
.query(() -> renderer.render(cypherGenerator.createStatementReturningDynamicLabels(entityMetaData)))
.in(inDatabase).bind(propertyAccessor.getProperty(entityMetaData.getRequiredIdProperty()))
.in(inDatabase).bind(convertIdValues(idProperty, propertyAccessor.getProperty(idProperty)))
.to(Constants.NAME_OF_ID).bind(entityMetaData.getStaticLabels())
.to(Constants.NAME_OF_STATIC_LABELS_PARAM);

View File

@@ -220,6 +220,10 @@ public final class ReactiveNeo4jTemplate implements ReactiveNeo4jOperations, Bea
private Object convertIdValues(@Nullable Neo4jPersistentProperty idProperty, Object idValues) {
if (((Neo4jPersistentEntity<?>) idProperty.getOwner()).isUsingInternalIds()) {
return idValues;
}
return neo4jMappingContext.getConversionService().writeValue(idValues,
ClassTypeInformation.from(idValues.getClass()), idProperty == null ? null : idProperty.getOptionalWritingConverter());
}
@@ -267,9 +271,10 @@ public final class ReactiveNeo4jTemplate implements ReactiveNeo4jOperations, Bea
return entityMetaData.getDynamicLabelsProperty().map(p -> {
PersistentPropertyAccessor propertyAccessor = entityMetaData.getPropertyAccessor(entityToBeSaved);
Neo4jPersistentProperty idProperty = entityMetaData.getRequiredIdProperty();
ReactiveNeo4jClient.RunnableSpecTightToDatabase runnableQuery = neo4jClient
.query(() -> renderer.render(cypherGenerator.createStatementReturningDynamicLabels(entityMetaData)))
.in(inDatabase).bind(propertyAccessor.getProperty(entityMetaData.getRequiredIdProperty()))
.in(inDatabase).bind(convertIdValues(idProperty, propertyAccessor.getProperty(idProperty)))
.to(Constants.NAME_OF_ID).bind(entityMetaData.getStaticLabels()).to(Constants.NAME_OF_STATIC_LABELS_PARAM);
if (entityMetaData.hasVersionProperty()) {

View File

@@ -54,6 +54,7 @@ import org.springframework.data.neo4j.integration.shared.common.EntitiesWithDyna
import org.springframework.data.neo4j.integration.shared.common.EntitiesWithDynamicLabels.SimpleDynamicLabelsWithBusinessIdAndVersion;
import org.springframework.data.neo4j.integration.shared.common.EntitiesWithDynamicLabels.SimpleDynamicLabelsWithVersion;
import org.springframework.data.neo4j.integration.shared.common.EntitiesWithDynamicLabels.SuperNode;
import org.springframework.data.neo4j.integration.shared.common.EntityWithDynamicLabelsAndIdThatNeedsToBeConverted;
import org.springframework.data.neo4j.test.Neo4jExtension;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
@@ -357,6 +358,20 @@ public class DynamicLabelsIT {
entity -> assertThat(entity.moreLabels).containsExactlyInAnyOrder("SimpleDynamicLabels", "Baz", "Foobar"));
}
@Test // GH-2296
void shouldConvertIds(@Autowired Neo4jTemplate template) {
template.deleteAll(EntityWithDynamicLabelsAndIdThatNeedsToBeConverted.class);
EntityWithDynamicLabelsAndIdThatNeedsToBeConverted savedInstance = template
.save(new EntityWithDynamicLabelsAndIdThatNeedsToBeConverted("value_1"));
assertThat(savedInstance.getValue()).isEqualTo("value_1");
assertThat(savedInstance.getExtraLabels()).containsExactlyInAnyOrder("value_1");
Optional<EntityWithDynamicLabelsAndIdThatNeedsToBeConverted> optionalReloadedInstance =
template.findById(savedInstance.getId(), EntityWithDynamicLabelsAndIdThatNeedsToBeConverted.class);
assertThat(optionalReloadedInstance).hasValueSatisfying(v -> v.getExtraLabels().contains("value_1"));
}
}
@Nested

View File

@@ -26,6 +26,8 @@ import reactor.test.StepVerifier;
import java.util.Collections;
import java.util.HashSet;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Predicate;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
@@ -56,6 +58,7 @@ import org.springframework.data.neo4j.integration.shared.common.EntitiesWithDyna
import org.springframework.data.neo4j.integration.shared.common.EntitiesWithDynamicLabels.SimpleDynamicLabelsWithBusinessIdAndVersion;
import org.springframework.data.neo4j.integration.shared.common.EntitiesWithDynamicLabels.SimpleDynamicLabelsWithVersion;
import org.springframework.data.neo4j.integration.shared.common.EntitiesWithDynamicLabels.SuperNode;
import org.springframework.data.neo4j.integration.shared.common.EntityWithDynamicLabelsAndIdThatNeedsToBeConverted;
import org.springframework.data.neo4j.test.Neo4jExtension;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
@@ -349,6 +352,27 @@ public class ReactiveDynamicLabelsIT {
.flatMapMany(entity -> Flux.fromIterable(entity.moreLabels)).sort().as(StepVerifier::create)
.expectNext("Baz", "Foobar", "SimpleDynamicLabels");
}
@Test // GH-2296
void shouldConvertIds(@Autowired ReactiveNeo4jTemplate template) {
String label = "value_1";
Predicate<EntityWithDynamicLabelsAndIdThatNeedsToBeConverted> expectatations = savedInstance ->
label.equals(savedInstance.getValue()) && savedInstance.getExtraLabels().contains(label);
AtomicReference<UUID> generatedUUID = new AtomicReference<>();
template.deleteAll(EntityWithDynamicLabelsAndIdThatNeedsToBeConverted.class)
.then(template.save(new EntityWithDynamicLabelsAndIdThatNeedsToBeConverted(label)))
.doOnNext(s -> generatedUUID.set(s.getId()))
.as(StepVerifier::create)
.expectNextMatches(expectatations)
.verifyComplete();
template.findById(generatedUUID.get(), EntityWithDynamicLabelsAndIdThatNeedsToBeConverted.class)
.as(StepVerifier::create)
.expectNextMatches(expectatations)
.verifyComplete();
}
}
@Nested

View File

@@ -0,0 +1,68 @@
/*
* Copyright 2011-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.neo4j.integration.shared.common;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import org.springframework.data.neo4j.core.schema.DynamicLabels;
import org.springframework.data.neo4j.core.schema.GeneratedValue;
import org.springframework.data.neo4j.core.schema.Id;
import org.springframework.data.neo4j.core.schema.Node;
/**
* Provided via Github as reproducer for entities with dynamic labels and ids that are subject to conversion. Needed for GH-2296.
*
* @author Michael J. Simons
*/
@Node
public class EntityWithDynamicLabelsAndIdThatNeedsToBeConverted {
@Id
@GeneratedValue
private UUID id;
@DynamicLabels
private Set<String> extraLabels;
private String value;
public EntityWithDynamicLabelsAndIdThatNeedsToBeConverted(String value) {
setValue(value);
}
public void setValue(String value) {
this.value = value;
if (Objects.isNull(extraLabels)) {
extraLabels = new HashSet<>();
}
extraLabels.add(value);
}
public String getValue() {
return value;
}
public Set<String> getExtraLabels() {
return extraLabels;
}
public UUID getId() {
return id;
}
}