/* * Copyright (c) 2019-2020 "Neo4j," * Neo4j Sweden AB [https://neo4j.com] * * This file is part of Neo4j. * * 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.neo4j.springframework.data.integration.reactive; import static org.assertj.core.api.Assertions.*; import static org.neo4j.springframework.data.test.Neo4jExtension.*; import reactor.test.StepVerifier; import java.util.Collections; import java.util.List; import java.util.function.Function; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; import org.neo4j.driver.Driver; import org.neo4j.driver.Record; import org.neo4j.driver.Session; import org.neo4j.springframework.data.config.AbstractReactiveNeo4jConfig; import org.neo4j.springframework.data.integration.shared.MultipleRelationshipsThing; import org.neo4j.springframework.data.integration.shared.RelationshipsITBase; import org.neo4j.springframework.data.repository.config.EnableReactiveNeo4jRepositories; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.repository.reactive.ReactiveCrudRepository; import org.springframework.transaction.annotation.EnableTransactionManagement; /** * Test cases for various relationship scenarios (self references, multiple times to same instance). * * @author Michael J. Simons */ @Tag(NEEDS_REACTIVE_SUPPORT) class ReactiveRelationshipsIT extends RelationshipsITBase { @Autowired ReactiveRelationshipsIT(Driver driver) { super(driver); } @Test void shouldSaveSingleRelationship(@Autowired MultipleRelationshipsThingRepository repository) { MultipleRelationshipsThing p = new MultipleRelationshipsThing("p"); p.setTypeA(new MultipleRelationshipsThing("c")); repository.save(p) .map(MultipleRelationshipsThing::getId) .flatMap(repository::findById) .as(StepVerifier::create) .assertNext(loadedThing -> assertThat(loadedThing) .extracting(MultipleRelationshipsThing::getTypeA) .extracting(MultipleRelationshipsThing::getName) .isEqualTo("c")) .verifyComplete(); try (Session session = driver.session()) { List<String> names = session.run("MATCH (n:MultipleRelationshipsThing) RETURN n.name AS name") .list(r -> r.get("name").asString()); assertThat(names).hasSize(2).containsExactlyInAnyOrder("p", "c"); } } @Test void shouldSaveSingleRelationshipInList(@Autowired MultipleRelationshipsThingRepository repository) { MultipleRelationshipsThing p = new MultipleRelationshipsThing("p"); p.setTypeB(Collections.singletonList(new MultipleRelationshipsThing("c"))); repository.save(p) .map(MultipleRelationshipsThing::getId) .flatMap(repository::findById) .as(StepVerifier::create) .assertNext(loadedThing -> assertThat(loadedThing.getTypeB()) .extracting(MultipleRelationshipsThing::getName) .containsExactly("c")) .verifyComplete(); try (Session session = driver.session()) { List<String> names = session.run("MATCH (n:MultipleRelationshipsThing) RETURN n.name AS name") .list(r -> r.get("name").asString()); assertThat(names).hasSize(2).containsExactlyInAnyOrder("p", "c"); } } /** * This stores multiple, different instances. * * @param repository The repository to use. */ @Test void shouldSaveMultipleRelationshipsOfSameObjectType(@Autowired MultipleRelationshipsThingRepository repository) { MultipleRelationshipsThing p = new MultipleRelationshipsThing("p"); p.setTypeA(new MultipleRelationshipsThing("c1")); p.setTypeB(Collections.singletonList(new MultipleRelationshipsThing("c2"))); p.setTypeC(Collections.singletonList(new MultipleRelationshipsThing("c3"))); repository.save(p) .map(MultipleRelationshipsThing::getId) .flatMap(repository::findById) .as(StepVerifier::create) .assertNext(loadedThing -> { MultipleRelationshipsThing typeA = loadedThing.getTypeA(); List<MultipleRelationshipsThing> typeB = loadedThing.getTypeB(); List<MultipleRelationshipsThing> typeC = loadedThing.getTypeC(); assertThat(typeA).isNotNull(); assertThat(typeA).extracting(MultipleRelationshipsThing::getName).isEqualTo("c1"); assertThat(typeB).extracting(MultipleRelationshipsThing::getName).containsExactly("c2"); assertThat(typeC).extracting(MultipleRelationshipsThing::getName).containsExactly("c3"); }) .verifyComplete(); try (Session session = driver.session()) { List<String> names = session.run( "MATCH (n:MultipleRelationshipsThing {name: 'p'}) - [r:TYPE_A|TYPE_B|TYPE_C] -> (o) RETURN r, o") .list(record -> { String type = record.get("r").asRelationship().type(); String name = record.get("o").get("name").asString(); return type + "_" + name; }); assertThat(names).containsExactlyInAnyOrder("TYPE_A_c1", "TYPE_B_c2", "TYPE_C_c3"); } } /** * This stores the same instance in different relationships * * @param repository The repository to use. */ @Test void shouldSaveMultipleRelationshipsOfSameInstance(@Autowired MultipleRelationshipsThingRepository repository) { MultipleRelationshipsThing p = new MultipleRelationshipsThing("p"); MultipleRelationshipsThing c = new MultipleRelationshipsThing("c1"); p.setTypeA(c); p.setTypeB(Collections.singletonList(c)); p.setTypeC(Collections.singletonList(c)); repository.save(p) .map(MultipleRelationshipsThing::getId) .flatMap(repository::findById) .as(StepVerifier::create) .assertNext(loadedThing -> { MultipleRelationshipsThing typeA = loadedThing.getTypeA(); List<MultipleRelationshipsThing> typeB = loadedThing.getTypeB(); List<MultipleRelationshipsThing> typeC = loadedThing.getTypeC(); assertThat(typeA).isNotNull(); assertThat(typeA).extracting(MultipleRelationshipsThing::getName).isEqualTo("c1"); assertThat(typeB).extracting(MultipleRelationshipsThing::getName).containsExactly("c1"); assertThat(typeC).extracting(MultipleRelationshipsThing::getName).containsExactly("c1"); }) .verifyComplete(); try (Session session = driver.session()) { List<String> names = session.run( "MATCH (n:MultipleRelationshipsThing {name: 'p'}) - [r:TYPE_A|TYPE_B|TYPE_C] -> (o) RETURN r, o") .list(record -> { String type = record.get("r").asRelationship().type(); String name = record.get("o").get("name").asString(); return type + "_" + name; }); assertThat(names).containsExactlyInAnyOrder("TYPE_A_c1", "TYPE_B_c1", "TYPE_C_c1"); } } /** * This stores the same instance in different relationships * * @param repository The repository to use. */ @Test void shouldSaveMultipleRelationshipsOfSameInstanceWithBackReference( @Autowired MultipleRelationshipsThingRepository repository) { MultipleRelationshipsThing p = new MultipleRelationshipsThing("p"); MultipleRelationshipsThing c = new MultipleRelationshipsThing("c1"); p.setTypeA(c); p.setTypeB(Collections.singletonList(c)); p.setTypeC(Collections.singletonList(c)); c.setTypeA(p); repository.save(p) .map(MultipleRelationshipsThing::getId) .flatMap(repository::findById) .as(StepVerifier::create) .assertNext(loadedThing -> { MultipleRelationshipsThing typeA = loadedThing.getTypeA(); List<MultipleRelationshipsThing> typeB = loadedThing.getTypeB(); List<MultipleRelationshipsThing> typeC = loadedThing.getTypeC(); assertThat(typeA).isNotNull(); assertThat(typeA).extracting(MultipleRelationshipsThing::getName).isEqualTo("c1"); assertThat(typeB).extracting(MultipleRelationshipsThing::getName).containsExactly("c1"); assertThat(typeC).extracting(MultipleRelationshipsThing::getName).containsExactly("c1"); }) .verifyComplete(); try (Session session = driver.session()) { Function<Record, String> withMapper = record -> { String type = record.get("r").asRelationship().type(); String name = record.get("o").get("name").asString(); return type + "_" + name; }; String query = "MATCH (n:MultipleRelationshipsThing {name: $name}) - [r:TYPE_A|TYPE_B|TYPE_C] -> (o) RETURN r, o"; List<String> names = session.run(query, Collections.singletonMap("name", "p")).list(withMapper); assertThat(names).containsExactlyInAnyOrder("TYPE_A_c1", "TYPE_B_c1", "TYPE_C_c1"); names = session.run(query, Collections.singletonMap("name", "c1")).list(withMapper); assertThat(names).containsExactlyInAnyOrder("TYPE_A_p"); } } interface MultipleRelationshipsThingRepository extends ReactiveCrudRepository<MultipleRelationshipsThing, Long> { } @Configuration @EnableTransactionManagement @EnableReactiveNeo4jRepositories(considerNestedRepositories = true) static class Config extends AbstractReactiveNeo4jConfig { @Bean public Driver driver() { return neo4jConnectionSupport.getDriver(); } } }