Skip to content

Commit d393f55

Browse files
michael-simonsma-ku
andcommitted
fix: Use direction as part of the node collection name for each relationship.
This avoids having duplicate keys in the map projection used to collect the nodes for each relationship in cases where a node has two relationships with the same name to the same label in different directions. Fixes #2918. Co-authored-by: Mathias Kühn <[email protected]>
1 parent 2fe421f commit d393f55

File tree

6 files changed

+144
-1
lines changed

6 files changed

+144
-1
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ default boolean isIncoming() {
117117
@NonNull
118118
default String generateRelatedNodesCollectionName(NodeDescription<?> mostAbstractNodeDescription) {
119119

120-
return this.getSource().getMostAbstractParentLabel(mostAbstractNodeDescription) + "_" + this.getType() + "_" + this.getTarget().getPrimaryLabel();
120+
return this.getSource().getMostAbstractParentLabel(mostAbstractNodeDescription) + "_" + this.getType() + "_" + this.getTarget().getPrimaryLabel() + "_" + this.isOutgoing();
121121
}
122122

123123
/**

src/test/java/org/springframework/data/neo4j/integration/issues/IssuesIT.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import static org.assertj.core.api.Assertions.as;
1919
import static org.assertj.core.api.Assertions.assertThat;
2020
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
21+
import static org.assertj.core.api.Assertions.assertThatNoException;
2122
import static org.assertj.core.api.Assertions.tuple;
2223

2324
import java.util.ArrayList;
@@ -151,6 +152,8 @@
151152
import org.springframework.data.neo4j.integration.issues.gh2886.Apple;
152153
import org.springframework.data.neo4j.integration.issues.gh2886.FruitRepository;
153154
import org.springframework.data.neo4j.integration.issues.gh2886.Orange;
155+
import org.springframework.data.neo4j.integration.issues.gh2918.ConditionNode;
156+
import org.springframework.data.neo4j.integration.issues.gh2918.ConditionRepository;
154157
import org.springframework.data.neo4j.integration.issues.qbe.A;
155158
import org.springframework.data.neo4j.integration.issues.qbe.ARepository;
156159
import org.springframework.data.neo4j.integration.issues.qbe.B;
@@ -1217,6 +1220,18 @@ void dynamicLabels(@Autowired FruitRepository repository) {
12171220
assertThat(fruits).allMatch(f -> f instanceof Apple || f instanceof Orange);
12181221
}
12191222

1223+
@Test
1224+
@Tag("GH-2918")
1225+
void loadCycleFreeWithInAndOutgoingRelationship(@Autowired ConditionRepository conditionRepository) {
1226+
1227+
var conditionSaved = conditionRepository.save(new ConditionNode());
1228+
1229+
// Condition has both an incoming and outgoing relationship typed CAUSES that will cause a duplicate key
1230+
// in the map projection for the relationships to load. The fix was to indicate the direction in the name
1231+
// used for projecting the relationship, too
1232+
assertThatNoException().isThrownBy(() -> conditionRepository.findById(conditionSaved.uuid));
1233+
}
1234+
12201235
@Configuration
12211236
@EnableTransactionManagement
12221237
@EnableNeo4jRepositories(namedQueriesLocation = "more-custom-queries.properties")
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright 2011-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.neo4j.integration.issues.gh2918;
17+
18+
import java.util.Set;
19+
20+
import org.springframework.data.neo4j.core.schema.GeneratedValue;
21+
import org.springframework.data.neo4j.core.schema.Id;
22+
import org.springframework.data.neo4j.core.schema.Node;
23+
import org.springframework.data.neo4j.core.schema.Relationship;
24+
import org.springframework.data.neo4j.core.support.UUIDStringGenerator;
25+
26+
/**
27+
* @author Mathias Kühn
28+
*/
29+
@Node
30+
public class ConditionNode {
31+
@Id
32+
@GeneratedValue(UUIDStringGenerator.class)
33+
public String uuid;
34+
35+
@Relationship(type = "CAUSES", direction = Relationship.Direction.INCOMING)
36+
public Set<FailureRelationship> upstreamFailures;
37+
38+
@Relationship(type = "CAUSES", direction = Relationship.Direction.OUTGOING)
39+
public Set<FailureRelationship> downstreamFailures;
40+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Copyright 2011-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.neo4j.integration.issues.gh2918;
17+
18+
import org.springframework.data.neo4j.repository.Neo4jRepository;
19+
20+
/**
21+
* @author Mathias Kühn
22+
*/
23+
public interface ConditionRepository extends Neo4jRepository<ConditionNode, String> {
24+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
* Copyright 2011-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.neo4j.integration.issues.gh2918;
17+
18+
import org.springframework.data.neo4j.core.schema.GeneratedValue;
19+
import org.springframework.data.neo4j.core.schema.Id;
20+
import org.springframework.data.neo4j.core.schema.Node;
21+
import org.springframework.data.neo4j.core.support.UUIDStringGenerator;
22+
23+
/**
24+
* @author Mathias Kühn
25+
*/
26+
@Node
27+
public class FailureNode {
28+
@Id
29+
@GeneratedValue(UUIDStringGenerator.class)
30+
public String uuid;
31+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright 2011-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.neo4j.integration.issues.gh2918;
17+
18+
import org.springframework.data.neo4j.core.schema.RelationshipId;
19+
import org.springframework.data.neo4j.core.schema.RelationshipProperties;
20+
import org.springframework.data.neo4j.core.schema.TargetNode;
21+
22+
/**
23+
* @author Mathias Kühn
24+
*/
25+
@RelationshipProperties
26+
public abstract class FailureRelationship {
27+
28+
@RelationshipId
29+
public String id;
30+
31+
@TargetNode
32+
public FailureNode target;
33+
}

0 commit comments

Comments
 (0)