From fb1f05acb83ca3e8e0f3e7db2cefbbe23149fbad Mon Sep 17 00:00:00 2001 From: Michael Simons Date: Mon, 20 Jun 2022 13:12:29 +0200 Subject: [PATCH] GH-2537 - Improve documentation. # Conflicts: # src/test/java/org/springframework/data/neo4j/integration/issues/IssuesIT.java # src/test/java/org/springframework/data/neo4j/integration/issues/gh2323/PersonRepository.java # src/test/java/org/springframework/data/neo4j/integration/issues/gh2323/PersonService.java --- .../asciidoc/appendix/custom-queries.adoc | 5 ++- .../integration/issues/gh2323/GH2323IT.java | 39 +++++++++++++++++++ .../integration/issues/gh2323/Person.java | 3 ++ 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/main/asciidoc/appendix/custom-queries.adoc b/src/main/asciidoc/appendix/custom-queries.adoc index 5bb7ac12f..bca6df686 100644 --- a/src/main/asciidoc/appendix/custom-queries.adoc +++ b/src/main/asciidoc/appendix/custom-queries.adoc @@ -357,7 +357,10 @@ All properties - and type of relationships - appear in those maps as they would have been written by SDN. Values will have the correct Cypher type and won't need further conversion. -All relationships are lists of maps. Dynamic relationships will be resolved accordingly. +TIP: All relationships are lists of maps. Dynamic relationships will be resolved accordingly. + One-to-one relationships will also be serialized as singleton lists. So to access a one-to-one mapping + between people, you would write this das `$person.\\__properties__.BEST_FRIEND[0].\\__target__.\\__id__`. + If an entity has a relationship with the same type to different types of others nodes, they will all appear in the same list. If you need such a mapping and also have the need to work with those custom parameters, you have to unroll it accordingly. One way to do this are correlated subqueries (Neo4j 4.1+ required). diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2323/GH2323IT.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2323/GH2323IT.java index 42acefe1b..1288c7111 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2323/GH2323IT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2323/GH2323IT.java @@ -18,6 +18,7 @@ package org.springframework.data.neo4j.integration.issues.gh2323; import static org.assertj.core.api.Assertions.assertThat; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; @@ -65,6 +66,9 @@ class GH2323IT { .asString(); transaction.run("unwind ['German', 'English'] as name create (n:Language {name: name}) return name") .consume(); + personId = transaction.run("MATCH (l:Language {name: 'German'}) CREATE (n:Person {id: randomUUID(), name: 'Helge'}) -[:HAS_MOTHER_TONGUE]-> (l) return n.id").single() + .get(0) + .asString(); transaction.commit(); bookmarkCapture.seedWith(session.lastBookmark()); } @@ -105,6 +109,20 @@ class GH2323IT { }); } + @Test // "GH-2537" + void ensure1To1RelationshipsAreSerialized(@Autowired PersonService personService) { + + Optional optionalPerson = personService.updateRel3(personId); + assertThat(optionalPerson).isPresent().hasValueSatisfying(person -> { + + assertThat(person.getKnownLanguages()).hasSize(1); + assertThat(person.getKnownLanguages()).first().satisfies(knows -> { + assertThat(knows.getDescription()).isEqualTo("Whatever"); + assertThat(knows.getLanguage()).extracting(Language::getName).isEqualTo("German"); + }); + }); + } + @Repository public interface PersonRepository extends Neo4jRepository { @@ -126,6 +144,16 @@ class GH2323IT { + "CREATE (f) - [r:KNOWS {description: rel.__properties__.description}] -> (t) " + "RETURN f, collect(r), collect(t)") Person updateRel2(@Param("person") Person person); + + @Query("" + + "MATCH (f:Person {id: $person.__id__}) " + + "MATCH (mt:Language {name: $person.__properties__.HAS_MOTHER_TONGUE[0].__target__.__id__}) " + + "MATCH (f)-[frl:HAS_MOTHER_TONGUE]->(mt) WITH f, frl, mt " + + "UNWIND $person.__properties__.KNOWS As rel WITH f, frl, mt, rel " + + "MATCH (t:Language {name: rel.__target__.__id__}) " + + "MERGE (f)- [r:KNOWS {description: rel.__properties__.description}] -> (t) " + + "RETURN f, frl, mt, collect(r), collect(t)") + Person updateRelWith11(@Param("person") Person person); } @Service @@ -159,6 +187,17 @@ class GH2323IT { return original; } + + public Optional updateRel3(String id) { + Optional original = personRepository.findById(id); + if (original.isPresent()) { + Person person = original.get(); + person.setKnownLanguages(Collections.singletonList(new Knows("Whatever", new Language("German")))); + return Optional.of(personRepository.updateRelWith11(person)); + } + + return original; + } } @Configuration diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2323/Person.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2323/Person.java index 261958e1d..8497fb8a5 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2323/Person.java +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2323/Person.java @@ -37,6 +37,9 @@ public class Person { @Relationship("KNOWS") private List knownLanguages = new ArrayList<>(); + @Relationship("HAS_MOTHER_TONGUE") + private Knows motherTongue; + public Person(String name) { this.name = name; }