Skip to content

Allow the use of composite properties as ids. #2618

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
michael-simons opened this issue Oct 26, 2022 · 0 comments
Closed

Allow the use of composite properties as ids. #2618

michael-simons opened this issue Oct 26, 2022 · 0 comments
Assignees
Labels
type: new-feature A completely new feature

Comments

@michael-simons
Copy link
Collaborator

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");
	}
}
@michael-simons michael-simons added type: bug A general bug type: enhancement A general enhancement type: new-feature A completely new feature and removed type: bug A general bug type: enhancement A general enhancement labels Oct 26, 2022
@michael-simons michael-simons self-assigned this Oct 28, 2022
@michael-simons michael-simons added this to the 6.3.6 (2021.2.6) milestone Oct 28, 2022
michael-simons added a commit that referenced this issue Oct 28, 2022
Also allow the use of composite values in derived findBy… methods.

Closes #2618.
@michael-simons michael-simons mentioned this issue Jan 4, 2023
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: new-feature A completely new feature
Projects
None yet
Development

No branches or pull requests

1 participant