From f7bf8a0350ec580d863df7e467d8168372e55f03 Mon Sep 17 00:00:00 2001 From: Michael Simons Date: Tue, 20 Apr 2021 14:28:23 +0200 Subject: [PATCH] GH-1985 - Make sure derived queries on the same property of the same entity but different relationships use multiple matches. This closes #1985 by adding the same test that is available in Neo4j-OGM and prior versions of SDN. --- .../integration/imperative/RepositoryIT.java | 29 +++++++++- .../repositories/FlightRepository.java | 28 ++++++++++ .../integration/issues/gh2210/GH2210IT.java | 5 +- .../integration/shared/common/Airport.java | 47 ++++++++++++++++ .../integration/shared/common/Flight.java | 56 +++++++++++++++++++ 5 files changed, 161 insertions(+), 4 deletions(-) create mode 100644 src/test/java/org/springframework/data/neo4j/integration/imperative/repositories/FlightRepository.java create mode 100644 src/test/java/org/springframework/data/neo4j/integration/shared/common/Airport.java create mode 100644 src/test/java/org/springframework/data/neo4j/integration/shared/common/Flight.java diff --git a/src/test/java/org/springframework/data/neo4j/integration/imperative/RepositoryIT.java b/src/test/java/org/springframework/data/neo4j/integration/imperative/RepositoryIT.java index 98f2a9dae..e8485c95e 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/imperative/RepositoryIT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/imperative/RepositoryIT.java @@ -86,6 +86,8 @@ import org.springframework.data.neo4j.integration.imperative.repositories.Person import org.springframework.data.neo4j.integration.imperative.repositories.PersonWithNoConstructorRepository; import org.springframework.data.neo4j.integration.imperative.repositories.PersonWithWitherRepository; import org.springframework.data.neo4j.integration.imperative.repositories.ThingRepository; +import org.springframework.data.neo4j.integration.shared.common.Flight; +import org.springframework.data.neo4j.integration.imperative.repositories.FlightRepository; import org.springframework.data.neo4j.integration.shared.common.AltHobby; import org.springframework.data.neo4j.integration.shared.common.AltLikedByPersonRelationship; import org.springframework.data.neo4j.integration.shared.common.AltPerson; @@ -210,6 +212,20 @@ class RepositoryIT { true, 1L, TEST_PERSON1_BORN_ON, "something", Arrays.asList("a", "b"), NEO4J_HQ, createdAt.toInstant()); person2 = new PersonWithAllConstructor(id2, TEST_PERSON2_NAME, TEST_PERSON2_FIRST_NAME, TEST_PERSON_SAMEVALUE, false, 2L, TEST_PERSON2_BORN_ON, null, Collections.emptyList(), SFO, null); + + transaction.run("CREATE (lhr:Airport {code: 'LHR', name: 'London Heathrow'})\n" + + "CREATE (lax:Airport {code: 'LAX', name: 'Los Angeles'})\n" + + "CREATE (cdg:Airport {code: 'CDG', name: 'Paris Charles de Gaulle'})\n" + + "CREATE (f1:Flight {name: 'FL 001'})\n" + + "CREATE (f2:Flight {name: 'FL 002'})\n" + + "CREATE (f3:Flight {name: 'FL 003'})\n" + + "CREATE (f1) -[:DEPARTS] ->(lhr)\n" + + "CREATE (f1) -[:ARRIVES] ->(lax)\n" + + "CREATE (f2) -[:DEPARTS] ->(lhr)\n" + + "CREATE (f2) -[:ARRIVES] ->(cdg)\n" + + "CREATE (f3) -[:DEPARTS] ->(lax)\n" + + "CREATE (f3) -[:ARRIVES] ->(lhr)\n" + + "RETURN *"); } @Test @@ -734,6 +750,14 @@ class RepositoryIT { assertThat(slice.get()).hasSize(1).extracting("name").containsExactly(TEST_PERSON1_NAME); assertThat(slice.hasNext()).isFalse(); } + + @Test // GH-1985 + void filtersOnSameEntitiesButDifferentRelationsShouldWork(@Autowired FlightRepository repository) { + + List flights = repository.findAllByDepartureCodeAndArrivalCode("LHR", "LAX"); + assertThat(flights).hasSize(1) + .first().extracting(Flight::getName).isEqualTo("FL 001"); + } } @Nested @@ -4271,7 +4295,10 @@ class RepositoryIT { @Override protected Collection getMappingBasePackages() { - return Arrays.asList(PersonWithAllConstructor.class.getPackage().getName()); + return Arrays.asList( + PersonWithAllConstructor.class.getPackage().getName(), + Flight.class.getPackage().getName() + ); } @Bean diff --git a/src/test/java/org/springframework/data/neo4j/integration/imperative/repositories/FlightRepository.java b/src/test/java/org/springframework/data/neo4j/integration/imperative/repositories/FlightRepository.java new file mode 100644 index 000000000..9dc04ac38 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/imperative/repositories/FlightRepository.java @@ -0,0 +1,28 @@ +/* + * Copyright 2011-2021 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.imperative.repositories; + +import org.springframework.data.neo4j.integration.shared.common.Flight; +import org.springframework.data.neo4j.repository.Neo4jRepository; + +import java.util.List; + +/** + * @author Michael J. Simons + */ +public interface FlightRepository extends Neo4jRepository { + List findAllByDepartureCodeAndArrivalCode(String departureCode, String arrivalCode); +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2210/GH2210IT.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2210/GH2210IT.java index 577286f18..195ef4150 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2210/GH2210IT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2210/GH2210IT.java @@ -18,7 +18,6 @@ package org.springframework.data.neo4j.integration.issues.gh2210; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.neo4j.driver.Driver; -import org.neo4j.driver.Record; import org.neo4j.driver.Transaction; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; @@ -70,14 +69,14 @@ class GH2210IT { params.put("numberB", numberB); params.put("numberC", numberC); params.put("numberD", numberD); - Record r = transaction.run("create (a:SomeEntity {number: $numberA, name: \"A\"})\n" + transaction.run("create (a:SomeEntity {number: $numberA, name: \"A\"})\n" + "create (b:SomeEntity {number: $numberB, name: \"B\"})\n" + "create (c:SomeEntity {number: $numberC, name: \"C\"})\n" + "create (d:SomeEntity {number: $numberD, name: \"D\"})\n" + "create (a) -[:SOME_RELATION_TO {someData: \"d1\"}] -> (b)\n" + "create (b) <-[:SOME_RELATION_TO {someData: \"d2\"}] - (c)\n" + "create (c) <-[:SOME_RELATION_TO {someData: \"d3\"}] - (d)\n" - + "return * ", params).single(); + + "return * ", params); transaction.commit(); } } diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/Airport.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/Airport.java new file mode 100644 index 000000000..228ad3d27 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/Airport.java @@ -0,0 +1,47 @@ +/* + * Copyright 2011-2021 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.shared.common; + +import org.springframework.data.neo4j.core.schema.Id; +import org.springframework.data.neo4j.core.schema.Node; + +/** + * @author Michael J. Simons + */ +@Node +public class Airport { + + @Id + String code; // e.g. "LAX" + String name; // e.g. "Los Angeles" + + public Airport(String code, String name) { + this.code = code; + this.name = name; + } + + public String getCode() { + return code; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/Flight.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/Flight.java new file mode 100644 index 000000000..114de694b --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/Flight.java @@ -0,0 +1,56 @@ +/* + * Copyright 2011-2021 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.shared.common; + +import org.springframework.data.neo4j.core.schema.GeneratedValue; +import org.springframework.data.neo4j.core.schema.Id; +import org.springframework.data.neo4j.core.schema.Node; +import org.springframework.data.neo4j.core.schema.Relationship; + +/** + * @author Michael J. Simons + */ +@Node +public class Flight { + + @Id @GeneratedValue + private Long id; + + private final String name; + + @Relationship(type = "DEPARTS") + private final Airport departure; + @Relationship(type = "ARRIVES") + private final Airport arrival; + + public Flight(String name, Airport departure, Airport arrival) { + this.name = name; + this.departure = departure; + this.arrival = arrival; + } + + public String getName() { + return name; + } + + public Airport getDeparture() { + return departure; + } + + public Airport getArrival() { + return arrival; + } +}