docs: Add additional tests proving bidi relationships with properties work as intended.

Closes #2905.
This commit is contained in:
Michael Simons
2024-05-23 14:54:37 +02:00
parent 68762fd073
commit 7d38286218
5 changed files with 419 additions and 0 deletions

View File

@@ -0,0 +1,78 @@
/*
* Copyright 2011-2024 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.issues.gh2905;
import org.springframework.data.neo4j.core.schema.GeneratedValue;
import org.springframework.data.neo4j.core.schema.Id;
import org.springframework.data.neo4j.core.schema.Relationship;
import org.springframework.data.neo4j.core.support.UUIDStringGenerator;
/**
* @author Mathias Kühn
*/
@SuppressWarnings("HiddenField") // Not worth cleaning up the Delomboked version
class BugFrom {
@Id
@GeneratedValue(UUIDStringGenerator.class)
protected String uuid;
private String name;
@Relationship(type = "RELI", direction = Relationship.Direction.INCOMING)
private BugRelationship reli;
BugFrom(String uuid, String name, BugRelationship reli) {
this.uuid = uuid;
this.name = name;
this.reli = reli;
}
public static BugFromBuilder builder() {
return new BugFromBuilder();
}
public static class BugFromBuilder {
private String uuid;
private String name;
private BugRelationship reli;
BugFromBuilder() {
}
public BugFromBuilder uuid(String uuid) {
this.uuid = uuid;
return this;
}
public BugFromBuilder name(String name) {
this.name = name;
return this;
}
public BugFromBuilder reli(BugRelationship reli) {
this.reli = reli;
return this;
}
public BugFrom build() {
return new BugFrom(this.uuid, this.name, this.reli);
}
public String toString() {
return "BugFrom.BugFromBuilder(uuid=" + this.uuid + ", name=" + this.name + ", reli=" + this.reli + ")";
}
}
}

View File

@@ -0,0 +1,77 @@
/*
* Copyright 2011-2024 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.issues.gh2905;
import org.springframework.data.neo4j.core.schema.RelationshipId;
import org.springframework.data.neo4j.core.schema.RelationshipProperties;
import org.springframework.data.neo4j.core.schema.TargetNode;
/**
* @author Mathias Kühn
*/
@SuppressWarnings("HiddenField") // Not worth cleaning up the Delomboked version
@RelationshipProperties
class BugRelationship {
@RelationshipId
protected Long id;
protected String comment;
@TargetNode
private BugTargetBase target;
BugRelationship(Long id, String comment, BugTargetBase target) {
this.id = id;
this.comment = comment;
this.target = target;
}
public static BugRelationshipBuilder builder() {
return new BugRelationshipBuilder();
}
public static class BugRelationshipBuilder {
private Long id;
private String comment;
private BugTargetBase target;
BugRelationshipBuilder() {
}
public BugRelationshipBuilder id(Long id) {
this.id = id;
return this;
}
public BugRelationshipBuilder comment(String comment) {
this.comment = comment;
return this;
}
public BugRelationshipBuilder target(BugTargetBase target) {
this.target = target;
return this;
}
public BugRelationship build() {
return new BugRelationship(this.id, this.comment, this.target);
}
public String toString() {
return "BugRelationship.BugRelationshipBuilder(id=" + this.id + ", comment=" + this.comment + ", target=" + this.target + ")";
}
}
}

View File

@@ -0,0 +1,73 @@
/*
* Copyright 2011-2024 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.issues.gh2905;
import java.util.Set;
/**
* @author Mathias Kühn
*/
@SuppressWarnings("HiddenField") // Not worth cleaning up the Delomboked version
class BugTarget extends BugTargetBase {
private String type;
BugTarget(String uuid, String name, Set<BugFrom> relatedBugs, String type) {
super(uuid, name, relatedBugs);
this.type = type;
}
public static BugTargetBuilder builder() {
return new BugTargetBuilder();
}
public static class BugTargetBuilder {
private String uuid;
private String name;
private Set<BugFrom> relatedBugs;
private String type;
BugTargetBuilder() {
}
public BugTargetBuilder uuid(String uuid) {
this.uuid = uuid;
return this;
}
public BugTargetBuilder name(String name) {
this.name = name;
return this;
}
public BugTargetBuilder relatedBugs(Set<BugFrom> relatedBugs) {
this.relatedBugs = relatedBugs;
return this;
}
public BugTargetBuilder type(String type) {
this.type = type;
return this;
}
public BugTarget build() {
return new BugTarget(this.uuid, this.name, this.relatedBugs, this.type);
}
public String toString() {
return "BugTarget.BugTargetBuilder(uuid=" + this.uuid + ", name=" + this.name + ", relatedBugs=" + this.relatedBugs + ", type=" + this.type + ")";
}
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright 2011-2024 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.issues.gh2905;
import java.util.Set;
import org.springframework.data.neo4j.core.schema.GeneratedValue;
import org.springframework.data.neo4j.core.schema.Id;
import org.springframework.data.neo4j.core.schema.Relationship;
import org.springframework.data.neo4j.core.support.UUIDStringGenerator;
/**
* @author Mathias Kühn
*/
abstract class BugTargetBase {
@Id
@GeneratedValue(UUIDStringGenerator.class)
protected String uuid;
private String name;
@Relationship(type = "RELI", direction = Relationship.Direction.OUTGOING)
Set<BugFrom> relatedBugs;
BugTargetBase(String uuid, String name, Set<BugFrom> relatedBugs) {
this.uuid = uuid;
this.name = name;
this.relatedBugs = relatedBugs;
}
}

View File

@@ -0,0 +1,148 @@
/*
* Copyright 2011-2024 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.issues.gh2905;
import static org.assertj.core.api.Assertions.as;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.assertj.core.api.InstanceOfAssertFactories;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.neo4j.driver.Driver;
import org.neo4j.driver.Value;
import org.neo4j.driver.types.TypeSystem;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.neo4j.repository.Neo4jRepository;
import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories;
import org.springframework.data.neo4j.test.Neo4jExtension;
import org.springframework.data.neo4j.test.Neo4jImperativeTestConfiguration;
import org.springframework.data.neo4j.test.Neo4jIntegrationTest;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
* @author Michael J. Simons
*/
@Neo4jIntegrationTest
public class Gh2905IT {
protected static Neo4jExtension.Neo4jConnectionSupport neo4jConnectionSupport;
interface FromRepository extends Neo4jRepository<BugFrom, String> {
}
interface ToRepository extends Neo4jRepository<BugTarget, String> {
}
@BeforeEach
void clearDatabase(@Autowired Driver driver) {
driver.executableQuery("MATCH (n) DETACH DELETE n").execute();
}
@Test
void storeFromRootAggregate(@Autowired ToRepository toRepository, @Autowired Driver driver) {
var to1 = BugTarget.builder().name("T1").type("BUG").build();
var from1 = BugFrom.builder()
.name("F1")
.reli(BugRelationship.builder().target(to1).comment("F1<-T1").build())
.build();
var from2 = BugFrom.builder()
.name("F2")
.reli(BugRelationship.builder().target(to1).comment("F2<-T1").build())
.build();
var from3 = BugFrom.builder()
.name("F3")
.reli(BugRelationship.builder().target(to1).comment("F3<-T1").build())
.build();
to1.relatedBugs = Set.of(from1, from2, from3);
toRepository.save(to1);
assertGraph(driver);
}
@Test
void saveSingleEntities(@Autowired FromRepository fromRepository, @Autowired ToRepository toRepository, @Autowired Driver driver) {
var to1 = BugTarget.builder().name("T1").type("BUG").build();
to1.relatedBugs = new HashSet<>();
to1 = toRepository.save(to1);
var from1 = BugFrom.builder()
.name("F1")
.reli(BugRelationship.builder().target(to1).comment("F1<-T1").build())
.build();
// This is the key to solve 2905 when you had the annotation previously, you must maintain both ends of the bidirectional relationship.
// SDN does not do this for you.
to1.relatedBugs.add(from1);
from1 = fromRepository.save(from1);
var from2 = BugFrom.builder()
.name("F2")
.reli(BugRelationship.builder().target(to1).comment("F2<-T1").build())
.build();
// See above
to1.relatedBugs.add(from2);
var from3 = BugFrom.builder()
.name("F3")
.reli(BugRelationship.builder().target(to1).comment("F3<-T1").build())
.build();
to1.relatedBugs.add(from3);
// See above
fromRepository.saveAll(List.of(from1, from2, from3));
assertGraph(driver);
}
private static void assertGraph(Driver driver) {
var result = driver.executableQuery("MATCH (t:BugTarget) -[:RELI] ->(f:BugFrom) RETURN t, collect(f) AS f").execute().records();
assertThat(result)
.hasSize(1)
.element(0).satisfies(r -> {
assertThat(r.get("t")).matches(TypeSystem.getDefault().NODE()::isTypeOf);
assertThat(r.get("f"))
.matches(TypeSystem.getDefault().LIST()::isTypeOf)
.extracting(Value::asList, as(InstanceOfAssertFactories.LIST))
.hasSize(3);
});
}
@Configuration
@EnableTransactionManagement
@EnableNeo4jRepositories(considerNestedRepositories = true)
static class Config extends Neo4jImperativeTestConfiguration {
@Bean
public Driver driver() {
return neo4jConnectionSupport.getDriver();
}
@Override
public boolean isCypher5Compatible() {
return false;
}
}
}