-
Notifications
You must be signed in to change notification settings - Fork 616
Closed
Labels
type: new-featureA completely new featureA completely new feature
Milestone
Description
It would be nice to allow composite properties as @Id
properties:
@Node
public class Thing {
@Id
@CompositeProperty(converter = CustomId.Converter.class)
private final CustomId customId;
@Version
private Long version;
private String name;
public Thing(CustomId customId, String name) {
this.customId = customId;
this.name = name;
}
public CustomId getCustomId() {
return customId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Long getVersion() {
return version;
}
}
with CustomId
being defined as
package com.example.compositeids;
import java.util.HashMap;
import java.util.Map;
import org.neo4j.driver.Value;
import org.neo4j.driver.Values;
import org.springframework.data.neo4j.core.convert.Neo4jConversionService;
import org.springframework.data.neo4j.core.convert.Neo4jPersistentPropertyToMapConverter;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
public record CustomId(String value1, Integer value2) {
static class Converter implements Neo4jPersistentPropertyToMapConverter<String, CustomId> {
@NonNull
@Override
public Map<String, Value> decompose(@Nullable CustomId property, Neo4jConversionService conversionService) {
final HashMap<String, Value> decomposed = new HashMap<>();
if (property == null) {
decomposed.put("value1", Values.NULL);
decomposed.put("value2", Values.NULL);
} else {
decomposed.put("value1", Values.value(property.value1));
decomposed.put("value2", Values.value(property.value2));
}
return decomposed;
}
@Override
public CustomId compose(Map<String, Value> source, Neo4jConversionService conversionService) {
return source.isEmpty() ?
null :
new CustomId(source.get("value1").asString(), source.get("value2").asInt());
}
}
}
this does not work yet but it only needs a fix in rendering the id attributes target.
Not sure whether to treat as as a bug or enhancement, so labelled it as both.
Test case for reference:
package com.example.compositeids;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.Test;
import org.neo4j.driver.Driver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.testcontainers.containers.Neo4jContainer;
import org.testcontainers.junit.jupiter.Testcontainers;
@SpringBootTest
@Testcontainers(disabledWithoutDocker = true)
public class ThingRepositoryIT {
@SuppressWarnings("resource")
private static final Neo4jContainer<?> neo4j = new Neo4jContainer<>("neo4j:4.4")
.withReuse(true);
@DynamicPropertySource
static void prepareNeo4j(DynamicPropertyRegistry registry) {
neo4j.start();
registry.add("spring.neo4j.authentication.username", () -> "neo4j");
registry.add("spring.neo4j.authentication.password", neo4j::getAdminPassword);
registry.add("spring.neo4j.uri", neo4j::getBoltUrl);
}
@Test
void compositeIdsShouldWork(@Autowired Driver driver, @Autowired ThingRepository repository) {
var thing = new Thing(new CustomId("a,", 1), "first entity");
var saved = repository.save(thing);
assertThat(saved.getVersion()).isGreaterThanOrEqualTo(0);
saved.setName("foobar");
saved = repository.save(saved);
assertThat(saved.getVersion()).isGreaterThan(0);
assertThat(saved.getName()).isEqualTo("foobar");
}
}
Metadata
Metadata
Assignees
Labels
type: new-featureA completely new featureA completely new feature