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 a693db7cc0
commit 5ba8493d4e
5 changed files with 119 additions and 2 deletions

View File

@@ -300,6 +300,10 @@ public final class Neo4jTemplate implements Neo4jOperations, FluentNeo4jOperatio
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());
@@ -388,9 +392,10 @@ public final class Neo4jTemplate implements Neo4jOperations, FluentNeo4jOperatio
return entityMetaData.getDynamicLabelsProperty().map(p -> {
PersistentPropertyAccessor<T> propertyAccessor = entityMetaData.getPropertyAccessor(entityToBeSaved);
Neo4jPersistentProperty idProperty = entityMetaData.getRequiredIdProperty();
Neo4jClient.RunnableSpecTightToDatabase runnableQuery = neo4jClient
.query(() -> renderer.render(cypherGenerator.createStatementReturningDynamicLabels(entityMetaData)))
.bind(propertyAccessor.getProperty(entityMetaData.getRequiredIdProperty()))
.bind(convertIdValues(idProperty, propertyAccessor.getProperty(idProperty)))
.to(Constants.NAME_OF_ID).bind(entityMetaData.getStaticLabels())
.to(Constants.NAME_OF_STATIC_LABELS_PARAM);

View File

@@ -284,6 +284,10 @@ public final class ReactiveNeo4jTemplate implements ReactiveNeo4jOperations, Rea
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());
}
@@ -379,9 +383,10 @@ public final class ReactiveNeo4jTemplate implements ReactiveNeo4jOperations, Rea
return entityMetaData.getDynamicLabelsProperty().map(p -> {
PersistentPropertyAccessor propertyAccessor = entityMetaData.getPropertyAccessor(entityToBeSaved);
Neo4jPersistentProperty idProperty = entityMetaData.getRequiredIdProperty();
ReactiveNeo4jClient.RunnableSpecTightToDatabase runnableQuery = neo4jClient
.query(() -> renderer.render(cypherGenerator.createStatementReturningDynamicLabels(entityMetaData)))
.bind(propertyAccessor.getProperty(entityMetaData.getRequiredIdProperty()))
.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

@@ -58,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.BookmarkCapture;
import org.springframework.data.neo4j.test.Neo4jExtension;
import org.springframework.test.annotation.DirtiesContext;
@@ -393,6 +394,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;
@@ -59,6 +61,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.BookmarkCapture;
import org.springframework.data.neo4j.test.Neo4jExtension;
import org.springframework.test.annotation.DirtiesContext;
@@ -372,6 +375,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;
}
}