docs: Add additional tests proving bidi relationships with properties work as intended.
Closes #2905.
This commit is contained in:
@@ -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 + ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 + ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 + ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user