Skip to content

Commit a9a59ff

Browse files
meistermeiermichael-simons
authored andcommitted
DATAGRAPH-1395 - Support [At]TargetNode properties in persistence constructors.
1 parent 559d98a commit a9a59ff

File tree

15 files changed

+77
-56
lines changed

15 files changed

+77
-56
lines changed

src/main/java/org/springframework/data/neo4j/core/mapping/DefaultNeo4jEntityConverter.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ private <ET> ET map(MapAccessor queryResult, Neo4jPersistentEntity<ET> nodeDescr
238238
Collection<RelationshipDescription> relationships = concreteNodeDescription.getRelationships();
239239

240240
ET instance = instantiate(concreteNodeDescription, queryResult, knownObjects, relationships,
241-
nodeDescriptionAndLabels.getDynamicLabels(), processedSegments);
241+
nodeDescriptionAndLabels.getDynamicLabels(), lastMappedEntity, processedSegments);
242242

243243
PersistentPropertyAccessor<ET> propertyAccessor = concreteNodeDescription.getPropertyAccessor(instance);
244244

@@ -294,7 +294,8 @@ private List<String> getLabels(MapAccessor queryResult) {
294294
}
295295

296296
private <ET> ET instantiate(Neo4jPersistentEntity<ET> nodeDescription, MapAccessor values, KnownObjects knownObjects,
297-
Collection<RelationshipDescription> relationships, Collection<String> surplusLabels, Set<Path.Segment> processedSegments) {
297+
Collection<RelationshipDescription> relationships, Collection<String> surplusLabels, Object lastMappedEntity,
298+
Set<Path.Segment> processedSegments) {
298299

299300
ParameterValueProvider<Neo4jPersistentProperty> parameterValueProvider = new ParameterValueProvider<Neo4jPersistentProperty>() {
300301
@Override
@@ -306,6 +307,8 @@ public Object getParameterValue(PreferredConstructor.Parameter parameter) {
306307
return createInstanceOfRelationships(matchingProperty, values, knownObjects, relationships, processedSegments).orElse(null);
307308
} else if (matchingProperty.isDynamicLabels()) {
308309
return createDynamicLabelsProperty(matchingProperty.getTypeInformation(), surplusLabels);
310+
} else if (matchingProperty.isEntityInRelationshipWithProperties()) {
311+
return lastMappedEntity;
309312
}
310313
return conversionService.readValue(extractValueOf(matchingProperty, values), parameter.getType(), matchingProperty.getOptionalReadingConverter());
311314
}

src/main/java/org/springframework/data/neo4j/core/mapping/DefaultNeo4jPersistentProperty.java

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ final class DefaultNeo4jPersistentProperty extends AnnotationBasedPersistentProp
4646

4747
private final Lazy<String> graphPropertyName;
4848
private final Lazy<Boolean> isAssociation;
49-
private final boolean isEntityInRelationshipWithProperties;
5049

5150
private final Neo4jMappingContext mappingContext;
5251

@@ -60,11 +59,9 @@ final class DefaultNeo4jPersistentProperty extends AnnotationBasedPersistentProp
6059
* @param simpleTypeHolder type holder
6160
*/
6261
DefaultNeo4jPersistentProperty(Property property, PersistentEntity<?, Neo4jPersistentProperty> owner,
63-
Neo4jMappingContext mappingContext, SimpleTypeHolder simpleTypeHolder,
64-
boolean isEntityInRelationshipWithProperties) {
62+
Neo4jMappingContext mappingContext, SimpleTypeHolder simpleTypeHolder) {
6563

6664
super(property, owner, simpleTypeHolder);
67-
this.isEntityInRelationshipWithProperties = isEntityInRelationshipWithProperties;
6865
this.mappingContext = mappingContext;
6966

7067
this.graphPropertyName = Lazy.of(this::computeGraphPropertyName);
@@ -183,7 +180,7 @@ public boolean isAssociation() {
183180

184181
@Override
185182
public boolean isEntity() {
186-
return super.isEntity() && isAssociation() || (super.isEntity() && isEntityInRelationshipWithProperties() && !isComposite());
183+
return super.isEntity() && isAssociation() || (isEntityInRelationshipWithProperties() && !isComposite());
187184
}
188185

189186
private static Function<Object, Value> nullSafeWrite(Function<Object, Value> delegate) {
@@ -206,7 +203,7 @@ public Function<Value, Object> getOptionalReadingConverter() {
206203

207204
@Override
208205
public boolean isEntityInRelationshipWithProperties() {
209-
return isEntityInRelationshipWithProperties;
206+
return super.isEntity() && ((Neo4jPersistentEntity<?>) getOwner()).isRelationshipPropertiesEntity();
210207
}
211208

212209
/**

src/main/java/org/springframework/data/neo4j/core/mapping/Neo4jMappingContext.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ private boolean isValidParentNode(@Nullable Class<?> parentClass) {
194194
protected Neo4jPersistentProperty createPersistentProperty(Property property, Neo4jPersistentEntity<?> owner,
195195
SimpleTypeHolder simpleTypeHolder) {
196196

197-
return new DefaultNeo4jPersistentProperty(property, owner, this, simpleTypeHolder, owner.isRelationshipPropertiesEntity());
197+
return new DefaultNeo4jPersistentProperty(property, owner, this, simpleTypeHolder);
198198
}
199199

200200
@Override

src/main/java/org/springframework/data/neo4j/core/schema/GeneratedValue.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ public Void generateId(String primaryLabel, Object entity) {
7878
* This generator is automatically applied when a field of type {@link java.util.UUID} is annotated with
7979
* {@link Id @Id} and {@link GeneratedValue @GeneratedValue}.
8080
*
81-
* @since 6.0.1
8281
*/
8382
final class UUIDGenerator implements IdGenerator<UUID> {
8483

src/main/kotlin/org/springframework/data/neo4j/core/cypher/Parameters.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ package org.springframework.data.neo4j.core.cypher
2424
* @author Michael J. Simons
2525
* @since 6.0
2626
*/
27-
inline fun String.asParam() = "\$" + this
27+
fun String.asParam() = "\$" + this
2828

2929
/**
3030
* Extension on [String]'s companion object returning the string passed to it prefixed with an escaped `$`.

src/test/java/org/springframework/data/neo4j/integration/imperative/RepositoryIT.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,8 @@ void setupData(Transaction transaction) {
182182
transaction.run("CREATE (n:PersonWithNoConstructor) SET n.name = $name, n.first_name = $firstName",
183183
Values.parameters("name", TEST_PERSON1_NAME, "firstName", TEST_PERSON1_FIRST_NAME));
184184
transaction.run("CREATE (n:PersonWithWither) SET n.name = '" + TEST_PERSON1_NAME + "'");
185-
transaction.run("CREATE (n:KotlinPerson) SET n.name = '" + TEST_PERSON1_NAME + "'");
185+
transaction.run("CREATE (n:KotlinPerson), "
186+
+ " (n)-[:WORKS_IN{since: 2019}]->(:KotlinClub{name: 'Golf club'}) SET n.name = '" + TEST_PERSON1_NAME + "'");
186187
transaction.run("CREATE (a:Thing {theId: 'anId', name: 'Homer'})-[:Has]->(b:Thing2{theId: 4711, name: 'Bart'})");
187188

188189
IntStream.rangeClosed(1, 20)
@@ -1080,16 +1081,14 @@ void saveEntityWithRelationshipWithProperties(
10801081
rel2.setHobby(h2);
10811082

10821083
List<LikesHobbyRelationship> hobbies = new ArrayList<>();
1083-
PersonWithRelationshipWithProperties person = new PersonWithRelationshipWithProperties("Freddie clone");
10841084
hobbies.add(rel1);
10851085
hobbies.add(rel2);
1086-
person.setHobbies(hobbies);
10871086

1088-
WorksInClubRelationship worksInClub = new WorksInClubRelationship(2002);
10891087
Club club = new Club();
10901088
club.setName("BlubbClub");
1091-
worksInClub.setClub(club);
1092-
person.setClub(worksInClub);
1089+
WorksInClubRelationship worksInClub = new WorksInClubRelationship(2002, club);
1090+
PersonWithRelationshipWithProperties person =
1091+
new PersonWithRelationshipWithProperties("Freddie clone", hobbies, worksInClub);
10931092

10941093
// when
10951094
PersonWithRelationshipWithProperties shouldBeDifferentPerson = repository.save(person);

src/test/java/org/springframework/data/neo4j/integration/imperative/repositories/PersonRepository.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,13 +94,13 @@ Optional<PersonWithAllConstructor> getOptionalPersonViaNamedQuery(@Param("part1"
9494
@Query("MATCH (n:PersonWithWither{name:'Test'}) return n")
9595
Optional<PersonWithWither> getOptionalPersonWithWitherViaQuery();
9696

97-
@Query("MATCH (n:KotlinPerson) return n")
97+
@Query("MATCH (n:KotlinPerson)-[w:WORKS_IN]->(c:KotlinClub) return n, collect(w), collect(c)")
9898
List<KotlinPerson> getAllKotlinPersonsViaQuery();
9999

100-
@Query("MATCH (n:KotlinPerson{name:'Test'}) return n")
100+
@Query("MATCH (n:KotlinPerson{name:'Test'})-[w:WORKS_IN]->(c:KotlinClub) return n, collect(w), collect(c)")
101101
KotlinPerson getOneKotlinPersonViaQuery();
102102

103-
@Query("MATCH (n:KotlinPerson{name:'Test'}) return n")
103+
@Query("MATCH (n:KotlinPerson{name:'Test'})-[w:WORKS_IN]->(c:KotlinClub) return n, collect(w), collect(c)")
104104
Optional<KotlinPerson> getOptionalKotlinPersonViaQuery();
105105

106106
// Derived finders, should be extracted into another repo.

src/test/java/org/springframework/data/neo4j/integration/kotlin/KotlinIT.java

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,46 +27,52 @@
2727
import org.springframework.context.annotation.Bean;
2828
import org.springframework.context.annotation.Configuration;
2929
import org.springframework.data.neo4j.config.AbstractNeo4jConfig;
30+
import org.springframework.data.neo4j.integration.shared.KotlinClub;
31+
import org.springframework.data.neo4j.integration.shared.KotlinClubRelationship;
3032
import org.springframework.data.neo4j.integration.shared.KotlinPerson;
3133
import org.springframework.data.neo4j.integration.shared.KotlinRepository;
3234
import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories;
3335
import org.springframework.data.neo4j.test.Neo4jExtension.Neo4jConnectionSupport;
3436
import org.springframework.data.neo4j.test.Neo4jIntegrationTest;
37+
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
3538
import org.springframework.transaction.annotation.EnableTransactionManagement;
3639

3740
/**
3841
* @author Gerrit Meier
3942
* @author Michael J. Simons
4043
*/
44+
@SpringJUnitConfig(KotlinIT.Config.class)
4145
@Neo4jIntegrationTest
4246
class KotlinIT {
4347

4448
private final static String PERSON_NAME = "test";
4549

4650
private static Neo4jConnectionSupport neo4jConnectionSupport;
4751

48-
private final Driver driver;
49-
5052
@Autowired
51-
KotlinIT(Driver driver) {
52-
this.driver = driver;
53-
}
53+
private Driver driver;
5454

5555
@BeforeEach
5656
void setup() {
5757
try (Session session = driver.session(); Transaction transaction = session.beginTransaction()) {
5858
transaction.run("MATCH (n) detach delete n").consume();
59-
transaction.run("CREATE (n:KotlinPerson) SET n.name = $personName", Values.parameters("personName", PERSON_NAME))
59+
transaction.run("CREATE (n:KotlinPerson), "
60+
+ " (n)-[:WORKS_IN{since: 2019}]->(:KotlinClub{name: 'Golf club'}) SET n.name = $personName",
61+
Values.parameters("personName", PERSON_NAME))
6062
.consume();
6163
transaction.commit();
6264
}
6365
}
6466

65-
@Test
67+
@Test // with addition by DATAGRAPH-1395
6668
void findAllKotlinPersons(@Autowired KotlinRepository repository) {
6769

68-
Iterable<KotlinPerson> person = repository.findAll();
69-
assertThat(person.iterator().next().getName()).isEqualTo(PERSON_NAME);
70+
Iterable<KotlinPerson> people = repository.findAll();
71+
assertThat(people).extracting(KotlinPerson::getName).containsExactly(PERSON_NAME);
72+
KotlinPerson person = people.iterator().next();
73+
assertThat(person.getClubs()).extracting(KotlinClubRelationship::getSince).containsExactly(2019);
74+
assertThat(person.getClubs()).extracting(KotlinClubRelationship::getClub)
75+
.extracting(KotlinClub::getName).containsExactly("Golf club");
7076
}
7177

7278
@Configuration

src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveRepositoryIT.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,14 +1056,13 @@ void saveEntityWithRelationshipWithProperties(
10561056
List<LikesHobbyRelationship> hobbies = new ArrayList<>();
10571057
hobbies.add(rel1);
10581058
hobbies.add(rel2);
1059-
PersonWithRelationshipWithProperties person = new PersonWithRelationshipWithProperties("Freddie clone");
1060-
person.setHobbies(hobbies);
10611059

1062-
WorksInClubRelationship worksInClub = new WorksInClubRelationship(2002);
10631060
Club club = new Club();
10641061
club.setName("BlubbClub");
1065-
worksInClub.setClub(club);
1066-
person.setClub(worksInClub);
1062+
WorksInClubRelationship worksInClub = new WorksInClubRelationship(2002, club);
1063+
1064+
PersonWithRelationshipWithProperties person =
1065+
new PersonWithRelationshipWithProperties("Freddie clone", hobbies, worksInClub);
10671066

10681067
// when
10691068
Mono<PersonWithRelationshipWithProperties> operationUnderTest = repository.save(person);

src/test/java/org/springframework/data/neo4j/integration/shared/PersonWithRelationshipWithProperties.java

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import java.util.List;
1919
import java.util.Set;
2020

21+
import org.springframework.data.annotation.PersistenceConstructor;
2122
import org.springframework.data.neo4j.core.schema.GeneratedValue;
2223
import org.springframework.data.neo4j.core.schema.Id;
2324
import org.springframework.data.neo4j.core.schema.Node;
@@ -26,6 +27,7 @@
2627
/**
2728
* @author Gerrit Meier
2829
* @author Philipp Tölle
30+
* @author Michael J. Simons
2931
*/
3032
@Node
3133
public class PersonWithRelationshipWithProperties {
@@ -34,32 +36,38 @@ public class PersonWithRelationshipWithProperties {
3436

3537
private final String name;
3638

37-
@Relationship("LIKES") private List<LikesHobbyRelationship> hobbies;
39+
@Relationship("LIKES") private final List<LikesHobbyRelationship> hobbies;
3840

39-
@Relationship("WORKS_IN") private WorksInClubRelationship club;
41+
@Relationship("WORKS_IN") private final WorksInClubRelationship club;
4042

4143
@Relationship("OWNS") private Set<Pet> pets;
4244

4345
@Relationship("OWNS") private List<ClubRelationship> clubs;
4446

45-
public PersonWithRelationshipWithProperties(String name) {
47+
@PersistenceConstructor
48+
public PersonWithRelationshipWithProperties(Long id, String name, List<LikesHobbyRelationship> hobbies, WorksInClubRelationship club) {
49+
this.id = id;
4650
this.name = name;
51+
this.hobbies = hobbies;
52+
this.club = club;
4753
}
4854

49-
public String getName() {
50-
return name;
55+
public PersonWithRelationshipWithProperties(String name, List<LikesHobbyRelationship> hobbies, WorksInClubRelationship club) {
56+
this.name = name;
57+
this.hobbies = hobbies;
58+
this.club = club;
5159
}
5260

53-
public List<LikesHobbyRelationship> getHobbies() {
54-
return hobbies;
61+
public PersonWithRelationshipWithProperties withId(Long newId) {
62+
return new PersonWithRelationshipWithProperties(newId, this.name, this.hobbies, this.club);
5563
}
5664

57-
public void setHobbies(List<LikesHobbyRelationship> hobbies) {
58-
this.hobbies = hobbies;
65+
public String getName() {
66+
return name;
5967
}
6068

61-
public void setClub(WorksInClubRelationship club) {
62-
this.club = club;
69+
public List<LikesHobbyRelationship> getHobbies() {
70+
return hobbies;
6371
}
6472

6573
public WorksInClubRelationship getClub() {

0 commit comments

Comments
 (0)