diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index e4e722b003..0b976f1052 100755 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -1,2 +1,2 @@ -#Mon Oct 11 14:30:21 CEST 2021 -distributionUrl=https\://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.3/apache-maven-3.8.3-bin.zip +#Fri Jun 03 09:39:34 CEST 2022 +distributionUrl=https\://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.5/apache-maven-3.8.5-bin.zip diff --git a/Jenkinsfile b/Jenkinsfile index e61f867b60..a300b41c43 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,9 +1,15 @@ +def p = [:] +node { + checkout scm + p = readProperties interpolate: true, file: 'ci/pipeline.properties' +} + pipeline { agent none triggers { pollSCM 'H/10 * * * *' - upstream(upstreamProjects: "spring-data-commons/main", threshold: hudson.model.Result.SUCCESS) + upstream(upstreamProjects: "spring-data-commons/2.7.x", threshold: hudson.model.Result.SUCCESS) } options { @@ -12,27 +18,28 @@ pipeline { } stages { - stage("test: baseline (jdk8)") { + stage("test: baseline (main)") { when { + beforeAgent(true) anyOf { - branch 'main' + branch(pattern: "main|(\\d\\.\\d\\.x)", comparator: "REGEXP") not { triggeredBy 'UpstreamCause' } } } agent { label 'data' } - options { timeout(time: 30, unit: 'MINUTES') } + options { timeout(time: 60, unit: 'MINUTES') } environment { - DOCKER_HUB = credentials('hub.docker.com-springbuildmaster') - ARTIFACTORY = credentials('02bd1690-b54f-4c9f-819d-a77cb7a9822c') + DOCKER_HUB = credentials("${p['docker.credentials']}") + ARTIFACTORY = credentials("${p['artifactory.credentials']}") } steps { script { - docker.withRegistry('', 'hub.docker.com-springbuildmaster') { - docker.image('adoptopenjdk/openjdk8:latest').inside('-u root -v /var/run/docker.sock:/var/run/docker.sock -v /usr/bin/docker:/usr/bin/docker -v $HOME:/tmp/jenkins-home') { + docker.withRegistry(p['docker.registry'], p['docker.credentials']) { + docker.image(p['docker.java.main.image']).inside(p['docker.java.inside.docker']) { sh "docker login --username ${DOCKER_HUB_USR} --password ${DOCKER_HUB_PSW}" sh "PROFILE=none ci/test.sh" sh "ci/clean.sh" @@ -44,29 +51,30 @@ pipeline { stage("Test other configurations") { when { + beforeAgent(true) allOf { - branch 'main' + branch(pattern: "main|(\\d\\.\\d\\.x)", comparator: "REGEXP") not { triggeredBy 'UpstreamCause' } } } parallel { - stage("test: baseline (jdk11)") { + stage("test: baseline (next)") { agent { label 'data' } - options { timeout(time: 30, unit: 'MINUTES') } + options { timeout(time: 60, unit: 'MINUTES') } environment { - DOCKER_HUB = credentials('hub.docker.com-springbuildmaster') - ARTIFACTORY = credentials('02bd1690-b54f-4c9f-819d-a77cb7a9822c') + DOCKER_HUB = credentials("${p['docker.credentials']}") + ARTIFACTORY = credentials("${p['artifactory.credentials']}") } steps { script { - docker.withRegistry('', 'hub.docker.com-springbuildmaster') { - docker.image('adoptopenjdk/openjdk11:latest').inside('-u root -v /var/run/docker.sock:/var/run/docker.sock -v /usr/bin/docker:/usr/bin/docker -v $HOME:/tmp/jenkins-home') { + docker.withRegistry(p['docker.registry'], p['docker.credentials']) { + docker.image(p['docker.java.next.image']).inside(p['docker.java.inside.docker']) { sh "docker login --username ${DOCKER_HUB_USR} --password ${DOCKER_HUB_PSW}" - sh "PROFILE=java11 ci/test.sh" + sh "PROFILE=none ci/test.sh" sh "ci/clean.sh" } } @@ -74,23 +82,23 @@ pipeline { } } - stage("test: baseline (jdk16)") { + stage("test: baseline (LTS)") { agent { label 'data' } - options { timeout(time: 30, unit: 'MINUTES') } + options { timeout(time: 60, unit: 'MINUTES') } environment { - DOCKER_HUB = credentials('hub.docker.com-springbuildmaster') - ARTIFACTORY = credentials('02bd1690-b54f-4c9f-819d-a77cb7a9822c') + DOCKER_HUB = credentials("${p['docker.credentials']}") + ARTIFACTORY = credentials("${p['artifactory.credentials']}") } steps { script { - docker.withRegistry('', 'hub.docker.com-springbuildmaster') { - docker.image('adoptopenjdk/openjdk16:latest').inside('-u root -v /var/run/docker.sock:/var/run/docker.sock -v /usr/bin/docker:/usr/bin/docker -v $HOME:/tmp/jenkins-home') { + docker.withRegistry(p['docker.registry'], p['docker.credentials']) { + docker.image(p['docker.java.lts.image']).inside(p['docker.java.inside.docker']) { sh "docker login --username ${DOCKER_HUB_USR} --password ${DOCKER_HUB_PSW}" - sh "PROFILE=java11 ci/test.sh" + sh "PROFILE=none ci/test.sh" sh "ci/clean.sh" } } @@ -102,8 +110,9 @@ pipeline { stage('Release to artifactory') { when { + beforeAgent(true) anyOf { - branch 'main' + branch(pattern: "main|(\\d\\.\\d\\.x)", comparator: "REGEXP") not { triggeredBy 'UpstreamCause' } } } @@ -113,13 +122,13 @@ pipeline { options { timeout(time: 20, unit: 'MINUTES') } environment { - ARTIFACTORY = credentials('02bd1690-b54f-4c9f-819d-a77cb7a9822c') + ARTIFACTORY = credentials("${p['artifactory.credentials']}") } steps { script { - docker.withRegistry('', 'hub.docker.com-springbuildmaster') { - docker.image('adoptopenjdk/openjdk8:latest').inside('-v $HOME:/tmp/jenkins-home') { + docker.withRegistry(p['docker.registry'], p['docker.credentials']) { + docker.image(p['docker.java.main.image']).inside(p['docker.java.inside.basic']) { sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw -s settings.xml -Pci,artifactory -Dmaven.repo.local=/tmp/jenkins-home/.m2/spring-data-neo4j-non-root ' + '-Dartifactory.server=https://repo.spring.io ' + "-Dartifactory.username=${ARTIFACTORY_USR} " + @@ -136,7 +145,11 @@ pipeline { stage('Publish documentation') { when { - branch 'main' + beforeAgent(true) + anyOf { + branch(pattern: "main|(\\d\\.\\d\\.x)", comparator: "REGEXP") + not { triggeredBy 'UpstreamCause' } + } } agent { label 'data' @@ -144,13 +157,13 @@ pipeline { options { timeout(time: 20, unit: 'MINUTES') } environment { - ARTIFACTORY = credentials('02bd1690-b54f-4c9f-819d-a77cb7a9822c') + ARTIFACTORY = credentials("${p['artifactory.credentials']}") } steps { script { - docker.withRegistry('', 'hub.docker.com-springbuildmaster') { - docker.image('adoptopenjdk/openjdk8:latest').inside('-v $HOME:/tmp/jenkins-home') { + docker.withRegistry(p['docker.registry'], p['docker.credentials']) { + docker.image(p['docker.java.main.image']).inside(p['docker.java.inside.basic']) { sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw -s settings.xml -Pci,distribute -Dmaven.repo.local=/tmp/jenkins-home/.m2/spring-data-neo4j-non-root ' + '-Dartifactory.server=https://repo.spring.io ' + "-Dartifactory.username=${ARTIFACTORY_USR} " + diff --git a/README.adoc b/README.adoc index 305bcd8030..3dd4d69553 100644 --- a/README.adoc +++ b/README.adoc @@ -10,8 +10,8 @@ image:https://spring.io/badges/spring-data-neo4j/ga.svg[Spring Data Neo4j,link=h :artifactIdStarter: spring-boot-starter-data-neo4j :neo4j-version: 4.1.5 -:spring-boot-version: 2.5.3 -:spring-data-neo4j-version: 6.1.3 +:spring-boot-version: 2.6.3 +:spring-data-neo4j-version: 6.2.1 // end::properties[] [abstract] diff --git a/ci/pipeline.properties b/ci/pipeline.properties new file mode 100644 index 0000000000..773ada37f0 --- /dev/null +++ b/ci/pipeline.properties @@ -0,0 +1,29 @@ +# Java versions +java.main.tag=8u352-b08-jdk-focal +java.next.tag=11.0.17_8-jdk-focal +java.lts.tag=17.0.5_8-jdk-focal + +# Docker container images - standard +docker.java.main.image=harbor-repo.vmware.com/dockerhub-proxy-cache/library/eclipse-temurin:${java.main.tag} +docker.java.next.image=harbor-repo.vmware.com/dockerhub-proxy-cache/library/eclipse-temurin:${java.next.tag} +docker.java.lts.image=harbor-repo.vmware.com/dockerhub-proxy-cache/library/eclipse-temurin:${java.lts.tag} + +# Supported versions of MongoDB +docker.mongodb.4.0.version=4.0.28 +docker.mongodb.4.4.version=4.4.17 +docker.mongodb.5.0.version=5.0.13 + +# Supported versions of Redis +docker.redis.6.version=6.2.6 + +# Supported versions of Cassandra +docker.cassandra.3.version=3.11.14 + +# Docker environment settings +docker.java.inside.basic=-v $HOME:/tmp/jenkins-home +docker.java.inside.docker=-u root -v /var/run/docker.sock:/var/run/docker.sock -v /usr/bin/docker:/usr/bin/docker -v $HOME:/tmp/jenkins-home + +# Credentials +docker.registry= +docker.credentials=hub.docker.com-springbuildmaster +artifactory.credentials=02bd1690-b54f-4c9f-819d-a77cb7a9822c diff --git a/etc/adr/general-discussion.adoc b/etc/adr/general-discussion.adoc index 102accb5c4..7bab300e07 100644 --- a/etc/adr/general-discussion.adoc +++ b/etc/adr/general-discussion.adoc @@ -318,7 +318,7 @@ Thus we stay consistent with all other Spring Boot starters, that are actually p ==== Responsibilities -The starter and it's automatic configuration is responsible for configuring Spring Data Neo4j repositories and infrastructure. +The starter and its automatic configuration is responsible for configuring Spring Data Neo4j repositories and infrastructure. It needs a configured Neo4j Java Driver and therefor is itself dependent on `org.neo4j.driver:neo4j-java-driver-spring-boot-starter`, the official starter for the Neo4j Java Driver. diff --git a/pom.xml b/pom.xml index 4bdd4b9552..f5e4d22283 100644 --- a/pom.xml +++ b/pom.xml @@ -1,6 +1,6 @@ (:Person))" + .run("" + "MATCH (t:" + labelOfTestSubject + ")-[r]->(:Person) WHERE id(t) = $id " + "RETURN count(r)" + " as numberOfRelations", Values.parameters("id", newPerson.getId())) .single().get("numberOfRelations").asLong(); assertThat(numberOfRelations).isEqualTo(2L); numberOfRelations = transaction - .run("" + "MATCH (t:" + labelOfTestSubject + ") WHERE id(t) = $id " + "RETURN size((t)-->(:Club))" + .run("" + "MATCH (t:" + labelOfTestSubject + ")-[r]->(:Club) WHERE id(t) = $id " + "RETURN count(r)" + " as numberOfRelations", Values.parameters("id", newPerson.getId())) .single().get("numberOfRelations").asLong(); assertThat(numberOfRelations).isEqualTo(2L); @@ -262,14 +274,14 @@ void shouldWriteDynamicCollectionRelationships(@Autowired PersonWithRelativesRep pets = newPerson.getPets(); assertThat(pets).containsOnlyKeys(TypeOfPet.MONSTERS, TypeOfPet.FISH); - try (Transaction transaction = driver.session().beginTransaction()) { + try (Transaction transaction = driver.session(bookmarkCapture.createSessionConfig()).beginTransaction()) { long numberOfRelations = transaction - .run("" + "MATCH (t:" + labelOfTestSubject + ") WHERE id(t) = $id " + "RETURN size((t)-->(:Pet))" + .run("" + "MATCH (t:" + labelOfTestSubject + ")-[r]->(:Pet) WHERE id(t) = $id RETURN count(r)" + " as numberOfRelations", Values.parameters("id", newPerson.getId())) .single().get("numberOfRelations").asLong(); assertThat(numberOfRelations).isEqualTo(3L); numberOfRelations = transaction - .run("" + "MATCH (t:" + labelOfTestSubject + ") WHERE id(t) = $id " + "RETURN size((t)-->(:Hobby))" + .run("" + "MATCH (t:" + labelOfTestSubject + ")-[r]->(:Hobby) WHERE id(t) = $id RETURN count(r)" + " as numberOfRelations", Values.parameters("id", newPerson.getId())) .single().get("numberOfRelations").asLong(); assertThat(numberOfRelations).isEqualTo(2L); @@ -321,7 +333,7 @@ interface PersonWithRelativesRepository extends CrudRepository {} @Configuration @EnableNeo4jRepositories(considerNestedRepositories = true) @EnableTransactionManagement - static class Config extends AbstractNeo4jConfig { + static class Config extends Neo4jImperativeTestConfiguration { @Override protected Collection getMappingBasePackages() { @@ -521,5 +521,10 @@ public PlatformTransactionManager transactionManager(Driver driver, DatabaseSele public TransactionTemplate transactionTemplate(PlatformTransactionManager transactionManager) { return new TransactionTemplate(transactionManager); } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } } } diff --git a/src/test/java/org/springframework/data/neo4j/integration/imperative/Neo4jClientIT.java b/src/test/java/org/springframework/data/neo4j/integration/imperative/Neo4jClientIT.java index 3165922df8..fa12f59aa3 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/imperative/Neo4jClientIT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/imperative/Neo4jClientIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -34,7 +34,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.neo4j.config.AbstractNeo4jConfig; +import org.springframework.data.neo4j.test.Neo4jImperativeTestConfiguration; import org.springframework.data.neo4j.core.DatabaseSelectionProvider; import org.springframework.data.neo4j.core.Neo4jClient; import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager; @@ -97,7 +97,7 @@ void clientShouldIntegrateWithCypherDSL(@Autowired TransactionTemplate transacti @Configuration @EnableTransactionManagement - static class Config extends AbstractNeo4jConfig { + static class Config extends Neo4jImperativeTestConfiguration { @Bean @Override @@ -128,5 +128,10 @@ public PlatformTransactionManager transactionManager(Driver driver, public TransactionTemplate transactionTemplate(PlatformTransactionManager transactionManager) { return new TransactionTemplate(transactionManager); } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } } } diff --git a/src/test/java/org/springframework/data/neo4j/integration/imperative/Neo4jTemplateIT.java b/src/test/java/org/springframework/data/neo4j/integration/imperative/Neo4jTemplateIT.java index f7bf16de35..ff98c37720 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/imperative/Neo4jTemplateIT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/imperative/Neo4jTemplateIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -17,9 +17,11 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import lombok.Data; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -48,7 +50,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.dao.IncorrectResultSizeDataAccessException; import org.springframework.data.mapping.PropertyPath; -import org.springframework.data.neo4j.config.AbstractNeo4jConfig; +import org.springframework.data.neo4j.test.Neo4jImperativeTestConfiguration; import org.springframework.data.neo4j.core.DatabaseSelectionProvider; import org.springframework.data.neo4j.core.Neo4jTemplate; import org.springframework.data.neo4j.core.mapping.Constants; @@ -60,6 +62,7 @@ import org.springframework.data.neo4j.integration.issues.gh2415.BaseNodeEntity; import org.springframework.data.neo4j.integration.issues.gh2415.NodeEntity; import org.springframework.data.neo4j.integration.issues.gh2415.NodeWithDefinedCredentials; +import org.springframework.data.neo4j.integration.shared.common.EntityWithPrimitiveConstructorArguments; import org.springframework.data.neo4j.integration.shared.common.Person; import org.springframework.data.neo4j.integration.shared.common.PersonWithAllConstructor; import org.springframework.data.neo4j.integration.shared.common.PersonWithAssignedId; @@ -75,6 +78,7 @@ * @author Gerrit Meier * @author Michael J. Simons * @author Rosetta Roberts + * @author Corey Beres */ @Neo4jIntegrationTest class Neo4jTemplateIT { @@ -113,7 +117,7 @@ void setupData() { transaction.run("CREATE (p:Person{firstName: 'A', lastName: 'LA'})"); transaction.run("CREATE (p:Person{firstName: 'Michael', lastName: 'Siemons'})" + - " -[:LIVES_AT]-> (a:Address {city: 'Aachen'})" + + " -[:LIVES_AT]-> (a:Address {city: 'Aachen', id: 1})" + " -[:BASED_IN]->(c:YetAnotherCountryEntity{name: 'Gemany', countryCode: 'DE'})" + " RETURN id(p)"); transaction.run( @@ -404,6 +408,15 @@ void saveProjectionShouldWork() { assertThat(person.getAddress()).isNotNull(); } + @Test // GH-2505 + void savePrimitivesShouldWork() { + EntityWithPrimitiveConstructorArguments entity = new EntityWithPrimitiveConstructorArguments(true, 42); + EntityWithPrimitiveConstructorArguments savedEntity = neo4jTemplate.save(EntityWithPrimitiveConstructorArguments.class).one(entity); + + assertThat(savedEntity.someIntValue).isEqualTo(entity.someIntValue); + assertThat(savedEntity.someBooleanValue).isEqualTo(entity.someBooleanValue); + } + @Test // GH-2215 void saveAllProjectionShouldWork() { @@ -785,6 +798,30 @@ void saveAllAsWithClosedProjectionShouldWork() { assertThat(people).allMatch(p -> p.getAddress() != null); } + @Test // GH-2544 + void saveAllAsWithEmptyList() { + List projections = neo4jTemplate.saveAllAs(Collections.emptyList(), ClosedProjection.class); + + assertThat(projections).isEmpty(); + } + + static class X { + } + + static class Y { + } + + @Test // GH-2544 + void saveWeirdHierarchy() { + + List things = new ArrayList<>(); + things.add(new X()); + things.add(new Y()); + + assertThatIllegalArgumentException().isThrownBy(() -> neo4jTemplate.saveAllAs(things, ClosedProjection.class)) + .withMessage("Could not determine a common element of an heterogeneous collection."); + } + @Test void updatingFindShouldWork() { Map params = new HashMap<>(); @@ -903,7 +940,7 @@ void saveWithProjectionImplementedByEntity(@Autowired Neo4jMappingContext mappin @Configuration @EnableTransactionManagement - static class Config extends AbstractNeo4jConfig { + static class Config extends Neo4jImperativeTestConfiguration { @Bean @Override @@ -927,5 +964,10 @@ public PlatformTransactionManager transactionManager(Driver driver, DatabaseSele BookmarkCapture bookmarkCapture = bookmarkCapture(); return new Neo4jTransactionManager(driver, databaseNameProvider, Neo4jBookmarkManager.create(bookmarkCapture)); } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } } } diff --git a/src/test/java/org/springframework/data/neo4j/integration/imperative/Neo4jTransactionManagerTestIT.java b/src/test/java/org/springframework/data/neo4j/integration/imperative/Neo4jTransactionManagerTestIT.java index fc668774a7..5cbd23c82f 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/imperative/Neo4jTransactionManagerTestIT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/imperative/Neo4jTransactionManagerTestIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -26,7 +26,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.dao.InvalidDataAccessResourceUsageException; -import org.springframework.data.neo4j.config.AbstractNeo4jConfig; +import org.springframework.data.neo4j.test.Neo4jImperativeTestConfiguration; import org.springframework.data.neo4j.core.DatabaseSelectionProvider; import org.springframework.data.neo4j.core.Neo4jClient; import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager; @@ -91,7 +91,7 @@ interface SomeRepository extends Neo4jRepository { @Configuration @EnableTransactionManagement @EnableNeo4jRepositories(considerNestedRepositories = true) - static class Config extends AbstractNeo4jConfig { + static class Config extends Neo4jImperativeTestConfiguration { @Bean public Driver driver() { @@ -115,5 +115,10 @@ public PlatformTransactionManager transactionManager(Driver driver, DatabaseSele BookmarkCapture bookmarkCapture = bookmarkCapture(); return new Neo4jTransactionManager(driver, databaseNameProvider, Neo4jBookmarkManager.create(bookmarkCapture)); } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } } } diff --git a/src/test/java/org/springframework/data/neo4j/integration/imperative/OptimisticLockingIT.java b/src/test/java/org/springframework/data/neo4j/integration/imperative/OptimisticLockingIT.java index 87ebb4f851..67f902740f 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/imperative/OptimisticLockingIT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/imperative/OptimisticLockingIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -41,7 +41,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.dao.OptimisticLockingFailureException; -import org.springframework.data.neo4j.config.AbstractNeo4jConfig; +import org.springframework.data.neo4j.test.Neo4jImperativeTestConfiguration; import org.springframework.data.neo4j.core.DatabaseSelectionProvider; import org.springframework.data.neo4j.core.Neo4jTemplate; import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager; @@ -426,7 +426,7 @@ interface VersionedThingWithAssignedIdRepository extends Neo4jRepository(department:DepartmentEntity {id: 'd1', name: 'Dep1'}) RETURN p"); + transaction.run("CREATE (p:PersonWithNoConstructor {name: 'meistermeier', first_name: 'Gerrit', mittlererName: 'unknown'}) RETURN p"); for (Map.Entry person : new Map.Entry[] { new AbstractMap.SimpleEntry(FIRST_NAME, LAST_NAME), @@ -133,6 +144,9 @@ void setup() { projectionTestRootId = result.get(0).asLong(); projectionTestLevel1Id = result.get(1).asLong(); projectionTest1O1Id = result.get(2).asLong(); + + transaction.run("create (w:Widget {code: 'Window1', label: 'yyy'})").consume(); + transaction.commit(); bookmarkCapture.seedWith(session.lastBookmark()); } @@ -365,6 +379,86 @@ void projectionsContainingKnownEntitiesShouldWorkFromTemplate(@Autowired Neo4jTe .satisfies(ProjectionIT::projectedEntities); } + @Test // GH-2451 + void compositePropertiesShouldBeIncludedInProjections(@Autowired WidgetRepository repository, + @Autowired Neo4jTemplate template) { + + String code = "Window1"; + WidgetEntity window = repository.findByCode(code).get(); + window.setLabel("changed"); + window.getAdditionalFields().put("key1", "value1"); + + template.saveAs(window, WidgetProjection.class); + + window = repository.findByCode(code).get(); + assertThat(window.getLabel()).isEqualTo("changed"); + assertThat(window.getAdditionalFields()).containsEntry("key1", "value1"); + } + + @Test // GH-2371 + void findWithCustomPropertyNameWorks(@Autowired PersonWithNoConstructorRepository repository) { + + assertThat(repository.findAll()).hasSize(1); + + ProjectedPersonWithNoConstructor person = repository.findByName("meistermeier"); + assertThat(person.getFirstName()).isEqualTo("Gerrit"); + assertThat(person.getMittlererName()).isEqualTo("unknown"); + } + + @Test // GH-2371 + void saveWithCustomPropertyNameWorks(@Autowired Neo4jTemplate neo4jTemplate) { + PersonWithNoConstructor person = neo4jTemplate.findOne("MATCH (p:PersonWithNoConstructor {name: 'meistermeier'}) RETURN p", Collections.emptyMap(), + PersonWithNoConstructor.class).get(); + + person.setName("rotnroll666"); + person.setFirstName("Michael"); + person.setMiddleName("foo"); + + neo4jTemplate.saveAs(person, ProjectedPersonWithNoConstructor.class); + + try (Session session = driver.session(bookmarkCapture.createSessionConfig())) { + Record record = session + .run("MATCH (p:PersonWithNoConstructor {name: 'rotnroll666'}) RETURN p") + .single(); + + MapAccessor p = record.get("p").asNode(); + assertThat(p.get("first_name").asString()).isEqualTo("Michael"); + assertThat(p.get("mittlererName").asString()).isEqualTo("foo"); + } + } + + @Test // GH-2578 + public void projectionRespectedWithInexactPropertyNameMatch(@Autowired Neo4jOperations neo4jOperations) { + final DoritoEatingPerson person = new DoritoEatingPerson("Bob"); + person.setEatsDoritos(true); + person.setFriendsAlsoEatDoritos(true); + Set friends = new HashSet<>(); + friends.add(new DoritoEatingPerson("Alice")); + friends.add(new DoritoEatingPerson("Zoey")); + person.setFriends(friends); + + neo4jOperations.saveAs(person, DoritoEatingPerson.PropertiesProjection1.class); + + final Optional saved = neo4jOperations.findById(person.getId(), DoritoEatingPerson.class); + assertThat(saved).hasValueSatisfying(it -> assertThat(it.getFriends()).isEmpty()); + } + + @Test // GH-2578 + public void projectionRespected(@Autowired Neo4jOperations neo4jOperations) { + final DoritoEatingPerson person = new DoritoEatingPerson("Ben"); + person.setEatsDoritos(true); + person.setFriendsAlsoEatDoritos(true); + Set friends = new HashSet<>(); + friends.add(new DoritoEatingPerson("Kid")); + friends.add(new DoritoEatingPerson("Jeremias")); + person.setFriends(friends); + + neo4jOperations.saveAs(person, DoritoEatingPerson.PropertiesProjection2.class); + + final Optional saved = neo4jOperations.findById(person.getId(), DoritoEatingPerson.class); + assertThat(saved).hasValueSatisfying(it -> assertThat(it.getFriends()).isEmpty()); + } + private static void projectedEntities(PersonDepartmentQueryResult personAndDepartment) { assertThat(personAndDepartment.getPerson()).extracting(PersonEntity::getId).isEqualTo("p1"); assertThat(personAndDepartment.getPerson()).extracting(PersonEntity::getEmail).isEqualTo("p1@dep1.org"); @@ -382,6 +476,20 @@ private static Statement whoHasFirstName(String firstName) { .build(); } + interface ProjectedPersonWithNoConstructor { + + String getName(); + + String getFirstName(); + + String getMittlererName(); + } + + interface PersonWithNoConstructorRepository extends Neo4jRepository { + + ProjectedPersonWithNoConstructor findByName(String name); + } + interface ProjectionPersonRepository extends Neo4jRepository, CypherdslStatementExecutor { Collection findByLastName(String lastName); @@ -479,9 +587,9 @@ interface PersonRepository extends Neo4jRepository { } @Configuration - @EnableNeo4jRepositories(considerNestedRepositories = true) + @EnableNeo4jRepositories(considerNestedRepositories = true, basePackageClasses = {ProjectionIT.class, WidgetEntity.class}) @EnableTransactionManagement - static class Config extends AbstractNeo4jConfig { + static class Config extends Neo4jImperativeTestConfiguration { @Bean public Driver driver() { @@ -495,7 +603,11 @@ public BookmarkCapture bookmarkCapture() { @Override protected Collection getMappingBasePackages() { - return Collections.singletonList(DepartmentEntity.class.getPackage().getName()); + + List packages = new ArrayList<>(); + packages.add(DepartmentEntity.class.getPackage().getName()); + packages.add(WidgetEntity.class.getPackage().getName()); + return packages; } @Override @@ -504,5 +616,10 @@ public PlatformTransactionManager transactionManager(Driver driver, DatabaseSele BookmarkCapture bookmarkCapture = bookmarkCapture(); return new Neo4jTransactionManager(driver, databaseNameProvider, Neo4jBookmarkManager.create(bookmarkCapture)); } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } } } diff --git a/src/test/java/org/springframework/data/neo4j/integration/imperative/QuerydslNeo4jPredicateExecutorIT.java b/src/test/java/org/springframework/data/neo4j/integration/imperative/QuerydslNeo4jPredicateExecutorIT.java index fef617eb81..7574392497 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/imperative/QuerydslNeo4jPredicateExecutorIT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/imperative/QuerydslNeo4jPredicateExecutorIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -31,7 +31,7 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; -import org.springframework.data.neo4j.config.AbstractNeo4jConfig; +import org.springframework.data.neo4j.test.Neo4jImperativeTestConfiguration; import org.springframework.data.neo4j.core.DatabaseSelectionProvider; import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager; import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager; @@ -329,7 +329,7 @@ interface QueryDSLPersonRepository extends @Configuration @EnableTransactionManagement @EnableNeo4jRepositories(considerNestedRepositories = true) - static class Config extends AbstractNeo4jConfig { + static class Config extends Neo4jImperativeTestConfiguration { @Bean public Driver driver() { @@ -348,5 +348,10 @@ public PlatformTransactionManager transactionManager(Driver driver, DatabaseSele BookmarkCapture bookmarkCapture = bookmarkCapture(); return new Neo4jTransactionManager(driver, databaseNameProvider, Neo4jBookmarkManager.create(bookmarkCapture)); } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } } } diff --git a/src/test/java/org/springframework/data/neo4j/integration/imperative/RelationshipsAsConstructorParametersIT.java b/src/test/java/org/springframework/data/neo4j/integration/imperative/RelationshipsAsConstructorParametersIT.java index 22c18ee6b0..027b980d67 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/imperative/RelationshipsAsConstructorParametersIT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/imperative/RelationshipsAsConstructorParametersIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -27,7 +27,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.neo4j.config.AbstractNeo4jConfig; +import org.springframework.data.neo4j.test.Neo4jImperativeTestConfiguration; import org.springframework.data.neo4j.core.DatabaseSelectionProvider; import org.springframework.data.neo4j.core.Neo4jTemplate; import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager; @@ -86,7 +86,7 @@ void shouldCreateMasterDetailRelationshipViaConstructor(@Autowired Neo4jTemplate @Configuration @EnableTransactionManagement - static class Config extends AbstractNeo4jConfig { + static class Config extends Neo4jImperativeTestConfiguration { @Bean public Driver driver() { @@ -105,5 +105,9 @@ public PlatformTransactionManager transactionManager(Driver driver, DatabaseSele return new Neo4jTransactionManager(driver, databaseNameProvider, Neo4jBookmarkManager.create(bookmarkCapture)); } + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } } } diff --git a/src/test/java/org/springframework/data/neo4j/integration/imperative/RelationshipsIT.java b/src/test/java/org/springframework/data/neo4j/integration/imperative/RelationshipsIT.java index 8a4447a8a9..abaddf0329 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/imperative/RelationshipsIT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/imperative/RelationshipsIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -30,7 +30,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.neo4j.config.AbstractNeo4jConfig; +import org.springframework.data.neo4j.test.Neo4jImperativeTestConfiguration; import org.springframework.data.neo4j.core.DatabaseSelectionProvider; import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager; import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager; @@ -268,7 +268,7 @@ interface Multiple1O1RelationshipsRepository extends CrudRepository + session + .run("CREATE (:Pet{name: 'Pet2'})-[:Has]->(p1:Pet{name: 'Pet1'})-[:Has]->(p1) RETURN p1") + .consume()); + + List allPets = repository.findAllFriends(); + for (Pet pet : allPets) { + // everybody has a friend + assertThat(pet.getFriends()).hasSize(1); + // but only Pet1 is its own best friend + if (pet.getName().equals("Pet1")) { + assertThat(pet.getFriends().get(0)).isEqualTo(pet); + } + } + } } @Nested @@ -1648,6 +1666,26 @@ void findAndMapMultipleLevelRelationshipProperties( assertThat(entity.getRelationshipA().getEntityA().getRelationshipB().getEntityB()).isNotNull(); } + @Test + void updateAndCreateRelationshipProperties(@Autowired HobbyWithRelationshipWithPropertiesRepository repository) { + + long hobbyId = doWithSession( + session -> session.run("CREATE (n:AltPerson{name:'Freddie'}), (n)-[l1:LIKES {rating: 5}]->(h1:AltHobby{name:'Music'}) RETURN n, h1").single().get("h1").asNode().id()); + + AltHobby hobby = repository.findById(hobbyId).get(); + assertThat(hobby.getName()).isEqualTo("Music"); + assertThat(hobby.getLikedBy()).hasSize(1); + + AltLikedByPersonRelationship liked = new AltLikedByPersonRelationship(); + liked.setAltPerson(new AltPerson("SomethingElse")); + hobby.getLikedBy().add(liked); + + repository.save(hobby); + + AltHobby savedHobby = repository.findById(hobbyId).get(); + assertThat(savedHobby.getLikedBy()).hasSize(2); + + } } @Nested @@ -4273,6 +4311,11 @@ interface PetRepository extends Neo4jRepository { @Query("MATCH (n:Pet) where n.name='Luna' OPTIONAL MATCH (n)-[r:Has]->(m:Pet) return n, collect(r), collect(m)") List findLunas(); + + @Query("MATCH (p:Pet)" + + " OPTIONAL MATCH (p)-[rel:Has]->(op)" + + " RETURN p, collect(rel), collect(op)") + List findAllFriends(); } interface ImmutablePetRepository extends Neo4jRepository { @@ -4533,7 +4576,7 @@ void assertWithSession(Consumer consumer) { @Configuration @EnableNeo4jRepositories(considerNestedRepositories = true) @EnableTransactionManagement - static class Config extends AbstractNeo4jConfig { + static class Config extends Neo4jImperativeTestConfiguration { @Bean public Driver driver() { @@ -4596,5 +4639,10 @@ public DatabaseSelectionProvider databaseSelectionProvider() { public UserSelectionProvider getUserSelectionProvider() { return () -> userSelection.get(); } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } } } diff --git a/src/test/java/org/springframework/data/neo4j/integration/imperative/RepositoryWithADifferentDatabaseIT.java b/src/test/java/org/springframework/data/neo4j/integration/imperative/RepositoryWithADifferentDatabaseIT.java index c11fb5c439..05e37eb60a 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/imperative/RepositoryWithADifferentDatabaseIT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/imperative/RepositoryWithADifferentDatabaseIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/imperative/RepositoryWithADifferentUserIT.java b/src/test/java/org/springframework/data/neo4j/integration/imperative/RepositoryWithADifferentUserIT.java index 6ee6e91eee..952f23e590 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/imperative/RepositoryWithADifferentUserIT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/imperative/RepositoryWithADifferentUserIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/imperative/StringlyTypedDynamicRelationshipsIT.java b/src/test/java/org/springframework/data/neo4j/integration/imperative/StringlyTypedDynamicRelationshipsIT.java index 4dedefdedb..9917059dde 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/imperative/StringlyTypedDynamicRelationshipsIT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/imperative/StringlyTypedDynamicRelationshipsIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -30,7 +30,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.neo4j.config.AbstractNeo4jConfig; +import org.springframework.data.neo4j.test.Neo4jImperativeTestConfiguration; import org.springframework.data.neo4j.core.DatabaseSelectionProvider; import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager; import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager; @@ -211,12 +211,12 @@ void shouldWriteDynamicRelationships(@Autowired PersonWithRelativesRepository re try (Transaction transaction = driver.session(bookmarkCapture.createSessionConfig()).beginTransaction()) { long numberOfRelations = transaction - .run("" + "MATCH (t:" + labelOfTestSubject + ") WHERE id(t) = $id " + "RETURN size((t)-->(:Person))" + .run("" + "MATCH (t:" + labelOfTestSubject + ")-[r]->(:Person) WHERE id(t) = $id " + "RETURN count(r)" + " as numberOfRelations", Values.parameters("id", newPerson.getId())) .single().get("numberOfRelations").asLong(); assertThat(numberOfRelations).isEqualTo(2L); numberOfRelations = transaction - .run("" + "MATCH (t:" + labelOfTestSubject + ") WHERE id(t) = $id " + "RETURN size((t)-->(:Club))" + .run("" + "MATCH (t:" + labelOfTestSubject + ")-[r]->(:Club) WHERE id(t) = $id " + "RETURN count(r)" + " as numberOfRelations", Values.parameters("id", newPerson.getId())) .single().get("numberOfRelations").asLong(); assertThat(numberOfRelations).isEqualTo(2L); @@ -257,12 +257,12 @@ void shouldWriteDynamicCollectionRelationships(@Autowired PersonWithRelativesRep try (Transaction transaction = driver.session(bookmarkCapture.createSessionConfig()).beginTransaction()) { long numberOfRelations = transaction - .run("" + "MATCH (t:" + labelOfTestSubject + ") WHERE id(t) = $id " + "RETURN size((t)-->(:Pet))" + .run("" + "MATCH (t:" + labelOfTestSubject + ")-[r]->(:Pet) WHERE id(t) = $id RETURN count(r)" + " as numberOfRelations", Values.parameters("id", newPerson.getId())) .single().get("numberOfRelations").asLong(); assertThat(numberOfRelations).isEqualTo(3L); numberOfRelations = transaction - .run("" + "MATCH (t:" + labelOfTestSubject + ") WHERE id(t) = $id " + "RETURN size((t)-->(:Hobby))" + .run("" + "MATCH (t:" + labelOfTestSubject + ")-[r]->(:Hobby) WHERE id(t) = $id RETURN count(r)" + " as numberOfRelations", Values.parameters("id", newPerson.getId())) .single().get("numberOfRelations").asLong(); assertThat(numberOfRelations).isEqualTo(2L); @@ -313,7 +313,7 @@ interface PersonWithRelativesRepository extends CrudRepository id(m) " - + "RETURN [{n: n, otherPeople: collect(m), someLongValue: 4711, someDoubles: [21.42, 42.21]}]") + + "WITH n MATCH(m:PersonWithAllConstructor) WHERE id(n) <> id(m)" + + " WITH n, collect(m) as ms " + + "RETURN [{n: n, otherPeople: ms, someLongValue: 4711, someDoubles: [21.42, 42.21]}]") CustomAggregationOfDto findAllDtoProjectionsWithAdditionalPropertiesAsCustomAggregation(@Param("name") String name); @Query("MATCH (n:PersonWithAllConstructor) where n.name = $name return n{.name}") diff --git a/src/test/java/org/springframework/data/neo4j/integration/imperative/repositories/PersonWithNoConstructorRepository.java b/src/test/java/org/springframework/data/neo4j/integration/imperative/repositories/PersonWithNoConstructorRepository.java index 1ab5ad170d..cd22acb9b3 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/imperative/repositories/PersonWithNoConstructorRepository.java +++ b/src/test/java/org/springframework/data/neo4j/integration/imperative/repositories/PersonWithNoConstructorRepository.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/imperative/repositories/PersonWithWitherRepository.java b/src/test/java/org/springframework/data/neo4j/integration/imperative/repositories/PersonWithWitherRepository.java index a5cbd48121..8ea82e9338 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/imperative/repositories/PersonWithWitherRepository.java +++ b/src/test/java/org/springframework/data/neo4j/integration/imperative/repositories/PersonWithWitherRepository.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/imperative/repositories/ThingRepository.java b/src/test/java/org/springframework/data/neo4j/integration/imperative/repositories/ThingRepository.java index 97a83e2485..5173380b14 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/imperative/repositories/ThingRepository.java +++ b/src/test/java/org/springframework/data/neo4j/integration/imperative/repositories/ThingRepository.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/events/EventsPublisherIT.java b/src/test/java/org/springframework/data/neo4j/integration/issues/events/EventsPublisherIT.java new file mode 100644 index 0000000000..bdb8ff5b80 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/events/EventsPublisherIT.java @@ -0,0 +1,150 @@ +/* + * Copyright 2011-2023 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.events; + +import static org.assertj.core.api.Assertions.assertThat; + +import lombok.Data; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.util.Collection; +import java.util.Collections; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.neo4j.driver.Driver; +import org.neo4j.driver.Session; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.neo4j.core.DatabaseSelectionProvider; +import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager; +import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager; +import org.springframework.data.neo4j.repository.Neo4jRepository; +import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories; +import org.springframework.data.neo4j.test.BookmarkCapture; +import org.springframework.data.neo4j.test.Neo4jExtension; +import org.springframework.data.neo4j.test.Neo4jImperativeTestConfiguration; +import org.springframework.data.neo4j.test.Neo4jIntegrationTest; +import org.springframework.stereotype.Component; +import org.springframework.stereotype.Repository; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.event.TransactionPhase; +import org.springframework.transaction.event.TransactionalEventListener; + +/** + * @author Michael J. Simons + */ +@Neo4jIntegrationTest +class EventsPublisherIT { + + protected static Neo4jExtension.Neo4jConnectionSupport neo4jConnectionSupport; + + @BeforeEach + void setupData(@Autowired Driver driver, @Autowired BookmarkCapture bookmarkCapture) { + + try (Session session = driver.session()) { + session.run("MATCH (n) DETACH DELETE n").consume(); + bookmarkCapture.seedWith(session.lastBookmark()); + } + } + + static AtomicBoolean receivedBeforeCommitEvent = new AtomicBoolean(false); + + static AtomicBoolean receivedAfterCommitEvent = new AtomicBoolean(false); + + @Test // GH-2580 + void beforeAndAfterCommitEventsShouldWork(@Autowired Neo4jObjectService service) { + + service.save("foobar"); + assertThat(receivedBeforeCommitEvent).isTrue(); + assertThat(receivedAfterCommitEvent).isTrue(); + } + + @Slf4j + @Component + @RequiredArgsConstructor + static class Neo4jObjectListener { + + private final Neo4jObjectService service; + + @TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT) + public void onBeforeCommit(Neo4jMessage message) { + Optional optionalNeo4jObject = service.findById(message.getMessageId()); + receivedBeforeCommitEvent.compareAndSet(false, optionalNeo4jObject.isPresent()); + } + + @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT) + @Transactional(propagation = Propagation.REQUIRES_NEW) + public void onAfterCommit(Neo4jMessage message) { + Optional optionalNeo4jObject = service.findById(message.getMessageId()); + receivedAfterCommitEvent.compareAndSet(false, optionalNeo4jObject.isPresent()); + } + } + + @Configuration + @EnableTransactionManagement + @EnableNeo4jRepositories(considerNestedRepositories = true) + @ComponentScan + static class Config extends Neo4jImperativeTestConfiguration { + + @Bean + public BookmarkCapture bookmarkCapture() { + return new BookmarkCapture(); + } + + @Override + public PlatformTransactionManager transactionManager( + Driver driver, DatabaseSelectionProvider databaseNameProvider) { + + BookmarkCapture bookmarkCapture = bookmarkCapture(); + return new Neo4jTransactionManager(driver, databaseNameProvider, + Neo4jBookmarkManager.create(bookmarkCapture)); + } + + @Override + protected Collection getMappingBasePackages() { + return Collections.singleton(Neo4jObject.class.getPackage().getName()); + } + + @Bean + public Driver driver() { + + return neo4jConnectionSupport.getDriver(); + } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } + } + + @Data + static class Neo4jMessage { + private final String messageId; + } + + @Repository + interface Neo4jObjectRepository extends Neo4jRepository { + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/events/Neo4jObject.java b/src/test/java/org/springframework/data/neo4j/integration/issues/events/Neo4jObject.java new file mode 100644 index 0000000000..7367a73704 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/events/Neo4jObject.java @@ -0,0 +1,38 @@ +/* + * Copyright 2011-2023 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.events; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import org.springframework.data.neo4j.core.schema.Id; +import org.springframework.data.neo4j.core.schema.Node; +import org.springframework.data.neo4j.core.schema.Property; + +/** + * @author Michael J. Simons + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Node(primaryLabel = "Neo4jObject") +public class Neo4jObject { + + @Id + @Property(name = "id") + private String id; +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/events/Neo4jObjectService.java b/src/test/java/org/springframework/data/neo4j/integration/issues/events/Neo4jObjectService.java new file mode 100644 index 0000000000..1dc0a5c3d8 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/events/Neo4jObjectService.java @@ -0,0 +1,46 @@ +/* + * Copyright 2011-2023 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.events; + +import lombok.AllArgsConstructor; + +import java.util.Optional; + +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** + * @author Michael J. Simons + */ +@Service +@Transactional +@AllArgsConstructor +public class Neo4jObjectService { + + private final EventsPublisherIT.Neo4jObjectRepository neo4jObjectRepository; + private final ApplicationEventPublisher publisher; + + public Optional findById(String id) { + return neo4jObjectRepository.findById(id); + } + + public Neo4jObject save(String id) { + Neo4jObject saved = neo4jObjectRepository.save(new Neo4jObject(id)); + publisher.publishEvent(new EventsPublisherIT.Neo4jMessage(id)); + return saved; + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2168/DomainObject.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2168/DomainObject.java index c58d2faada..bac0130943 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2168/DomainObject.java +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2168/DomainObject.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2168/GeneratedValueStrategy.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2168/GeneratedValueStrategy.java index bdef810713..f247ee9cd3 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2168/GeneratedValueStrategy.java +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2168/GeneratedValueStrategy.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2168/Gh2168IT.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2168/Gh2168IT.java index f8e8b0aed9..9ca8d282c8 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2168/Gh2168IT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2168/Gh2168IT.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -30,7 +30,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.mapping.PersistentPropertyAccessor; -import org.springframework.data.neo4j.config.AbstractNeo4jConfig; +import org.springframework.data.neo4j.test.Neo4jImperativeTestConfiguration; import org.springframework.data.neo4j.core.DatabaseSelectionProvider; import org.springframework.data.neo4j.core.mapping.Neo4jMappingContext; import org.springframework.data.neo4j.core.mapping.Neo4jPersistentEntity; @@ -161,7 +161,7 @@ interface DomainObjectRepository extends Neo4jRepository { @Configuration @EnableTransactionManagement @EnableNeo4jRepositories(considerNestedRepositories = true) - static class Config extends AbstractNeo4jConfig { + static class Config extends Neo4jImperativeTestConfiguration { @Bean public Driver driver() { @@ -185,5 +185,10 @@ public PlatformTransactionManager transactionManager(Driver driver, DatabaseSele BookmarkCapture bookmarkCapture = bookmarkCapture(); return new Neo4jTransactionManager(driver, databaseNameProvider, Neo4jBookmarkManager.create(bookmarkCapture)); } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } } } diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2168/UnrelatedObject.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2168/UnrelatedObject.java index 373ccff088..29d0095884 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2168/UnrelatedObject.java +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2168/UnrelatedObject.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2168/UnrelatedObjectCompositePropertyConverter.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2168/UnrelatedObjectCompositePropertyConverter.java index 925270dfa2..3028e0763d 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2168/UnrelatedObjectCompositePropertyConverter.java +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2168/UnrelatedObjectCompositePropertyConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2168/UnrelatedObjectPropertyConverter.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2168/UnrelatedObjectPropertyConverter.java index cd68af495b..9be0f6b9c8 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2168/UnrelatedObjectPropertyConverter.java +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2168/UnrelatedObjectPropertyConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2168/UnrelatedObjectPropertyConverterAsBean.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2168/UnrelatedObjectPropertyConverterAsBean.java index fee0b5cbbd..544dafed8a 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2168/UnrelatedObjectPropertyConverterAsBean.java +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2168/UnrelatedObjectPropertyConverterAsBean.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. 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 6f1b2fe3d7..63b2e6fb41 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 @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -23,7 +23,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.neo4j.config.AbstractNeo4jConfig; +import org.springframework.data.neo4j.test.Neo4jImperativeTestConfiguration; import org.springframework.data.neo4j.core.DatabaseSelectionProvider; import org.springframework.data.neo4j.core.Neo4jTemplate; import org.springframework.data.neo4j.core.convert.Neo4jConversions; @@ -243,7 +243,7 @@ public SomeEntity getTargetPerson() { @Configuration @EnableTransactionManagement - static class Config extends AbstractNeo4jConfig { + static class Config extends Neo4jImperativeTestConfiguration { @Bean public Driver driver() { @@ -270,5 +270,10 @@ public PlatformTransactionManager transactionManager(Driver driver, DatabaseSele BookmarkCapture bookmarkCapture = bookmarkCapture(); return new Neo4jTransactionManager(driver, databaseNameProvider, Neo4jBookmarkManager.create(bookmarkCapture)); } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } } } diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2244/GH2244IT.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2244/GH2244IT.java index 33bc9aa700..93e1f43695 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2244/GH2244IT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2244/GH2244IT.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -26,7 +26,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.neo4j.config.AbstractNeo4jConfig; +import org.springframework.data.neo4j.test.Neo4jImperativeTestConfiguration; import org.springframework.data.neo4j.core.Neo4jTemplate; import org.springframework.data.neo4j.core.convert.Neo4jConversions; import org.springframework.data.neo4j.core.mapping.Neo4jMappingContext; @@ -86,7 +86,7 @@ public static class Origin extends Step { @Configuration @EnableTransactionManagement - static class Config extends AbstractNeo4jConfig { + static class Config extends Neo4jImperativeTestConfiguration { @Bean public Driver driver() { @@ -103,5 +103,10 @@ public Neo4jMappingContext neo4jMappingContext(Neo4jConversions neo4JConversions Step.Origin.class))); return ctx; } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } } } diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2289/GH2289IT.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2289/GH2289IT.java index 67a598b1fd..bff60aa40a 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2289/GH2289IT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2289/GH2289IT.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -26,7 +26,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.neo4j.config.AbstractNeo4jConfig; +import org.springframework.data.neo4j.test.Neo4jImperativeTestConfiguration; import org.springframework.data.neo4j.repository.Neo4jRepository; import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories; import org.springframework.data.neo4j.test.BookmarkCapture; @@ -132,7 +132,7 @@ public interface SkuRORepository extends Neo4jRepository { @Configuration @EnableTransactionManagement @EnableNeo4jRepositories(considerNestedRepositories = true) - static class Config extends AbstractNeo4jConfig { + static class Config extends Neo4jImperativeTestConfiguration { @Bean public BookmarkCapture bookmarkCapture() { @@ -144,5 +144,10 @@ public Driver driver() { return neo4jConnectionSupport.getDriver(); } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } } } diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2289/RangeRelation.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2289/RangeRelation.java index 739e574df8..1cde2f24de 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2289/RangeRelation.java +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2289/RangeRelation.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2289/RangeRelationRO.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2289/RangeRelationRO.java index 854380d2ea..a50bab6b7a 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2289/RangeRelationRO.java +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2289/RangeRelationRO.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2289/ReactiveGH2289IT.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2289/ReactiveGH2289IT.java index 42a0ee9caa..1c87d7d1c2 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2289/ReactiveGH2289IT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2289/ReactiveGH2289IT.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -17,6 +17,7 @@ import static org.assertj.core.api.Assertions.assertThat; +import org.springframework.data.neo4j.test.Neo4jReactiveTestConfiguration; import reactor.core.publisher.Mono; import reactor.test.StepVerifier; @@ -33,7 +34,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.neo4j.config.AbstractReactiveNeo4jConfig; import org.springframework.data.neo4j.repository.ReactiveNeo4jRepository; import org.springframework.data.neo4j.repository.config.EnableReactiveNeo4jRepositories; import org.springframework.data.neo4j.test.BookmarkCapture; @@ -181,7 +181,7 @@ public interface SkuRORepository extends ReactiveNeo4jRepository { @Configuration @EnableTransactionManagement @EnableReactiveNeo4jRepositories(considerNestedRepositories = true) - static class Config extends AbstractReactiveNeo4jConfig { + static class Config extends Neo4jReactiveTestConfiguration { @Bean public BookmarkCapture bookmarkCapture() { @@ -193,5 +193,10 @@ public Driver driver() { return neo4jConnectionSupport.getDriver(); } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } } } diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2289/RelationType.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2289/RelationType.java index 7dc0f7b189..463b38e95d 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2289/RelationType.java +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2289/RelationType.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2289/Sku.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2289/Sku.java index bf5c43a83d..e4a380892b 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2289/Sku.java +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2289/Sku.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2289/SkuRO.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2289/SkuRO.java index b127db7d56..df1f88d939 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2289/SkuRO.java +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2289/SkuRO.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2323/GH2323IT.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2323/GH2323IT.java index 26ca38a887..46dd64868c 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2323/GH2323IT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2323/GH2323IT.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -18,10 +18,13 @@ import static org.assertj.core.api.Assertions.assertThat; import java.util.Arrays; +import java.util.Collections; import java.util.List; +import java.util.Optional; import java.util.stream.Collectors; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.neo4j.driver.Driver; import org.neo4j.driver.Session; @@ -30,12 +33,12 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; -import org.springframework.data.neo4j.config.AbstractNeo4jConfig; import org.springframework.data.neo4j.repository.Neo4jRepository; import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories; import org.springframework.data.neo4j.repository.query.Query; import org.springframework.data.neo4j.test.BookmarkCapture; import org.springframework.data.neo4j.test.Neo4jExtension; +import org.springframework.data.neo4j.test.Neo4jImperativeTestConfiguration; import org.springframework.data.neo4j.test.Neo4jIntegrationTest; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; @@ -63,6 +66,20 @@ protected static void setupData(@Autowired BookmarkCapture bookmarkCapture) { .asString(); transaction.run("unwind ['German', 'English'] as name create (n:Language {name: name}) return name") .consume(); + personId = transaction.run("MATCH (l:Language {name: 'German'}) CREATE (n:Person {id: randomUUID(), name: 'Helge'}) -[:HAS_MOTHER_TONGUE]-> (l) return n.id").single() + .get(0) + .asString(); + transaction.commit(); + bookmarkCapture.seedWith(session.lastBookmark()); + } + } + + @BeforeEach + protected void removeRelationships(@Autowired BookmarkCapture bookmarkCapture) { + try (Session session = neo4jConnectionSupport.getDriver().session(bookmarkCapture.createSessionConfig()); + Transaction transaction = session.beginTransaction(); + ) { + transaction.run("MATCH ()- [r:KNOWS]-() delete r").consume(); transaction.commit(); bookmarkCapture.seedWith(session.lastBookmark()); } @@ -79,14 +96,64 @@ void listOfRelationshipPropertiesShouldBeUnwindable(@Autowired PersonService per }); } + @Test // GH-2537 + void ensureRelationshipsAreSerialized(@Autowired PersonService personService) { + + Optional optionalPerson = personService.updateRel2(personId, Arrays.asList("German")); + assertThat(optionalPerson).isPresent().hasValueSatisfying(person -> { + assertThat(person.getKnownLanguages()).hasSize(1); + assertThat(person.getKnownLanguages()).first().satisfies(knows -> { + assertThat(knows.getDescription()).isEqualTo("Some description"); + assertThat(knows.getLanguage()).extracting(Language::getName).isEqualTo("German"); + }); + }); + } + + @Test // "GH-2537" + void ensure1To1RelationshipsAreSerialized(@Autowired PersonService personService) { + + Optional optionalPerson = personService.updateRel3(personId); + assertThat(optionalPerson).isPresent().hasValueSatisfying(person -> { + + assertThat(person.getKnownLanguages()).hasSize(1); + assertThat(person.getKnownLanguages()).first().satisfies(knows -> { + assertThat(knows.getDescription()).isEqualTo("Whatever"); + assertThat(knows.getLanguage()).extracting(Language::getName).isEqualTo("German"); + }); + }); + } + @Repository public interface PersonRepository extends Neo4jRepository { - @Query("UNWIND $relations As rel WITH rel " + - "CREATE (f:Person {id: $from}) - [r:KNOWS {description: rel.__properties__.description}] -> (t:Language {name: rel.__properties__.__target__.__id__}) " - + - "RETURN f, collect(r), collect(t)") + // Using separate id and than relationships on top level + @Query("" + + "UNWIND $relations As rel WITH rel " + + "MATCH (f:Person {id: $from}) " + + "MATCH (t:Language {name: rel.__target__.__id__}) " + + "CREATE (f)- [r:KNOWS {description: rel.__properties__.description}] -> (t) " + + "RETURN f, collect(r), collect(t)" + ) Person updateRel(@Param("from") String from, @Param("relations") List relations); + + // Using the whole person object + @Query("" + + "UNWIND $person.__properties__.KNOWS As rel WITH rel " + + "MATCH (f:Person {id: $person.__id__}) " + + "MATCH (t:Language {name: rel.__target__.__id__}) " + + "CREATE (f) - [r:KNOWS {description: rel.__properties__.description}] -> (t) " + + "RETURN f, collect(r), collect(t)") + Person updateRel2(@Param("person") Person person); + + @Query("" + + "MATCH (f:Person {id: $person.__id__}) " + + "MATCH (mt:Language {name: $person.__properties__.HAS_MOTHER_TONGUE[0].__target__.__id__}) " + + "MATCH (f)-[frl:HAS_MOTHER_TONGUE]->(mt) WITH f, frl, mt " + + "UNWIND $person.__properties__.KNOWS As rel WITH f, frl, mt, rel " + + "MATCH (t:Language {name: rel.__target__.__id__}) " + + "MERGE (f)- [r:KNOWS {description: rel.__properties__.description}] -> (t) " + + "RETURN f, frl, mt, collect(r), collect(t)") + Person updateRelWith11(@Param("person") Person person); } @Service @@ -105,13 +172,39 @@ public Person updateRel(String from, List languageNames) { .collect(Collectors.toList()); return personRepository.updateRel(from, knownLanguages); } + + public Optional updateRel2(String id, List languageNames) { + + Optional original = personRepository.findById(id); + if (original.isPresent()) { + Person person = original.get(); + List knownLanguages = languageNames.stream().map(Language::new) + .map(language -> new Knows("Some description", language)) + .collect(Collectors.toList()); + person.setKnownLanguages(knownLanguages); + return Optional.of(personRepository.updateRel2(person)); + } + + return original; + } + + public Optional updateRel3(String id) { + Optional original = personRepository.findById(id); + if (original.isPresent()) { + Person person = original.get(); + person.setKnownLanguages(Collections.singletonList(new Knows("Whatever", new Language("German")))); + return Optional.of(personRepository.updateRelWith11(person)); + } + + return original; + } } @Configuration @EnableTransactionManagement @EnableNeo4jRepositories(considerNestedRepositories = true) @ComponentScan - static class Config extends AbstractNeo4jConfig { + static class Config extends Neo4jImperativeTestConfiguration { @Bean public BookmarkCapture bookmarkCapture() { @@ -123,5 +216,10 @@ public Driver driver() { return neo4jConnectionSupport.getDriver(); } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } } } diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2323/Knows.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2323/Knows.java index c449f61694..ebaa06135c 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2323/Knows.java +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2323/Knows.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2323/Language.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2323/Language.java index 55632d4ea8..1a50f13908 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2323/Language.java +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2323/Language.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2323/Person.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2323/Person.java index 392c5837d2..3a2514c208 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2323/Person.java +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2323/Person.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -37,6 +37,9 @@ public class Person { @Relationship("KNOWS") private List knownLanguages = new ArrayList<>(); + @Relationship("HAS_MOTHER_TONGUE") + private Knows motherTongue; + public Person(String name) { this.name = name; } @@ -52,4 +55,8 @@ public String getName() { public List getKnownLanguages() { return knownLanguages; } + + public void setKnownLanguages(List knownLanguages) { + this.knownLanguages = knownLanguages; + } } diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2326/Animal.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2326/Animal.java index 28fecbb329..c0c3966761 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2326/Animal.java +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2326/Animal.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2326/BaseEntity.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2326/BaseEntity.java index 6358bb8b9c..f5b1d53de0 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2326/BaseEntity.java +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2326/BaseEntity.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2326/GH2326IT.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2326/GH2326IT.java index f11f596a32..84761240e3 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2326/GH2326IT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2326/GH2326IT.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -24,7 +24,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.neo4j.config.AbstractNeo4jConfig; +import org.springframework.data.neo4j.test.Neo4jImperativeTestConfiguration; import org.springframework.data.neo4j.repository.Neo4jRepository; import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories; import org.springframework.data.neo4j.test.BookmarkCapture; @@ -63,7 +63,7 @@ public interface AnimalRepository extends Neo4jRepository { @Configuration @EnableTransactionManagement @EnableNeo4jRepositories(considerNestedRepositories = true) - static class Config extends AbstractNeo4jConfig { + static class Config extends Neo4jImperativeTestConfiguration { @Bean public BookmarkCapture bookmarkCapture() { @@ -75,5 +75,10 @@ public Driver driver() { return neo4jConnectionSupport.getDriver(); } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } } } diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2326/ReactiveGH2326IT.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2326/ReactiveGH2326IT.java index 45795f3ae7..815cc055cf 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2326/ReactiveGH2326IT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2326/ReactiveGH2326IT.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -15,6 +15,7 @@ */ package org.springframework.data.neo4j.integration.issues.gh2326; +import org.springframework.data.neo4j.test.Neo4jReactiveTestConfiguration; import reactor.core.publisher.Flux; import reactor.test.StepVerifier; @@ -27,7 +28,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.neo4j.config.AbstractReactiveNeo4jConfig; import org.springframework.data.neo4j.repository.ReactiveNeo4jRepository; import org.springframework.data.neo4j.repository.config.EnableReactiveNeo4jRepositories; import org.springframework.data.neo4j.test.BookmarkCapture; @@ -76,7 +76,7 @@ public interface AnimalRepository extends ReactiveNeo4jRepository { @Configuration @EnableTransactionManagement @EnableNeo4jRepositories(considerNestedRepositories = true, namedQueriesLocation = "more-custom-queries.properties") - static class Config extends AbstractNeo4jConfig { + static class Config extends Neo4jImperativeTestConfiguration { @Bean public BookmarkCapture bookmarkCapture() { @@ -69,5 +69,10 @@ public Driver driver() { return neo4jConnectionSupport.getDriver(); } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } } } diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2328/ReactiveGH2328IT.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2328/ReactiveGH2328IT.java index 061ee142d9..b5c79bbf35 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2328/ReactiveGH2328IT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2328/ReactiveGH2328IT.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -15,6 +15,7 @@ */ package org.springframework.data.neo4j.integration.issues.gh2328; +import org.springframework.data.neo4j.test.Neo4jReactiveTestConfiguration; import reactor.core.publisher.Mono; import reactor.test.StepVerifier; @@ -25,7 +26,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.neo4j.config.AbstractReactiveNeo4jConfig; import org.springframework.data.neo4j.repository.ReactiveNeo4jRepository; import org.springframework.data.neo4j.repository.config.EnableReactiveNeo4jRepositories; import org.springframework.data.neo4j.test.BookmarkCapture; @@ -60,7 +60,7 @@ public interface SomeRepository extends ReactiveNeo4jRepository { @Configuration @EnableTransactionManagement @EnableNeo4jRepositories(considerNestedRepositories = true) - static class Config extends AbstractNeo4jConfig { + static class Config extends Neo4jImperativeTestConfiguration { @Bean public BookmarkCapture bookmarkCapture() { @@ -122,5 +122,10 @@ public Driver driver() { return neo4jConnectionSupport.getDriver(); } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } } } diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2347/ReactiveGH2347IT.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2347/ReactiveGH2347IT.java index 4a3793f164..b723fa8d56 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2347/ReactiveGH2347IT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2347/ReactiveGH2347IT.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -15,6 +15,7 @@ */ package org.springframework.data.neo4j.integration.issues.gh2347; +import org.springframework.data.neo4j.test.Neo4jReactiveTestConfiguration; import reactor.test.StepVerifier; import java.util.Collections; @@ -24,7 +25,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.neo4j.config.AbstractReactiveNeo4jConfig; import org.springframework.data.neo4j.core.ReactiveDatabaseSelectionProvider; import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager; import org.springframework.data.neo4j.core.transaction.ReactiveNeo4jTransactionManager; @@ -110,7 +110,7 @@ interface WorkflowRepository extends ReactiveNeo4jRepository { @Configuration @EnableTransactionManagement @EnableReactiveNeo4jRepositories(considerNestedRepositories = true) - static class Config extends AbstractReactiveNeo4jConfig { + static class Config extends Neo4jReactiveTestConfiguration { @Bean public BookmarkCapture bookmarkCapture() { @@ -130,5 +130,10 @@ public Driver driver() { return neo4jConnectionSupport.getDriver(); } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } } } diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2347/TestBase.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2347/TestBase.java index 4235d23963..aa8a42815d 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2347/TestBase.java +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2347/TestBase.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2347/Workflow.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2347/Workflow.java index 2841afdcab..b23fefdce0 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2347/Workflow.java +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2347/Workflow.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2415/BaseNodeEntity.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2415/BaseNodeEntity.java index d8bbd3db4e..b64b5321f9 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2415/BaseNodeEntity.java +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2415/BaseNodeEntity.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2415/Credential.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2415/Credential.java index 470f007ffd..a3eaa05f15 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2415/Credential.java +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2415/Credential.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2415/NodeEntity.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2415/NodeEntity.java index 3633c8a633..4eb46fb25e 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2415/NodeEntity.java +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2415/NodeEntity.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2415/NodeWithDefinedCredentials.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2415/NodeWithDefinedCredentials.java index 7ff26d6a89..acf322a673 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2415/NodeWithDefinedCredentials.java +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2415/NodeWithDefinedCredentials.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2451/WidgetEntity.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2451/WidgetEntity.java new file mode 100644 index 0000000000..2214c221f9 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2451/WidgetEntity.java @@ -0,0 +1,68 @@ +/* + * Copyright 2011-2023 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.gh2451; + +import java.util.HashMap; +import java.util.Map; + +import org.springframework.data.neo4j.core.schema.CompositeProperty; +import org.springframework.data.neo4j.core.schema.GeneratedValue; +import org.springframework.data.neo4j.core.schema.Id; +import org.springframework.data.neo4j.core.schema.Node; + +/** + * @author Michael J. Simons + */ +@Node("Widget") +public class WidgetEntity { + + @GeneratedValue + @Id + private Long id; + private String code; + private String label; + + @CompositeProperty + private Map additionalFields = new HashMap<>(); + + public Long getId() { + return id; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public Map getAdditionalFields() { + return additionalFields; + } + + public void setAdditionalFields(Map additionalFields) { + this.additionalFields = additionalFields; + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2451/WidgetProjection.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2451/WidgetProjection.java new file mode 100644 index 0000000000..b07d702b93 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2451/WidgetProjection.java @@ -0,0 +1,30 @@ +/* + * Copyright 2011-2023 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.gh2451; + +import java.util.Map; + +/** + * @author Michael J. Simons + */ +public interface WidgetProjection { + + String getCode(); + + String getLabel(); + + Map getAdditionalFields(); +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2451/WidgetRepository.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2451/WidgetRepository.java new file mode 100644 index 0000000000..cdffb67a00 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2451/WidgetRepository.java @@ -0,0 +1,28 @@ +/* + * Copyright 2011-2023 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.gh2451; + +import java.util.Optional; + +import org.springframework.data.neo4j.repository.Neo4jRepository; + +/** + * @author Michael J. Simons + */ +public interface WidgetRepository extends Neo4jRepository { + + Optional findByCode(String code); +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2459/GH2459IT.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2459/GH2459IT.java index eb399f574e..63f2e07495 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2459/GH2459IT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2459/GH2459IT.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -22,7 +22,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.neo4j.config.AbstractNeo4jConfig; +import org.springframework.data.neo4j.test.Neo4jImperativeTestConfiguration; import org.springframework.data.neo4j.core.DatabaseSelectionProvider; import org.springframework.data.neo4j.core.schema.Id; import org.springframework.data.neo4j.core.schema.Node; @@ -124,7 +124,7 @@ public static class Cat extends Animal {} @Configuration @EnableTransactionManagement @EnableNeo4jRepositories(considerNestedRepositories = true) - static class Config extends AbstractNeo4jConfig { + static class Config extends Neo4jImperativeTestConfiguration { @Bean public BookmarkCapture bookmarkCapture() { @@ -144,5 +144,10 @@ public Driver driver() { return neo4jConnectionSupport.getDriver(); } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } } } diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2474/CityModel.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2474/CityModel.java new file mode 100644 index 0000000000..0a0e19be52 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2474/CityModel.java @@ -0,0 +1,53 @@ +/* + * Copyright 2011-2023 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.gh2474; + +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +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.Property; +import org.springframework.data.neo4j.core.schema.Relationship; + +/** + * @author Stephen Jackson + */ +@Node +@Data +public class CityModel { + @Id + @GeneratedValue(generatorClass = GeneratedValue.UUIDGenerator.class) + private UUID cityId; + + @Relationship(value = "MAYOR") + private PersonModel mayor; + + @Relationship(value = "CITIZEN") + private List citizens = new ArrayList<>(); + + @Relationship(value = "EMPLOYEE") + private List cityEmployees = new ArrayList<>(); + + private String name; + + @Property("exotic.property") + private String exoticProperty; +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2474/CityModelDTO.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2474/CityModelDTO.java new file mode 100644 index 0000000000..0bf765c7a0 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2474/CityModelDTO.java @@ -0,0 +1,52 @@ +/* + * Copyright 2011-2023 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.gh2474; + +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +/** + * @author Stephen Jackson + */ +@Data +public class CityModelDTO { + private UUID cityId; + private String name; + private String exoticProperty; + + public PersonModelDTO mayor; + public List citizens = new ArrayList<>(); + public List cityEmployees = new ArrayList<>(); + + /** + * Nested projection + */ + @Data + public static class PersonModelDTO { + private UUID personId; + } + + /** + * Nested projection + */ + @Data + public static class JobRelationshipDTO { + private PersonModelDTO person; + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2474/CityModelRepository.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2474/CityModelRepository.java new file mode 100644 index 0000000000..42a28c0776 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2474/CityModelRepository.java @@ -0,0 +1,40 @@ +/* + * Copyright 2011-2023 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.gh2474; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +import org.springframework.data.domain.Sort; +import org.springframework.data.neo4j.repository.Neo4jRepository; +import org.springframework.data.neo4j.repository.query.Query; + +/** + * @author Stephen Jackson + * @author Michael J. Simons + */ +public interface CityModelRepository extends Neo4jRepository { + + Optional findByCityId(UUID cityId); + + @Query("" + + "MATCH (n:CityModel)" + + "RETURN n :#{orderBy(#sort)}") + List customQuery(Sort sort); + + long deleteAllByExoticProperty(String property); +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2474/GH2474IT.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2474/GH2474IT.java new file mode 100644 index 0000000000..080b488488 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2474/GH2474IT.java @@ -0,0 +1,191 @@ +/* + * Copyright 2011-2023 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.gh2474; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.neo4j.driver.Driver; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.domain.Sort; +import org.springframework.data.neo4j.test.Neo4jImperativeTestConfiguration; +import org.springframework.data.neo4j.core.DatabaseSelectionProvider; +import org.springframework.data.neo4j.core.Neo4jTemplate; +import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager; +import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager; +import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories; +import org.springframework.data.neo4j.test.BookmarkCapture; +import org.springframework.data.neo4j.test.Neo4jExtension; +import org.springframework.data.neo4j.test.Neo4jIntegrationTest; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +/** + * @author Stephen Jackson + * @author Michael J. Simons + */ +@Neo4jIntegrationTest +public class GH2474IT { + + protected static Neo4jExtension.Neo4jConnectionSupport neo4jConnectionSupport; + + @Autowired + Driver driver; + + @Autowired + BookmarkCapture bookmarkCapture; + + @Autowired + CityModelRepository cityModelRepository; + + @Autowired + PersonModelRepository personModelRepository; + + @Autowired + Neo4jTemplate neo4jTemplate; + + @BeforeEach + void setupData() { + + cityModelRepository.deleteAll(); + + CityModel aachen = new CityModel(); + aachen.setName("Aachen"); + aachen.setExoticProperty("Cars"); + + CityModel utrecht = new CityModel(); + utrecht.setName("Utrecht"); + utrecht.setExoticProperty("Bikes"); + + cityModelRepository.saveAll(Arrays.asList(aachen, utrecht)); + } + + @Test + public void testStoreExoticProperty() { + + CityModel cityModel = new CityModel(); + cityModel.setName("The Jungle"); + cityModel.setExoticProperty("lions"); + cityModel = cityModelRepository.save(cityModel); + + CityModel reloaded = cityModelRepository.findById(cityModel.getCityId()) + .orElseThrow(RuntimeException::new); + assertThat(reloaded.getExoticProperty()).isEqualTo("lions"); + + long cnt = cityModelRepository.deleteAllByExoticProperty("lions"); + assertThat(cnt).isOne(); + } + + @Test + public void testSortOnExoticProperty() { + + Sort sort = Sort.by(Sort.Order.asc("exoticProperty")); + List cityModels = cityModelRepository.findAll(sort); + + assertThat(cityModels).extracting(CityModel::getExoticProperty).containsExactly("Bikes", "Cars"); + } + + @Test + public void testSortOnExoticPropertyCustomQuery_MakeSureIUnderstand() { + + Sort sort = Sort.by(Sort.Order.asc("n.name")); + List cityModels = cityModelRepository.customQuery(sort); + + assertThat(cityModels).extracting(CityModel::getExoticProperty).containsExactly("Cars", "Bikes"); + } + + @Test + public void testSortOnExoticPropertyCustomQuery() { + Sort sort = Sort.by(Sort.Order.asc("n.`exotic.property`")); + List cityModels = cityModelRepository.customQuery(sort); + + assertThat(cityModels).extracting(CityModel::getExoticProperty).containsExactly("Bikes", "Cars"); + } + + @Test // GH-2475 + public void testCityModelProjectionPersistence() { + CityModel cityModel = new CityModel(); + cityModel.setName("New Cool City"); + cityModel = cityModelRepository.save(cityModel); + + PersonModel personModel = new PersonModel(); + personModel.setName("Mr. Mayor"); + personModel.setAddress("1600 City Avenue"); + personModel.setFavoriteFood("tacos"); + personModelRepository.save(personModel); + + CityModelDTO cityModelDTO = cityModelRepository.findByCityId(cityModel.getCityId()) + .orElseThrow(RuntimeException::new); + cityModelDTO.setName("Changed name"); + cityModelDTO.setExoticProperty("tigers"); + + CityModelDTO.PersonModelDTO personModelDTO = new CityModelDTO.PersonModelDTO(); + personModelDTO.setPersonId(personModelDTO.getPersonId()); + + CityModelDTO.JobRelationshipDTO jobRelationshipDTO = new CityModelDTO.JobRelationshipDTO(); + jobRelationshipDTO.setPerson(personModelDTO); + + cityModelDTO.setMayor(personModelDTO); + cityModelDTO.setCitizens(Collections.singletonList(personModelDTO)); + cityModelDTO.setCityEmployees(Collections.singletonList(jobRelationshipDTO)); + neo4jTemplate.save(CityModel.class).one(cityModelDTO); + + CityModel reloaded = cityModelRepository.findById(cityModel.getCityId()) + .orElseThrow(RuntimeException::new); + assertThat(reloaded.getName()).isEqualTo("Changed name"); + assertThat(reloaded.getMayor()).isNotNull(); + assertThat(reloaded.getCitizens()).hasSize(1); + assertThat(reloaded.getCityEmployees()).hasSize(1); + } + + @Configuration + @EnableTransactionManagement + @EnableNeo4jRepositories + static class Config extends Neo4jImperativeTestConfiguration { + + @Bean + public BookmarkCapture bookmarkCapture() { + return new BookmarkCapture(); + } + + @Override + public PlatformTransactionManager transactionManager( + Driver driver, DatabaseSelectionProvider databaseNameProvider) { + + BookmarkCapture bookmarkCapture = bookmarkCapture(); + return new Neo4jTransactionManager(driver, databaseNameProvider, + Neo4jBookmarkManager.create(bookmarkCapture)); + } + + @Bean + public Driver driver() { + + return neo4jConnectionSupport.getDriver(); + } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2474/JobRelationship.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2474/JobRelationship.java new file mode 100644 index 0000000000..d6f057a0d6 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2474/JobRelationship.java @@ -0,0 +1,38 @@ +/* + * Copyright 2011-2023 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.gh2474; + +import lombok.Data; +import org.springframework.data.neo4j.core.schema.GeneratedValue; +import org.springframework.data.neo4j.core.schema.Id; +import org.springframework.data.neo4j.core.schema.RelationshipProperties; +import org.springframework.data.neo4j.core.schema.TargetNode; + +/** + * @author Stephen Jackson + */ +@RelationshipProperties +@Data +public class JobRelationship { + @Id + @GeneratedValue + private Long id; + + @TargetNode + private PersonModel person; + + private String jobTitle; +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2474/PersonModel.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2474/PersonModel.java new file mode 100644 index 0000000000..528009026c --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2474/PersonModel.java @@ -0,0 +1,39 @@ +/* + * Copyright 2011-2023 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.gh2474; + +import lombok.Data; + +import java.util.UUID; + +import org.springframework.data.neo4j.core.schema.GeneratedValue; +import org.springframework.data.neo4j.core.schema.Id; +import org.springframework.data.neo4j.core.schema.Node; + +/** + * @author Stephen Jackson + */ +@Node +@Data +public class PersonModel { + @Id + @GeneratedValue(generatorClass = GeneratedValue.UUIDGenerator.class) + private UUID personId; + + private String address; + private String name; + private String favoriteFood; +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2474/PersonModelRepository.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2474/PersonModelRepository.java new file mode 100644 index 0000000000..e85b542d76 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2474/PersonModelRepository.java @@ -0,0 +1,26 @@ +/* + * Copyright 2011-2023 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.gh2474; + +import org.springframework.data.neo4j.repository.Neo4jRepository; + +import java.util.UUID; + +/** + * @author Stephen Jackson + */ +public interface PersonModelRepository extends Neo4jRepository { +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2493/Gh2493IT.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2493/Gh2493IT.java new file mode 100644 index 0000000000..4ff9041d50 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2493/Gh2493IT.java @@ -0,0 +1,130 @@ +/* + * Copyright 2011-2023 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.gh2493; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.neo4j.driver.Driver; +import org.neo4j.driver.Session; +import org.neo4j.driver.Transaction; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.neo4j.test.Neo4jImperativeTestConfiguration; +import org.springframework.data.neo4j.core.DatabaseSelectionProvider; +import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager; +import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager; +import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories; +import org.springframework.data.neo4j.test.BookmarkCapture; +import org.springframework.data.neo4j.test.Neo4jExtension; +import org.springframework.data.neo4j.test.Neo4jIntegrationTest; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +/** + * @author Michael J. Simons + */ +@Neo4jIntegrationTest +public class Gh2493IT { + + protected static Neo4jExtension.Neo4jConnectionSupport neo4jConnectionSupport; + + @BeforeAll + protected static void setupData(@Autowired BookmarkCapture bookmarkCapture) { + + try (Session session = neo4jConnectionSupport.getDriver().session(bookmarkCapture.createSessionConfig()); + Transaction transaction = session.beginTransaction(); + ) { + transaction.run("MATCH (n) DETACH DELETE n").consume(); + transaction.commit(); + bookmarkCapture.seedWith(session.lastBookmark()); + } + } + + @Test + void saveOneShouldWork(@Autowired Driver driver, @Autowired BookmarkCapture bookmarkCapture, + @Autowired TestObjectRepository repository) { + + TestObject testObject = new TestObject(new TestData(4711, "Foobar")); + testObject = repository.save(testObject); + + assertThat(testObject.getId()).isNotNull(); + assertThatTestObjectHasBeenCreated(driver, bookmarkCapture, testObject); + } + + @Test + void saveAllShouldWork(@Autowired Driver driver, @Autowired BookmarkCapture bookmarkCapture, + @Autowired TestObjectRepository repository) { + + TestObject testObject = new TestObject(new TestData(4711, "Foobar")); + testObject = repository.saveAll(Collections.singletonList(testObject)).get(0); + + assertThat(testObject.getId()).isNotNull(); + assertThatTestObjectHasBeenCreated(driver, bookmarkCapture, testObject); + } + + private static void assertThatTestObjectHasBeenCreated(Driver driver, BookmarkCapture bookmarkCapture, + TestObject testObject) { + try (Session session = driver.session(bookmarkCapture.createSessionConfig())) { + Map arguments = new HashMap<>(); + arguments.put("id", testObject.getId()); + arguments.put("num", testObject.getData().getNum()); + arguments.put("string", testObject.getData().getString()); + long cnt = session.run( + "MATCH (n:TestObject) WHERE n.id = $id AND n.dataNum = $num AND n.dataString = $string RETURN count(n)", + arguments) + .single().get(0).asLong(); + assertThat(cnt).isOne(); + } + } + + @Configuration + @EnableTransactionManagement + @EnableNeo4jRepositories + static class Config extends Neo4jImperativeTestConfiguration { + + @Bean + public Driver driver() { + + return neo4jConnectionSupport.getDriver(); + } + + @Bean + public BookmarkCapture bookmarkCapture() { + return new BookmarkCapture(); + } + + @Override + public PlatformTransactionManager transactionManager(Driver driver, + DatabaseSelectionProvider databaseNameProvider) { + + BookmarkCapture bookmarkCapture = bookmarkCapture(); + return new Neo4jTransactionManager(driver, databaseNameProvider, + Neo4jBookmarkManager.create(bookmarkCapture)); + } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2493/TestConverter.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2493/TestConverter.java new file mode 100644 index 0000000000..e509b9ee6e --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2493/TestConverter.java @@ -0,0 +1,61 @@ +/* + * Copyright 2011-2023 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.gh2493; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.neo4j.driver.Value; +import org.neo4j.driver.Values; +import org.springframework.data.neo4j.core.convert.Neo4jConversionService; +import org.springframework.data.neo4j.core.convert.Neo4jPersistentPropertyToMapConverter; + +/** + * @author Michael J. Simons + */ +public class TestConverter implements Neo4jPersistentPropertyToMapConverter { + + static final String NUM = "Num"; + static final String STRING = "String"; + + @Override + public Map decompose(TestData property, + Neo4jConversionService neo4jConversionService) { + + if (property == null) { + return Collections.emptyMap(); + } + + Map result = new HashMap<>(); + result.put(NUM, Values.value(property.getNum())); + result.put(STRING, Values.value(property.getString())); + return result; + } + + @Override + public TestData compose(Map source, + Neo4jConversionService neo4jConversionService) { + TestData data = new TestData(); + if (source.get(NUM) != null) { + data.setNum(source.get(NUM).asInt()); + } + if (source.get(STRING) != null) { + data.setString(source.get(STRING).asString()); + } + return data; + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2493/TestData.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2493/TestData.java new file mode 100644 index 0000000000..675b29ab12 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2493/TestData.java @@ -0,0 +1,39 @@ +/* + * Copyright 2011-2023 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.gh2493; + +import lombok.Getter; +import lombok.Setter; + +/** + * @author Michael J. Simons + */ +@Getter +@Setter +public class TestData { + + private int num; + private String string; + + public TestData() { + super(); + } + + public TestData(int num, String string) { + this.num = num; + this.string = string; + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2493/TestObject.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2493/TestObject.java new file mode 100644 index 0000000000..fc0127f585 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2493/TestObject.java @@ -0,0 +1,51 @@ +/* + * Copyright 2011-2023 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.gh2493; + +import lombok.Getter; +import lombok.Setter; + +import org.springframework.data.neo4j.core.schema.CompositeProperty; +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.Property; +import org.springframework.data.neo4j.core.support.UUIDStringGenerator; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +/** + * @author Michael J. Simons + */ +@Node +@Getter +@Setter +public class TestObject { + + @Id + @Property(name = "id") + @GeneratedValue(value = UUIDStringGenerator.class) + protected String id; + + @JsonIgnore + @CompositeProperty(delimiter = "", converter = TestConverter.class) + private TestData data; + + public TestObject(TestData aData) { + super(); + data = aData; + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2493/TestObjectRepository.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2493/TestObjectRepository.java new file mode 100644 index 0000000000..9304ec3281 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2493/TestObjectRepository.java @@ -0,0 +1,24 @@ +/* + * Copyright 2011-2023 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.gh2493; + +import org.springframework.data.neo4j.repository.Neo4jRepository; + +/** + * @author Michael J. Simons + */ +public interface TestObjectRepository extends Neo4jRepository { +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2498/DomainModel.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2498/DomainModel.java new file mode 100644 index 0000000000..766a8ecc07 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2498/DomainModel.java @@ -0,0 +1,45 @@ +/* + * Copyright 2011-2023 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.gh2498; + +import java.util.UUID; + +import org.springframework.data.neo4j.core.schema.GeneratedValue; +import org.springframework.data.neo4j.core.schema.Id; +import org.springframework.data.neo4j.core.schema.Node; + +/** + * @author Michael J. Simons + */ +@Node +public class DomainModel { + + @Id @GeneratedValue UUID id; + + private final String name; + + public DomainModel(String name) { + this.name = name; + } + + public UUID getId() { + return id; + } + + public String getName() { + return name; + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2498/DomainModelRepository.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2498/DomainModelRepository.java new file mode 100644 index 0000000000..7b3be72d72 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2498/DomainModelRepository.java @@ -0,0 +1,27 @@ +/* + * Copyright 2011-2023 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.gh2498; + +import java.util.UUID; + +import org.springframework.data.neo4j.repository.Neo4jRepository; +import org.springframework.data.neo4j.repository.support.CypherdslConditionExecutor; + +/** + * @author Michael J. Simons + */ +public interface DomainModelRepository extends Neo4jRepository, CypherdslConditionExecutor { +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2498/GH2498IT.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2498/GH2498IT.java new file mode 100644 index 0000000000..0bce2f5cbc --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2498/GH2498IT.java @@ -0,0 +1,126 @@ +/* + * Copyright 2011-2023 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.gh2498; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.neo4j.cypherdsl.core.Condition; +import org.neo4j.cypherdsl.core.Cypher; +import org.neo4j.cypherdsl.core.Node; +import org.neo4j.cypherdsl.core.Parameter; +import org.neo4j.cypherdsl.core.Property; +import org.neo4j.driver.Driver; +import org.neo4j.driver.Session; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.neo4j.test.Neo4jImperativeTestConfiguration; +import org.springframework.data.neo4j.core.DatabaseSelectionProvider; +import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager; +import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager; +import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories; +import org.springframework.data.neo4j.test.BookmarkCapture; +import org.springframework.data.neo4j.test.Neo4jExtension; +import org.springframework.data.neo4j.test.Neo4jIntegrationTest; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +/** + * @author Michael J. Simons + */ +@Neo4jIntegrationTest +public class GH2498IT { + + protected static Neo4jExtension.Neo4jConnectionSupport neo4jConnectionSupport; + + @BeforeEach + void setupData(@Autowired Driver driver, @Autowired BookmarkCapture bookmarkCapture) { + + try (Session session = driver.session()) { + session.writeTransaction(tx -> tx.run("MATCH (n:DomainModel) DETACH DELETE n").consume()); + session.writeTransaction(tx -> tx.run( + "UNWIND ['A', 'B', 'C'] AS name WITH name CREATE (n:DomainModel {id: randomUUID(), name: name})") + .consume()); + session.writeTransaction(tx -> tx.run("MATCH (n:Person) DETACH DELETE n").consume()); + session.writeTransaction(tx -> tx.run( + "CREATE (n:Person {name: 'a'}) -[:KNOWS] ->(m:Person {name: 'b'})") + .consume()); + bookmarkCapture.seedWith(session.lastBookmark()); + } + } + + @Test // GH-2498 + void cypherdslConditionExecutorShouldWorkWithAnonParameters(@Autowired DomainModelRepository repository) { + + Node node = Cypher.node("DomainModel").named("domainModel"); + Property name = node.property("name"); + Parameter> parameters = Cypher.anonParameter(Arrays.asList("A", "C")); + Condition in = name.in(parameters); + Collection result = repository.findAll(in, Cypher.sort(name).descending()); + assertThat(result).hasSize(2) + .map(DomainModel::getName) + .containsExactly("C", "A"); + } + + @Test // GH-2498 + void cypherdslConditionExecutorMustApplyParametersToNestedStatementsToo(@Autowired PersonRepository repository) { + Node personNode = Cypher.node("Person").named("person"); + Property name = personNode.property("name"); + Parameter> param = Cypher.anonParameter(Arrays.asList("a", "b")); + Condition in = name.in(param); + Collection people = repository.findAll(in); + assertThat(people) + .extracting(Person::getName) + .containsExactlyInAnyOrder("a", "b"); + } + + @Configuration + @EnableTransactionManagement + @EnableNeo4jRepositories + static class Config extends Neo4jImperativeTestConfiguration { + + @Bean + public BookmarkCapture bookmarkCapture() { + return new BookmarkCapture(); + } + + @Override + public PlatformTransactionManager transactionManager( + Driver driver, DatabaseSelectionProvider databaseNameProvider) { + + BookmarkCapture bookmarkCapture = bookmarkCapture(); + return new Neo4jTransactionManager(driver, databaseNameProvider, + Neo4jBookmarkManager.create(bookmarkCapture)); + } + + @Bean + public Driver driver() { + + return neo4jConnectionSupport.getDriver(); + } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2498/Know.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2498/Know.java new file mode 100644 index 0000000000..470e62cb6e --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2498/Know.java @@ -0,0 +1,44 @@ +/* + * Copyright 2011-2023 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.gh2498; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import org.springframework.data.neo4j.core.schema.GeneratedValue; +import org.springframework.data.neo4j.core.schema.Id; +import org.springframework.data.neo4j.core.schema.RelationshipProperties; +import org.springframework.data.neo4j.core.schema.TargetNode; + +/** + * @author Michael J. Simons + */ +@RelationshipProperties +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder(toBuilder = true) +public class Know { + @Id + @GeneratedValue + Long id; + @TargetNode + Person person; +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2498/Person.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2498/Person.java new file mode 100644 index 0000000000..ca8b0b034d --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2498/Person.java @@ -0,0 +1,47 @@ +/* + * Copyright 2011-2023 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.gh2498; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.util.List; + +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 + */ +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Node("Person") +@Builder(toBuilder = true) +public class Person { + @Id + @GeneratedValue + Long id; + String name; + @Relationship(type = "KNOW", direction = Relationship.Direction.INCOMING) + List knows; +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2498/PersonRepository.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2498/PersonRepository.java new file mode 100644 index 0000000000..052f280863 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2498/PersonRepository.java @@ -0,0 +1,27 @@ +/* + * Copyright 2011-2023 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.gh2498; + +import org.springframework.data.neo4j.repository.Neo4jRepository; +import org.springframework.data.neo4j.repository.support.CypherdslConditionExecutor; +import org.springframework.stereotype.Repository; + +/** + * @author Michael J. Simons + */ +@Repository +public interface PersonRepository extends Neo4jRepository, CypherdslConditionExecutor { +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2500/Device.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2500/Device.java new file mode 100644 index 0000000000..5a5ceba17c --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2500/Device.java @@ -0,0 +1,68 @@ +/* + * Copyright 2011-2023 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.gh2500; + +import lombok.Getter; +import lombok.Setter; + +import java.util.LinkedHashSet; +import java.util.Set; + +import org.springframework.data.annotation.Version; +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 +@Getter +@Setter +public class Device { + + @Id + private Long id; + + @Version + private Long version; + + private String name; + + @Relationship(type = "BELONGS_TO", direction = Relationship.Direction.OUTGOING) + private Set groups = new LinkedHashSet<>(); + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + Device device = (Device) o; + + return id.equals(device.id); + } + + @Override + public int hashCode() { + int result = id != null ? id.hashCode() : 0; + result = 31 * result + (name != null ? name.hashCode() : 0); + return result; + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2500/GH2500IT.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2500/GH2500IT.java new file mode 100644 index 0000000000..873f058752 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2500/GH2500IT.java @@ -0,0 +1,95 @@ +/* + * Copyright 2011-2023 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.gh2500; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.jupiter.api.Test; +import org.neo4j.driver.Driver; +import org.neo4j.driver.Session; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.neo4j.test.Neo4jImperativeTestConfiguration; +import org.springframework.data.neo4j.core.DatabaseSelectionProvider; +import org.springframework.data.neo4j.core.Neo4jTemplate; +import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager; +import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager; +import org.springframework.data.neo4j.test.BookmarkCapture; +import org.springframework.data.neo4j.test.Neo4jIntegrationTest; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +/** + * @author Michael J. Simons + */ +@Neo4jIntegrationTest +public class GH2500IT extends TestBase { + + @Test // GH-2498 + void shouldNotDeleteFreshlyCreatedRelationships(@Autowired Driver driver, @Autowired Neo4jTemplate template) { + + Group group = new Group(); + group.setName("test"); + group.getDevices().add(template.findById(1L, Device.class).get()); + + template.save(group); + + try (Session session = driver.session()) { + Map parameters = new HashMap<>(); + parameters.put("name", group.getName()); + parameters.put("deviceId", 1L); + long cnt = session.run( + "MATCH (g:Group {name: $name}) <-[:BELONGS_TO]- (d:Device {id: $deviceId}) RETURN count(*)", + parameters) + .single().get(0).asLong(); + assertThat(cnt).isOne(); + } + } + + @Configuration + @EnableTransactionManagement + static class Config extends Neo4jImperativeTestConfiguration { + + @Bean + public BookmarkCapture bookmarkCapture() { + return new BookmarkCapture(); + } + + @Override + public PlatformTransactionManager transactionManager( + Driver driver, DatabaseSelectionProvider databaseNameProvider) { + + BookmarkCapture bookmarkCapture = bookmarkCapture(); + return new Neo4jTransactionManager(driver, databaseNameProvider, + Neo4jBookmarkManager.create(bookmarkCapture)); + } + + @Bean + public Driver driver() { + + return neo4jConnectionSupport.getDriver(); + } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2500/Group.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2500/Group.java new file mode 100644 index 0000000000..a3a32db0e1 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2500/Group.java @@ -0,0 +1,80 @@ +/* + * Copyright 2011-2023 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.gh2500; + +import lombok.Getter; +import lombok.Setter; + +import java.util.LinkedHashSet; +import java.util.Set; + +import org.springframework.data.annotation.Version; +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; +import org.springframework.data.neo4j.core.support.UUIDStringGenerator; +import org.springframework.lang.NonNull; + +/** + * @author Michael J. Simons + */ +@Node +@Getter +@Setter +public class Group { + + @Id + @GeneratedValue(generatorClass = UUIDStringGenerator.class) + private String id; + + @Version + private Long version; + + @NonNull + private String name; + + @Relationship(type = "BELONGS_TO", direction = Relationship.Direction.INCOMING) + private Set devices = new LinkedHashSet<>(); + + @Relationship(type = "GROUP_LINK") + private Set groups = new LinkedHashSet<>(); + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + Group group = (Group) o; + + if (!id.equals(group.id)) { + return false; + } + return name.equals(group.name); + } + + @Override + public int hashCode() { + int result = 7; + result = 31 * result + id.hashCode(); + result = 31 * result + name.hashCode(); + return result; + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2500/ReactiveGH2500IT.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2500/ReactiveGH2500IT.java new file mode 100644 index 0000000000..841304e304 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2500/ReactiveGH2500IT.java @@ -0,0 +1,103 @@ +/* + * Copyright 2011-2023 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.gh2500; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.springframework.data.neo4j.test.Neo4jReactiveTestConfiguration; +import reactor.test.StepVerifier; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.jupiter.api.Test; +import org.neo4j.driver.Driver; +import org.neo4j.driver.Session; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.neo4j.core.ReactiveDatabaseSelectionProvider; +import org.springframework.data.neo4j.core.ReactiveNeo4jTemplate; +import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager; +import org.springframework.data.neo4j.core.transaction.ReactiveNeo4jTransactionManager; +import org.springframework.data.neo4j.test.BookmarkCapture; +import org.springframework.data.neo4j.test.Neo4jIntegrationTest; +import org.springframework.transaction.ReactiveTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +/** + * @author Michael J. Simons + */ +@Neo4jIntegrationTest +public class ReactiveGH2500IT extends TestBase { + + @Test // GH-2498 + void shouldNotDeleteFreshlyCreatedRelationships(@Autowired Driver driver, @Autowired + ReactiveNeo4jTemplate template) { + + Group group = new Group(); + group.setName("test"); + template.findById(1L, Device.class) + .flatMap(d -> { + group.getDevices().add(d); + return template.save(group); + }) + .as(StepVerifier::create) + .expectNextCount(1L) + .verifyComplete(); + + + try (Session session = driver.session()) { + Map parameters = new HashMap<>(); + parameters.put("name", group.getName()); + parameters.put("deviceId", 1L); + long cnt = session.run( + "MATCH (g:Group {name: $name}) <-[:BELONGS_TO]- (d:Device {id: $deviceId}) RETURN count(*)", + parameters) + .single().get(0).asLong(); + assertThat(cnt).isOne(); + } + } + + @Configuration + @EnableTransactionManagement + static class Config extends Neo4jReactiveTestConfiguration { + + @Bean + public BookmarkCapture bookmarkCapture() { + return new BookmarkCapture(); + } + + @Override + public ReactiveTransactionManager reactiveTransactionManager(Driver driver, + ReactiveDatabaseSelectionProvider databaseSelectionProvider) { + BookmarkCapture bookmarkCapture = bookmarkCapture(); + return new ReactiveNeo4jTransactionManager(driver, databaseSelectionProvider, + Neo4jBookmarkManager.create(bookmarkCapture)); + } + + @Bean + public Driver driver() { + + return neo4jConnectionSupport.getDriver(); + } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2500/TestBase.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2500/TestBase.java new file mode 100644 index 0000000000..873cda7aac --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2500/TestBase.java @@ -0,0 +1,41 @@ +/* + * Copyright 2011-2023 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.gh2500; + +import org.junit.jupiter.api.BeforeEach; +import org.neo4j.driver.Driver; +import org.neo4j.driver.Session; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.neo4j.test.BookmarkCapture; +import org.springframework.data.neo4j.test.Neo4jExtension; + +/** + * @author Michael J. Simons + */ +abstract class TestBase { + protected static Neo4jExtension.Neo4jConnectionSupport neo4jConnectionSupport; + + @BeforeEach + void setupData(@Autowired Driver driver, @Autowired BookmarkCapture bookmarkCapture) { + + try (Session session = driver.session()) { + session.run("MATCH (n) DETACH DELETE n").consume(); + session.run("CREATE (d:Device {id: 1, name:'Testdevice', version:0})").consume(); + bookmarkCapture.seedWith(session.lastBookmark()); + } + } + +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2526/GH2526IT.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2526/GH2526IT.java new file mode 100644 index 0000000000..21b94c84a0 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2526/GH2526IT.java @@ -0,0 +1,262 @@ +/* + * Copyright 2011-2023 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.gh2526; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.Value; +import lombok.With; +import lombok.experimental.NonFinal; +import lombok.experimental.SuperBuilder; +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.Session; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.annotation.Immutable; +import org.springframework.data.neo4j.core.DatabaseSelectionProvider; +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; +import org.springframework.data.neo4j.core.schema.RelationshipId; +import org.springframework.data.neo4j.core.schema.RelationshipProperties; +import org.springframework.data.neo4j.core.schema.TargetNode; +import org.springframework.data.neo4j.core.support.UUIDStringGenerator; +import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager; +import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager; +import org.springframework.data.neo4j.repository.Neo4jRepository; +import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories; +import org.springframework.data.neo4j.test.BookmarkCapture; +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.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +import java.util.Set; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.tuple; + +/** + * Test setup for GH-2526: Query creation of and picking the correct named relationship out of the result. + */ +@Neo4jIntegrationTest +public class GH2526IT { + + protected static Neo4jExtension.Neo4jConnectionSupport neo4jConnectionSupport; + + @BeforeEach + void setupData(@Autowired Driver driver, @Autowired BookmarkCapture bookmarkCapture) { + + try (Session session = driver.session()) { + session.run("MATCH (n) DETACH DELETE n").consume(); + session.run( + "CREATE (o1:Measurand {measurandId: 'o1'})\n" + + "CREATE (acc1:AccountingMeasurementMeta:MeasurementMeta:BaseNodeEntity {nodeId: 'acc1'})\n" + + "CREATE (m1:MeasurementMeta:BaseNodeEntity {nodeId: 'm1'})\n" + + "CREATE (acc1)-[:USES{variable: 'A'}]->(m1)\n" + + "CREATE (o1)-[:IS_MEASURED_BY{ manual: true }]->(acc1)\n" + ).consume(); + bookmarkCapture.seedWith(session.lastBookmark()); + } + } + + @Test + void relationshipWillGetFoundInResultOfMultilevelInheritance(@Autowired BaseNodeRepository repository) { + MeasurementProjection m = repository.findByNodeId("acc1", MeasurementProjection.class); + assertThat(m).isNotNull(); + assertThat(m.getDataPoints()).isNotEmpty(); + assertThat(m).extracting(MeasurementProjection::getDataPoints, InstanceOfAssertFactories.collection(DataPoint.class)) + .extracting(DataPoint::isManual, DataPoint::getMeasurand).contains(tuple(true, new Measurand("o1"))); + } + + interface BaseNodeFieldsProjection { + String getNodeId(); + } + + + interface MeasurementProjection extends BaseNodeFieldsProjection { + Set getDataPoints(); + Set getVariables(); + } + + interface VariableProjection { + BaseNodeFieldsProjection getMeasurement(); + String getVariable(); + } + + + /** + * Defining most concrete entity + */ + @Node + @Data + @Setter(AccessLevel.PRIVATE) + @NoArgsConstructor(access = AccessLevel.PROTECTED) + @AllArgsConstructor(access = AccessLevel.PROTECTED) + @EqualsAndHashCode(callSuper = true, onlyExplicitlyIncluded = true) + @SuperBuilder(toBuilder = true) + public static class AccountingMeasurementMeta extends MeasurementMeta { + + private String formula; + + @Relationship(type = "WEIGHTS", direction = Relationship.Direction.OUTGOING) + private MeasurementMeta baseMeasurement; + } + + /** + * Defining base entity + */ + @Node + @NonFinal + @Data + @Setter(AccessLevel.PRIVATE) + @NoArgsConstructor(access = AccessLevel.PROTECTED) + @AllArgsConstructor(access = AccessLevel.PROTECTED) + @EqualsAndHashCode(onlyExplicitlyIncluded = true) + @SuperBuilder(toBuilder = true) + public static class BaseNodeEntity { + + @Id + @GeneratedValue(UUIDStringGenerator.class) + @EqualsAndHashCode.Include + private String nodeId; + } + + /** + * Target node + */ + @Node + @Value + @AllArgsConstructor + @Immutable + public static class Measurand { + + @Id + String measurandId; + } + + /** + * Defining relationship to measurand + */ + @Node + @Data + @Setter(AccessLevel.PRIVATE) + @NoArgsConstructor(access = AccessLevel.PROTECTED) + @AllArgsConstructor(access = AccessLevel.PROTECTED) + @EqualsAndHashCode(callSuper = true, onlyExplicitlyIncluded = true) + @SuperBuilder(toBuilder = true) + public static class MeasurementMeta extends BaseNodeEntity { + + @Relationship(type = "IS_MEASURED_BY", direction = Relationship.Direction.INCOMING) + private Set dataPoints; + + @Relationship(type = "USES", direction = Relationship.Direction.OUTGOING) + private Set variables; + } + + /** + * Second type of relationship + */ + @RelationshipProperties + @Value + @With + @AllArgsConstructor + @EqualsAndHashCode + @Immutable + public static class Variable { + @RelationshipId + Long id; + + @TargetNode + MeasurementMeta measurement; + + String variable; + + public static Variable create(MeasurementMeta measurement, String variable) { + return new Variable(null, measurement, variable); + } + + @Override + public String toString() { + return variable + ": " + measurement.getNodeId(); + } + } + + /** + * Relationship with properties between measurement and measurand + */ + @RelationshipProperties + @Value + @With + @AllArgsConstructor + @Immutable + @EqualsAndHashCode(onlyExplicitlyIncluded = true) + public static class DataPoint { + + @RelationshipId + Long id; + + boolean manual; + + @TargetNode + @EqualsAndHashCode.Include + Measurand measurand; + } + + interface BaseNodeRepository extends Neo4jRepository { + R findByNodeId(String nodeIds, Class clazz); + } + + @Configuration + @EnableTransactionManagement + @EnableNeo4jRepositories(considerNestedRepositories = true) + static class Config extends Neo4jImperativeTestConfiguration { + + @Bean + public BookmarkCapture bookmarkCapture() { + return new BookmarkCapture(); + } + + @Override + public PlatformTransactionManager transactionManager( + Driver driver, DatabaseSelectionProvider databaseNameProvider) { + + BookmarkCapture bookmarkCapture = bookmarkCapture(); + return new Neo4jTransactionManager(driver, databaseNameProvider, + Neo4jBookmarkManager.create(bookmarkCapture)); + } + + @Bean + public Driver driver() { + return neo4jConnectionSupport.getDriver(); + } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2530/ConcreteImplementationTwo.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2530/ConcreteImplementationTwo.java new file mode 100644 index 0000000000..6a10f95fe6 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2530/ConcreteImplementationTwo.java @@ -0,0 +1,27 @@ +/* + * Copyright 2011-2023 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.gh2530; + +import org.springframework.data.neo4j.core.schema.Node; +import org.springframework.data.neo4j.integration.issues.gh2530.domain.InitialEntities; + +/** + * The entity to get discovered later. + */ +@Node +public class ConcreteImplementationTwo extends InitialEntities.SomethingInBetween implements InitialEntities.SpecialKind { + +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2530/GH2530IT.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2530/GH2530IT.java new file mode 100644 index 0000000000..341951b5e6 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2530/GH2530IT.java @@ -0,0 +1,120 @@ +/* + * Copyright 2011-2023 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.gh2530; + +import org.assertj.core.api.SoftAssertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.neo4j.driver.Driver; +import org.neo4j.driver.Session; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.neo4j.core.DatabaseSelectionProvider; +import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager; +import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager; +import org.springframework.data.neo4j.integration.issues.gh2530.domain.InitialEntities; +import org.springframework.data.neo4j.repository.Neo4jRepository; +import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories; +import org.springframework.data.neo4j.test.BookmarkCapture; +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.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +import java.util.Collection; +import java.util.Collections; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Testing lazy added entities + */ +@Neo4jIntegrationTest +public class GH2530IT { + + protected static Neo4jExtension.Neo4jConnectionSupport neo4jConnectionSupport; + + @Autowired + SomethingInBetweenRepository repository; + + @BeforeEach + void setupData(@Autowired Driver driver, @Autowired BookmarkCapture bookmarkCapture) { + + try (Session session = driver.session()) { + session.run("MATCH (n) DETACH DELETE n").consume(); + bookmarkCapture.seedWith(session.lastBookmark()); + } + } + + @Test // GH-2530 + void shouldPutLazyFoundEntityIntoHierarchy() { + InitialEntities.ConcreteImplementationOne cc1 = new InitialEntities.ConcreteImplementationOne(); + cc1.name = "CC1"; + repository.save(cc1); + + InitialEntities.SpecialKind foundCC1 = (InitialEntities.SpecialKind) repository.findById(cc1.id).get(); + SoftAssertions softly = new SoftAssertions(); + softly.assertThat(foundCC1).as("type").isInstanceOf(InitialEntities.ConcreteImplementationOne.class); + softly.assertThat(((InitialEntities.ConcreteImplementationOne) foundCC1).name).as("CC1").isNotEmpty(); + softly.assertAll(); + + ConcreteImplementationTwo cat = new ConcreteImplementationTwo(); + repository.save(cat); + + InitialEntities.SpecialKind foundCC2 = (InitialEntities.SpecialKind) repository.findById(cat.id).get(); + assertThat(foundCC2).as("type").isInstanceOf(ConcreteImplementationTwo.class); + } + + interface SomethingInBetweenRepository extends Neo4jRepository {} + + @Configuration + @EnableTransactionManagement + @EnableNeo4jRepositories(considerNestedRepositories = true) + static class Config extends Neo4jImperativeTestConfiguration { + + @Bean + public BookmarkCapture bookmarkCapture() { + return new BookmarkCapture(); + } + + @Override + public PlatformTransactionManager transactionManager( + Driver driver, DatabaseSelectionProvider databaseNameProvider) { + + BookmarkCapture bookmarkCapture = bookmarkCapture(); + return new Neo4jTransactionManager(driver, databaseNameProvider, + Neo4jBookmarkManager.create(bookmarkCapture)); + } + + @Override + protected Collection getMappingBasePackages() { + return Collections.singleton(InitialEntities.class.getPackage().getName()); + } + + @Bean + public Driver driver() { + + return neo4jConnectionSupport.getDriver(); + } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2530/domain/InitialEntities.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2530/domain/InitialEntities.java new file mode 100644 index 0000000000..14d8df3990 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2530/domain/InitialEntities.java @@ -0,0 +1,62 @@ +/* + * Copyright 2011-2023 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.gh2530.domain; + +import org.springframework.data.neo4j.core.schema.GeneratedValue; +import org.springframework.data.neo4j.core.schema.Id; +import org.springframework.data.neo4j.core.schema.Node; + +/** + * Collection of initial entities to get registered on startup. + */ +public class InitialEntities { + + /** + * Base + */ + public static abstract class BaseEntity { + + @Id + @GeneratedValue(generatorClass = SomeStringGenerator.class) + public String id; + + } + + /** + * This is where the repository accesses the domain. + */ + @Node + public static abstract class SomethingInBetween extends BaseEntity { + public String name; + } + + /** + * Parallel node type + */ + @Node + public interface SpecialKind { + + } + + /** + * Concrete implementation registered on startup. + */ + @Node + public static class ConcreteImplementationOne extends SomethingInBetween implements SpecialKind { + + } + +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2530/domain/SomeStringGenerator.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2530/domain/SomeStringGenerator.java new file mode 100644 index 0000000000..ba1fa7aead --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2530/domain/SomeStringGenerator.java @@ -0,0 +1,31 @@ +/* + * Copyright 2011-2023 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.gh2530.domain; + +import org.springframework.data.neo4j.core.schema.IdGenerator; + +import java.util.UUID; + +/** + * Generator to mimic the reported behaviour. + */ +public class SomeStringGenerator implements IdGenerator { + + @Override + public String generateId(String primaryLabel, Object entity) { + return primaryLabel + UUID.randomUUID(); + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2533/EntitiesAndProjections.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2533/EntitiesAndProjections.java new file mode 100644 index 0000000000..2a39e1e1d4 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2533/EntitiesAndProjections.java @@ -0,0 +1,102 @@ +/* + * Copyright 2011-2023 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.gh2533; + +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; +import org.springframework.data.neo4j.core.schema.RelationshipId; +import org.springframework.data.neo4j.core.schema.RelationshipProperties; +import org.springframework.data.neo4j.core.schema.TargetNode; + +import java.util.List; +import java.util.Map; + +/** + * Collection of entities for GH2533. + */ +public class EntitiesAndProjections { + + /** + * Entity + */ + @Node + public static class GH2533Entity { + @Id + @GeneratedValue + public Long id; + + public String name; + + @Relationship + public Map> relationships; + } + + /** + * Relationship + */ + @RelationshipProperties + public static class GH2533Relationship { + @RelationshipId + public Long id; + + @TargetNode + public GH2533Entity target; + } + + /** + * Projection breaking the infinite lopp + */ + public interface GH2533EntityWithoutRelationship { + Long getId(); + + String getName(); + } + + /** + * Projection with one level of relationship + */ + public interface GH2533EntityNodeWithOneLevelLinks { + Long getId(); + + String getName(); + + Map> getRelationships(); + } + + /** + * Projection of the relationship properties + */ + public interface GH2533RelationshipWithoutTargetRelationships { + Long getId(); + + boolean isActive(); + + GH2533EntityWithoutRelationship getTarget(); + } + + /** + * Projection to entity + */ + public interface GH2533EntityWithRelationshipToEntity { + Long getId(); + + String getName(); + + Map> getRelationships(); + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2533/GH2533IT.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2533/GH2533IT.java new file mode 100644 index 0000000000..5fa3955bfc --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2533/GH2533IT.java @@ -0,0 +1,153 @@ +/* + * Copyright 2011-2023 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.gh2533; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.neo4j.driver.Driver; +import org.neo4j.driver.Session; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.neo4j.core.DatabaseSelectionProvider; +import org.springframework.data.neo4j.core.Neo4jTemplate; +import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager; +import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager; +import org.springframework.data.neo4j.repository.Neo4jRepository; +import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories; +import org.springframework.data.neo4j.repository.query.Query; +import org.springframework.data.neo4j.test.BookmarkCapture; +import org.springframework.data.neo4j.test.Neo4jExtension; +import org.springframework.data.neo4j.test.Neo4jImperativeTestConfiguration; +import org.springframework.data.neo4j.test.Neo4jIntegrationTest; +import org.springframework.data.repository.query.Param; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Test for projection with dynamic relationships. + */ +@Neo4jIntegrationTest +public class GH2533IT { + protected static Neo4jExtension.Neo4jConnectionSupport neo4jConnectionSupport; + + @Autowired + private GH2533Repository repository; + + @Autowired + private Neo4jTemplate neo4jTemplate; + + @BeforeEach + void setupData(@Autowired Driver driver, @Autowired BookmarkCapture bookmarkCapture) { + + try (Session session = driver.session()) { + session.run("MATCH (n) DETACH DELETE n").consume(); + bookmarkCapture.seedWith(session.lastBookmark()); + } + } + + @Test // GH-2533 + void projectionWorksForDynamicRelationshipsOnSave() { + EntitiesAndProjections.GH2533Entity rootEntity = createData(); + + rootEntity = repository.findByIdWithLevelOneLinks(rootEntity.id).get(); + + // this had caused the rootEntity -> child -X-> child relationship to get removed (X). + neo4jTemplate.saveAs(rootEntity, EntitiesAndProjections.GH2533EntityNodeWithOneLevelLinks.class); + + EntitiesAndProjections.GH2533Entity entity = neo4jTemplate.findById(rootEntity.id, EntitiesAndProjections.GH2533Entity.class).get(); + + assertThat(entity.relationships).isNotEmpty(); + assertThat(entity.relationships.get("has_relationship_with")).isNotEmpty(); + assertThat(entity.relationships.get("has_relationship_with").get(0).target).isNotNull(); + assertThat(entity.relationships.get("has_relationship_with").get(0).target.relationships).isNotEmpty(); + } + + @Test // GH-2533 + void saveRelatedEntityWithRelationships() { + EntitiesAndProjections.GH2533Entity rootEntity = createData(); + + neo4jTemplate.saveAs(rootEntity, EntitiesAndProjections.GH2533EntityWithRelationshipToEntity.class); + + EntitiesAndProjections.GH2533Entity entity = neo4jTemplate.findById(rootEntity.id, EntitiesAndProjections.GH2533Entity.class).get(); + + assertThat(entity.relationships.get("has_relationship_with").get(0).target.name).isEqualTo("n2"); + assertThat(entity.relationships.get("has_relationship_with").get(0).target.relationships.get("has_relationship_with").get(0).target.name).isEqualTo("n3"); + } + + private EntitiesAndProjections.GH2533Entity createData() { + EntitiesAndProjections.GH2533Entity n1 = new EntitiesAndProjections.GH2533Entity(); + EntitiesAndProjections.GH2533Entity n2 = new EntitiesAndProjections.GH2533Entity(); + EntitiesAndProjections.GH2533Entity n3 = new EntitiesAndProjections.GH2533Entity(); + + EntitiesAndProjections.GH2533Relationship r1 = new EntitiesAndProjections.GH2533Relationship(); + EntitiesAndProjections.GH2533Relationship r2 = new EntitiesAndProjections.GH2533Relationship(); + + n1.name = "n1"; + n2.name = "n2"; + n3.name = "n3"; + + r1.target = n2; + r2.target = n3; + + n1.relationships = Collections.singletonMap("has_relationship_with", Arrays.asList(r1)); + n2.relationships = Collections.singletonMap("has_relationship_with", Arrays.asList(r2)); + + return repository.save(n1); + } + + + interface GH2533Repository extends Neo4jRepository { + @Query("MATCH p=(n)-[*0..1]->(m) WHERE id(n)=$id RETURN n, collect(relationships(p)), collect(m);") + Optional findByIdWithLevelOneLinks(@Param("id") Long id); + } + + @Configuration + @EnableTransactionManagement + @EnableNeo4jRepositories(considerNestedRepositories = true) + static class Config extends Neo4jImperativeTestConfiguration { + + @Bean + public BookmarkCapture bookmarkCapture() { + return new BookmarkCapture(); + } + + @Override + public PlatformTransactionManager transactionManager( + Driver driver, DatabaseSelectionProvider databaseNameProvider) { + + BookmarkCapture bookmarkCapture = bookmarkCapture(); + return new Neo4jTransactionManager(driver, databaseNameProvider, + Neo4jBookmarkManager.create(bookmarkCapture)); + } + + @Bean + public Driver driver() { + return neo4jConnectionSupport.getDriver(); + } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2533/GH2533ReactiveIT.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2533/GH2533ReactiveIT.java new file mode 100644 index 0000000000..3f2260fe51 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2533/GH2533ReactiveIT.java @@ -0,0 +1,140 @@ +/* + * Copyright 2011-2023 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.gh2533; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.neo4j.driver.Driver; +import org.neo4j.driver.Session; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.neo4j.core.ReactiveNeo4jTemplate; +import org.springframework.data.neo4j.repository.ReactiveNeo4jRepository; +import org.springframework.data.neo4j.repository.config.EnableReactiveNeo4jRepositories; +import org.springframework.data.neo4j.repository.query.Query; +import org.springframework.data.neo4j.test.BookmarkCapture; +import org.springframework.data.neo4j.test.Neo4jExtension; +import org.springframework.data.neo4j.test.Neo4jIntegrationTest; +import org.springframework.data.neo4j.test.Neo4jReactiveTestConfiguration; +import org.springframework.data.repository.query.Param; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import java.util.Arrays; +import java.util.Collections; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Test for projection with dynamic relationships. + */ +@Neo4jIntegrationTest +public class GH2533ReactiveIT { + protected static Neo4jExtension.Neo4jConnectionSupport neo4jConnectionSupport; + + @Autowired + private ReactiveGH2533Repository repository; + + @Autowired + private ReactiveNeo4jTemplate neo4jTemplate; + + @BeforeEach + void setupData(@Autowired Driver driver, @Autowired BookmarkCapture bookmarkCapture) { + + try (Session session = driver.session()) { + session.run("MATCH (n) DETACH DELETE n").consume(); + bookmarkCapture.seedWith(session.lastBookmark()); + } + } + + @Test // GH-2533 + void projectionWorksForDynamicRelationshipsOnSave() { + createData() + .flatMap(rootEntity -> repository.findByIdWithLevelOneLinks(rootEntity.id)) + .flatMap(rootEntity -> neo4jTemplate.saveAs(rootEntity, EntitiesAndProjections.GH2533EntityNodeWithOneLevelLinks.class)) + .flatMap(rootEntity -> neo4jTemplate.findById(rootEntity.getId(), EntitiesAndProjections.GH2533Entity.class)) + .as(StepVerifier::create) + .assertNext(entity -> { + assertThat(entity.relationships).isNotEmpty(); + assertThat(entity.relationships.get("has_relationship_with")).isNotEmpty(); + assertThat(entity.relationships.get("has_relationship_with").get(0).target).isNotNull(); + assertThat(entity.relationships.get("has_relationship_with").get(0).target.relationships).isNotEmpty(); + }) + .verifyComplete(); + } + + @Test // GH-2533 + void saveRelatedEntityWithRelationships() { + createData() + .flatMap(rootEntity -> repository.findByIdWithLevelOneLinks(rootEntity.id)) + .flatMap(rootEntity -> neo4jTemplate.saveAs(rootEntity, EntitiesAndProjections.GH2533EntityNodeWithOneLevelLinks.class)) + .flatMap(rootEntity -> neo4jTemplate.findById(rootEntity.getId(), EntitiesAndProjections.GH2533Entity.class)) + .as(StepVerifier::create) + .assertNext(entity -> { + assertThat(entity.relationships.get("has_relationship_with").get(0).target.name).isEqualTo("n2"); + assertThat(entity.relationships.get("has_relationship_with").get(0).target.relationships.get("has_relationship_with").get(0).target.name).isEqualTo("n3"); + }) + .verifyComplete(); + } + + private Mono createData() { + EntitiesAndProjections.GH2533Entity n1 = new EntitiesAndProjections.GH2533Entity(); + EntitiesAndProjections.GH2533Entity n2 = new EntitiesAndProjections.GH2533Entity(); + EntitiesAndProjections.GH2533Entity n3 = new EntitiesAndProjections.GH2533Entity(); + + EntitiesAndProjections.GH2533Relationship r1 = new EntitiesAndProjections.GH2533Relationship(); + EntitiesAndProjections.GH2533Relationship r2 = new EntitiesAndProjections.GH2533Relationship(); + + n1.name = "n1"; + n2.name = "n2"; + n3.name = "n3"; + + r1.target = n2; + r2.target = n3; + + n1.relationships = Collections.singletonMap("has_relationship_with", Arrays.asList(r1)); + n2.relationships = Collections.singletonMap("has_relationship_with", Arrays.asList(r2)); + + return repository.save(n1); + } + + + interface ReactiveGH2533Repository extends ReactiveNeo4jRepository { + @Query("MATCH p=(n)-[*0..1]->(m) WHERE id(n)=$id RETURN n, collect(relationships(p)), collect(m);") + Mono findByIdWithLevelOneLinks(@Param("id") Long id); + } + + @Configuration + @EnableReactiveNeo4jRepositories(considerNestedRepositories = true) + static class Config extends Neo4jReactiveTestConfiguration { + + @Bean + public BookmarkCapture bookmarkCapture() { + return new BookmarkCapture(); + } + + @Bean + public Driver driver() { + return neo4jConnectionSupport.getDriver(); + } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2572/GH2572BaseEntity.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2572/GH2572BaseEntity.java new file mode 100644 index 0000000000..8ca408401e --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2572/GH2572BaseEntity.java @@ -0,0 +1,30 @@ +/* + * Copyright 2011-2023 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.gh2572; + +import org.springframework.data.neo4j.core.schema.GeneratedValue; +import org.springframework.data.neo4j.core.schema.Id; + +/** + * @author Michael J. Simons + * @param The concrete type + */ +abstract class GH2572BaseEntity> { + + @Id + @GeneratedValue(value = MyStrategy.class) + protected String id; +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2572/GH2572Child.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2572/GH2572Child.java new file mode 100644 index 0000000000..3c94e8b4fd --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2572/GH2572Child.java @@ -0,0 +1,39 @@ +/* + * Copyright 2011-2023 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.gh2572; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import org.springframework.data.neo4j.core.schema.Node; +import org.springframework.data.neo4j.core.schema.Relationship; + +/** + * @author Michael J. Simons + */ +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Node +public class GH2572Child extends GH2572BaseEntity { + private String name; + + @Relationship(value = "IS_PET", direction = Relationship.Direction.OUTGOING) + private GH2572Parent owner; +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2572/GH2572IT.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2572/GH2572IT.java new file mode 100644 index 0000000000..cf92473dad --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2572/GH2572IT.java @@ -0,0 +1,155 @@ +/* + * Copyright 2011-2023 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.gh2572; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.neo4j.driver.Driver; +import org.neo4j.driver.Session; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.neo4j.core.DatabaseSelectionProvider; +import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager; +import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager; +import org.springframework.data.neo4j.repository.Neo4jRepository; +import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories; +import org.springframework.data.neo4j.repository.query.Query; +import org.springframework.data.neo4j.test.BookmarkCapture; +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.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +/** + * @author Michael J. Simons + */ +@Neo4jIntegrationTest +class GH2572IT { + + protected static Neo4jExtension.Neo4jConnectionSupport neo4jConnectionSupport; + + @BeforeEach + void setupData(@Autowired Driver driver, @Autowired BookmarkCapture bookmarkCapture) { + + try (Session session = driver.session()) { + session.run("MATCH (n) DETACH DELETE n").consume(); + session.run("CREATE (p:GH2572Parent {id: 'GH2572Parent-1', name:'no-pets'})"); + session.run("CREATE (p:GH2572Parent {id: 'GH2572Parent-2', name:'one-pet'}) <-[:IS_PET]- (:GH2572Child {id: 'GH2572Child-3', name: 'a-pet'})"); + session.run("MATCH (p:GH2572Parent {id: 'GH2572Parent-2'}) CREATE (p) <-[:IS_PET]- (:GH2572Child {id: 'GH2572Child-4', name: 'another-pet'})"); + bookmarkCapture.seedWith(session.lastBookmark()); + } + } + + @Test // GH-2572 + void allShouldFetchCorrectNumberOfChildNodes(@Autowired DogRepository dogRepository) { + List dogsForPerson = dogRepository.getDogsForPerson("GH2572Parent-2"); + assertThat(dogsForPerson).hasSize(2); + } + + @Test // GH-2572 + void allShouldNotFailWithoutMatchingRootNodes(@Autowired DogRepository dogRepository) { + List dogsForPerson = dogRepository.getDogsForPerson("GH2572Parent-1"); + assertThat(dogsForPerson).isEmpty(); + } + + @Test // GH-2572 + void oneShouldFetchCorrectNumberOfChildNodes(@Autowired DogRepository dogRepository) { + Optional optionalChild = dogRepository.findOneDogForPerson("GH2572Parent-2"); + assertThat(optionalChild).map(GH2572Child::getName).hasValue("a-pet"); + } + + @Test // GH-2572 + void oneShouldNotFailWithoutMatchingRootNodes(@Autowired DogRepository dogRepository) { + Optional optionalChild = dogRepository.findOneDogForPerson("GH2572Parent-1"); + assertThat(optionalChild).isEmpty(); + } + + @Test // GH-2572 + void getOneShouldFetchCorrectNumberOfChildNodes(@Autowired DogRepository dogRepository) { + GH2572Child gh2572Child = dogRepository.getOneDogForPerson("GH2572Parent-2"); + assertThat(gh2572Child.getName()).isEqualTo("a-pet"); + } + + @Test // GH-2572 + void getOneShouldNotFailWithoutMatchingRootNodes(@Autowired DogRepository dogRepository) { + GH2572Child gh2572Child = dogRepository.getOneDogForPerson("GH2572Parent-1"); + assertThat(gh2572Child).isNull(); + } + + public interface DogRepository extends Neo4jRepository { + + @Query("MATCH(person:GH2572Parent {id: $id}) " + + "OPTIONAL MATCH (person)<-[:IS_PET]-(dog:GH2572Child) " + + "RETURN dog") + List getDogsForPerson(String id); + + @Query("MATCH(person:GH2572Parent {id: $id}) " + + "OPTIONAL MATCH (person)<-[:IS_PET]-(dog:GH2572Child) " + + "RETURN dog ORDER BY dog.name ASC LIMIT 1") + Optional findOneDogForPerson(String id); + + @Query("MATCH(person:GH2572Parent {id: $id}) " + + "OPTIONAL MATCH (person)<-[:IS_PET]-(dog:GH2572Child) " + + "RETURN dog ORDER BY dog.name ASC LIMIT 1") + GH2572Child getOneDogForPerson(String id); + } + + + @Configuration + @EnableTransactionManagement + @EnableNeo4jRepositories(considerNestedRepositories = true) + static class Config extends Neo4jImperativeTestConfiguration { + + @Bean + public BookmarkCapture bookmarkCapture() { + return new BookmarkCapture(); + } + + @Override + public PlatformTransactionManager transactionManager( + Driver driver, DatabaseSelectionProvider databaseNameProvider) { + + BookmarkCapture bookmarkCapture = bookmarkCapture(); + return new Neo4jTransactionManager(driver, databaseNameProvider, + Neo4jBookmarkManager.create(bookmarkCapture)); + } + + @Override + protected Collection getMappingBasePackages() { + return Collections.singleton(GH2572BaseEntity.class.getPackage().getName()); + } + + @Bean + public Driver driver() { + + return neo4jConnectionSupport.getDriver(); + } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2572/GH2572Parent.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2572/GH2572Parent.java new file mode 100644 index 0000000000..4b8b653a5e --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2572/GH2572Parent.java @@ -0,0 +1,38 @@ +/* + * Copyright 2011-2023 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.gh2572; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import org.springframework.data.neo4j.core.schema.Node; + +/** + * @author Michael J. Simons + */ +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Node +public class GH2572Parent extends GH2572BaseEntity { + + private String name; + + private int age; +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2572/GH2572ReactiveIT.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2572/GH2572ReactiveIT.java new file mode 100644 index 0000000000..3adc124e58 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2572/GH2572ReactiveIT.java @@ -0,0 +1,148 @@ +/* + * Copyright 2011-2023 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.gh2572; + +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import java.util.Collection; +import java.util.Collections; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.neo4j.driver.Driver; +import org.neo4j.driver.Session; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.neo4j.core.ReactiveDatabaseSelectionProvider; +import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager; +import org.springframework.data.neo4j.core.transaction.ReactiveNeo4jTransactionManager; +import org.springframework.data.neo4j.repository.ReactiveNeo4jRepository; +import org.springframework.data.neo4j.repository.config.EnableReactiveNeo4jRepositories; +import org.springframework.data.neo4j.repository.query.Query; +import org.springframework.data.neo4j.test.BookmarkCapture; +import org.springframework.data.neo4j.test.Neo4jExtension; +import org.springframework.data.neo4j.test.Neo4jIntegrationTest; +import org.springframework.data.neo4j.test.Neo4jReactiveTestConfiguration; +import org.springframework.transaction.ReactiveTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +/** + * @author Michael J. Simons + */ +@Neo4jIntegrationTest +class GH2572ReactiveIT { + + protected static Neo4jExtension.Neo4jConnectionSupport neo4jConnectionSupport; + + @BeforeEach + void setupData(@Autowired Driver driver, @Autowired BookmarkCapture bookmarkCapture) { + + try (Session session = driver.session()) { + session.run("MATCH (n) DETACH DELETE n").consume(); + session.run("CREATE (p:GH2572Parent {id: 'GH2572Parent-1', name:'no-pets'})"); + session.run( + "CREATE (p:GH2572Parent {id: 'GH2572Parent-2', name:'one-pet'}) <-[:IS_PET]- (:GH2572Child {id: 'GH2572Child-3', name: 'a-pet'})"); + session.run( + "MATCH (p:GH2572Parent {id: 'GH2572Parent-2'}) CREATE (p) <-[:IS_PET]- (:GH2572Child {id: 'GH2572Child-4', name: 'another-pet'})"); + bookmarkCapture.seedWith(session.lastBookmark()); + } + } + + @Test // GH-2572 + void allShouldFetchCorrectNumberOfChildNodes(@Autowired DogRepository dogRepository) { + dogRepository.getDogsForPerson("GH2572Parent-2") + .as(StepVerifier::create) + .expectNextCount(2L) + .verifyComplete(); + } + + @Test // GH-2572 + void allShouldNotFailWithoutMatchingRootNodes(@Autowired DogRepository dogRepository) { + dogRepository.getDogsForPerson("GH2572Parent-1") + .as(StepVerifier::create) + .expectNextCount(0L) + .verifyComplete(); + } + + @Test // GH-2572 + void oneShouldFetchCorrectNumberOfChildNodes(@Autowired DogRepository dogRepository) { + dogRepository.findOneDogForPerson("GH2572Parent-2") + .map(GH2572Child::getName) + .as(StepVerifier::create) + .expectNext("a-pet") + .verifyComplete(); + } + + @Test // GH-2572 + void oneShouldNotFailWithoutMatchingRootNodes(@Autowired DogRepository dogRepository) { + dogRepository.findOneDogForPerson("GH2572Parent-1") + .as(StepVerifier::create) + .expectNextCount(0L) + .verifyComplete(); + } + + public interface DogRepository extends ReactiveNeo4jRepository { + + @Query("MATCH(person:GH2572Parent {id: $id}) " + + "OPTIONAL MATCH (person)<-[:IS_PET]-(dog:GH2572Child) " + + "RETURN dog") + Flux getDogsForPerson(String id); + + @Query("MATCH(person:GH2572Parent {id: $id}) " + + "OPTIONAL MATCH (person)<-[:IS_PET]-(dog:GH2572Child) " + + "RETURN dog ORDER BY dog.name ASC LIMIT 1") + Mono findOneDogForPerson(String id); + } + + @Configuration + @EnableTransactionManagement + @EnableReactiveNeo4jRepositories(considerNestedRepositories = true) + static class Config extends Neo4jReactiveTestConfiguration { + + @Bean + public BookmarkCapture bookmarkCapture() { + return new BookmarkCapture(); + } + + @Override + public ReactiveTransactionManager reactiveTransactionManager(Driver driver, + ReactiveDatabaseSelectionProvider databaseSelectionProvider) { + + BookmarkCapture bookmarkCapture = bookmarkCapture(); + return new ReactiveNeo4jTransactionManager(driver, databaseSelectionProvider, + Neo4jBookmarkManager.create(bookmarkCapture)); + } + + @Override + protected Collection getMappingBasePackages() { + return Collections.singleton(GH2572BaseEntity.class.getPackage().getName()); + } + + @Bean + public Driver driver() { + + return neo4jConnectionSupport.getDriver(); + } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2572/MyStrategy.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2572/MyStrategy.java new file mode 100644 index 0000000000..79a5cfc80c --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2572/MyStrategy.java @@ -0,0 +1,35 @@ +/* + * Copyright 2011-2023 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.gh2572; + +import java.util.concurrent.atomic.AtomicInteger; + +import org.springframework.data.neo4j.core.schema.IdGenerator; + +/** + * Not actually needed during the test, but added to recreate the issue scenario as much as possible. + * + * @author Michael J. Simons + */ +public final class MyStrategy implements IdGenerator { + + private final AtomicInteger sequence = new AtomicInteger(10); + + @Override + public String generateId(String primaryLabel, Object entity) { + return primaryLabel + sequence.incrementAndGet(); + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2576/College.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2576/College.java new file mode 100644 index 0000000000..c2a879a5a0 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2576/College.java @@ -0,0 +1,49 @@ +/* + * Copyright 2011-2023 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.gh2576; + +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.support.UUIDStringGenerator; + +/** + * @author Michael J. Simons + */ +@Node +public class College { + + @Id @GeneratedValue(UUIDStringGenerator.class) + private String guid; + + private String name; + + public College(String name) { + this.name = name; + } + + public String getGuid() { + return guid; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2576/CollegeRepository.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2576/CollegeRepository.java new file mode 100644 index 0000000000..01a9816af9 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2576/CollegeRepository.java @@ -0,0 +1,45 @@ +/* + * Copyright 2011-2023 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.gh2576; + +import java.util.List; +import java.util.Map; + +import org.neo4j.driver.Value; +import org.springframework.data.neo4j.repository.Neo4jRepository; +import org.springframework.data.neo4j.repository.query.Query; + +/** + * @author Michael J. Simons + */ +public interface CollegeRepository extends Neo4jRepository { + + @Query("" + + "UNWIND $0 AS row\n" + + "MATCH (student:Student{guid:row.stuGuid})\n" + + "MATCH (college:College{guid:row.collegeGuid})\n" + + "CREATE (student)<-[:STUDENT_OF]-(college) RETURN student.guid" + ) + List addStudentToCollege(List> list); + + @Query("" + + "UNWIND $0 AS row\n" + + "MATCH (student:Student{guid:row.stuGuid})\n" + + "MATCH (college:College{guid:row.collegeGuid})\n" + + "CREATE (student)<-[:STUDENT_OF]-(college) RETURN student.guid" + ) + List addStudentToCollegeWorkaround(List list); +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2576/GH2576IT.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2576/GH2576IT.java new file mode 100644 index 0000000000..e250b38898 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2576/GH2576IT.java @@ -0,0 +1,123 @@ +/* + * Copyright 2011-2023 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.gh2576; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.neo4j.driver.Driver; +import org.neo4j.driver.Value; +import org.neo4j.driver.Values; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.neo4j.core.DatabaseSelectionProvider; +import org.springframework.data.neo4j.core.Neo4jTemplate; +import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager; +import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager; +import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories; +import org.springframework.data.neo4j.test.BookmarkCapture; +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.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +/** + * @author Michael J. Simons + */ +@Neo4jIntegrationTest +class GH2576IT { + + protected static Neo4jExtension.Neo4jConnectionSupport neo4jConnectionSupport; + + @Test + @Tag("GH-2576") + void listOfMapsShouldBeUsableAsArguments(@Autowired Neo4jTemplate template, + @Autowired CollegeRepository collegeRepository) { + + Student student = template.save(new Student("S1")); + College college = template.save(new College("C1")); + + Map pair = new HashMap<>(); + pair.put("stuGuid", student.getGuid()); + pair.put("collegeGuid", college.getGuid()); + List> listOfPairs = Collections.singletonList(pair); + + List uuids = collegeRepository.addStudentToCollege(listOfPairs); + assertThat(uuids).containsExactly(student.getGuid()); + } + + @Test + @Tag("GH-2576") + void listOfMapsShouldBeUsableAsArgumentsWithWorkaround(@Autowired Neo4jTemplate template, + @Autowired CollegeRepository collegeRepository) { + + Student student = template.save(new Student("S1")); + College college = template.save(new College("C1")); + + Map pair = new HashMap<>(); + pair.put("stuGuid", student.getGuid()); + pair.put("collegeGuid", college.getGuid()); + List listOfPairs = Collections.singletonList(Values.value(pair)); + + List uuids = collegeRepository.addStudentToCollegeWorkaround(listOfPairs); + assertThat(uuids).containsExactly(student.getGuid()); + } + + @Configuration + @EnableTransactionManagement + @EnableNeo4jRepositories(considerNestedRepositories = true) + static class Config extends Neo4jImperativeTestConfiguration { + + @Bean + public BookmarkCapture bookmarkCapture() { + return new BookmarkCapture(); + } + + @Override + public PlatformTransactionManager transactionManager( + Driver driver, DatabaseSelectionProvider databaseNameProvider) { + + BookmarkCapture bookmarkCapture = bookmarkCapture(); + return new Neo4jTransactionManager(driver, databaseNameProvider, + Neo4jBookmarkManager.create(bookmarkCapture)); + } + + @Override + protected Collection getMappingBasePackages() { + return Collections.singleton(Student.class.getPackage().getName()); + } + + @Bean + public Driver driver() { + + return neo4jConnectionSupport.getDriver(); + } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2576/Student.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2576/Student.java new file mode 100644 index 0000000000..3514b6dada --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2576/Student.java @@ -0,0 +1,61 @@ +/* + * Copyright 2011-2023 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.gh2576; + +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; +import org.springframework.data.neo4j.core.support.UUIDStringGenerator; + +/** + * @author Michael J. Simons + */ +@Node +public class Student { + + @Id @GeneratedValue(UUIDStringGenerator.class) + private String guid; + + private String name; + + @Relationship(type = "STUDENT_OF", direction = Relationship.Direction.OUTGOING) + private College college; + + public Student(String name) { + this.name = name; + } + + public String getGuid() { + return guid; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public College getCollege() { + return college; + } + + public void setCollege(College college) { + this.college = college; + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2579/ColumnNode.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2579/ColumnNode.java new file mode 100644 index 0000000000..76ef35722c --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2579/ColumnNode.java @@ -0,0 +1,42 @@ +/* + * Copyright 2011-2023 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.gh2579; + +import lombok.Data; + +import org.springframework.data.neo4j.core.schema.GeneratedValue; +import org.springframework.data.neo4j.core.schema.Id; +import org.springframework.data.neo4j.core.schema.Node; + +/** + * @author Michael J. Simons + */ +@Data +@Node("Column") +public class ColumnNode { + + @Id + @GeneratedValue + private Long id; + + private String sourceName; + + private String schemaName; + + private String tableName; + + private String name; +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2579/GH2579IT.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2579/GH2579IT.java new file mode 100644 index 0000000000..cba37f6bb2 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2579/GH2579IT.java @@ -0,0 +1,134 @@ +/* + * Copyright 2011-2023 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.gh2579; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Optional; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.neo4j.driver.Driver; +import org.neo4j.driver.Session; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.neo4j.core.DatabaseSelectionProvider; +import org.springframework.data.neo4j.core.Neo4jTemplate; +import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager; +import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager; +import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories; +import org.springframework.data.neo4j.test.BookmarkCapture; +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.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +/** + * @author Michael J. Simons + */ +@Neo4jIntegrationTest +class GH2579IT { + + protected static Neo4jExtension.Neo4jConnectionSupport neo4jConnectionSupport; + + @BeforeEach + void setupData(@Autowired Driver driver, @Autowired BookmarkCapture bookmarkCapture) { + + try (Session session = driver.session()) { + session.run("MATCH (n) DETACH DELETE n").consume(); + bookmarkCapture.seedWith(session.lastBookmark()); + } + } + + @Test + @Tag("GH-2579") + void unwindWithMergeShouldWork(@Autowired Neo4jTemplate template, @Autowired TableRepository tableRepository) { + + TableNode tableNode = new TableNode(); + tableNode.setName("t1"); + tableNode.setSchemaName("a"); + tableNode.setSourceName("source1"); + tableNode = template.save(tableNode); + + ColumnNode c1 = new ColumnNode(); + c1.setName("c1"); + c1.setSchemaName("a"); + c1.setSourceName("source1"); + c1.setTableName(tableNode.getName()); + long c1Id = template.save(c1).getId(); + + ColumnNode c2 = new ColumnNode(); + c2.setName("c2"); + c2.setSchemaName("a"); + c2.setSourceName("source2"); + c2.setTableName(tableNode.getName()); + long c2Id = template.save(c2).getId(); + + tableRepository.mergeTableAndColumnRelations(Arrays.asList(c1, c2), tableNode); + + Optional resolvedTableNode = tableRepository.findById(tableNode.getId()); + assertThat(resolvedTableNode) + .map(TableNode::getTableAndColumnRelation) + .hasValueSatisfying(l -> { + assertThat(l) + .map(TableAndColumnRelation::getColumnNode) + .map(ColumnNode::getId) + .containsExactlyInAnyOrder(c1Id, c2Id); + }); + } + + @Configuration + @EnableTransactionManagement + @EnableNeo4jRepositories(considerNestedRepositories = true) + static class Config extends Neo4jImperativeTestConfiguration { + + @Bean + public BookmarkCapture bookmarkCapture() { + return new BookmarkCapture(); + } + + @Override + public PlatformTransactionManager transactionManager( + Driver driver, DatabaseSelectionProvider databaseNameProvider) { + + BookmarkCapture bookmarkCapture = bookmarkCapture(); + return new Neo4jTransactionManager(driver, databaseNameProvider, + Neo4jBookmarkManager.create(bookmarkCapture)); + } + + @Override + protected Collection getMappingBasePackages() { + return Collections.singleton(TableNode.class.getPackage().getName()); + } + + @Bean + public Driver driver() { + + return neo4jConnectionSupport.getDriver(); + } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2579/TableAndColumnRelation.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2579/TableAndColumnRelation.java new file mode 100644 index 0000000000..8612bbe6f2 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2579/TableAndColumnRelation.java @@ -0,0 +1,36 @@ +/* + * Copyright 2011-2023 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.gh2579; + +import lombok.Data; + +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 Michael J. Simons + */ +@Data +@RelationshipProperties +public class TableAndColumnRelation { + + @RelationshipId + private Long id; + + @TargetNode + private ColumnNode columnNode; +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2579/TableNode.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2579/TableNode.java new file mode 100644 index 0000000000..ee095f2c36 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2579/TableNode.java @@ -0,0 +1,48 @@ +/* + * Copyright 2011-2023 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.gh2579; + +import lombok.Data; + +import java.util.List; + +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 + */ +@Data +@Node("Table") +public class TableNode { + + @Id + @GeneratedValue + private Long id; + + private String sourceName; + + private String schemaName; + + private String name; + + private String tableComment; + + @Relationship(type = "BELONG", direction = Relationship.Direction.INCOMING) + private List tableAndColumnRelation; +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2579/TableRepository.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2579/TableRepository.java new file mode 100644 index 0000000000..4fc43abf31 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2579/TableRepository.java @@ -0,0 +1,41 @@ +/* + * Copyright 2011-2023 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.gh2579; + +import java.util.List; + +import org.springframework.data.neo4j.repository.Neo4jRepository; +import org.springframework.data.neo4j.repository.query.Query; +import org.springframework.data.repository.query.Param; + +/** + * @author Michael J. Simons + */ +public interface TableRepository extends Neo4jRepository { + + @Query(value = + "UNWIND :#{#froms} AS col " + + "WITH col.__properties__ AS col, :#{#to}.__properties__ AS to " + + "MERGE (c:Column { sourceName : col.sourceName, " + + "schemaName : col.schemaName, " + + "tableName : col.tableName, " + + "name : col.name }) " + + "MERGE (t:Table {sourceName : to.sourceName, " + + "schemaName : to.schemaName, " + + "name : to.name }) " + + "MERGE (c) -[r:BELONG]-> (t) ") + void mergeTableAndColumnRelations(@Param("froms") List froms, @Param("to") TableNode to); +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2583/GH2583IT.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2583/GH2583IT.java new file mode 100644 index 0000000000..ba70b8dcab --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2583/GH2583IT.java @@ -0,0 +1,116 @@ +/* + * Copyright 2011-2023 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.gh2583; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.neo4j.driver.Driver; +import org.neo4j.driver.Session; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.neo4j.core.DatabaseSelectionProvider; +import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager; +import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager; +import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories; +import org.springframework.data.neo4j.test.BookmarkCapture; +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.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Integration test to ensure that also backward updated through the result set work without + * running into a StackOverflowError. + */ +@Neo4jIntegrationTest +public class GH2583IT { + + protected static Neo4jExtension.Neo4jConnectionSupport neo4jConnectionSupport; + + @BeforeEach + void setupData(@Autowired Driver driver, @Autowired BookmarkCapture bookmarkCapture) { + + try (Session session = driver.session(bookmarkCapture.createSessionConfig())) { + session.run("MATCH (n) DETACH DELETE n").consume(); + session.run("CREATE (n:GH2583Node)-[:LINKED]->(m:GH2583Node)-[:LINKED]->(n)-[:LINKED]->(m)" + + "-[:LINKED]->(n)-[:LINKED]->(m)-[:LINKED]->(n)-[:LINKED]->(m)" + + "-[:LINKED]->(n)-[:LINKED]->(m)-[:LINKED]->(n)-[:LINKED]->(m)" + + "-[:LINKED]->(n)-[:LINKED]->(m)-[:LINKED]->(n)-[:LINKED]->(m)" + + "-[:LINKED]->(n)-[:LINKED]->(m)-[:LINKED]->(n)-[:LINKED]->(m)" + + "-[:LINKED]->(n)-[:LINKED]->(m)-[:LINKED]->(n)-[:LINKED]->(m)" + + "-[:LINKED]->(n)-[:LINKED]->(m)-[:LINKED]->(n)-[:LINKED]->(m)" + + "-[:LINKED]->(n)-[:LINKED]->(m)-[:LINKED]->(n)-[:LINKED]->(m)" + + "-[:LINKED]->(n)-[:LINKED]->(m)-[:LINKED]->(n)-[:LINKED]->(m)" + + "-[:LINKED]->(n)-[:LINKED]->(m)-[:LINKED]->(n)-[:LINKED]->(m)" + + "-[:LINKED]->(n)-[:LINKED]->(m)-[:LINKED]->(n)-[:LINKED]->(m)").consume(); + bookmarkCapture.seedWith(session.lastBookmark()); + } + } + + @Test + void mapStandardCustomQueryWithLotsOfRelationshipsProperly(@Autowired GH2583Repository repository) { + Page nodePage = repository.getNodesByCustomQuery(PageRequest.of(0, 300)); + + List nodes = nodePage.getContent(); + assertThat(nodes).hasSize(2); + } + + @Configuration + @EnableTransactionManagement + @EnableNeo4jRepositories(considerNestedRepositories = true) + static class Config extends Neo4jImperativeTestConfiguration { + + @Bean + public BookmarkCapture bookmarkCapture() { + return new BookmarkCapture(); + } + + @Override + public PlatformTransactionManager transactionManager( + Driver driver, DatabaseSelectionProvider databaseNameProvider) { + + BookmarkCapture bookmarkCapture = bookmarkCapture(); + return new Neo4jTransactionManager(driver, databaseNameProvider, + Neo4jBookmarkManager.create(bookmarkCapture)); + } + + @Override + protected Collection getMappingBasePackages() { + return Collections.singleton(GH2583Node.class.getPackage().getName()); + } + + @Bean + public Driver driver() { + + return neo4jConnectionSupport.getDriver(); + } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2583/GH2583Node.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2583/GH2583Node.java new file mode 100644 index 0000000000..684e60044c --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2583/GH2583Node.java @@ -0,0 +1,39 @@ +/* + * Copyright 2011-2023 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.gh2583; + +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; + +import java.util.List; + +/** + * A simple node with bidirectional relationship mapping to the very same type. + */ +@Node +public class GH2583Node { + @Id + @GeneratedValue + Long id; + + @Relationship(type = "LINKED", direction = Relationship.Direction.OUTGOING) + public List outgoingNodes; + + @Relationship(type = "LINKED", direction = Relationship.Direction.INCOMING) + public List incomingNodes; +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2583/GH2583Repository.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2583/GH2583Repository.java new file mode 100644 index 0000000000..94fe358323 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2583/GH2583Repository.java @@ -0,0 +1,31 @@ +/* + * Copyright 2011-2023 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.gh2583; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.neo4j.repository.Neo4jRepository; +import org.springframework.data.neo4j.repository.query.Query; + +interface GH2583Repository extends Neo4jRepository { + + @Query(value = "MATCH (s:GH2583Node) " + + "WITH s OPTIONAL MATCH (s)-[r:LINKED]->(t:GH2583Node) " + + "RETURN s, collect(r), collect(t) " + + ":#{orderBy(#pageable)} SKIP $skip LIMIT $limit", + countQuery = "MATCH (s:hktxjm) RETURN count(s)") + Page getNodesByCustomQuery(Pageable pageable); +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2632/Movie.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2632/Movie.java new file mode 100644 index 0000000000..ab6f814dd3 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2632/Movie.java @@ -0,0 +1,46 @@ +/* + * Copyright 2011-2023 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.gh2632; + +import java.util.UUID; + +import org.springframework.data.neo4j.core.schema.GeneratedValue; +import org.springframework.data.neo4j.core.schema.Id; +import org.springframework.data.neo4j.core.schema.Node; + +/** + * @author Michael J. Simons + */ +@Node +public class Movie { + + @Id @GeneratedValue + private UUID id; + + private String title; + + public UUID getId() { + return id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2632/MovieRepository.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2632/MovieRepository.java new file mode 100644 index 0000000000..428474d026 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2632/MovieRepository.java @@ -0,0 +1,26 @@ +/* + * Copyright 2011-2023 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.gh2632; + +import java.util.UUID; + +import org.springframework.data.neo4j.repository.ReactiveNeo4jRepository; + +/** + * @author Michael J. Simons + */ +public interface MovieRepository extends ReactiveNeo4jRepository { +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2632/ReactiveConnectionAcquisitionIT.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2632/ReactiveConnectionAcquisitionIT.java new file mode 100644 index 0000000000..9b56334866 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2632/ReactiveConnectionAcquisitionIT.java @@ -0,0 +1,152 @@ +/* + * Copyright 2011-2023 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.gh2632; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Collections; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +import org.junit.jupiter.api.Test; +import org.neo4j.driver.Driver; +import org.neo4j.driver.GraphDatabase; +import org.neo4j.driver.Query; +import org.neo4j.driver.Session; +import org.neo4j.driver.reactive.RxResult; +import org.neo4j.driver.reactive.RxSession; +import org.neo4j.driver.reactive.RxTransaction; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.neo4j.config.AbstractReactiveNeo4jConfig; +import org.springframework.data.neo4j.repository.config.EnableReactiveNeo4jRepositories; +import org.springframework.data.neo4j.test.Neo4jExtension; +import org.springframework.data.neo4j.test.Neo4jIntegrationTest; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +/** + * @author Michael J. Simons + */ +@Neo4jIntegrationTest +class ReactiveConnectionAcquisitionIT { + + protected static Neo4jExtension.Neo4jConnectionSupport neo4jConnectionSupport; + + @Test // GH-2632 + void connectionAcquisitionAfterErrorViaSDNTxManagerShouldWork(@Autowired MovieRepository movieRepository, @Autowired Driver driver) { + UUID id = UUID.randomUUID(); + Flux + .range(1, 5) + .flatMap( + i -> movieRepository + .findById(id) + .switchIfEmpty(Mono.error(new RuntimeException())) + ) + .then() + .as(StepVerifier::create) + .verifyError(); + + try (Session session = driver.session()) { + long aNumber = session.run("RETURN 1").single().get(0).asLong(); + assertThat(aNumber).isOne(); + } + } + + @Test // GH-2632 + void connectionAcquisitionAfterErrorViaImplicitTXShouldWork(@Autowired Driver driver) { + Flux + .range(1, 5) + .flatMap( + i -> { + Query query = new Query("MATCH (p:Product) WHERE p.id = $id RETURN p.title", Collections.singletonMap("id", 0)); + return Flux.usingWhen( + Mono.fromSupplier(driver::rxSession), + session -> Mono.fromSupplier(() -> session.run(query)) + .flatMapMany(result -> Flux.from(result.records())) + .map(record -> record.get(0).asString()), + session -> Mono.fromDirect(session.close())) + .switchIfEmpty(Mono.error(new RuntimeException())); + } + ) + .then() + .as(StepVerifier::create) + .verifyError(); + + try (Session session = driver.session()) { + long aNumber = session.run("RETURN 1").single().get(0).asLong(); + assertThat(aNumber).isOne(); + } + } + + private static class SessionAndTx { + RxSession session; + RxTransaction tx; + + SessionAndTx(RxSession session, RxTransaction tx) { + this.session = session; + this.tx = tx; + } + } + + @Test // GH-2632 + void connectionAcquisitionAfterErrorViaExplicitTXShouldWork(@Autowired Driver driver) { + Flux + .range(1, 5) + .flatMap( + i -> { + Mono f = Mono + .just(driver.rxSession()) + .flatMap(s -> Mono.fromDirect(s.beginTransaction()).map(tx -> new SessionAndTx(s, tx))); + return Flux.usingWhen(f, + h -> Mono.fromSupplier(() -> h.tx.run("MATCH (n) WHERE false = true RETURN n")).flatMapMany(RxResult::records), + h -> Mono.from(h.tx.commit()).then(Mono.from(h.session.close())), + (h, e) -> Mono.from(h.tx.rollback()).then(Mono.from(h.session.close())), + h -> Mono.from(h.tx.rollback()).then(Mono.from(h.session.close())) + ).switchIfEmpty(Mono.error(new RuntimeException())); + } + ) + .then() + .as(StepVerifier::create) + .verifyError(); + + try (Session session = driver.session()) { + long aNumber = session.run("RETURN 1").single().get(0).asLong(); + assertThat(aNumber).isOne(); + } + } + + @Configuration + @EnableTransactionManagement + @EnableReactiveNeo4jRepositories(considerNestedRepositories = true) + static class Config extends AbstractReactiveNeo4jConfig { + + @Bean + public Driver driver() { + org.neo4j.driver.Config config = org.neo4j.driver.Config.builder() + .withMaxConnectionPoolSize(2) + .withConnectionAcquisitionTimeout(20, TimeUnit.SECONDS) + .withLeakedSessionsLogging() + .build(); + return + GraphDatabase.driver(neo4jConnectionSupport.url, neo4jConnectionSupport.authToken, config); + } + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2639/Company.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2639/Company.java new file mode 100644 index 0000000000..cf5390ae72 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2639/Company.java @@ -0,0 +1,62 @@ +/* + * Copyright 2011-2023 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.gh2639; + +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; + +import java.util.List; +import java.util.StringJoiner; + +/** + * Root node + */ +@Node +public class Company { + + @Id + @GeneratedValue + private Long id; + + private final String name; + @Relationship(type = "EMPLOYEE") + private final List employees; + + + public Company(String name, List employees) { + this.name = name; + this.employees = employees; + } + + public void addEmployee(Person person) { + employees.add(person); + } + + public List getEmployees() { + return employees; + } + + @Override + public String toString() { + return new StringJoiner(", ", Company.class.getSimpleName() + "[", "]") + .add("id=" + id) + .add("name='" + name + "'") + .add("employees=" + employees) + .toString(); + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2639/CompanyRepository.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2639/CompanyRepository.java new file mode 100644 index 0000000000..a93b56b5bb --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2639/CompanyRepository.java @@ -0,0 +1,27 @@ +/* + * Copyright 2011-2023 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.gh2639; + +import org.springframework.data.neo4j.repository.Neo4jRepository; + +/** + * Fetch the root node by name. + */ +public interface CompanyRepository extends Neo4jRepository { + + Company findByName(String name); + +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2639/Developer.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2639/Developer.java new file mode 100644 index 0000000000..e1c6c3089e --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2639/Developer.java @@ -0,0 +1,53 @@ +/* + * Copyright 2011-2023 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.gh2639; + +import org.springframework.data.neo4j.core.schema.Node; + +import java.util.List; +import java.util.StringJoiner; + +/** + * Developer holds the specific relationship we are trying to map + * in this test case. + */ +@Node +public class Developer extends Person { + + private final List programmingLanguages; + private final String name; + + public Developer(String name, List programmingLanguages) { + this.name = name; + this.programmingLanguages = programmingLanguages; + } + + public List getProgrammingLanguages() { + return programmingLanguages; + } + + public String getName() { + return name; + } + + @Override + public String toString() { + return new StringJoiner(", ", Developer.class.getSimpleName() + "[", "]") + .add("name='" + name + "'") + .add("programmingLanguages=" + programmingLanguages) + .toString(); + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2639/Enterprise.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2639/Enterprise.java new file mode 100644 index 0000000000..f2bacc3dd2 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2639/Enterprise.java @@ -0,0 +1,51 @@ +/* + * Copyright 2011-2023 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.gh2639; + +import org.springframework.data.neo4j.core.schema.Node; + +import java.util.Objects; + +/** + * @author Gerrit Meier + */ +@Node +public class Enterprise extends Inventor { + + final String someEnterpriseProperty; + + public Enterprise(String name, String someEnterpriseProperty) { + super(name); + this.someEnterpriseProperty = someEnterpriseProperty; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Enterprise that = (Enterprise) o; + return someEnterpriseProperty.equals(that.someEnterpriseProperty); + } + + @Override + public int hashCode() { + return Objects.hash(someEnterpriseProperty); + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2639/Gh2639IT.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2639/Gh2639IT.java new file mode 100644 index 0000000000..c08a0178bc --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2639/Gh2639IT.java @@ -0,0 +1,145 @@ +/* + * Copyright 2011-2023 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.gh2639; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.neo4j.driver.Driver; +import org.neo4j.driver.Session; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.neo4j.core.DatabaseSelectionProvider; +import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager; +import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager; +import org.springframework.data.neo4j.repository.Neo4jRepository; +import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories; +import org.springframework.data.neo4j.test.BookmarkCapture; +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.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Test to verify that relationships within generic entity based relationships work. + * + * @author Gerrit Meier + */ +@Neo4jIntegrationTest +public class Gh2639IT { + + protected static Neo4jExtension.Neo4jConnectionSupport neo4jConnectionSupport; + + @BeforeAll + static void setup(@Autowired Driver driver, @Autowired BookmarkCapture bookmarkCapture) { + try (Session session = driver.session(bookmarkCapture.createSessionConfig())) { + session.run("MATCH (n) detach delete n").consume(); + bookmarkCapture.seedWith(session.lastBookmark()); + } + } + + @Test + void relationshipsOfGenericRelationshipsGetResolvedCorrectly(@Autowired CompanyRepository companyRepository) { + Person greg = new Sales("Greg"); + Person roy = new Sales("Roy"); + Person craig = new Sales("Craig"); + + Language java = new Language("java", "1.5"); + java.inventor = new Enterprise("Sun", ";("); + Language perl = new Language("perl", "6.0"); + perl.inventor = new Individual("Larry Wall", "larryW"); + + List languageRelationships = new ArrayList<>(); + LanguageRelationship javaRelationship = new LanguageRelationship(5, java); + LanguageRelationship perlRelationship = new LanguageRelationship(2, perl); + languageRelationships.add(javaRelationship); + languageRelationships.add(perlRelationship); + + Developer harry = new Developer("Harry", languageRelationships); + List team = Arrays.asList(greg, roy, craig, harry); + Company acme = new Company("ACME", team); + companyRepository.save(acme); + + Company loadedAcme = companyRepository.findByName("ACME"); + + Developer loadedHarry = loadedAcme.getEmployees().stream() + .filter(e -> e instanceof Developer) + .map(e -> (Developer) e) + .filter(developer -> developer.getName().equals("Harry")) + .findFirst().get(); + + List programmingLanguages = loadedHarry.getProgrammingLanguages(); + assertThat(programmingLanguages) + .isNotEmpty() + .extracting("score") + .containsExactlyInAnyOrder(5, 2); + + assertThat(programmingLanguages) + .extracting("language") + .extracting("inventor") + .containsExactlyInAnyOrder( + new Individual("Larry Wall", "larryW"), new Enterprise("Sun", ";(") + ); + } + + interface CompanyRepository extends Neo4jRepository { + Company findByName(String name); + } + + @Configuration + @EnableTransactionManagement + @EnableNeo4jRepositories(considerNestedRepositories = true) + static class Config extends Neo4jImperativeTestConfiguration { + + @Bean + public BookmarkCapture bookmarkCapture() { + return new BookmarkCapture(); + } + + @Override + public PlatformTransactionManager transactionManager( + Driver driver, DatabaseSelectionProvider databaseNameProvider) { + + BookmarkCapture bookmarkCapture = bookmarkCapture(); + return new Neo4jTransactionManager(driver, databaseNameProvider, + Neo4jBookmarkManager.create(bookmarkCapture)); + } + + @Override + protected Collection getMappingBasePackages() { + return Collections.singleton(Company.class.getPackage().getName()); + } + + @Bean + public Driver driver() { + return neo4jConnectionSupport.getDriver(); + } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2639/Individual.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2639/Individual.java new file mode 100644 index 0000000000..89e2d63628 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2639/Individual.java @@ -0,0 +1,51 @@ +/* + * Copyright 2011-2023 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.gh2639; + +import org.springframework.data.neo4j.core.schema.Node; + +import java.util.Objects; + +/** + * @author Gerrit Meier + */ +@Node +public class Individual extends Inventor { + + final String username; + + public Individual(String name, String username) { + super(name); + this.username = username; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Individual that = (Individual) o; + return username.equals(that.username); + } + + @Override + public int hashCode() { + return Objects.hash(username); + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2639/Inventor.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2639/Inventor.java new file mode 100644 index 0000000000..3ebd15fc22 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2639/Inventor.java @@ -0,0 +1,33 @@ +/* + * Copyright 2011-2023 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.gh2639; + +import org.springframework.data.neo4j.core.schema.Id; +import org.springframework.data.neo4j.core.schema.Node; + +/** + * @author Gerrit Meier + */ +@Node +public abstract class Inventor { + + @Id + final String name; + + public Inventor(String name) { + this.name = name; + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2639/Language.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2639/Language.java new file mode 100644 index 0000000000..62597e9347 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2639/Language.java @@ -0,0 +1,62 @@ +/* + * Copyright 2011-2023 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.gh2639; + +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; + +import java.util.StringJoiner; + +/** + * Programming language to represent. + * Only available at the Developer entity. + */ +@Node +public class Language { + + @Id + @GeneratedValue + private Long id; + private final String name; + private final String version; + + @Relationship("INVENTED_BY") + Inventor inventor; + + public Language(String name, String version) { + this.name = name; + this.version = version; + } + + public String getName() { + return name; + } + + public String getVersion() { + return version; + } + + @Override + public String toString() { + return new StringJoiner(", ", Language.class.getSimpleName() + "[", "]") + .add("id=" + id) + .add("name='" + name + "'") + .add("version='" + version + "'") + .toString(); + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2639/LanguageRelationship.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2639/LanguageRelationship.java new file mode 100644 index 0000000000..6e294189bf --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2639/LanguageRelationship.java @@ -0,0 +1,40 @@ +/* + * Copyright 2011-2023 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.gh2639; + +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 Gerrit Meier + */ +@RelationshipProperties +public class LanguageRelationship { + + @RelationshipId + private Long id; + + private final int score; + + @TargetNode + private final Language language; + + public LanguageRelationship(int score, Language language) { + this.score = score; + this.language = language; + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2639/Person.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2639/Person.java new file mode 100644 index 0000000000..8c089a2433 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2639/Person.java @@ -0,0 +1,32 @@ +/* + * Copyright 2011-2023 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.gh2639; + +import org.springframework.data.neo4j.core.schema.GeneratedValue; +import org.springframework.data.neo4j.core.schema.Id; +import org.springframework.data.neo4j.core.schema.Node; + +/** + * Abstract base class for relationships from company to specific persons. + */ +@Node +public abstract class Person { + + @Id + @GeneratedValue + private Long id; + +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2639/Sales.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2639/Sales.java new file mode 100644 index 0000000000..191525bd6b --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2639/Sales.java @@ -0,0 +1,44 @@ +/* + * Copyright 2011-2023 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.gh2639; + +import org.springframework.data.neo4j.core.schema.Node; + +import java.util.StringJoiner; + +/** + * Sales person, some noise for the developer and company's generic person relationship. + */ +@Node +public class Sales extends Person { + + private final String name; + + public Sales(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + @Override + public String toString() { + return new StringJoiner(", ", Sales.class.getSimpleName() + "[", "]") + .add("name='" + name + "'") + .toString(); + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/gh2640/PersistentPropertyCharacteristicsIT.java b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2640/PersistentPropertyCharacteristicsIT.java new file mode 100644 index 0000000000..6d134f10df --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/gh2640/PersistentPropertyCharacteristicsIT.java @@ -0,0 +1,159 @@ +/* + * Copyright 2011-2023 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.gh2640; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.neo4j.driver.Driver; +import org.neo4j.driver.Record; +import org.neo4j.driver.Session; +import org.neo4j.driver.Values; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.neo4j.core.DatabaseSelectionProvider; +import org.springframework.data.neo4j.core.Neo4jTemplate; +import org.springframework.data.neo4j.core.mapping.PersistentPropertyCharacteristics; +import org.springframework.data.neo4j.core.mapping.PersistentPropertyCharacteristicsProvider; +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.transaction.Neo4jBookmarkManager; +import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager; +import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories; +import org.springframework.data.neo4j.test.BookmarkCapture; +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.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +/** + * @author Michael J. Simons + */ +@Neo4jIntegrationTest +class PersistentPropertyCharacteristicsIT { + + protected static Neo4jExtension.Neo4jConnectionSupport neo4jConnectionSupport; + + @BeforeEach + void setupData(@Autowired Driver driver, @Autowired BookmarkCapture bookmarkCapture) { + + try (Session session = driver.session()) { + session.run("MATCH (n) DETACH DELETE n").consume(); + bookmarkCapture.seedWith(session.lastBookmark()); + } + } + + @Test + // GH-2640 + void implicitTransientPropertiesShouldNotBeWritten(@Autowired Driver driver, @Autowired BookmarkCapture bookmarkCapture, @Autowired Neo4jTemplate template) { + + SomeWithImplicitTransientProperties1 node1 = template.save(new SomeWithImplicitTransientProperties1("the name", 1.23)); + SomeWithImplicitTransientProperties2 node2 = template.save(new SomeWithImplicitTransientProperties2(47.11)); + + try (Session session = driver.session(bookmarkCapture.createSessionConfig())) { + List records = session.run("MATCH (n) WHERE n.id IN $ids RETURN n", Values.parameters("ids", Arrays.asList(node1.id.toString(), node2.id.toString()))).list(); + assertThat(records) + .hasSize(2) + .noneMatch(r -> { + Map properties = r.get("n").asNode().asMap(); + return properties.containsKey("foobar") || properties.containsKey("bazbar"); + }); + } + } + + @Node + static class SomeWithImplicitTransientProperties1 { + + @Id + @GeneratedValue + private UUID id; + + private String name; + + private Double foobar; + + SomeWithImplicitTransientProperties1(String name, Double foobar) { + this.name = name; + this.foobar = foobar; + } + } + + @Node + static class SomeWithImplicitTransientProperties2 { + + @Id + @GeneratedValue + private UUID id; + + private Double bazbar; + + SomeWithImplicitTransientProperties2(Double bazbar) { + this.bazbar = bazbar; + } + } + + @Configuration + @EnableTransactionManagement + @EnableNeo4jRepositories(considerNestedRepositories = true) + static class Config extends Neo4jImperativeTestConfiguration { + + @Bean + public BookmarkCapture bookmarkCapture() { + return new BookmarkCapture(); + } + + @Override + public PlatformTransactionManager transactionManager( + Driver driver, DatabaseSelectionProvider databaseNameProvider) { + + BookmarkCapture bookmarkCapture = bookmarkCapture(); + return new Neo4jTransactionManager(driver, databaseNameProvider, + Neo4jBookmarkManager.create(bookmarkCapture)); + } + + @Bean + public PersistentPropertyCharacteristicsProvider persistentPropertyCharacteristicsProvider() { + return (property, owner) -> { + + if (property.getType().equals(Double.class)) { + return PersistentPropertyCharacteristics.treatAsTransient(); + } + + return PersistentPropertyCharacteristics.useDefaults(); + }; + } + + @Bean + public Driver driver() { + + return neo4jConnectionSupport.getDriver(); + } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/projections/NestedProjectionsIT.java b/src/test/java/org/springframework/data/neo4j/integration/issues/projections/NestedProjectionsIT.java new file mode 100644 index 0000000000..aa9237c032 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/projections/NestedProjectionsIT.java @@ -0,0 +1,133 @@ +/* + * Copyright 2011-2023 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.projections; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Collection; +import java.util.Collections; +import java.util.Optional; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.RepeatedTest; +import org.neo4j.driver.Driver; +import org.neo4j.driver.Session; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.neo4j.core.DatabaseSelectionProvider; +import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager; +import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager; +import org.springframework.data.neo4j.integration.issues.projections.model.SourceNodeA; +import org.springframework.data.neo4j.integration.issues.projections.projection.SourceNodeAProjection; +import org.springframework.data.neo4j.integration.issues.projections.repository.SourceNodeARepository; +import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories; +import org.springframework.data.neo4j.test.BookmarkCapture; +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.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +/** + * @author Michael J. Simons + */ +@Neo4jIntegrationTest +class NestedProjectionsIT { + + protected static Neo4jExtension.Neo4jConnectionSupport neo4jConnectionSupport; + + @BeforeAll + static void setupData(@Autowired Driver driver, @Autowired BookmarkCapture bookmarkCapture) { + try (Session session = driver.session()) { + session.run("MATCH (n) DETACH DELETE n").consume(); + session.run("CREATE (l:SourceNodeA {id: 'L-l1', version: 1})-[:A_TO_CENTRAL]->(e:CentralNode {id: 'E-l1', version: 1})<-[:B_TO_CENTRAL]-(c:SourceNodeB {id: 'C-l1', version: 1}) RETURN id(l)").consume(); + bookmarkCapture.seedWith(session.lastBookmark()); + } + } + + @BeforeEach + void clearChangedProperties(@Autowired Driver driver, @Autowired BookmarkCapture bookmarkCapture) { + try (Session session = driver.session()) { + session.run("MATCH (n:SourceNodeA) SET n.value = null").consume(); + session.run("MATCH (n:CentralNode) SET n.name = null").consume(); + bookmarkCapture.seedWith(session.lastBookmark()); + } + } + + @RepeatedTest(20) // GH-2581 + void excludedHopMustNotVanish(@Autowired SourceNodeARepository repository) { + + Optional optionalSourceNode = repository.findById("L-l1"); + assertThat(optionalSourceNode).isPresent(); + + SourceNodeA toUpdate = optionalSourceNode.get(); + toUpdate.setValue("newValue"); + toUpdate.getCentralNode().setName("whatever"); + SourceNodeAProjection projectedSourceNode = repository.saveWithProjection(toUpdate); + + + SourceNodeA updatedNode = repository.findById("L-l1").orElseThrow(IllegalStateException::new); + + assertThat(updatedNode.getCentralNode()).isNotNull(); + assertThat(updatedNode.getCentralNode().getSourceNodeB()).isNotNull(); + + assertThat(projectedSourceNode.getCentralNode().getName()).isEqualTo("whatever"); + assertThat(updatedNode.getCentralNode().getName()).isEqualTo(projectedSourceNode.getCentralNode().getName()); + + assertThat(projectedSourceNode.getValue()).isEqualTo("newValue"); + assertThat(updatedNode.getValue()).isEqualTo(projectedSourceNode.getValue()); + } + + @Configuration + @EnableTransactionManagement + @EnableNeo4jRepositories(considerNestedRepositories = true) + @ComponentScan + static class Config extends Neo4jImperativeTestConfiguration { + + @Bean + public BookmarkCapture bookmarkCapture() { + return new BookmarkCapture(); + } + + @Override + public PlatformTransactionManager transactionManager( + Driver driver, DatabaseSelectionProvider databaseNameProvider) { + + BookmarkCapture bookmarkCapture = bookmarkCapture(); + return new Neo4jTransactionManager(driver, databaseNameProvider, + Neo4jBookmarkManager.create(bookmarkCapture)); + } + + @Override + protected Collection getMappingBasePackages() { + return Collections.singleton(NestedProjectionsIT.class.getPackage().getName()); + } + + @Bean + public Driver driver() { + + return neo4jConnectionSupport.getDriver(); + } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/projections/model/CentralNode.java b/src/test/java/org/springframework/data/neo4j/integration/issues/projections/model/CentralNode.java new file mode 100644 index 0000000000..457cbe327b --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/projections/model/CentralNode.java @@ -0,0 +1,75 @@ +/* + * Copyright 2011-2023 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.projections.model; + +import java.util.Objects; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import org.springframework.data.annotation.Version; +import org.springframework.data.neo4j.core.schema.Id; +import org.springframework.data.neo4j.core.schema.Node; +import org.springframework.data.neo4j.core.schema.Property; +import org.springframework.data.neo4j.core.schema.Relationship; + +/** + * @author Michael J. Simons + */ +@Getter +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Node +public class CentralNode { + + @Id + @Property(name = "id") + private String id; + + @Version Long version; + + private String name; + + @Relationship(value = "B_TO_CENTRAL", direction = Relationship.Direction.INCOMING) + private SourceNodeB sourceNodeB; + + @Override public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + CentralNode centralNode = (CentralNode) o; + return Objects.equals(id, centralNode.id) && Objects.equals(name, centralNode.name); + } + + @Override + public int hashCode() { + return Objects.hash(id, name); + } + + public void setSourceNodeB(SourceNodeB sourceNodeB) { + this.sourceNodeB = sourceNodeB; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/projections/model/SourceNodeA.java b/src/test/java/org/springframework/data/neo4j/integration/issues/projections/model/SourceNodeA.java new file mode 100644 index 0000000000..d281453730 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/projections/model/SourceNodeA.java @@ -0,0 +1,68 @@ +/* + * Copyright 2011-2023 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.projections.model; + +import java.util.Objects; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import org.springframework.data.annotation.Version; +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 + */ +@Getter +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Node +public class SourceNodeA { + + @Id + private String id; + + @Version Long version; + + private String value; + + @Relationship("A_TO_CENTRAL") + private CentralNode centralNode; + + @Override public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + SourceNodeA sourceNodeA = (SourceNodeA) o; + return Objects.equals(id, sourceNodeA.id) && Objects.equals(value, sourceNodeA.value); + } + + @Override public int hashCode() { + return Objects.hash(id, value); + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/projections/model/SourceNodeB.java b/src/test/java/org/springframework/data/neo4j/integration/issues/projections/model/SourceNodeB.java new file mode 100644 index 0000000000..2c8d43f97b --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/projections/model/SourceNodeB.java @@ -0,0 +1,72 @@ +/* + * Copyright 2011-2023 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.projections.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.util.List; +import java.util.Objects; + +import org.springframework.data.annotation.Version; +import org.springframework.data.neo4j.core.schema.Id; +import org.springframework.data.neo4j.core.schema.Node; +import org.springframework.data.neo4j.core.schema.Property; +import org.springframework.data.neo4j.core.schema.Relationship; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +/** + * @author Michael J. Simons + */ +@Getter +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Node +public class SourceNodeB { + + @Id + @Property(name = "id") + private String id; + + @Version Long version; + + private String name; + + @JsonIgnore + @Relationship("B_TO_CENTRAL") + private List centralNodes; + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + SourceNodeB sourceNodeB = (SourceNodeB) o; + return Objects.equals(id, sourceNodeB.id) && Objects.equals(name, sourceNodeB.name); + } + + @Override + public int hashCode() { + return Objects.hash(id, name); + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/projections/projection/SourceNodeAProjection.java b/src/test/java/org/springframework/data/neo4j/integration/issues/projections/projection/SourceNodeAProjection.java new file mode 100644 index 0000000000..f635b4cd35 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/projections/projection/SourceNodeAProjection.java @@ -0,0 +1,34 @@ +/* + * Copyright 2011-2023 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.projections.projection; + +/** + * @author Michael J. Simons + */ +public interface SourceNodeAProjection { + String getValue(); + + CentralNode getCentralNode(); + + /** + * Nested projection. + */ + interface CentralNode { + String getId(); + + String getName(); + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/projections/repository/CustomRepository.java b/src/test/java/org/springframework/data/neo4j/integration/issues/projections/repository/CustomRepository.java new file mode 100644 index 0000000000..d25212ae1e --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/projections/repository/CustomRepository.java @@ -0,0 +1,26 @@ +/* + * Copyright 2011-2023 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.projections.repository; + +import org.springframework.data.neo4j.integration.issues.projections.model.SourceNodeA; +import org.springframework.data.neo4j.integration.issues.projections.projection.SourceNodeAProjection; + +/** + * @author Michael J. Simons + */ +public interface CustomRepository { + SourceNodeAProjection saveWithProjection(SourceNodeA sourceNodeA); +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/projections/repository/CustomRepositoryImpl.java b/src/test/java/org/springframework/data/neo4j/integration/issues/projections/repository/CustomRepositoryImpl.java new file mode 100644 index 0000000000..76cfd110d6 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/projections/repository/CustomRepositoryImpl.java @@ -0,0 +1,36 @@ +/* + * Copyright 2011-2023 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.projections.repository; + +import lombok.AllArgsConstructor; + +import org.springframework.data.neo4j.core.Neo4jOperations; +import org.springframework.data.neo4j.integration.issues.projections.model.SourceNodeA; +import org.springframework.data.neo4j.integration.issues.projections.projection.SourceNodeAProjection; + +/** + * @author Michael J. Simons + */ +@AllArgsConstructor +class CustomRepositoryImpl implements CustomRepository { + + private final Neo4jOperations neo4jOperations; + + @Override + public SourceNodeAProjection saveWithProjection(SourceNodeA sourceNodeA) { + return neo4jOperations.saveAs(sourceNodeA, SourceNodeAProjection.class); + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/issues/projections/repository/SourceNodeARepository.java b/src/test/java/org/springframework/data/neo4j/integration/issues/projections/repository/SourceNodeARepository.java new file mode 100644 index 0000000000..a7007e88be --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/issues/projections/repository/SourceNodeARepository.java @@ -0,0 +1,27 @@ +/* + * Copyright 2011-2023 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.projections.repository; + +import org.springframework.data.neo4j.integration.issues.projections.model.SourceNodeA; +import org.springframework.data.neo4j.repository.Neo4jRepository; +import org.springframework.stereotype.Repository; + +/** + * @author Michael J. Simons + */ +@Repository +public interface SourceNodeARepository extends Neo4jRepository, CustomRepository { +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/kotlin/KotlinIT.java b/src/test/java/org/springframework/data/neo4j/integration/kotlin/KotlinIT.java index d6e568555c..732a30d0d1 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/kotlin/KotlinIT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/kotlin/KotlinIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -26,7 +26,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.neo4j.config.AbstractNeo4jConfig; +import org.springframework.data.neo4j.test.Neo4jImperativeTestConfiguration; import org.springframework.data.neo4j.core.DatabaseSelectionProvider; import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager; import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager; @@ -109,7 +109,7 @@ void primitiveDefaultValuesShouldWork(@Autowired TestPersonRepository repository @Configuration @EnableNeo4jRepositories(basePackageClasses = KotlinPerson.class) @EnableTransactionManagement - static class Config extends AbstractNeo4jConfig { + static class Config extends Neo4jImperativeTestConfiguration { @Bean public Driver driver() { @@ -128,5 +128,9 @@ public PlatformTransactionManager transactionManager(Driver driver, DatabaseSele return new Neo4jTransactionManager(driver, databaseNameProvider, Neo4jBookmarkManager.create(bookmarkCapture)); } + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } } } diff --git a/src/test/java/org/springframework/data/neo4j/integration/lite/A.java b/src/test/java/org/springframework/data/neo4j/integration/lite/A.java new file mode 100644 index 0000000000..359d5c151d --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/lite/A.java @@ -0,0 +1,43 @@ +/* + * Copyright 2011-2023 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.lite; + +/** + * DTO with nested DTO + * + * @author Michael J. Simons + */ +public class A { + private String outer; + + private B nested; + + public String getOuter() { + return outer; + } + + public void setOuter(String outer) { + this.outer = outer; + } + + public B getNested() { + return nested; + } + + public void setNested(B nested) { + this.nested = nested; + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/lite/B.java b/src/test/java/org/springframework/data/neo4j/integration/lite/B.java new file mode 100644 index 0000000000..1e7975f7c8 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/lite/B.java @@ -0,0 +1,33 @@ +/* + * Copyright 2011-2023 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.lite; + +/** + * Inner DTO + * + * @author Michael J. Simons + */ +public class B { + private String inner; + + public String getInner() { + return inner; + } + + public void setInner(String inner) { + this.inner = inner; + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/lite/LightweightMappingIT.java b/src/test/java/org/springframework/data/neo4j/integration/lite/LightweightMappingIT.java new file mode 100644 index 0000000000..f1dcde9d50 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/lite/LightweightMappingIT.java @@ -0,0 +1,144 @@ +/* + * Copyright 2011-2023 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.lite; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Collection; +import java.util.Optional; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.neo4j.driver.Driver; +import org.neo4j.driver.Session; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.neo4j.core.DatabaseSelectionProvider; +import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager; +import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager; +import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories; +import org.springframework.data.neo4j.test.BookmarkCapture; +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.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +@Neo4jIntegrationTest +class LightweightMappingIT { + + protected static Neo4jExtension.Neo4jConnectionSupport neo4jConnectionSupport; + + @BeforeAll + static void setupData(@Autowired Driver driver, @Autowired BookmarkCapture bookmarkCapture) { + + try (Session session = driver.session(bookmarkCapture.createSessionConfig())) { + session.run("MATCH (n) DETACH DELETE n").consume(); + // language=cypher + session.run( + "CREATE (u1:User {login: 'michael', id: randomUUID()})\n" + + "CREATE (u2:User {login: 'gerrit', id: randomUUID()})\n" + + "CREATE (so1:SomeDomainObject {name: 'name1', id: randomUUID()})\n" + + "CREATE (so2:SomeDomainObject {name: 'name2', id: randomUUID()})\n" + + "CREATE (so1)<-[:OWNS]-(u1)-[:OWNS]->(so2)\n" + ); + bookmarkCapture.seedWith(session.lastBookmark()); + } + } + + @Test + void getAllFlatShouldWork(@Autowired SomeDomainRepository repository) { + + Collection dtos = repository.getAllFlat(); + assertThat(dtos).hasSize(10) + .allSatisfy(dto -> { + assertThat(dto.counter).isGreaterThan(0); + assertThat(dto.resyncId).isNotNull(); + }); + } + + @Test + void getOneFlatShouldWork(@Autowired SomeDomainRepository repository) { + + Optional dtos = repository.getOneFlat(); + assertThat(dtos).hasValueSatisfying(dto -> { + assertThat(dto.counter).isEqualTo(4711L); + assertThat(dto.resyncId).isNotNull(); + }); + } + + @Test + void getAllNestedShouldWork(@Autowired SomeDomainRepository repository) { + + Collection dtos = repository.getNestedStuff(); + assertThat(dtos).hasSize(1) + .first() + .satisfies(dto -> { + assertThat(dto.counter).isEqualTo(4711L); + assertThat(dto.resyncId).isNotNull(); + assertThat(dto.user) + .isNotNull() + .extracting(User::getLogin) + .isEqualTo("michael"); + assertThat(dto.user.getOwnedObjects()) + .hasSize(2); + + }); + } + + + @Test + void getTestedDTOsShouldWork(@Autowired SomeDomainRepository repository) { + + Optional dto = repository.getOneNestedDTO(); + assertThat(dto).hasValueSatisfying(v -> { + assertThat(v.getOuter()).isEqualTo("av"); + assertThat(v.getNested()).isNotNull() + .extracting(B::getInner).isEqualTo("bv"); + }); + + } + + @Configuration + @EnableTransactionManagement + @EnableNeo4jRepositories(considerNestedRepositories = true) + static class Config extends Neo4jImperativeTestConfiguration { + + @Bean + public Driver driver() { + return neo4jConnectionSupport.getDriver(); + } + + @Bean + public BookmarkCapture bookmarkCapture() { + return new BookmarkCapture(); + } + + @Override + public PlatformTransactionManager transactionManager(Driver driver, DatabaseSelectionProvider databaseNameProvider) { + + BookmarkCapture bookmarkCapture = bookmarkCapture(); + return new Neo4jTransactionManager(driver, databaseNameProvider, Neo4jBookmarkManager.create(bookmarkCapture)); + } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } + } + +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/lite/MyDTO.java b/src/test/java/org/springframework/data/neo4j/integration/lite/MyDTO.java new file mode 100644 index 0000000000..dc85c7a1c6 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/lite/MyDTO.java @@ -0,0 +1,29 @@ +/* + * Copyright 2011-2023 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.lite; + +/** + * DTO with optionally linked domain object + * + * @author Michael J. Simons + */ +public class MyDTO { + String resyncId; + + Long counter; + + User user; +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/lite/SomeDomainObject.java b/src/test/java/org/springframework/data/neo4j/integration/lite/SomeDomainObject.java new file mode 100644 index 0000000000..17d6bb334a --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/lite/SomeDomainObject.java @@ -0,0 +1,49 @@ +/* + * Copyright 2011-2023 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.lite; + +import java.util.UUID; + +import org.springframework.data.neo4j.core.schema.GeneratedValue; +import org.springframework.data.neo4j.core.schema.Id; +import org.springframework.data.neo4j.core.schema.Node; + +/** + * Irrelevant to the tests in this package, but needed for setting up a repository. + * + * @author Michael J. Simons + */ +@Node +public class SomeDomainObject { + + @Id + @GeneratedValue + private UUID id; + + private final String name; + + public SomeDomainObject(String name) { + this.name = name; + } + + public UUID getId() { + return id; + } + + public String getName() { + return name; + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/lite/SomeDomainRepository.java b/src/test/java/org/springframework/data/neo4j/integration/lite/SomeDomainRepository.java new file mode 100644 index 0000000000..4a43914a6d --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/lite/SomeDomainRepository.java @@ -0,0 +1,61 @@ +/* + * Copyright 2011-2023 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.lite; + +import java.util.Collection; +import java.util.Optional; +import java.util.UUID; + +import org.springframework.data.neo4j.repository.Neo4jRepository; +import org.springframework.data.neo4j.repository.query.Query; + +/** + * @author Michael J. Simons + */ +public interface SomeDomainRepository extends Neo4jRepository { + + /** + * @return Mapping arbitrary, ungrouped results into a dto + */ + // language=cypher + @Query("UNWIND range(1,10) AS x RETURN randomUUID() AS resyncId, tointeger(x*rand()*10)+1 AS counter ORDER BY counter") + Collection getAllFlat(); + + /** + * @return Mapping a single ungrouped result + */ + // language=cypher + @Query("RETURN randomUUID() AS resyncId, 4711 AS counter") + Optional getOneFlat(); + + /** + * @return Mapping a dto plus known domain objects + */ + // language=cypher + @Query("MATCH (u:User {login:'michael'}) -[r:OWNS] -> (s:SomeDomainObject)\n" + + "WITH u, collect(r) AS r, collect(s) AS ownedObjects\n" + + "RETURN\n" + + " u{.*, __internalNeo4jId__: id(u), r, ownedObjects} AS user,\n" + + " randomUUID() AS resyncId, 4711 AS counter,u\n") + Collection getNestedStuff(); + + /** + * @return Mapping nested dtos + */ + // language=cypher + @Query("RETURN 'av' AS outer, {inner: 'bv'} AS nested") + Optional getOneNestedDTO(); +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/lite/User.java b/src/test/java/org/springframework/data/neo4j/integration/lite/User.java new file mode 100644 index 0000000000..e3dc2ff10c --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/lite/User.java @@ -0,0 +1,66 @@ +/* + * Copyright 2011-2023 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.lite; + +import java.util.List; +import java.util.UUID; + +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; + +/** + * Another known node. + * + * @author Michael J. Simons + */ +@Node +public class User { + + @Id + @GeneratedValue + private UUID id; + + private final String login; + + @Relationship(direction = Relationship.Direction.OUTGOING, type = "OWNS") + private List ownedObjects; + + public User(String login) { + this.login = login; + } + + public UUID getId() { + return id; + } + + public String getLogin() { + return login; + } + + public void setId(UUID id) { + this.id = id; + } + + public List getOwnedObjects() { + return ownedObjects; + } + + public void setOwnedObjects(List ownedObjects) { + this.ownedObjects = ownedObjects; + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/movies/imperative/AdvancedMappingIT.java b/src/test/java/org/springframework/data/neo4j/integration/movies/imperative/AdvancedMappingIT.java index 8260b608af..716d16b1f6 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/movies/imperative/AdvancedMappingIT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/movies/imperative/AdvancedMappingIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -22,7 +22,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.neo4j.config.AbstractNeo4jConfig; +import org.springframework.data.neo4j.test.Neo4jImperativeTestConfiguration; import org.springframework.data.neo4j.core.DatabaseSelectionProvider; import org.springframework.data.neo4j.core.Neo4jTemplate; import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager; @@ -132,6 +132,12 @@ interface MovieWithSequelEntity { Movie getSequel(); } + interface MovieWithMovieList { + String getTitle(); + + List getSequel(); + } + interface MovieRepository extends Neo4jRepository { MovieProjection findProjectionByTitle(String title); @@ -155,6 +161,12 @@ interface MovieRepository extends Neo4jRepository { @Query("MATCH (m:Movie{title:'The Matrix'})<-[a:ACTED_IN]-(p:Person) WITH a,p,m order by p.name DESC return m, collect(a), collect(p)") Movie findMatrixWithSortedDescActors(); + + @Query("MATCH p=(:Movie{title:'The Matrix'}) return p") + Movie findSingleNodeWithPath(); + + @Query("MATCH p=(m:Movie{title:'The Matrix'})<-[:ACTED_IN]-(:Person) return m, collect(nodes(p)), collect(relationships(p))") + List findMultipleSameTypeRelationshipsWithPath(); } @Test // GH-1906 @@ -469,6 +481,7 @@ void findPreservesOrderFromResultAscInRelationshipList(@Autowired MovieRepositor .containsExactly("Carrie-Anne Moss", "Emil Eifrem", "Gloria Foster", "Hugo Weaving", "Keanu Reeves", "Laurence Fishburne"); } + @Test // GH-2458 void findPreservesOrderFromResultDescInRelationshipList(@Autowired MovieRepository repository) { assertThat(repository.findMatrixWithSortedDescActors().getActors()).extracting("person").extracting("name") @@ -476,10 +489,36 @@ void findPreservesOrderFromResultDescInRelationshipList(@Autowired MovieReposito "Carrie-Anne Moss"); } + + @Test // GH-2470 + void mapPathWithSingleNode(@Autowired MovieRepository repository) { + assertThat(repository.findSingleNodeWithPath()).isNotNull(); + } + + @Test // GH-2473 + void mapPathWithMultipleSameTypeRelationships(@Autowired MovieRepository repository) { + List movies = repository.findMultipleSameTypeRelationshipsWithPath(); + assertThat(movies).hasSize(1); + assertThat(movies.get(0).getActors()).hasSize(6); + } + + @Test // GH-2591 + void createPropertyFilterPathCorrectly(@Autowired Neo4jTemplate neo4jTemplate) { + Movie movie = new Movie("Test", "Movie"); + neo4jTemplate.saveAs(movie, MovieWithMovieList.class); + + Movie foundMovie = neo4jTemplate.findOne("MATCH (m:Movie{title:'Test'}) return m", Collections.emptyMap(), Movie.class).get(); + assertThat(foundMovie.getTitle()).isEqualTo("Test"); + assertThat(foundMovie.getDescription()).isNull(); + + // clean up to keep the other tests healthy + neo4jTemplate.deleteById("Test", Movie.class); + } + @Configuration @EnableTransactionManagement @EnableNeo4jRepositories(considerNestedRepositories = true) - static class Config extends AbstractNeo4jConfig { + static class Config extends Neo4jImperativeTestConfiguration { @Bean public Driver driver() { @@ -497,5 +536,10 @@ public PlatformTransactionManager transactionManager(Driver driver, DatabaseSele BookmarkCapture bookmarkCapture = bookmarkCapture(); return new Neo4jTransactionManager(driver, databaseNameProvider, Neo4jBookmarkManager.create(bookmarkCapture)); } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } } } diff --git a/src/test/java/org/springframework/data/neo4j/integration/movies/reactive/ReactiveAdvancedMappingIT.java b/src/test/java/org/springframework/data/neo4j/integration/movies/reactive/ReactiveAdvancedMappingIT.java index 42b8ef3e39..3ce872b7b2 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/movies/reactive/ReactiveAdvancedMappingIT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/movies/reactive/ReactiveAdvancedMappingIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -23,7 +23,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.neo4j.config.AbstractReactiveNeo4jConfig; import org.springframework.data.neo4j.core.ReactiveDatabaseSelectionProvider; import org.springframework.data.neo4j.core.ReactiveNeo4jTemplate; import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager; @@ -38,6 +37,7 @@ import org.springframework.data.neo4j.test.BookmarkCapture; import org.springframework.data.neo4j.test.Neo4jExtension; import org.springframework.data.neo4j.test.Neo4jIntegrationTest; +import org.springframework.data.neo4j.test.Neo4jReactiveTestConfiguration; import org.springframework.data.repository.query.Param; import org.springframework.transaction.ReactiveTransactionManager; import org.springframework.transaction.annotation.EnableTransactionManagement; @@ -483,7 +483,7 @@ void projectDirectCycleEntityReference(@Autowired MovieRepository movieRepositor @Configuration @EnableTransactionManagement @EnableReactiveNeo4jRepositories(considerNestedRepositories = true) - static class Config extends AbstractReactiveNeo4jConfig { + static class Config extends Neo4jReactiveTestConfiguration { @Bean public Driver driver() { @@ -501,5 +501,10 @@ public ReactiveTransactionManager reactiveTransactionManager(Driver driver, Reac BookmarkCapture bookmarkCapture = bookmarkCapture(); return new ReactiveNeo4jTransactionManager(driver, databaseSelectionProvider, Neo4jBookmarkManager.create(bookmarkCapture)); } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } } } diff --git a/src/test/java/org/springframework/data/neo4j/integration/movies/shared/Actor.java b/src/test/java/org/springframework/data/neo4j/integration/movies/shared/Actor.java index a63269ddbe..c9d3b9c116 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/movies/shared/Actor.java +++ b/src/test/java/org/springframework/data/neo4j/integration/movies/shared/Actor.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/movies/shared/CypherUtils.java b/src/test/java/org/springframework/data/neo4j/integration/movies/shared/CypherUtils.java index f1cd5f2b5b..4bf11e9da9 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/movies/shared/CypherUtils.java +++ b/src/test/java/org/springframework/data/neo4j/integration/movies/shared/CypherUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/movies/shared/Movie.java b/src/test/java/org/springframework/data/neo4j/integration/movies/shared/Movie.java index e945446d9e..58b960bce7 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/movies/shared/Movie.java +++ b/src/test/java/org/springframework/data/neo4j/integration/movies/shared/Movie.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/movies/shared/Organisation.java b/src/test/java/org/springframework/data/neo4j/integration/movies/shared/Organisation.java index 6b469d083b..6537115eff 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/movies/shared/Organisation.java +++ b/src/test/java/org/springframework/data/neo4j/integration/movies/shared/Organisation.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/movies/shared/Partner.java b/src/test/java/org/springframework/data/neo4j/integration/movies/shared/Partner.java index f1f143ce3b..ebfec81ea8 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/movies/shared/Partner.java +++ b/src/test/java/org/springframework/data/neo4j/integration/movies/shared/Partner.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/movies/shared/Person.java b/src/test/java/org/springframework/data/neo4j/integration/movies/shared/Person.java index b965a4e32a..1623c341c6 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/movies/shared/Person.java +++ b/src/test/java/org/springframework/data/neo4j/integration/movies/shared/Person.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -18,7 +18,7 @@ import java.util.ArrayList; import java.util.List; -import org.springframework.data.annotation.PersistenceConstructor; +import org.springframework.data.annotation.PersistenceCreator; import org.springframework.data.neo4j.core.schema.GeneratedValue; import org.springframework.data.neo4j.core.schema.Id; import org.springframework.data.neo4j.core.schema.Node; @@ -44,7 +44,7 @@ public final class Person { @Relationship("ACTED_IN") private List actedIn = new ArrayList<>(); - @PersistenceConstructor + @PersistenceCreator private Person(Long id, String name, Integer born) { this.id = id; this.born = born; diff --git a/src/test/java/org/springframework/data/neo4j/integration/multiple_ctx_imperative/MultipleContextsIT.java b/src/test/java/org/springframework/data/neo4j/integration/multiple_ctx_imperative/MultipleContextsIT.java index efee23e63a..1cbc2c3251 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/multiple_ctx_imperative/MultipleContextsIT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/multiple_ctx_imperative/MultipleContextsIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -53,11 +53,11 @@ public class MultipleContextsIT { @Container - private static Neo4jContainer container1 = new Neo4jContainer<>("neo4j:4.0") + private static Neo4jContainer container1 = new Neo4jContainer<>("neo4j:4.4") .withAdminPassword("secret1"); @Container - private static Neo4jContainer container2 = new Neo4jContainer<>("neo4j:4.0") + private static Neo4jContainer container2 = new Neo4jContainer<>("neo4j:4.4") .withAdminPassword("secret2"); @DynamicPropertySource diff --git a/src/test/java/org/springframework/data/neo4j/integration/multiple_ctx_imperative/SharedConfig.java b/src/test/java/org/springframework/data/neo4j/integration/multiple_ctx_imperative/SharedConfig.java index 621863a5b7..08a7d2e265 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/multiple_ctx_imperative/SharedConfig.java +++ b/src/test/java/org/springframework/data/neo4j/integration/multiple_ctx_imperative/SharedConfig.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/multiple_ctx_imperative/domain1/Domain1Config.java b/src/test/java/org/springframework/data/neo4j/integration/multiple_ctx_imperative/domain1/Domain1Config.java index 3b63ffc26d..3e64a3210b 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/multiple_ctx_imperative/domain1/Domain1Config.java +++ b/src/test/java/org/springframework/data/neo4j/integration/multiple_ctx_imperative/domain1/Domain1Config.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/multiple_ctx_imperative/domain1/Domain1Entity.java b/src/test/java/org/springframework/data/neo4j/integration/multiple_ctx_imperative/domain1/Domain1Entity.java index 2ea2bc26e5..583d622194 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/multiple_ctx_imperative/domain1/Domain1Entity.java +++ b/src/test/java/org/springframework/data/neo4j/integration/multiple_ctx_imperative/domain1/Domain1Entity.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/multiple_ctx_imperative/domain1/Domain1Repository.java b/src/test/java/org/springframework/data/neo4j/integration/multiple_ctx_imperative/domain1/Domain1Repository.java index ad6059c176..549a082a89 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/multiple_ctx_imperative/domain1/Domain1Repository.java +++ b/src/test/java/org/springframework/data/neo4j/integration/multiple_ctx_imperative/domain1/Domain1Repository.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/multiple_ctx_imperative/domain2/Domain2Config.java b/src/test/java/org/springframework/data/neo4j/integration/multiple_ctx_imperative/domain2/Domain2Config.java index 457f398d0d..2b36a992f1 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/multiple_ctx_imperative/domain2/Domain2Config.java +++ b/src/test/java/org/springframework/data/neo4j/integration/multiple_ctx_imperative/domain2/Domain2Config.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/multiple_ctx_imperative/domain2/Domain2Entity.java b/src/test/java/org/springframework/data/neo4j/integration/multiple_ctx_imperative/domain2/Domain2Entity.java index 362f0ee77a..825b81b336 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/multiple_ctx_imperative/domain2/Domain2Entity.java +++ b/src/test/java/org/springframework/data/neo4j/integration/multiple_ctx_imperative/domain2/Domain2Entity.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/multiple_ctx_imperative/domain2/Domain2Repository.java b/src/test/java/org/springframework/data/neo4j/integration/multiple_ctx_imperative/domain2/Domain2Repository.java index 16c0e96146..4a52460aec 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/multiple_ctx_imperative/domain2/Domain2Repository.java +++ b/src/test/java/org/springframework/data/neo4j/integration/multiple_ctx_imperative/domain2/Domain2Repository.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/properties/DomainClasses.java b/src/test/java/org/springframework/data/neo4j/integration/properties/DomainClasses.java index 2f98ea58e4..7fe403e267 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/properties/DomainClasses.java +++ b/src/test/java/org/springframework/data/neo4j/integration/properties/DomainClasses.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/properties/PropertyIT.java b/src/test/java/org/springframework/data/neo4j/integration/properties/PropertyIT.java index 41014b98ba..23687e15d0 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/properties/PropertyIT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/properties/PropertyIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -30,7 +30,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.neo4j.config.AbstractNeo4jConfig; +import org.springframework.data.neo4j.test.Neo4jImperativeTestConfiguration; import org.springframework.data.neo4j.core.DatabaseSelectionProvider; import org.springframework.data.neo4j.core.Neo4jTemplate; import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager; @@ -266,7 +266,7 @@ void shouldNotFailWithEmptyOrNullRelationshipProperties() { @Configuration @EnableTransactionManagement - static class Config extends AbstractNeo4jConfig { + static class Config extends Neo4jImperativeTestConfiguration { @Bean public Driver driver() { @@ -284,5 +284,10 @@ public PlatformTransactionManager transactionManager(Driver driver, DatabaseSele BookmarkCapture bookmarkCapture = bookmarkCapture(); return new Neo4jTransactionManager(driver, databaseNameProvider, Neo4jBookmarkManager.create(bookmarkCapture)); } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } } } diff --git a/src/test/java/org/springframework/data/neo4j/integration/properties/ReactivePropertyIT.java b/src/test/java/org/springframework/data/neo4j/integration/properties/ReactivePropertyIT.java index 9439b1828d..1a50229b7a 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/properties/ReactivePropertyIT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/properties/ReactivePropertyIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -22,6 +22,7 @@ import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager; import org.springframework.data.neo4j.core.transaction.ReactiveNeo4jTransactionManager; import org.springframework.data.neo4j.test.BookmarkCapture; +import org.springframework.data.neo4j.test.Neo4jReactiveTestConfiguration; import org.springframework.transaction.ReactiveTransactionManager; import reactor.test.StepVerifier; @@ -38,7 +39,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.neo4j.config.AbstractReactiveNeo4jConfig; import org.springframework.data.neo4j.core.ReactiveNeo4jTemplate; import org.springframework.data.neo4j.test.Neo4jExtension; import org.springframework.data.neo4j.test.Neo4jIntegrationTest; @@ -288,7 +288,7 @@ void shouldNotFailWithEmptyOrNullRelationshipProperties() { @Configuration @EnableTransactionManagement - static class Config extends AbstractReactiveNeo4jConfig { + static class Config extends Neo4jReactiveTestConfiguration { @Bean public Driver driver() { @@ -306,5 +306,10 @@ public ReactiveTransactionManager reactiveTransactionManager(Driver driver, Reac BookmarkCapture bookmarkCapture = bookmarkCapture(); return new ReactiveNeo4jTransactionManager(driver, databaseSelectionProvider, Neo4jBookmarkManager.create(bookmarkCapture)); } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } } } diff --git a/src/test/java/org/springframework/data/neo4j/integration/reactive/CustomReactiveBaseRepositoryIT.java b/src/test/java/org/springframework/data/neo4j/integration/reactive/CustomReactiveBaseRepositoryIT.java index 51c983e4ab..e813dc0b0e 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/reactive/CustomReactiveBaseRepositoryIT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/reactive/CustomReactiveBaseRepositoryIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -17,6 +17,7 @@ import static org.assertj.core.api.Assertions.assertThat; +import org.springframework.data.neo4j.test.Neo4jReactiveTestConfiguration; import reactor.core.publisher.Flux; import reactor.test.StepVerifier; @@ -29,7 +30,6 @@ import org.springframework.context.annotation.ComponentScan.Filter; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.FilterType; -import org.springframework.data.neo4j.config.AbstractReactiveNeo4jConfig; import org.springframework.data.neo4j.core.ReactiveNeo4jOperations; import org.springframework.data.neo4j.integration.shared.common.PersonWithAllConstructor; import org.springframework.data.neo4j.repository.ReactiveNeo4jRepository; @@ -78,12 +78,16 @@ public Flux findAll() { @EnableReactiveNeo4jRepositories(repositoryBaseClass = MyRepositoryImpl.class, considerNestedRepositories = true, includeFilters = @Filter(type = FilterType.ASSIGNABLE_TYPE, value = MyPersonRepository.class)) @EnableTransactionManagement - static class Config extends AbstractReactiveNeo4jConfig { + static class Config extends Neo4jReactiveTestConfiguration { @Bean public Driver driver() { return DriverMocks.withOpenReactiveSessionAndTransaction(); } + @Override + public boolean isCypher5Compatible() { + return false; + } } } diff --git a/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveAuditingIT.java b/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveAuditingIT.java index 9f035d509f..1a1582246e 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveAuditingIT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveAuditingIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -17,6 +17,7 @@ import static org.assertj.core.api.Assertions.assertThat; +import org.springframework.data.neo4j.test.Neo4jReactiveTestConfiguration; import reactor.core.publisher.Mono; import reactor.test.StepVerifier; @@ -32,7 +33,6 @@ import org.springframework.context.annotation.Configuration; import org.springframework.data.auditing.DateTimeProvider; import org.springframework.data.domain.ReactiveAuditorAware; -import org.springframework.data.neo4j.config.AbstractReactiveNeo4jConfig; import org.springframework.data.neo4j.config.EnableReactiveNeo4jAuditing; import org.springframework.data.neo4j.core.ReactiveDatabaseSelectionProvider; import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager; @@ -158,7 +158,7 @@ interface ImmutableEntityWithGeneratedIdTestRepository @EnableReactiveNeo4jRepositories(considerNestedRepositories = true) @EnableReactiveNeo4jAuditing(modifyOnCreate = false, auditorAwareRef = "auditorProvider", dateTimeProviderRef = "fixedDateTimeProvider") - static class Config extends AbstractReactiveNeo4jConfig { + static class Config extends Neo4jReactiveTestConfiguration { @Bean public Driver driver() { @@ -186,5 +186,10 @@ public ReactiveTransactionManager reactiveTransactionManager(Driver driver, Reac BookmarkCapture bookmarkCapture = bookmarkCapture(); return new ReactiveNeo4jTransactionManager(driver, databaseSelectionProvider, Neo4jBookmarkManager.create(bookmarkCapture)); } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } } } diff --git a/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveAuditingWithoutDatesIT.java b/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveAuditingWithoutDatesIT.java index 89df987e77..2a068f9c74 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveAuditingWithoutDatesIT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveAuditingWithoutDatesIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -17,6 +17,7 @@ import static org.assertj.core.api.Assertions.assertThat; +import org.springframework.data.neo4j.test.Neo4jReactiveTestConfiguration; import reactor.core.publisher.Mono; import reactor.test.StepVerifier; @@ -30,7 +31,6 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.domain.ReactiveAuditorAware; -import org.springframework.data.neo4j.config.AbstractReactiveNeo4jConfig; import org.springframework.data.neo4j.config.EnableReactiveNeo4jAuditing; import org.springframework.data.neo4j.core.ReactiveDatabaseSelectionProvider; import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager; @@ -98,7 +98,7 @@ interface ImmutableEntityTestRepository extends ReactiveNeo4jRepository operationUnderTest = Mono.just(thing).flatMap(repository::save); List savedThings = new ArrayList<>(); TransactionalOperator transactionalOperator = TransactionalOperator.create(transactionManager); transactionalOperator.execute(t -> operationUnderTest).as(StepVerifier::create).recordWith(() -> savedThings) - .expectNextMatches(t -> t.getName().equals("A name (Edited)")).verifyComplete(); + .expectNextMatches(t -> t.getName().equals("A name (Edited)") && t.getRandomValue() == null) + .verifyComplete(); verifyDatabase(savedThings); } + @Test // GH-2499 + void onAfterConvertShouldBeCalledForSingleEntity(@Autowired ReactiveThingRepository repository) { + + repository.findById("E1") + .as(StepVerifier::create) + .assertNext(thingWithAssignedId -> { + assertThat(thingWithAssignedId.getTheId()).isEqualTo("E1"); + assertThat(thingWithAssignedId.getRandomValue()).isNotNull() + .satisfies(v -> assertThatNoException().isThrownBy(() -> UUID.fromString(v))); + assertThat(thingWithAssignedId.getAnotherRandomValue()).isNotNull() + .satisfies(v -> assertThatNoException().isThrownBy(() -> UUID.fromString(v))); + }) + .verifyComplete(); + } + @Test void onBeforeBindShouldBeCalledForAllEntitiesUsingIterable(@Autowired ReactiveThingRepository repository) { ThingWithAssignedId thing1 = new ThingWithAssignedId("id1", "A name"); + thing1.setRandomValue("a"); ThingWithAssignedId thing2 = new ThingWithAssignedId("id2", "Another name"); + thing2.setRandomValue("b"); repository.saveAll(Arrays.asList(thing1, thing2)); Flux operationUnderTest = repository.saveAll(Arrays.asList(thing1, thing2)); @@ -87,8 +111,8 @@ void onBeforeBindShouldBeCalledForAllEntitiesUsingIterable(@Autowired ReactiveTh List savedThings = new ArrayList<>(); TransactionalOperator transactionalOperator = TransactionalOperator.create(transactionManager); transactionalOperator.execute(t -> operationUnderTest).as(StepVerifier::create).recordWith(() -> savedThings) - .expectNextMatches(t -> t.getName().equals("A name (Edited)")) - .expectNextMatches(t -> t.getName().equals("Another name (Edited)")).verifyComplete(); + .expectNextMatches(t -> t.getName().equals("A name (Edited)") && t.getRandomValue() == null) + .expectNextMatches(t -> t.getName().equals("Another name (Edited)") && t.getRandomValue() == null).verifyComplete(); verifyDatabase(savedThings); } @@ -97,7 +121,9 @@ void onBeforeBindShouldBeCalledForAllEntitiesUsingIterable(@Autowired ReactiveTh void onBeforeBindShouldBeCalledForAllEntitiesUsingPublisher(@Autowired ReactiveThingRepository repository) { ThingWithAssignedId thing1 = new ThingWithAssignedId("id1", "A name"); + thing1.setRandomValue("a"); ThingWithAssignedId thing2 = new ThingWithAssignedId("id2", "Another name"); + thing2.setRandomValue("b"); repository.saveAll(Arrays.asList(thing1, thing2)); Flux operationUnderTest = repository.saveAll(Flux.just(thing1, thing2)); @@ -105,16 +131,37 @@ void onBeforeBindShouldBeCalledForAllEntitiesUsingPublisher(@Autowired ReactiveT List savedThings = new ArrayList<>(); TransactionalOperator transactionalOperator = TransactionalOperator.create(transactionManager); transactionalOperator.execute(t -> operationUnderTest).as(StepVerifier::create).recordWith(() -> savedThings) - .expectNextMatches(t -> t.getName().equals("A name (Edited)")) - .expectNextMatches(t -> t.getName().equals("Another name (Edited)")).verifyComplete(); + .expectNextMatches(t -> t.getName().equals("A name (Edited)") && t.getRandomValue() == null) + .expectNextMatches(t -> t.getName().equals("Another name (Edited)") && t.getRandomValue() == null).verifyComplete(); verifyDatabase(savedThings); } + @Test // GH-2499 + void onAfterConvertShouldBeCalledForAllEntities(@Autowired ReactiveThingRepository repository) { + + repository.findAllById(Arrays.asList("E1", "E2")) + .sort(Comparator.comparing(ThingWithAssignedId::getTheId)) + .as(StepVerifier::create) + .assertNext(thingWithAssignedId -> { + assertThat(thingWithAssignedId.getTheId()).isEqualTo("E1"); + assertThat(thingWithAssignedId.getRandomValue()).isNotNull() + .satisfies(v -> assertThatNoException().isThrownBy(() -> UUID.fromString(v))); + }) + .assertNext(thingWithAssignedId -> { + assertThat(thingWithAssignedId.getTheId()).isEqualTo("E2"); + assertThat(thingWithAssignedId.getRandomValue()).isNotNull() + .satisfies(v -> assertThatNoException().isThrownBy(() -> UUID.fromString(v))); + assertThat(thingWithAssignedId.getAnotherRandomValue()).isNotNull() + .satisfies(v -> assertThatNoException().isThrownBy(() -> UUID.fromString(v))); + }) + .verifyComplete(); + } + @Configuration @EnableReactiveNeo4jRepositories @EnableTransactionManagement - static class Config extends AbstractReactiveNeo4jConfig { + static class Config extends Neo4jReactiveTestConfiguration { @Bean ReactiveBeforeBindCallback nameChanger() { @@ -124,6 +171,15 @@ ReactiveBeforeBindCallback nameChanger() { }; } + + @Bean + AfterConvertCallback randomValueAssigner() { + return (entity, definition, source) -> { + entity.setRandomValue(UUID.randomUUID().toString()); + return entity; + }; + } + @Bean public Driver driver() { return neo4jConnectionSupport.getDriver(); @@ -140,5 +196,10 @@ public ReactiveTransactionManager reactiveTransactionManager(Driver driver, Reac BookmarkCapture bookmarkCapture = bookmarkCapture(); return new ReactiveNeo4jTransactionManager(driver, databaseSelectionProvider, Neo4jBookmarkManager.create(bookmarkCapture)); } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } } } diff --git a/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveCausalClusterLoadTestIT.java b/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveCausalClusterLoadTestIT.java index 38036939c7..b6824c7577 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveCausalClusterLoadTestIT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveCausalClusterLoadTestIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -15,6 +15,9 @@ */ package org.springframework.data.neo4j.integration.reactive; +import org.neo4j.driver.Session; +import org.neo4j.driver.internal.util.ServerVersion; +import org.springframework.data.neo4j.test.Neo4jReactiveTestConfiguration; import reactor.core.publisher.Mono; import reactor.test.StepVerifier; @@ -43,7 +46,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.neo4j.config.AbstractReactiveNeo4jConfig; import org.springframework.data.neo4j.core.ReactiveNeo4jClient; import org.springframework.data.neo4j.integration.shared.common.ThingWithSequence; import org.springframework.data.neo4j.repository.ReactiveNeo4jRepository; @@ -130,7 +132,7 @@ public Mono findOneBySequenceNumber(long sequenceNumber) { @Configuration @EnableTransactionManagement @EnableReactiveNeo4jRepositories(considerNestedRepositories = true) - static class TestConfig extends AbstractReactiveNeo4jConfig { + static class TestConfig extends Neo4jReactiveTestConfiguration { @Bean public Driver driver() { @@ -145,5 +147,17 @@ public Driver driver() { public ThingService thingService(ReactiveNeo4jClient neo4jClient, ThingRepository thingRepository) { return new ThingService(neo4jClient, thingRepository); } + + @Override + public boolean isCypher5Compatible() { + try (Session session = driver().session()) { + String version = session + .run("CALL dbms.components() YIELD versions RETURN 'Neo4j/' + versions[0] as version") + .single() + .get("version").asString(); + + return ServerVersion.version(version).greaterThanOrEqual(ServerVersion.v4_4_0); + } + } } } diff --git a/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveCypherdslConditionExecutorIT.java b/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveCypherdslConditionExecutorIT.java new file mode 100644 index 0000000000..a98001b4f5 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveCypherdslConditionExecutorIT.java @@ -0,0 +1,192 @@ +/* + * Copyright 2011-2023 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.reactive; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.neo4j.cypherdsl.core.Cypher; +import org.neo4j.cypherdsl.core.Node; +import org.neo4j.cypherdsl.core.Property; +import org.neo4j.driver.Driver; +import org.neo4j.driver.Session; +import org.neo4j.driver.Transaction; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.domain.Sort; +import org.springframework.data.neo4j.core.ReactiveDatabaseSelectionProvider; +import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager; +import org.springframework.data.neo4j.core.transaction.ReactiveNeo4jTransactionManager; +import org.springframework.data.neo4j.integration.shared.common.Person; +import org.springframework.data.neo4j.repository.ReactiveNeo4jRepository; +import org.springframework.data.neo4j.repository.config.EnableReactiveNeo4jRepositories; +import org.springframework.data.neo4j.repository.support.ReactiveCypherdslConditionExecutor; +import org.springframework.data.neo4j.test.BookmarkCapture; +import org.springframework.data.neo4j.test.Neo4jExtension; +import org.springframework.data.neo4j.test.Neo4jIntegrationTest; +import org.springframework.data.neo4j.test.Neo4jReactiveTestConfiguration; +import org.springframework.transaction.ReactiveTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; +import reactor.test.StepVerifier; + +/** + * @author Niklas Krieger + * @author Michael J. Simons + */ +@Tag(Neo4jExtension.NEEDS_REACTIVE_SUPPORT) +@Neo4jIntegrationTest +class ReactiveCypherdslConditionExecutorIT { + + protected static Neo4jExtension.Neo4jConnectionSupport neo4jConnectionSupport; + + private final Node person = Cypher.node("Person").named("person"); + private final Property firstName = person.property("firstName"); + private final Property lastName = person.property("lastName"); + + @BeforeAll + protected static void setupData(@Autowired BookmarkCapture bookmarkCapture) { + try (Session session = neo4jConnectionSupport.getDriver().session(bookmarkCapture.createSessionConfig()); + Transaction transaction = session.beginTransaction()) { + transaction.run("MATCH (n) detach delete n"); + transaction.run("CREATE (p:Person{firstName: 'A', lastName: 'LA'})"); + transaction.run("CREATE (p:Person{firstName: 'B', lastName: 'LB'})"); + transaction + .run("CREATE (p:Person{firstName: 'Helge', lastName: 'Schneider'}) -[:LIVES_AT]-> (a:Address {city: 'Mülheim an der Ruhr'})"); + transaction.run("CREATE (p:Person{firstName: 'Bela', lastName: 'B.'})"); + transaction.commit(); + bookmarkCapture.seedWith(session.lastBookmark()); + } + } + + @Test + void findOneShouldWork(@Autowired PersonRepository repository) { + + repository.findOne(firstName.eq(Cypher.literalOf("Helge"))) + .as(StepVerifier::create) + .expectNextMatches(p -> p.getLastName().equals("Schneider")) + .verifyComplete(); + } + + @Test + void findAllShouldWork(@Autowired PersonRepository repository) { + + repository.findAll(firstName.eq(Cypher.literalOf("Helge")).or(lastName.eq(Cypher.literalOf("B.")))) + .map(Person::getFirstName) + .sort() + .as(StepVerifier::create) + .expectNext("Bela", "Helge") + .verifyComplete(); + } + + @Test + void sortedFindAllShouldWork(@Autowired PersonRepository repository) { + + repository.findAll(firstName.eq(Cypher.literalOf("Helge")).or(lastName.eq(Cypher.literalOf("B."))), + Sort.by("lastName").descending() + ) + .map(Person::getFirstName) + .as(StepVerifier::create) + .expectNext("Helge", "Bela") + .verifyComplete(); + } + + @Test + void sortedFindAllShouldWorkWithParameter(@Autowired PersonRepository repository) { + + repository.findAll( + firstName.eq(Cypher.anonParameter("Helge")) + .or(lastName.eq(Cypher.parameter("someName", "B."))), // <.> + lastName.descending() // <.> + ) + .map(Person::getFirstName) + .as(StepVerifier::create) + .expectNext("Helge", "Bela") + .verifyComplete(); + } + + @Test + void orderedFindAllShouldWork(@Autowired PersonRepository repository) { + + repository.findAll(firstName.eq(Cypher.literalOf("Helge")).or(lastName.eq(Cypher.literalOf("B."))), + Sort.by("lastName").descending() + ) + .map(Person::getFirstName) + .as(StepVerifier::create) + .expectNext("Helge", "Bela") + .verifyComplete(); + } + + @Test + void orderedFindAllWithoutPredicateShouldWork(@Autowired PersonRepository repository) { + + repository.findAll(lastName.descending()) + .map(Person::getFirstName) + .as(StepVerifier::create) + .expectNext("Helge", "B", "A", "Bela") + .verifyComplete(); + } + + @Test + void countShouldWork(@Autowired PersonRepository repository) { + + repository.count(firstName.eq(Cypher.literalOf("Helge")).or(lastName.eq(Cypher.literalOf("B.")))) + .as(StepVerifier::create) + .expectNext(2L) + .verifyComplete(); + } + + @Test + void existsShouldWork(@Autowired PersonRepository repository) { + + repository.exists(firstName.eq(Cypher.literalOf("A"))) + .as(StepVerifier::create) + .expectNext(true) + .verifyComplete(); + } + + interface PersonRepository extends ReactiveNeo4jRepository, ReactiveCypherdslConditionExecutor { + } + + @Configuration + @EnableTransactionManagement + @EnableReactiveNeo4jRepositories(considerNestedRepositories = true) + static class Config extends Neo4jReactiveTestConfiguration { + + @Bean + public Driver driver() { + + return neo4jConnectionSupport.getDriver(); + } + + @Bean + public BookmarkCapture bookmarkCapture() { + return new BookmarkCapture(); + } + + @Override + public ReactiveTransactionManager reactiveTransactionManager(Driver driver, ReactiveDatabaseSelectionProvider databaseSelectionProvider) { + + BookmarkCapture bookmarkCapture = bookmarkCapture(); + return new ReactiveNeo4jTransactionManager(driver, databaseSelectionProvider, Neo4jBookmarkManager.create(bookmarkCapture)); + } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveCypherdslStatementExecutorIT.java b/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveCypherdslStatementExecutorIT.java index e6223c6aba..13233192dc 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveCypherdslStatementExecutorIT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveCypherdslStatementExecutorIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -20,6 +20,7 @@ import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager; import org.springframework.data.neo4j.core.transaction.ReactiveNeo4jTransactionManager; import org.springframework.data.neo4j.test.BookmarkCapture; +import org.springframework.data.neo4j.test.Neo4jReactiveTestConfiguration; import org.springframework.transaction.ReactiveTransactionManager; import reactor.test.StepVerifier; @@ -38,7 +39,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.neo4j.config.AbstractReactiveNeo4jConfig; import org.springframework.data.neo4j.core.mapping.Constants; import org.springframework.data.neo4j.integration.shared.common.NamesOnly; import org.springframework.data.neo4j.integration.shared.common.Person; @@ -195,7 +195,7 @@ interface PersonRepository extends ReactiveNeo4jRepository, Reacti @Configuration @EnableTransactionManagement @EnableReactiveNeo4jRepositories(considerNestedRepositories = true) - static class Config extends AbstractReactiveNeo4jConfig { + static class Config extends Neo4jReactiveTestConfiguration { @Bean public Driver driver() { @@ -214,5 +214,10 @@ public ReactiveTransactionManager reactiveTransactionManager(Driver driver, Reac BookmarkCapture bookmarkCapture = bookmarkCapture(); return new ReactiveNeo4jTransactionManager(driver, databaseSelectionProvider, Neo4jBookmarkManager.create(bookmarkCapture)); } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } } } diff --git a/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveDynamicLabelsIT.java b/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveDynamicLabelsIT.java index 4fda47803b..5aecb2a073 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveDynamicLabelsIT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveDynamicLabelsIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -16,15 +16,25 @@ package org.springframework.data.neo4j.integration.reactive; import static org.assertj.core.api.Assertions.assertThat; -import static org.neo4j.cypherdsl.core.Conditions.not; -import static org.neo4j.cypherdsl.core.Predicates.exists; +import org.junit.jupiter.api.RepeatedTest; +import org.springframework.data.neo4j.core.mapping.Neo4jMappingContext; +import org.springframework.data.neo4j.integration.shared.common.CounterMetric; +import org.springframework.data.neo4j.integration.shared.common.GaugeMetric; +import org.springframework.data.neo4j.integration.shared.common.HistogramMetric; +import org.springframework.data.neo4j.integration.shared.common.Metric; +import org.springframework.data.neo4j.integration.shared.common.SummaryMetric; +import org.springframework.data.neo4j.test.Neo4jReactiveTestConfiguration; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.test.StepVerifier; +import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; +import java.util.List; +import java.util.Map; import java.util.UUID; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Predicate; @@ -46,7 +56,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.neo4j.config.AbstractReactiveNeo4jConfig; import org.springframework.data.neo4j.core.ReactiveDatabaseSelectionProvider; import org.springframework.data.neo4j.core.ReactiveNeo4jTemplate; import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager; @@ -80,6 +89,38 @@ public class ReactiveDynamicLabelsIT { protected static Neo4jExtension.Neo4jConnectionSupport neo4jConnectionSupport; + + @Nested + class DynamicLabelsAndOrderOfClassesBeingLoaded extends SpringTestBase { + + @Override + Long createTestEntity(Transaction t) { + return t.run("CREATE (m:Metric:Counter:A:B:C:D {timestamp: datetime()}) RETURN id(m)").single().get(0).asLong(); + + } + + @RepeatedTest(100) // GH-2619 + void ownLabelsShouldNotEndUpWithDynamicLabels(@Autowired Neo4jMappingContext mappingContext, @Autowired ReactiveNeo4jTemplate template) { + + List> metrics = Arrays.asList(GaugeMetric.class, SummaryMetric.class, HistogramMetric.class, CounterMetric.class); + Collections.shuffle(metrics); + for (Class type : metrics) { + assertThat(mappingContext.getPersistentEntity(type)).isNotNull(); + } + + Map args = new HashMap<>(); + args.put("agentIdLabel", "B"); + template.findAll("MATCH (m:Metric) WHERE $agentIdLabel in labels(m) RETURN m ORDER BY m.timestamp DESC", args, Metric.class) + .as(StepVerifier::create) + .assertNext(cm -> { + assertThat(cm).isInstanceOf(CounterMetric.class); + assertThat(cm.getId()).isEqualTo(existingEntityId); + assertThat(cm.getDynamicLabels()).containsExactlyInAnyOrder("A", "B", "C", "D"); + }) + .verifyComplete(); + } + } + @Nested class EntityWithSingleStaticLabelAndGeneratedId extends SpringTestBase { @@ -452,7 +493,7 @@ protected final Flux getLabels(Condition idCondition, Object id) { Node n = Cypher.anyNode("n"); String cypher = Renderer.getDefaultRenderer().render(Cypher.match(n).where(idCondition) - .and(not(exists(n.property("moreLabels")))).unwind(n.labels()).as("label").returning("label").build()); + .and(n.property("moreLabels").isNull()).unwind(n.labels()).as("label").returning("label").build()); return Flux .usingWhen(Mono.fromSupplier(() -> driver.rxSession(bookmarkCapture.createSessionConfig())), s -> s.run(cypher, Collections.singletonMap("id", id)).records(), RxSession::close) @@ -461,7 +502,7 @@ protected final Flux getLabels(Condition idCondition, Object id) { @Configuration @EnableTransactionManagement - static class Config extends AbstractReactiveNeo4jConfig { + static class Config extends Neo4jReactiveTestConfiguration { @Bean public Driver driver() { @@ -484,6 +525,11 @@ public ReactiveTransactionManager reactiveTransactionManager(Driver driver, Reac public TransactionalOperator transactionalOperator(ReactiveTransactionManager transactionManager) { return TransactionalOperator.create(transactionManager); } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } } } diff --git a/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveDynamicRelationshipsIT.java b/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveDynamicRelationshipsIT.java index e32389f319..b69caa3cc6 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveDynamicRelationshipsIT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveDynamicRelationshipsIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -27,6 +27,7 @@ import org.springframework.data.neo4j.integration.shared.common.HobbyRelationship; import org.springframework.data.neo4j.integration.shared.common.PersonWithRelatives.TypeOfClub; import org.springframework.data.neo4j.integration.shared.common.PersonWithRelatives.TypeOfHobby; +import org.springframework.data.neo4j.test.Neo4jReactiveTestConfiguration; import reactor.test.StepVerifier; import java.util.ArrayList; @@ -42,7 +43,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.neo4j.config.AbstractReactiveNeo4jConfig; import org.springframework.data.neo4j.integration.shared.common.DynamicRelationshipsITBase; import org.springframework.data.neo4j.integration.shared.common.Person; import org.springframework.data.neo4j.integration.shared.common.PersonWithRelatives; @@ -220,14 +220,14 @@ void shouldWriteDynamicRelationships(@Autowired PersonWithRelativesRepository re assertThat(relatives).containsOnlyKeys(TypeOfRelative.RELATIVE_1, TypeOfRelative.RELATIVE_2); }).verifyComplete(); - try (Transaction transaction = driver.session().beginTransaction()) { + try (Transaction transaction = driver.session(bookmarkCapture.createSessionConfig()).beginTransaction()) { long numberOfRelations = transaction - .run("" + "MATCH (t:" + labelOfTestSubject + ") WHERE id(t) = $id " + "RETURN size((t)-->(:Person))" - + " as numberOfRelations", Values.parameters("id", recorded.get(0).getId())) + .run("" + "MATCH (t:" + labelOfTestSubject + ")-[r]->(:Person) WHERE id(t) = $id " + "RETURN count(r)" + + " as numberOfRelations", Values.parameters("id", newPerson.getId())) .single().get("numberOfRelations").asLong(); assertThat(numberOfRelations).isEqualTo(2L); numberOfRelations = transaction - .run("" + "MATCH (t:" + labelOfTestSubject + ") WHERE id(t) = $id " + "RETURN size((t)-->(:Club))" + .run("" + "MATCH (t:" + labelOfTestSubject + ")-[r]->(:Club) WHERE id(t) = $id " + "RETURN count(r)" + " as numberOfRelations", Values.parameters("id", newPerson.getId())) .single().get("numberOfRelations").asLong(); assertThat(numberOfRelations).isEqualTo(2L); @@ -272,14 +272,14 @@ void shouldWriteDynamicCollectionRelationships(@Autowired PersonWithRelativesRep assertThat(writtenPets).containsOnlyKeys(TypeOfPet.MONSTERS, TypeOfPet.FISH); }).verifyComplete(); - try (Transaction transaction = driver.session().beginTransaction()) { + try (Transaction transaction = driver.session(bookmarkCapture.createSessionConfig()).beginTransaction()) { long numberOfRelations = transaction - .run("" + "MATCH (t:" + labelOfTestSubject + ") WHERE id(t) = $id " + "RETURN size((t)-->(:Pet))" - + " as numberOfRelations", Values.parameters("id", recorded.get(0).getId())) + .run("" + "MATCH (t:" + labelOfTestSubject + ")-[r]->(:Pet) WHERE id(t) = $id RETURN count(r)" + + " as numberOfRelations", Values.parameters("id", newPerson.getId())) .single().get("numberOfRelations").asLong(); assertThat(numberOfRelations).isEqualTo(3L); numberOfRelations = transaction - .run("" + "MATCH (t:" + labelOfTestSubject + ") WHERE id(t) = $id " + "RETURN size((t)-->(:Hobby))" + .run("" + "MATCH (t:" + labelOfTestSubject + ")-[r]->(:Hobby) WHERE id(t) = $id RETURN count(r)" + " as numberOfRelations", Values.parameters("id", newPerson.getId())) .single().get("numberOfRelations").asLong(); assertThat(numberOfRelations).isEqualTo(2L); @@ -291,7 +291,7 @@ interface PersonWithRelativesRepository extends ReactiveNeo4jRepository session.run("CREATE CONSTRAINT ON (person:SimplePerson) ASSERT person.name IS UNIQUE").consume(), RxSession::close).then().as(StepVerifier::create).verifyComplete(); @@ -77,7 +77,7 @@ static void createConstraints(@Autowired Driver driver) { @AfterAll static void dropConstraints(@Autowired Driver driver) { - + assumeNeo4jLowerThan44(); Flux.using(driver::rxSession, session -> session.run("DROP CONSTRAINT ON (person:SimplePerson) ASSERT person.name IS UNIQUE").consume(), RxSession::close).then().as(StepVerifier::create).verifyComplete(); @@ -90,8 +90,7 @@ void clearDatabase(@Autowired Driver driver) { .then().as(StepVerifier::create).verifyComplete(); } - @BeforeEach - void assumeNeo4jLowerThan44() { + private static void assumeNeo4jLowerThan44() { assumeThat(neo4jConnectionSupport.getServerVersion() .lessThan(ServerVersion.version("Neo4j/4.4.0"))).isTrue(); @@ -123,7 +122,7 @@ void exceptionsOnRepositoryBeansShouldBeTranslated(@Autowired CustomDAO customDA @Configuration @EnableReactiveNeo4jRepositories(considerNestedRepositories = true) @EnableTransactionManagement - static class Config extends AbstractReactiveNeo4jConfig { + static class Config extends Neo4jReactiveTestConfiguration { @Bean public Driver driver() { @@ -146,6 +145,11 @@ public Neo4jPersistenceExceptionTranslator neo4jPersistenceExceptionTranslator() public ReactivePersistenceExceptionTranslationPostProcessor persistenceExceptionTranslationPostProcessor() { return new ReactivePersistenceExceptionTranslationPostProcessor(); } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } } interface SimplePersonRepository extends ReactiveNeo4jRepository {} diff --git a/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveIdGeneratorsIT.java b/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveIdGeneratorsIT.java index a724f0cba8..3b19a549f2 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveIdGeneratorsIT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveIdGeneratorsIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -17,6 +17,7 @@ import static org.assertj.core.api.Assertions.assertThat; +import org.springframework.data.neo4j.test.Neo4jReactiveTestConfiguration; import reactor.core.publisher.Mono; import reactor.test.StepVerifier; @@ -33,7 +34,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.neo4j.config.AbstractReactiveNeo4jConfig; import org.springframework.data.neo4j.core.ReactiveDatabaseSelectionProvider; import org.springframework.data.neo4j.core.schema.IdGenerator; import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager; @@ -138,7 +138,7 @@ interface ThingWithIdGeneratedByBeanRepository extends ReactiveCrudRepository(a:Address {city: 'Aachen'})" + + "-[:LIVES_AT]->(a:Address {city: 'Aachen', id: 1})" + "-[:BASED_IN]->(c:YetAnotherCountryEntity{name: 'Gemany', countryCode: 'DE'})" + "RETURN id(p)") .single().get(0).asLong(); @@ -688,6 +689,32 @@ void saveAsWithClosedProjectionOnThreeLevelShouldWork(@Autowired ReactiveNeo4jTe .verifyComplete(); } + @Test // GH-2544 + void saveAllAsWithEmptyList(@Autowired ReactiveNeo4jTemplate template) { + + template.saveAllAs(Collections.emptyList(), ClosedProjection.class) + .as(StepVerifier::create) + .verifyComplete(); + } + + static class X { + } + + static class Y { + } + + @Test // GH-2544 + void saveWeirdHierarchy(@Autowired ReactiveNeo4jTemplate template) { + + List things = new ArrayList<>(); + things.add(new X()); + things.add(new Y()); + + template.saveAllAs(things, ClosedProjection.class) + .as(StepVerifier::create) + .verifyErrorMatches(t -> t instanceof IllegalArgumentException && t.getMessage().equals("Could not determine a common element of an heterogeneous collection.")); + } + @Test void saveAllAsWithClosedProjectionShouldWork(@Autowired ReactiveNeo4jTemplate template) { @@ -909,7 +936,7 @@ void saveWithProjectionImplementedByEntity(@Autowired Neo4jMappingContext mappin @Configuration @EnableTransactionManagement - static class Config extends AbstractReactiveNeo4jConfig { + static class Config extends Neo4jReactiveTestConfiguration { @Bean public Driver driver() { @@ -932,5 +959,10 @@ public ReactiveTransactionManager reactiveTransactionManager(Driver driver, Reac BookmarkCapture bookmarkCapture = bookmarkCapture(); return new ReactiveNeo4jTransactionManager(driver, databaseSelectionProvider, Neo4jBookmarkManager.create(bookmarkCapture)); } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } } } diff --git a/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveNeo4jTransactionManagerTestIT.java b/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveNeo4jTransactionManagerTestIT.java index 12d3cf103d..fbd180043a 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveNeo4jTransactionManagerTestIT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveNeo4jTransactionManagerTestIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -20,6 +20,7 @@ import org.springframework.data.neo4j.core.ReactiveDatabaseSelectionProvider; import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager; import org.springframework.data.neo4j.test.BookmarkCapture; +import org.springframework.data.neo4j.test.Neo4jReactiveTestConfiguration; import org.springframework.transaction.ReactiveTransactionManager; import reactor.core.publisher.Mono; import reactor.test.StepVerifier; @@ -32,7 +33,6 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.dao.InvalidDataAccessResourceUsageException; -import org.springframework.data.neo4j.config.AbstractReactiveNeo4jConfig; import org.springframework.data.neo4j.core.ReactiveNeo4jClient; import org.springframework.data.neo4j.core.transaction.ReactiveNeo4jTransactionManager; import org.springframework.data.neo4j.integration.shared.common.Person; @@ -89,7 +89,7 @@ interface SomeRepository extends ReactiveNeo4jRepository { @Configuration @EnableTransactionManagement @EnableReactiveNeo4jRepositories(considerNestedRepositories = true) - static class Config extends AbstractReactiveNeo4jConfig { + static class Config extends Neo4jReactiveTestConfiguration { @Bean public Driver driver() { @@ -108,5 +108,10 @@ public ReactiveTransactionManager reactiveTransactionManager(Driver driver, Reac BookmarkCapture bookmarkCapture = bookmarkCapture(); return new ReactiveNeo4jTransactionManager(driver, databaseSelectionProvider, Neo4jBookmarkManager.create(bookmarkCapture)); } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } } } diff --git a/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveOptimisticLockingIT.java b/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveOptimisticLockingIT.java index 1e6fad7b48..d8e877f2ae 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveOptimisticLockingIT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveOptimisticLockingIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -17,6 +17,7 @@ import static org.assertj.core.api.Assertions.assertThat; +import org.springframework.data.neo4j.test.Neo4jReactiveTestConfiguration; import reactor.core.publisher.Flux; import reactor.test.StepVerifier; @@ -36,7 +37,6 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.dao.OptimisticLockingFailureException; -import org.springframework.data.neo4j.config.AbstractReactiveNeo4jConfig; import org.springframework.data.neo4j.core.ReactiveDatabaseSelectionProvider; import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager; import org.springframework.data.neo4j.core.transaction.ReactiveNeo4jTransactionManager; @@ -364,7 +364,7 @@ interface VersionedThingWithAssignedIdRepository @Configuration @EnableTransactionManagement @EnableReactiveNeo4jRepositories(considerNestedRepositories = true) - static class Config extends AbstractReactiveNeo4jConfig { + static class Config extends Neo4jReactiveTestConfiguration { @Bean public Driver driver() { @@ -382,5 +382,10 @@ public ReactiveTransactionManager reactiveTransactionManager(Driver driver, Reac BookmarkCapture bookmarkCapture = bookmarkCapture(); return new ReactiveNeo4jTransactionManager(driver, databaseSelectionProvider, Neo4jBookmarkManager.create(bookmarkCapture)); } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } } } diff --git a/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveProjectionIT.java b/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveProjectionIT.java index 6b36683bbe..3b6442c1d5 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveProjectionIT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveProjectionIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -17,48 +17,52 @@ import static org.assertj.core.api.Assertions.assertThat; -import org.neo4j.cypherdsl.core.Cypher; -import org.neo4j.cypherdsl.core.Node; -import org.neo4j.cypherdsl.core.Statement; -import org.neo4j.driver.Record; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.data.neo4j.core.ReactiveDatabaseSelectionProvider; -import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager; -import org.springframework.data.neo4j.core.transaction.ReactiveNeo4jTransactionManager; -import org.springframework.data.neo4j.integration.shared.common.ProjectionTest1O1; -import org.springframework.data.neo4j.integration.shared.common.ProjectionTestLevel1; -import org.springframework.data.neo4j.integration.shared.common.ProjectionTestRoot; -import org.springframework.data.neo4j.repository.query.Query; -import org.springframework.data.neo4j.repository.support.ReactiveCypherdslStatementExecutor; -import org.springframework.data.neo4j.test.BookmarkCapture; -import org.springframework.data.repository.query.Param; -import org.springframework.transaction.ReactiveTransactionManager; +import org.springframework.data.neo4j.test.Neo4jReactiveTestConfiguration; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.test.StepVerifier; +import java.util.Collections; +import java.util.List; + import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; +import org.neo4j.cypherdsl.core.Cypher; +import org.neo4j.cypherdsl.core.Node; +import org.neo4j.cypherdsl.core.Statement; import org.neo4j.driver.Driver; +import org.neo4j.driver.Record; import org.neo4j.driver.Session; import org.neo4j.driver.Transaction; +import org.neo4j.driver.types.MapAccessor; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.neo4j.config.AbstractReactiveNeo4jConfig; +import org.springframework.data.neo4j.core.ReactiveDatabaseSelectionProvider; +import org.springframework.data.neo4j.core.ReactiveNeo4jTemplate; +import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager; +import org.springframework.data.neo4j.core.transaction.ReactiveNeo4jTransactionManager; import org.springframework.data.neo4j.integration.shared.common.NamesOnly; import org.springframework.data.neo4j.integration.shared.common.NamesOnlyDto; import org.springframework.data.neo4j.integration.shared.common.Person; import org.springframework.data.neo4j.integration.shared.common.PersonSummary; +import org.springframework.data.neo4j.integration.shared.common.PersonWithNoConstructor; +import org.springframework.data.neo4j.integration.shared.common.ProjectionTest1O1; +import org.springframework.data.neo4j.integration.shared.common.ProjectionTestLevel1; +import org.springframework.data.neo4j.integration.shared.common.ProjectionTestRoot; import org.springframework.data.neo4j.repository.ReactiveNeo4jRepository; import org.springframework.data.neo4j.repository.config.EnableReactiveNeo4jRepositories; +import org.springframework.data.neo4j.repository.query.Query; +import org.springframework.data.neo4j.repository.support.ReactiveCypherdslStatementExecutor; +import org.springframework.data.neo4j.test.BookmarkCapture; import org.springframework.data.neo4j.test.Neo4jExtension; import org.springframework.data.neo4j.test.Neo4jIntegrationTest; +import org.springframework.data.repository.query.Param; +import org.springframework.transaction.ReactiveTransactionManager; import org.springframework.transaction.annotation.EnableTransactionManagement; -import java.util.List; - /** * @author Gerrit Meier */ @@ -91,6 +95,7 @@ void setup(@Autowired BookmarkCapture bookmarkCapture) { transaction.run("CREATE (:Person{firstName:'" + FIRST_NAME + "', lastName:'" + LAST_NAME + "'})" + "-[:LIVES_AT]->" + "(:Address{city:'" + CITY + "'})"); + transaction.run("CREATE (p:PersonWithNoConstructor {name: 'meistermeier', first_name: 'Gerrit', mittlererName: 'unknown'}) RETURN p"); Record result = transaction.run("create (r:ProjectionTestRoot {name: 'root'}) \n" + "create (o:ProjectionTest1O1 {name: '1o1'}) " @@ -302,6 +307,62 @@ void findByIdInDerivedFinderMethodInRelatedObjectWithProjectionShouldWork( .verifyComplete(); } + @Test // GH-2371 + void findWithCustomPropertyNameWorks(@Autowired PersonWithNoConstructorRepository repository) { + + repository.findAll().as(StepVerifier::create).expectNextCount(1L); + + repository.findByName("meistermeier") + .as(StepVerifier::create) + .assertNext(person -> { + assertThat(person.getFirstName()).isEqualTo("Gerrit"); + assertThat(person.getMittlererName()).isEqualTo("unknown"); + }) + .verifyComplete(); + } + + @Test // GH-2371 + void saveWithCustomPropertyNameWorks(@Autowired BookmarkCapture bookmarkCapture, @Autowired ReactiveNeo4jTemplate neo4jTemplate) { + + neo4jTemplate + .findOne("MATCH (p:PersonWithNoConstructor {name: 'meistermeier'}) RETURN p", Collections.emptyMap(), PersonWithNoConstructor.class) + .doOnNext(person -> { + person.setName("rotnroll666"); + person.setFirstName("Michael"); + person.setMiddleName("foo"); + }).flatMap(p -> neo4jTemplate.saveAs(p, ProjectedPersonWithNoConstructor.class)) + .as(StepVerifier::create) + .expectNextCount(1L) + .verifyComplete(); + + + + try (Session session = driver.session(bookmarkCapture.createSessionConfig())) { + Record record = session + .run("MATCH (p:PersonWithNoConstructor {name: 'rotnroll666'}) RETURN p") + .single(); + + MapAccessor p = record.get("p").asNode(); + assertThat(p.get("first_name").asString()).isEqualTo("Michael"); + assertThat(p.get("mittlererName").asString()).isEqualTo("foo"); + } + } + + interface ProjectedPersonWithNoConstructor { + + String getName(); + + String getFirstName(); + + String getMittlererName(); + } + + interface PersonWithNoConstructorRepository extends ReactiveNeo4jRepository { + + Mono findByName(String name); + } + + interface ReactiveProjectionPersonRepository extends ReactiveNeo4jRepository, ReactiveCypherdslStatementExecutor { @@ -391,7 +452,7 @@ interface Subprojection2 { @Configuration @EnableReactiveNeo4jRepositories(considerNestedRepositories = true) @EnableTransactionManagement - static class Config extends AbstractReactiveNeo4jConfig { + static class Config extends Neo4jReactiveTestConfiguration { @Bean public Driver driver() { @@ -410,6 +471,10 @@ public ReactiveTransactionManager reactiveTransactionManager(Driver driver, Reac return new ReactiveNeo4jTransactionManager(driver, databaseSelectionProvider, Neo4jBookmarkManager.create(bookmarkCapture)); } + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } } } diff --git a/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveQuerydslNeo4jPredicateExecutorIT.java b/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveQuerydslNeo4jPredicateExecutorIT.java index e76642ba6b..0cd583d619 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveQuerydslNeo4jPredicateExecutorIT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveQuerydslNeo4jPredicateExecutorIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -17,6 +17,7 @@ import static org.assertj.core.api.Assertions.assertThat; +import org.springframework.data.neo4j.test.Neo4jReactiveTestConfiguration; import reactor.test.StepVerifier; import org.junit.jupiter.api.BeforeAll; @@ -29,7 +30,6 @@ import org.springframework.context.annotation.Configuration; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; -import org.springframework.data.neo4j.config.AbstractReactiveNeo4jConfig; import org.springframework.data.neo4j.core.ReactiveDatabaseSelectionProvider; import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager; import org.springframework.data.neo4j.core.transaction.ReactiveNeo4jTransactionManager; @@ -286,7 +286,7 @@ interface QueryDSLPersonRepository extends ReactiveNeo4jRepository @Configuration @EnableTransactionManagement @EnableReactiveNeo4jRepositories(considerNestedRepositories = true) - static class Config extends AbstractReactiveNeo4jConfig { + static class Config extends Neo4jReactiveTestConfiguration { @Bean public Driver driver() { @@ -305,5 +305,10 @@ public ReactiveTransactionManager reactiveTransactionManager(Driver driver, Reac BookmarkCapture bookmarkCapture = bookmarkCapture(); return new ReactiveNeo4jTransactionManager(driver, databaseSelectionProvider, Neo4jBookmarkManager.create(bookmarkCapture)); } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } } } diff --git a/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveRelationshipsIT.java b/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveRelationshipsIT.java index fdf58789e8..3d88b5ac31 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveRelationshipsIT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveRelationshipsIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -21,6 +21,7 @@ import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager; import org.springframework.data.neo4j.core.transaction.ReactiveNeo4jTransactionManager; import org.springframework.data.neo4j.test.BookmarkCapture; +import org.springframework.data.neo4j.test.Neo4jReactiveTestConfiguration; import org.springframework.transaction.ReactiveTransactionManager; import reactor.test.StepVerifier; @@ -36,7 +37,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.neo4j.config.AbstractReactiveNeo4jConfig; import org.springframework.data.neo4j.integration.shared.common.MultipleRelationshipsThing; import org.springframework.data.neo4j.integration.shared.common.RelationshipsITBase; import org.springframework.data.neo4j.repository.config.EnableReactiveNeo4jRepositories; @@ -228,7 +228,7 @@ interface MultipleRelationshipsThingRepository extends ReactiveCrudRepository (ReactiveUserSelectionProvider) () -> Mono.just(u)) .orElse(ReactiveUserSelectionProvider.getDefaultSelectionProvider()); } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } } } diff --git a/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveRepositoryWithADifferentDatabaseIT.java b/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveRepositoryWithADifferentDatabaseIT.java index b787e3156d..f37d9a3c2e 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveRepositoryWithADifferentDatabaseIT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveRepositoryWithADifferentDatabaseIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveRepositoryWithADifferentUserIT.java b/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveRepositoryWithADifferentUserIT.java index b4dd1aea31..73dba160f0 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveRepositoryWithADifferentUserIT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveRepositoryWithADifferentUserIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveStringlyTypeDynamicRelationshipsIT.java b/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveStringlyTypeDynamicRelationshipsIT.java index e9360d3124..2ac1f2e5f0 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveStringlyTypeDynamicRelationshipsIT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveStringlyTypeDynamicRelationshipsIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -26,6 +26,7 @@ import org.springframework.data.neo4j.integration.shared.common.Hobby; import org.springframework.data.neo4j.integration.shared.common.HobbyRelationship; +import org.springframework.data.neo4j.test.Neo4jReactiveTestConfiguration; import reactor.test.StepVerifier; import java.util.ArrayList; @@ -41,7 +42,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.neo4j.config.AbstractReactiveNeo4jConfig; import org.springframework.data.neo4j.integration.shared.common.DynamicRelationshipsITBase; import org.springframework.data.neo4j.integration.shared.common.Person; import org.springframework.data.neo4j.integration.shared.common.PersonWithStringlyTypedRelatives; @@ -221,12 +221,12 @@ void shouldWriteDynamicRelationships(@Autowired PersonWithRelativesRepository re try (Transaction transaction = driver.session(bookmarkCapture.createSessionConfig()).beginTransaction()) { long numberOfRelations = transaction - .run("" + "MATCH (t:" + labelOfTestSubject + ") WHERE id(t) = $id " + "RETURN size((t)-->(:Person))" - + " as numberOfRelations", Values.parameters("id", recorded.get(0).getId())) + .run("" + "MATCH (t:" + labelOfTestSubject + ")-[r]->(:Person) WHERE id(t) = $id " + "RETURN count(r)" + + " as numberOfRelations", Values.parameters("id", newPerson.getId())) .single().get("numberOfRelations").asLong(); assertThat(numberOfRelations).isEqualTo(2L); numberOfRelations = transaction - .run("" + "MATCH (t:" + labelOfTestSubject + ") WHERE id(t) = $id " + "RETURN size((t)-->(:Club))" + .run("" + "MATCH (t:" + labelOfTestSubject + ")-[r]->(:Club) WHERE id(t) = $id " + "RETURN count(r)" + " as numberOfRelations", Values.parameters("id", newPerson.getId())) .single().get("numberOfRelations").asLong(); assertThat(numberOfRelations).isEqualTo(2L); @@ -270,12 +270,12 @@ void shouldWriteDynamicCollectionRelationships(@Autowired PersonWithRelativesRep try (Transaction transaction = driver.session(bookmarkCapture.createSessionConfig()).beginTransaction()) { long numberOfRelations = transaction - .run("" + "MATCH (t:" + labelOfTestSubject + ") WHERE id(t) = $id " + "RETURN size((t)-->(:Pet))" - + " as numberOfRelations", Values.parameters("id", recorded.get(0).getId())) + .run("" + "MATCH (t:" + labelOfTestSubject + ")-[r]->(:Pet) WHERE id(t) = $id RETURN count(r)" + + " as numberOfRelations", Values.parameters("id", newPerson.getId())) .single().get("numberOfRelations").asLong(); assertThat(numberOfRelations).isEqualTo(3L); numberOfRelations = transaction - .run("" + "MATCH (t:" + labelOfTestSubject + ") WHERE id(t) = $id " + "RETURN size((t)-->(:Hobby))" + .run("" + "MATCH (t:" + labelOfTestSubject + ")-[r]->(:Hobby) WHERE id(t) = $id RETURN count(r)" + " as numberOfRelations", Values.parameters("id", newPerson.getId())) .single().get("numberOfRelations").asLong(); assertThat(numberOfRelations).isEqualTo(2L); @@ -287,7 +287,7 @@ interface PersonWithRelativesRepository extends ReactiveNeo4jRepository friends = new HashSet<>(); + + public DoritoEatingPerson(String name) { + this.name = name; + } + + /** + * Projection containing ambiguous name + */ + public interface PropertiesProjection1 { + + boolean getEatsDoritos(); + + boolean getFriendsAlsoEatDoritos(); + } + + /** + * Projection not containing ambiguous name + */ + public interface PropertiesProjection2 { + + boolean getEatsDoritos(); + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/DtoPersonProjection.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/DtoPersonProjection.java index 12c9c964ac..bf0cb0b24f 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/DtoPersonProjection.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/DtoPersonProjection.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/DtoPersonProjectionContainingAdditionalFields.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/DtoPersonProjectionContainingAdditionalFields.java index 13790e62dd..ac1d034f80 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/DtoPersonProjectionContainingAdditionalFields.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/DtoPersonProjectionContainingAdditionalFields.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/DynamicRelationshipsITBase.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/DynamicRelationshipsITBase.java index 690e658834..3e8f067c87 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/DynamicRelationshipsITBase.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/DynamicRelationshipsITBase.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/Editor.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/Editor.java new file mode 100644 index 0000000000..80a90ded86 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/Editor.java @@ -0,0 +1,50 @@ +/* + * Copyright 2011-2023 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 java.util.UUID; + +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 Editor { + @Id @GeneratedValue + private UUID id; + + String name; + + @Relationship("HAS_PREDECESSOR") + private Editor predecessor; + + public Editor(String name, Editor predecessor) { + this.name = name; + this.predecessor = predecessor; + } + + public String getName() { + return name; + } + + public Editor getPredecessor() { + return predecessor; + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/EntitiesWithDynamicLabels.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/EntitiesWithDynamicLabels.java index c2ce48393b..6ee0104347 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/EntitiesWithDynamicLabels.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/EntitiesWithDynamicLabels.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -178,5 +178,37 @@ public static class EntityWithCustomIdAndDynamicLabels { @DynamicLabels public Set myLabels; } + /** + * Base entity for the multi-level abstraction + */ + @Node + public static abstract class BaseEntityWithoutDynamicLabels { + @Id public String id; + } + + /** + * adds the labels + */ + @Node + public static abstract class AbstractBaseEntityWithDynamicLabels extends BaseEntityWithoutDynamicLabels { + @DynamicLabels public Set labels; + } + + /** + * This might be the wrong most concrete class to be found + */ + @Node + public static abstract class AbstractEntityWithDynamicLabels extends AbstractBaseEntityWithDynamicLabels { + + } + + /** + * ...but this is the right one + */ + @Node + public static class EntityWithMultilevelInheritanceAndDynamicLabels extends AbstractEntityWithDynamicLabels { + public String name; + } + private EntitiesWithDynamicLabels() {} } diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/EntityWithConvertedId.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/EntityWithConvertedId.java index 0751a3f440..01ce0de588 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/EntityWithConvertedId.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/EntityWithConvertedId.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/EntityWithDynamicLabelsAndIdThatNeedsToBeConverted.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/EntityWithDynamicLabelsAndIdThatNeedsToBeConverted.java index ef696fe88e..bdc5b445a2 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/EntityWithDynamicLabelsAndIdThatNeedsToBeConverted.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/EntityWithDynamicLabelsAndIdThatNeedsToBeConverted.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/EntityWithPrimitiveConstructorArguments.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/EntityWithPrimitiveConstructorArguments.java new file mode 100644 index 0000000000..6810495d7b --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/EntityWithPrimitiveConstructorArguments.java @@ -0,0 +1,36 @@ +/* + * Copyright 2011-2023 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; + +/** + * Reproducer class for Gh-2505 + */ +@Node +public class EntityWithPrimitiveConstructorArguments { + @Id @GeneratedValue public Long id; + + public final boolean someBooleanValue; + public final int someIntValue; + + public EntityWithPrimitiveConstructorArguments(boolean someBooleanValue, int someIntValue) { + this.someBooleanValue = someBooleanValue; + this.someIntValue = someIntValue; + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/EntityWithRelationshipPropertiesPath.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/EntityWithRelationshipPropertiesPath.java index 603a5b8662..66e5d68017 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/EntityWithRelationshipPropertiesPath.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/EntityWithRelationshipPropertiesPath.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ExtendedParentNode.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ExtendedParentNode.java index d5de71217c..08e169413f 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ExtendedParentNode.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ExtendedParentNode.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. 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 index 4e7b8cb9ff..ef8ff2eb1e 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/Friend.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/Friend.java index b0ac351593..5e2962ab7e 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/Friend.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/Friend.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/FriendshipRelationship.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/FriendshipRelationship.java index 9f22d2f200..48b48fb10b 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/FriendshipRelationship.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/FriendshipRelationship.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/GaugeMetric.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/GaugeMetric.java new file mode 100644 index 0000000000..5315c68a3d --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/GaugeMetric.java @@ -0,0 +1,30 @@ +/* + * Copyright 2011-2023 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.Node; + + +/** + * @author Michael J. Simons + */ +@Node("Gauge") +public class GaugeMetric extends Metric { + + public GaugeMetric(String name) { + super(name); + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/HistogramMetric.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/HistogramMetric.java new file mode 100644 index 0000000000..7f8eb8a629 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/HistogramMetric.java @@ -0,0 +1,29 @@ +/* + * Copyright 2011-2023 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.Node; + +/** + * @author Michael J. Simons + */ +@Node("Histogram") +public class HistogramMetric extends Metric { + + public HistogramMetric(String name) { + super(name); + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/Hobby.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/Hobby.java index 4ce8325c0e..9c0acb0e7a 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/Hobby.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/Hobby.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/HobbyRelationship.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/HobbyRelationship.java index 1a057de627..9adb900bf6 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/HobbyRelationship.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/HobbyRelationship.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/IdGeneratorsITBase.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/IdGeneratorsITBase.java index 8238477c6e..909ad68508 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/IdGeneratorsITBase.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/IdGeneratorsITBase.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutableAuditableThing.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutableAuditableThing.java index 8bd2ef267a..f0ed8741b1 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutableAuditableThing.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutableAuditableThing.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -26,7 +26,7 @@ import org.springframework.data.annotation.Id; import org.springframework.data.annotation.LastModifiedBy; import org.springframework.data.annotation.LastModifiedDate; -import org.springframework.data.annotation.PersistenceConstructor; +import org.springframework.data.annotation.PersistenceCreator; import org.springframework.data.annotation.Persistent; import org.springframework.data.neo4j.core.schema.GeneratedValue; @@ -35,7 +35,7 @@ */ @Value @With -@AllArgsConstructor(onConstructor = @__(@PersistenceConstructor)) +@AllArgsConstructor(onConstructor = @__(@PersistenceCreator)) @Persistent public class ImmutableAuditableThing implements AuditableThing { diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutableAuditableThingWithGeneratedId.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutableAuditableThingWithGeneratedId.java index 9051e67dfa..d274176010 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutableAuditableThingWithGeneratedId.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutableAuditableThingWithGeneratedId.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -26,7 +26,7 @@ import org.springframework.data.annotation.Id; import org.springframework.data.annotation.LastModifiedBy; import org.springframework.data.annotation.LastModifiedDate; -import org.springframework.data.annotation.PersistenceConstructor; +import org.springframework.data.annotation.PersistenceCreator; import org.springframework.data.annotation.Persistent; import org.springframework.data.neo4j.core.schema.GeneratedValue; import org.springframework.data.neo4j.core.support.UUIDStringGenerator; @@ -36,7 +36,7 @@ */ @Value @With -@AllArgsConstructor(onConstructor = @__(@PersistenceConstructor)) +@AllArgsConstructor(onConstructor = @__(@PersistenceCreator)) @Persistent public class ImmutableAuditableThingWithGeneratedId implements AuditableThing { diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutablePerson.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutablePerson.java index 27d1632cf8..09a782aa52 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutablePerson.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutablePerson.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutablePersonWithAssignedId.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutablePersonWithAssignedId.java index ec2123a651..36e4db3d17 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutablePersonWithAssignedId.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutablePersonWithAssignedId.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -15,7 +15,7 @@ */ package org.springframework.data.neo4j.integration.shared.common; -import org.springframework.data.annotation.PersistenceConstructor; +import org.springframework.data.annotation.PersistenceCreator; import org.springframework.data.neo4j.core.schema.Id; import org.springframework.data.neo4j.core.schema.Node; import org.springframework.data.neo4j.core.schema.Relationship; @@ -57,7 +57,7 @@ public class ImmutablePersonWithAssignedId { public final Map relationshipPropertiesDynamic; public final Map> relationshipPropertiesDynamicCollection; - @PersistenceConstructor + @PersistenceCreator public ImmutablePersonWithAssignedId( Long id, List wasOnboardedBy, diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutablePersonWithAssignedIdRelationshipProperties.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutablePersonWithAssignedIdRelationshipProperties.java index 97f6e28c0d..3b10bccf9b 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutablePersonWithAssignedIdRelationshipProperties.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutablePersonWithAssignedIdRelationshipProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutablePersonWithExternallyGeneratedId.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutablePersonWithExternallyGeneratedId.java index 84842ac2ee..08395f386c 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutablePersonWithExternallyGeneratedId.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutablePersonWithExternallyGeneratedId.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -15,7 +15,7 @@ */ package org.springframework.data.neo4j.integration.shared.common; -import org.springframework.data.annotation.PersistenceConstructor; +import org.springframework.data.annotation.PersistenceCreator; import org.springframework.data.neo4j.core.schema.GeneratedValue; import org.springframework.data.neo4j.core.schema.Id; import org.springframework.data.neo4j.core.schema.Node; @@ -57,7 +57,7 @@ public class ImmutablePersonWithExternallyGeneratedId { public final Map relationshipPropertiesDynamic; public final Map> relationshipPropertiesDynamicCollection; - @PersistenceConstructor + @PersistenceCreator public ImmutablePersonWithExternallyGeneratedId( UUID id, List wasOnboardedBy, diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutablePersonWithExternallyGeneratedIdRelationshipProperties.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutablePersonWithExternallyGeneratedIdRelationshipProperties.java index 1424d90b26..716e431758 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutablePersonWithExternallyGeneratedIdRelationshipProperties.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutablePersonWithExternallyGeneratedIdRelationshipProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutablePersonWithGeneratedId.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutablePersonWithGeneratedId.java index 9db4faac5a..97a1a05c10 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutablePersonWithGeneratedId.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutablePersonWithGeneratedId.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -15,7 +15,7 @@ */ package org.springframework.data.neo4j.integration.shared.common; -import org.springframework.data.annotation.PersistenceConstructor; +import org.springframework.data.annotation.PersistenceCreator; import org.springframework.data.neo4j.core.schema.GeneratedValue; import org.springframework.data.neo4j.core.schema.Id; import org.springframework.data.neo4j.core.schema.Node; @@ -55,7 +55,7 @@ public class ImmutablePersonWithGeneratedId { public final Map relationshipPropertiesDynamic; public final Map> relationshipPropertiesDynamicCollection; - @PersistenceConstructor + @PersistenceCreator public ImmutablePersonWithGeneratedId( Long id, List wasOnboardedBy, diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutablePersonWithGeneratedIdRelationshipProperties.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutablePersonWithGeneratedIdRelationshipProperties.java index a876d4109d..1820759939 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutablePersonWithGeneratedIdRelationshipProperties.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutablePersonWithGeneratedIdRelationshipProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutablePet.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutablePet.java index 23610405cd..2b7875ea79 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutablePet.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutablePet.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -15,7 +15,7 @@ */ package org.springframework.data.neo4j.integration.shared.common; -import org.springframework.data.annotation.PersistenceConstructor; +import org.springframework.data.annotation.PersistenceCreator; import org.springframework.data.neo4j.core.schema.GeneratedValue; import org.springframework.data.neo4j.core.schema.Id; import org.springframework.data.neo4j.core.schema.Node; @@ -38,7 +38,7 @@ public class ImmutablePet { @Relationship("Has") public final Set friends; - @PersistenceConstructor + @PersistenceCreator public ImmutablePet(Long id, String name) { this.id = id; this.name = name; diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutableSecondPersonWithAssignedId.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutableSecondPersonWithAssignedId.java index 238a98f3d9..2931863d6c 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutableSecondPersonWithAssignedId.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutableSecondPersonWithAssignedId.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -15,7 +15,7 @@ */ package org.springframework.data.neo4j.integration.shared.common; -import org.springframework.data.annotation.PersistenceConstructor; +import org.springframework.data.annotation.PersistenceCreator; import org.springframework.data.neo4j.core.schema.Id; import org.springframework.data.neo4j.core.schema.Node; import org.springframework.data.neo4j.core.schema.Relationship; @@ -55,7 +55,7 @@ public class ImmutableSecondPersonWithAssignedId { public final Map relationshipPropertiesDynamic; public final Map> relationshipPropertiesDynamicCollection; - @PersistenceConstructor + @PersistenceCreator public ImmutableSecondPersonWithAssignedId( Long id, List wasOnboardedBy, diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutableSecondPersonWithAssignedIdRelationshipProperties.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutableSecondPersonWithAssignedIdRelationshipProperties.java index 66728eae6e..2ad12e1c94 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutableSecondPersonWithAssignedIdRelationshipProperties.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutableSecondPersonWithAssignedIdRelationshipProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutableSecondPersonWithExternallyGeneratedId.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutableSecondPersonWithExternallyGeneratedId.java index 6c2bb0ab9d..42430eebb8 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutableSecondPersonWithExternallyGeneratedId.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutableSecondPersonWithExternallyGeneratedId.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -15,7 +15,7 @@ */ package org.springframework.data.neo4j.integration.shared.common; -import org.springframework.data.annotation.PersistenceConstructor; +import org.springframework.data.annotation.PersistenceCreator; import org.springframework.data.neo4j.core.schema.GeneratedValue; import org.springframework.data.neo4j.core.schema.Id; import org.springframework.data.neo4j.core.schema.Node; @@ -57,7 +57,7 @@ public class ImmutableSecondPersonWithExternallyGeneratedId { public final Map relationshipPropertiesDynamic; public final Map> relationshipPropertiesDynamicCollection; - @PersistenceConstructor + @PersistenceCreator public ImmutableSecondPersonWithExternallyGeneratedId( UUID id, List wasOnboardedBy, diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutableSecondPersonWithExternallyGeneratedIdRelationshipProperties.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutableSecondPersonWithExternallyGeneratedIdRelationshipProperties.java index 5714ff2295..ef5046b339 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutableSecondPersonWithExternallyGeneratedIdRelationshipProperties.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutableSecondPersonWithExternallyGeneratedIdRelationshipProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutableSecondPersonWithGeneratedId.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutableSecondPersonWithGeneratedId.java index a1cff792ce..73dd2d017d 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutableSecondPersonWithGeneratedId.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutableSecondPersonWithGeneratedId.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -15,7 +15,7 @@ */ package org.springframework.data.neo4j.integration.shared.common; -import org.springframework.data.annotation.PersistenceConstructor; +import org.springframework.data.annotation.PersistenceCreator; import org.springframework.data.neo4j.core.schema.GeneratedValue; import org.springframework.data.neo4j.core.schema.Id; import org.springframework.data.neo4j.core.schema.Node; @@ -54,7 +54,7 @@ public class ImmutableSecondPersonWithGeneratedId { public final Map relationshipPropertiesDynamic; public final Map> relationshipPropertiesDynamicCollection; - @PersistenceConstructor + @PersistenceCreator public ImmutableSecondPersonWithGeneratedId( Long id, List wasOnboardedBy, diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutableSecondPersonWithGeneratedIdRelationshipProperties.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutableSecondPersonWithGeneratedIdRelationshipProperties.java index f18f3d2da8..c164f77fe5 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutableSecondPersonWithGeneratedIdRelationshipProperties.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutableSecondPersonWithGeneratedIdRelationshipProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutableVersionedThing.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutableVersionedThing.java index e0ce4b5799..3bb3741e86 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutableVersionedThing.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ImmutableVersionedThing.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/Inheritance.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/Inheritance.java index 37405fe8c9..8332dd16e5 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/Inheritance.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/Inheritance.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/LikesHobbyRelationship.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/LikesHobbyRelationship.java index a35495bc82..771ece3036 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/LikesHobbyRelationship.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/LikesHobbyRelationship.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/Metric.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/Metric.java new file mode 100644 index 0000000000..33c0e9ce9e --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/Metric.java @@ -0,0 +1,60 @@ +/* + * Copyright 2011-2023 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 java.util.ArrayList; +import java.util.List; + +import org.springframework.data.neo4j.core.schema.DynamicLabels; +import org.springframework.data.neo4j.core.schema.GeneratedValue; +import org.springframework.data.neo4j.core.schema.Id; +import org.springframework.data.neo4j.core.schema.Node; + +/** + * @author Michael J. Simons + */ +@Node("Metric") +public abstract class Metric { + + @Id + @GeneratedValue + Long id; + + @DynamicLabels + public List dynamicLabels = new ArrayList<>(); + + public Long getId() { + return id; + } + + public List getDynamicLabels() { + return dynamicLabels; + } + + private String name; + + public Metric(String name) { + this.name = name; + } + + 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/Multiple1O1Relationships.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/Multiple1O1Relationships.java index d5a1136a11..143db95fd3 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/Multiple1O1Relationships.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/Multiple1O1Relationships.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/MultipleLabels.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/MultipleLabels.java index 1f118c3061..0783e13e34 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/MultipleLabels.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/MultipleLabels.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/MultipleRelationshipsThing.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/MultipleRelationshipsThing.java index 0f5e4128c5..de3897ed98 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/MultipleRelationshipsThing.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/MultipleRelationshipsThing.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/MutableChild.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/MutableChild.java index 8f7640ca5f..a1d2adcf99 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/MutableChild.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/MutableChild.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/MutableParent.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/MutableParent.java index 0da81e31a4..71fc575daa 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/MutableParent.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/MutableParent.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/NamesOnly.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/NamesOnly.java index 38a10ff8fb..8facbe0189 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/NamesOnly.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/NamesOnly.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/NamesOnlyDto.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/NamesOnlyDto.java index 5a4214210a..e014a090b9 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/NamesOnlyDto.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/NamesOnlyDto.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/NamesWithSpELCity.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/NamesWithSpELCity.java index f9d803cc1d..58bf9b933b 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/NamesWithSpELCity.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/NamesWithSpELCity.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/OneToOneSource.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/OneToOneSource.java index 5015141d9f..9437f17055 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/OneToOneSource.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/OneToOneSource.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/OneToOneTarget.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/OneToOneTarget.java index 82a8bd6b8e..c414851e00 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/OneToOneTarget.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/OneToOneTarget.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ParentNode.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ParentNode.java index 42f2b126b5..cf48bf212e 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ParentNode.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ParentNode.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/Person.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/Person.java index 276fc78fd5..d92c768e05 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/Person.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/Person.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -39,7 +39,7 @@ public class Person { */ @Node public static class Address { - @Id @GeneratedValue private Long id; + @Id private Long id; private String zipCode; private String city; private String street; diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonDepartmentQueryResult.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonDepartmentQueryResult.java index 972c767eaa..09dabf79a4 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonDepartmentQueryResult.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonDepartmentQueryResult.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonEntity.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonEntity.java index f2b1a88604..f088bfaeee 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonEntity.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonEntity.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonProjection.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonProjection.java index dfc15031be..098a9caa1d 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonProjection.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonProjection.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonSummary.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonSummary.java index 4aa06ceb5e..e3fa3c7530 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonSummary.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonSummary.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonWithAllConstructor.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonWithAllConstructor.java index b1a9875694..fd8a9ff93d 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonWithAllConstructor.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonWithAllConstructor.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonWithAssignedId.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonWithAssignedId.java index 49324310d3..d4a9fe52f7 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonWithAssignedId.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonWithAssignedId.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonWithNoConstructor.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonWithNoConstructor.java index f53d9055ad..9e03f40380 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonWithNoConstructor.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonWithNoConstructor.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -38,4 +38,6 @@ public class PersonWithNoConstructor { private String name; @Property("first_name") private String firstName; + + @Property("mittlererName") private String middleName; } diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonWithRelationship.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonWithRelationship.java index 359ae4f40e..ec9cc48611 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonWithRelationship.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonWithRelationship.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonWithRelationshipWithProperties.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonWithRelationshipWithProperties.java index 047b7e5617..5f438ef90f 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonWithRelationshipWithProperties.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonWithRelationshipWithProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -18,7 +18,7 @@ import java.util.List; import java.util.Set; -import org.springframework.data.annotation.PersistenceConstructor; +import org.springframework.data.annotation.PersistenceCreator; import org.springframework.data.neo4j.core.schema.GeneratedValue; import org.springframework.data.neo4j.core.schema.Id; import org.springframework.data.neo4j.core.schema.Node; @@ -44,7 +44,7 @@ public class PersonWithRelationshipWithProperties { @Relationship("OWNS") private List clubs; - @PersistenceConstructor + @PersistenceCreator public PersonWithRelationshipWithProperties(Long id, String name, List hobbies, WorksInClubRelationship club) { this.id = id; this.name = name; diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonWithRelationshipWithProperties2.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonWithRelationshipWithProperties2.java index d22ccefd97..28cbadf982 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonWithRelationshipWithProperties2.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonWithRelationshipWithProperties2.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonWithRelatives.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonWithRelatives.java index a9a50c60a9..cb991a098d 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonWithRelatives.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonWithRelatives.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonWithStringlyTypedRelatives.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonWithStringlyTypedRelatives.java index 2676b4dc69..259d3baa14 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonWithStringlyTypedRelatives.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonWithStringlyTypedRelatives.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonWithWither.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonWithWither.java index 149ae6ee9c..fb70011f9a 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonWithWither.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/PersonWithWither.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/Pet.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/Pet.java index 13bf510ff0..5f19a71a28 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/Pet.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/Pet.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -22,7 +22,7 @@ import java.util.List; import java.util.Set; -import org.springframework.data.annotation.PersistenceConstructor; +import org.springframework.data.annotation.PersistenceCreator; import org.springframework.data.neo4j.core.schema.GeneratedValue; import org.springframework.data.neo4j.core.schema.Id; import org.springframework.data.neo4j.core.schema.Node; @@ -31,7 +31,7 @@ /** * @author Gerrit Meier */ -@RequiredArgsConstructor(onConstructor = @__(@PersistenceConstructor)) +@RequiredArgsConstructor(onConstructor = @__(@PersistenceCreator)) @Getter @EqualsAndHashCode(of = { "id", "name" }) @Node diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/Port.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/Port.java new file mode 100644 index 0000000000..19137c6c39 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/Port.java @@ -0,0 +1,37 @@ +/* + * Copyright 2011-2023 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 java.util.List; +import java.util.UUID; + +import org.springframework.data.neo4j.core.schema.DynamicLabels; +import org.springframework.data.neo4j.core.schema.GeneratedValue; +import org.springframework.data.neo4j.core.schema.Id; +import org.springframework.data.neo4j.core.schema.Node; + +/** + * @author Michael J. Simons + */ +@Node("Port") +public class Port { + @Id + @GeneratedValue + private UUID id; + private String code; + @DynamicLabels + private List labels; +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ProjectionTest1O1.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ProjectionTest1O1.java index 62a8ac8a6d..2b84f6e2c8 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ProjectionTest1O1.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ProjectionTest1O1.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ProjectionTestBase.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ProjectionTestBase.java index e3d6b6141b..f89939b78d 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ProjectionTestBase.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ProjectionTestBase.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ProjectionTestLevel1.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ProjectionTestLevel1.java index 36a117281e..f9231c3442 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ProjectionTestLevel1.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ProjectionTestLevel1.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ProjectionTestLevel2.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ProjectionTestLevel2.java index 9c92968f48..475d9a8f1d 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ProjectionTestLevel2.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ProjectionTestLevel2.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ProjectionTestRoot.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ProjectionTestRoot.java index a85e91128f..be57807a0e 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ProjectionTestRoot.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ProjectionTestRoot.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/RelationshipsAsConstructorParametersEntities.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/RelationshipsAsConstructorParametersEntities.java index 185fe579fb..9626bc18f0 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/RelationshipsAsConstructorParametersEntities.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/RelationshipsAsConstructorParametersEntities.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/RelationshipsITBase.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/RelationshipsITBase.java index c3bf712f25..a87c6e2124 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/RelationshipsITBase.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/RelationshipsITBase.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/SameIdProperty.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/SameIdProperty.java index 5e4d465150..ccb33a9f62 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/SameIdProperty.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/SameIdProperty.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2020 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/SimilarThing.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/SimilarThing.java index 9a1f1f6328..e86ceeee14 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/SimilarThing.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/SimilarThing.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/SimpleEntityWithRelationshipA.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/SimpleEntityWithRelationshipA.java index 2df5655850..f56ddc0e5c 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/SimpleEntityWithRelationshipA.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/SimpleEntityWithRelationshipA.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/SimpleEntityWithRelationshipB.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/SimpleEntityWithRelationshipB.java index f5614c3a17..953514e1e4 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/SimpleEntityWithRelationshipB.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/SimpleEntityWithRelationshipB.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/SimpleEntityWithRelationshipC.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/SimpleEntityWithRelationshipC.java index 3517bce8ac..502cc3e37a 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/SimpleEntityWithRelationshipC.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/SimpleEntityWithRelationshipC.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/SimplePerson.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/SimplePerson.java index e7e399c2e6..5e2e177f21 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/SimplePerson.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/SimplePerson.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/SummaryMetric.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/SummaryMetric.java new file mode 100644 index 0000000000..dd66353331 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/SummaryMetric.java @@ -0,0 +1,29 @@ +/* + * Copyright 2011-2023 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.Node; + +/** + * @author Michael J. Simons + */ +@Node("Summary") +public class SummaryMetric extends Metric { + + public SummaryMetric(String name) { + super(name); + } +} diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/TestSequenceGenerator.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/TestSequenceGenerator.java index ceaba0b7df..0c920f89ad 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/TestSequenceGenerator.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/TestSequenceGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ThingWithAllCypherTypes.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ThingWithAllCypherTypes.java index c1bf51e1a0..7eba065d04 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ThingWithAllCypherTypes.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ThingWithAllCypherTypes.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ThingWithAllCypherTypes2.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ThingWithAllCypherTypes2.java index 6bbd949bc0..51f3941dc5 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ThingWithAllCypherTypes2.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ThingWithAllCypherTypes2.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ThingWithAllSpatialTypes.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ThingWithAllSpatialTypes.java index 09892fab07..b645bb8fd6 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ThingWithAllSpatialTypes.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ThingWithAllSpatialTypes.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ThingWithAssignedId.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ThingWithAssignedId.java index 3a08bf1e9b..c95d165cc6 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ThingWithAssignedId.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ThingWithAssignedId.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -16,9 +16,12 @@ package org.springframework.data.neo4j.integration.shared.common; import java.util.List; +import java.util.UUID; +import org.springframework.data.annotation.Transient; import org.springframework.data.neo4j.core.schema.Id; import org.springframework.data.neo4j.core.schema.Node; +import org.springframework.data.neo4j.core.schema.PostLoad; import org.springframework.data.neo4j.core.schema.Relationship; /** @@ -33,6 +36,12 @@ public class ThingWithAssignedId extends AbstractNamedThing { @Relationship("Has") private List things; + @Transient + private String randomValue; + + @Transient + private String anotherRandomValue; + public ThingWithAssignedId(String theId, String name) { this.theId = theId; super.setName(name); @@ -49,4 +58,21 @@ public List getThings() { public void setThings(List things) { this.things = things; } + + public String getRandomValue() { + return randomValue; + } + + public void setRandomValue(String randomValue) { + this.randomValue = randomValue; + } + + public String getAnotherRandomValue() { + return anotherRandomValue; + } + + @PostLoad + public void generateValue() { + this.anotherRandomValue = UUID.randomUUID().toString(); + } } diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ThingWithFixedGeneratedId.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ThingWithFixedGeneratedId.java index edebfa58da..549ff32787 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ThingWithFixedGeneratedId.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ThingWithFixedGeneratedId.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ThingWithGeneratedId.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ThingWithGeneratedId.java index 92c67bfa7d..e192ded82b 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ThingWithGeneratedId.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ThingWithGeneratedId.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ThingWithIdGeneratedByBean.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ThingWithIdGeneratedByBean.java index 905f9720fd..78fb72be15 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ThingWithIdGeneratedByBean.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ThingWithIdGeneratedByBean.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ThingWithSequence.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ThingWithSequence.java index 007d6eee02..e0dba9a147 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ThingWithSequence.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ThingWithSequence.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ThingWithUUIDID.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ThingWithUUIDID.java index a7269d6aef..83fc95f2bf 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/ThingWithUUIDID.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/ThingWithUUIDID.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/VersionedThing.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/VersionedThing.java index d249d0a2b0..84e6645df4 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/VersionedThing.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/VersionedThing.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/VersionedThingWithAssignedId.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/VersionedThingWithAssignedId.java index 75eb393d45..80f23f48be 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/VersionedThingWithAssignedId.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/VersionedThingWithAssignedId.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/common/WorksInClubRelationship.java b/src/test/java/org/springframework/data/neo4j/integration/shared/common/WorksInClubRelationship.java index 77976b385c..1e9c750c8b 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/common/WorksInClubRelationship.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/common/WorksInClubRelationship.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/conversion/CompositePropertiesITBase.java b/src/test/java/org/springframework/data/neo4j/integration/shared/conversion/CompositePropertiesITBase.java index c9a59d99f9..1e9e8bea93 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/conversion/CompositePropertiesITBase.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/conversion/CompositePropertiesITBase.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/conversion/ListPropertyConversionIT.java b/src/test/java/org/springframework/data/neo4j/integration/shared/conversion/ListPropertyConversionIT.java index 01893a1d36..18fb7ee500 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/conversion/ListPropertyConversionIT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/conversion/ListPropertyConversionIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -37,7 +37,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.neo4j.config.AbstractNeo4jConfig; +import org.springframework.data.neo4j.test.Neo4jImperativeTestConfiguration; import org.springframework.data.neo4j.core.DatabaseSelectionProvider; import org.springframework.data.neo4j.core.Neo4jTemplate; import org.springframework.data.neo4j.core.convert.ConvertWith; @@ -321,7 +321,7 @@ public List read(Value source) { @Configuration @EnableTransactionManagement - static class Config extends AbstractNeo4jConfig { + static class Config extends Neo4jImperativeTestConfiguration { @Bean public Driver driver() { @@ -355,5 +355,10 @@ public PlatformTransactionManager transactionManager(Driver driver, return new Neo4jTransactionManager(driver, databaseNameProvider, Neo4jBookmarkManager.create(bookmarkCapture)); } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } } } diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/conversion/Neo4jConversionsITBase.java b/src/test/java/org/springframework/data/neo4j/integration/shared/conversion/Neo4jConversionsITBase.java index 571760d049..e9e646cbd7 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/conversion/Neo4jConversionsITBase.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/conversion/Neo4jConversionsITBase.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/conversion/PersonWithCustomId.java b/src/test/java/org/springframework/data/neo4j/integration/shared/conversion/PersonWithCustomId.java index fa6c777ab7..ab19f15e2f 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/conversion/PersonWithCustomId.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/conversion/PersonWithCustomId.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/conversion/RelationshipWithCompositeProperties.java b/src/test/java/org/springframework/data/neo4j/integration/shared/conversion/RelationshipWithCompositeProperties.java index 022bcbf601..6e2ef9ca65 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/conversion/RelationshipWithCompositeProperties.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/conversion/RelationshipWithCompositeProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/conversion/ThingWithAllAdditionalTypes.java b/src/test/java/org/springframework/data/neo4j/integration/shared/conversion/ThingWithAllAdditionalTypes.java index 83905ee1a1..5e1046b753 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/conversion/ThingWithAllAdditionalTypes.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/conversion/ThingWithAllAdditionalTypes.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/conversion/ThingWithCompositeProperties.java b/src/test/java/org/springframework/data/neo4j/integration/shared/conversion/ThingWithCompositeProperties.java index 12391b8bef..01d6ff0c02 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/conversion/ThingWithCompositeProperties.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/conversion/ThingWithCompositeProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/shared/conversion/ThingWithCustomTypes.java b/src/test/java/org/springframework/data/neo4j/integration/shared/conversion/ThingWithCustomTypes.java index f6b4254039..d7ced404d1 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/shared/conversion/ThingWithCustomTypes.java +++ b/src/test/java/org/springframework/data/neo4j/integration/shared/conversion/ThingWithCustomTypes.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/versioned_self_references/OptimisticLockingOfSelfReferencesIT.java b/src/test/java/org/springframework/data/neo4j/integration/versioned_self_references/OptimisticLockingOfSelfReferencesIT.java index 00db0c5dc1..3bddef69a7 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/versioned_self_references/OptimisticLockingOfSelfReferencesIT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/versioned_self_references/OptimisticLockingOfSelfReferencesIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -28,7 +28,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.neo4j.config.AbstractNeo4jConfig; +import org.springframework.data.neo4j.test.Neo4jImperativeTestConfiguration; import org.springframework.data.neo4j.core.DatabaseSelectionProvider; import org.springframework.data.neo4j.core.Neo4jTemplate; import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager; @@ -243,7 +243,7 @@ private > void assertLoadingViaSDN(Class type, Long... @Configuration @EnableTransactionManagement - static class Config extends AbstractNeo4jConfig { + static class Config extends Neo4jImperativeTestConfiguration { @Bean public BookmarkCapture bookmarkCapture() { @@ -264,5 +264,10 @@ public Driver driver() { return neo4jConnectionSupport.getDriver(); } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } } } diff --git a/src/test/java/org/springframework/data/neo4j/integration/versioned_self_references/ReactiveOptimisticLockingOfSelfReferencesIT.java b/src/test/java/org/springframework/data/neo4j/integration/versioned_self_references/ReactiveOptimisticLockingOfSelfReferencesIT.java index de22f8d57f..9844d3ebc3 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/versioned_self_references/ReactiveOptimisticLockingOfSelfReferencesIT.java +++ b/src/test/java/org/springframework/data/neo4j/integration/versioned_self_references/ReactiveOptimisticLockingOfSelfReferencesIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -17,6 +17,7 @@ import static org.assertj.core.api.Assertions.assertThat; +import org.springframework.data.neo4j.test.Neo4jReactiveTestConfiguration; import reactor.test.StepVerifier; import java.util.Arrays; @@ -32,7 +33,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.neo4j.config.AbstractReactiveNeo4jConfig; import org.springframework.data.neo4j.core.ReactiveDatabaseSelectionProvider; import org.springframework.data.neo4j.core.ReactiveNeo4jTemplate; import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager; @@ -304,7 +304,7 @@ private > void assertLoadingViaSDN(Class type, Long... @Configuration @EnableTransactionManagement - static class Config extends AbstractReactiveNeo4jConfig { + static class Config extends Neo4jReactiveTestConfiguration { @Bean public BookmarkCapture bookmarkCapture() { @@ -324,5 +324,10 @@ public Driver driver() { return neo4jConnectionSupport.getDriver(); } + + @Override + public boolean isCypher5Compatible() { + return neo4jConnectionSupport.isCypher5SyntaxCompatible(); + } } } diff --git a/src/test/java/org/springframework/data/neo4j/integration/versioned_self_references/Relatable.java b/src/test/java/org/springframework/data/neo4j/integration/versioned_self_references/Relatable.java index 3e7b1ce2f2..b70b77da13 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/versioned_self_references/Relatable.java +++ b/src/test/java/org/springframework/data/neo4j/integration/versioned_self_references/Relatable.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/versioned_self_references/TestBase.java b/src/test/java/org/springframework/data/neo4j/integration/versioned_self_references/TestBase.java index 37eca43811..48be0a4d91 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/versioned_self_references/TestBase.java +++ b/src/test/java/org/springframework/data/neo4j/integration/versioned_self_references/TestBase.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/versioned_self_references/VersionedExternalIdListBased.java b/src/test/java/org/springframework/data/neo4j/integration/versioned_self_references/VersionedExternalIdListBased.java index 653fe3e5f1..5535b4ff60 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/versioned_self_references/VersionedExternalIdListBased.java +++ b/src/test/java/org/springframework/data/neo4j/integration/versioned_self_references/VersionedExternalIdListBased.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/versioned_self_references/VersionedExternalIdWithEquals.java b/src/test/java/org/springframework/data/neo4j/integration/versioned_self_references/VersionedExternalIdWithEquals.java index 0cfb64e5b1..b6ee95c509 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/versioned_self_references/VersionedExternalIdWithEquals.java +++ b/src/test/java/org/springframework/data/neo4j/integration/versioned_self_references/VersionedExternalIdWithEquals.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/versioned_self_references/VersionedExternalIdWithoutEquals.java b/src/test/java/org/springframework/data/neo4j/integration/versioned_self_references/VersionedExternalIdWithoutEquals.java index b02c1dda23..659386dd37 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/versioned_self_references/VersionedExternalIdWithoutEquals.java +++ b/src/test/java/org/springframework/data/neo4j/integration/versioned_self_references/VersionedExternalIdWithoutEquals.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/versioned_self_references/VersionedInternalIdListBased.java b/src/test/java/org/springframework/data/neo4j/integration/versioned_self_references/VersionedInternalIdListBased.java index 6aa20e89c3..f677e0d9be 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/versioned_self_references/VersionedInternalIdListBased.java +++ b/src/test/java/org/springframework/data/neo4j/integration/versioned_self_references/VersionedInternalIdListBased.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/versioned_self_references/VersionedInternalIdWithEquals.java b/src/test/java/org/springframework/data/neo4j/integration/versioned_self_references/VersionedInternalIdWithEquals.java index 71b6343fde..99b2d18afc 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/versioned_self_references/VersionedInternalIdWithEquals.java +++ b/src/test/java/org/springframework/data/neo4j/integration/versioned_self_references/VersionedInternalIdWithEquals.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/integration/versioned_self_references/VersionedInternalIdWithoutEquals.java b/src/test/java/org/springframework/data/neo4j/integration/versioned_self_references/VersionedInternalIdWithoutEquals.java index 3781e03e63..ddc50b4406 100644 --- a/src/test/java/org/springframework/data/neo4j/integration/versioned_self_references/VersionedInternalIdWithoutEquals.java +++ b/src/test/java/org/springframework/data/neo4j/integration/versioned_self_references/VersionedInternalIdWithoutEquals.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/repository/config/AnEntity.java b/src/test/java/org/springframework/data/neo4j/repository/config/AnEntity.java index 6a83eaf92e..8b9e11f81d 100644 --- a/src/test/java/org/springframework/data/neo4j/repository/config/AnEntity.java +++ b/src/test/java/org/springframework/data/neo4j/repository/config/AnEntity.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/repository/config/EnableNeo4jRepositoriesTests.java b/src/test/java/org/springframework/data/neo4j/repository/config/EnableNeo4jRepositoriesTests.java index fbd86b8457..ce272f03fe 100644 --- a/src/test/java/org/springframework/data/neo4j/repository/config/EnableNeo4jRepositoriesTests.java +++ b/src/test/java/org/springframework/data/neo4j/repository/config/EnableNeo4jRepositoriesTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/repository/config/EnableReactiveNeo4jRepositoriesTests.java b/src/test/java/org/springframework/data/neo4j/repository/config/EnableReactiveNeo4jRepositoriesTests.java index 9225408c71..a97e499a25 100644 --- a/src/test/java/org/springframework/data/neo4j/repository/config/EnableReactiveNeo4jRepositoriesTests.java +++ b/src/test/java/org/springframework/data/neo4j/repository/config/EnableReactiveNeo4jRepositoriesTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/repository/config/StartupLoggerTest.java b/src/test/java/org/springframework/data/neo4j/repository/config/StartupLoggerTest.java index 04e3270d41..d5ff0ef4cf 100644 --- a/src/test/java/org/springframework/data/neo4j/repository/config/StartupLoggerTest.java +++ b/src/test/java/org/springframework/data/neo4j/repository/config/StartupLoggerTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/repository/query/BoundingBoxTest.java b/src/test/java/org/springframework/data/neo4j/repository/query/BoundingBoxTest.java index 1f9ef09142..60ff8ae143 100644 --- a/src/test/java/org/springframework/data/neo4j/repository/query/BoundingBoxTest.java +++ b/src/test/java/org/springframework/data/neo4j/repository/query/BoundingBoxTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/repository/query/ExtendedTestEntity.java b/src/test/java/org/springframework/data/neo4j/repository/query/ExtendedTestEntity.java index 7e0308c918..ab7f41b276 100644 --- a/src/test/java/org/springframework/data/neo4j/repository/query/ExtendedTestEntity.java +++ b/src/test/java/org/springframework/data/neo4j/repository/query/ExtendedTestEntity.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/repository/query/Neo4jNestedMapEntityWriterTest.java b/src/test/java/org/springframework/data/neo4j/repository/query/Neo4jNestedMapEntityWriterTest.java index 43b4ef8dd7..14b98c052c 100644 --- a/src/test/java/org/springframework/data/neo4j/repository/query/Neo4jNestedMapEntityWriterTest.java +++ b/src/test/java/org/springframework/data/neo4j/repository/query/Neo4jNestedMapEntityWriterTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -146,10 +146,10 @@ void relationshipPropertiesShouldBeSerializedWithTargetNodeWhenPassedFirstToWrit Map properties = (Map) result.get("__properties__"); assertThat(properties).containsEntry("description", Values.value("Some description")); - assertThat(properties).hasEntrySatisfying("__target__", isAMapValue); - properties = properties.get("__target__").asMap(Function.identity()); - assertThat(properties).containsEntry("__id__", Values.value("German")); - assertThat(properties).hasEntrySatisfying("__properties__", isAMapValue); + assertThat(result).hasEntrySatisfying("__target__", isAMapValue); + Map target = ((Value) result.get("__target__")).asMap(Function.identity()); + assertThat(target).containsEntry("__id__", Values.value("German")); + assertThat(target).hasEntrySatisfying("__properties__", isAMapValue); } @Test // DATAGRAPH-1452 diff --git a/src/test/java/org/springframework/data/neo4j/repository/query/Neo4jSpelSupportTest.java b/src/test/java/org/springframework/data/neo4j/repository/query/Neo4jSpelSupportTest.java index 724458b423..9da8896f8f 100644 --- a/src/test/java/org/springframework/data/neo4j/repository/query/Neo4jSpelSupportTest.java +++ b/src/test/java/org/springframework/data/neo4j/repository/query/Neo4jSpelSupportTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/repository/query/ReactiveRepositoryQueryTest.java b/src/test/java/org/springframework/data/neo4j/repository/query/ReactiveRepositoryQueryTest.java index 71044bc1c3..551b69c8bd 100644 --- a/src/test/java/org/springframework/data/neo4j/repository/query/ReactiveRepositoryQueryTest.java +++ b/src/test/java/org/springframework/data/neo4j/repository/query/ReactiveRepositoryQueryTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -142,7 +142,7 @@ void shouldWarnWhenUsingSortedAndCustomQuery(LogbackCapture logbackCapture) { query.prepareQuery( TestEntity.class, - Collections.emptyMap(), + Collections.emptySet(), parameterAccessor, Neo4jQueryType.DEFAULT, () -> (typeSystem, mapAccessor) -> new TestEntity() @@ -176,7 +176,7 @@ void orderBySpelShouldWork(LogbackCapture logbackCapture) { new Object[] { PageRequest.of(1, 1, Sort.by("name").ascending()) }); PreparedQuery pq = query.prepareQuery( TestEntity.class, - Collections.emptyMap(), + Collections.emptySet(), parameterAccessor, Neo4jQueryType.DEFAULT, () -> (typeSystem, mapAccessor) -> new TestEntity() @@ -212,7 +212,7 @@ void literalReplacementsShouldWork() { Sort.by("name").ascending() }); PreparedQuery pq = query.prepareQuery( TestEntity.class, - Collections.emptyMap(), + Collections.emptySet(), parameterAccessor, Neo4jQueryType.DEFAULT, () -> (typeSystem, mapAccessor) -> new TestEntity() diff --git a/src/test/java/org/springframework/data/neo4j/repository/query/RepositoryQueryTest.java b/src/test/java/org/springframework/data/neo4j/repository/query/RepositoryQueryTest.java index d34658b4ff..12053ccd8b 100644 --- a/src/test/java/org/springframework/data/neo4j/repository/query/RepositoryQueryTest.java +++ b/src/test/java/org/springframework/data/neo4j/repository/query/RepositoryQueryTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -333,7 +333,7 @@ void shouldWarnWhenUsingSortedAndCustomQuery(LogbackCapture logbackCapture) { query.prepareQuery( TestEntity.class, - Collections.emptyMap(), + Collections.emptySet(), parameterAccessor, Neo4jQueryType.DEFAULT, () -> (typeSystem, mapAccessor) -> new TestEntity(), @@ -359,7 +359,7 @@ void shouldWarnWhenUsingSortedPageable(LogbackCapture logbackCapture) { query.prepareQuery( TestEntity.class, - Collections.emptyMap(), + Collections.emptySet(), parameterAccessor, Neo4jQueryType.DEFAULT, () -> (typeSystem, mapAccessor) -> new TestEntity(), @@ -391,7 +391,7 @@ void orderBySpelShouldWork(LogbackCapture logbackCapture) { new Object[] { PageRequest.of(1, 1, Sort.by("name").ascending()) }); PreparedQuery pq = query.prepareQuery( TestEntity.class, - Collections.emptyMap(), + Collections.emptySet(), parameterAccessor, Neo4jQueryType.DEFAULT, () -> (typeSystem, mapAccessor) -> new TestEntity(), @@ -424,7 +424,7 @@ void literalReplacementsShouldWork() { Sort.by("name").ascending() }); PreparedQuery pq = query.prepareQuery( TestEntity.class, - Collections.emptyMap(), + Collections.emptySet(), parameterAccessor, Neo4jQueryType.DEFAULT, () -> (typeSystem, mapAccessor) -> new TestEntity(), diff --git a/src/test/java/org/springframework/data/neo4j/repository/query/TestEntity.java b/src/test/java/org/springframework/data/neo4j/repository/query/TestEntity.java index 15ddae41cf..13abd3e8e2 100644 --- a/src/test/java/org/springframework/data/neo4j/repository/query/TestEntity.java +++ b/src/test/java/org/springframework/data/neo4j/repository/query/TestEntity.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/repository/support/Neo4jRepositoryFactorySupportTest.java b/src/test/java/org/springframework/data/neo4j/repository/support/Neo4jRepositoryFactorySupportTest.java index d0d9a4e0d1..d4f101e831 100644 --- a/src/test/java/org/springframework/data/neo4j/repository/support/Neo4jRepositoryFactorySupportTest.java +++ b/src/test/java/org/springframework/data/neo4j/repository/support/Neo4jRepositoryFactorySupportTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/repository/support/Neo4jRepositoryFactoryTest.java b/src/test/java/org/springframework/data/neo4j/repository/support/Neo4jRepositoryFactoryTest.java index a33d885e69..b7a50452ca 100644 --- a/src/test/java/org/springframework/data/neo4j/repository/support/Neo4jRepositoryFactoryTest.java +++ b/src/test/java/org/springframework/data/neo4j/repository/support/Neo4jRepositoryFactoryTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -77,7 +77,7 @@ void matchingClassTypes() { when(metadata.getIdType()).thenReturn(repositoryIdentifierClass); assertThatThrownBy(() -> neo4jRepositoryFactory.getTargetRepository(metadata)) - .hasMessage("Target type must not be null!").isInstanceOf(IllegalArgumentException.class); + .hasMessageContaining("Target type must not be null").isInstanceOf(IllegalArgumentException.class); } @Test diff --git a/src/test/java/org/springframework/data/neo4j/repository/support/ReactiveNeo4jRepositoryFactoryTest.java b/src/test/java/org/springframework/data/neo4j/repository/support/ReactiveNeo4jRepositoryFactoryTest.java index c189dd4a8d..537361d840 100644 --- a/src/test/java/org/springframework/data/neo4j/repository/support/ReactiveNeo4jRepositoryFactoryTest.java +++ b/src/test/java/org/springframework/data/neo4j/repository/support/ReactiveNeo4jRepositoryFactoryTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -63,7 +63,7 @@ void matchingClassTypes() { when(metadata.getIdType()).thenReturn(repositoryIdentifierClass); assertThatThrownBy(() -> neo4jRepositoryFactory.getTargetRepository(metadata)) - .hasMessage("Target type must not be null!").isInstanceOf(IllegalArgumentException.class); + .hasMessageContaining("Target type must not be null").isInstanceOf(IllegalArgumentException.class); } @Test diff --git a/src/test/java/org/springframework/data/neo4j/test/BookmarkCapture.java b/src/test/java/org/springframework/data/neo4j/test/BookmarkCapture.java index 7eaa87b636..47f9710bc8 100644 --- a/src/test/java/org/springframework/data/neo4j/test/BookmarkCapture.java +++ b/src/test/java/org/springframework/data/neo4j/test/BookmarkCapture.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/test/CausalClusterIntegrationTest.java b/src/test/java/org/springframework/data/neo4j/test/CausalClusterIntegrationTest.java index ff394f993c..9aacfb66d2 100644 --- a/src/test/java/org/springframework/data/neo4j/test/CausalClusterIntegrationTest.java +++ b/src/test/java/org/springframework/data/neo4j/test/CausalClusterIntegrationTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/test/DriverMocks.java b/src/test/java/org/springframework/data/neo4j/test/DriverMocks.java index ea4cbb14d7..1502bc985b 100644 --- a/src/test/java/org/springframework/data/neo4j/test/DriverMocks.java +++ b/src/test/java/org/springframework/data/neo4j/test/DriverMocks.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/test/LogbackCapture.java b/src/test/java/org/springframework/data/neo4j/test/LogbackCapture.java index 8eebe4c8f4..7f83f43b70 100644 --- a/src/test/java/org/springframework/data/neo4j/test/LogbackCapture.java +++ b/src/test/java/org/springframework/data/neo4j/test/LogbackCapture.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/test/LogbackCapturingExtension.java b/src/test/java/org/springframework/data/neo4j/test/LogbackCapturingExtension.java index 3b5f999b82..ccb00b2517 100644 --- a/src/test/java/org/springframework/data/neo4j/test/LogbackCapturingExtension.java +++ b/src/test/java/org/springframework/data/neo4j/test/LogbackCapturingExtension.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/test/Neo4jExtension.java b/src/test/java/org/springframework/data/neo4j/test/Neo4jExtension.java index 496a8733ba..c1b56b2b4e 100644 --- a/src/test/java/org/springframework/data/neo4j/test/Neo4jExtension.java +++ b/src/test/java/org/springframework/data/neo4j/test/Neo4jExtension.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -269,6 +269,10 @@ boolean isCommercialEdition() { return COMMERCIAL_EDITION_INDICATOR.contains(getEdition()); } + public boolean isCypher5SyntaxCompatible() { + return getServerVersion().greaterThanOrEqual(ServerVersion.v4_4_0); + } + @Override public void close() { @@ -290,7 +294,7 @@ static class ContainerAdapter implements ExtensionContext.Store.CloseableResourc private final String repository = Optional.ofNullable(System.getenv(SYS_PROPERTY_NEO4J_REPOSITORY)).orElse("neo4j"); - private final String imageVersion = Optional.ofNullable(System.getenv(SYS_PROPERTY_NEO4J_VERSION)).orElse("4.3"); + private final String imageVersion = Optional.ofNullable(System.getenv(SYS_PROPERTY_NEO4J_VERSION)).orElse("4.4"); private final boolean containerReuseSupported = TestcontainersConfiguration .getInstance().environmentSupportsReuse(); diff --git a/src/test/java/org/springframework/data/neo4j/test/Neo4jImperativeTestConfiguration.java b/src/test/java/org/springframework/data/neo4j/test/Neo4jImperativeTestConfiguration.java new file mode 100644 index 0000000000..75da047efe --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/test/Neo4jImperativeTestConfiguration.java @@ -0,0 +1,31 @@ +/* + * Copyright 2011-2023 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.test; + +import org.neo4j.cypherdsl.core.renderer.Configuration; +import org.springframework.data.neo4j.config.AbstractNeo4jConfig; + +/** + * @author Gerrit Meier + */ +public abstract class Neo4jImperativeTestConfiguration extends AbstractNeo4jConfig implements Neo4jTestConfiguration { + + @Override + public Configuration cypherDslConfiguration() { + return getConfiguration(); + } + +} diff --git a/src/test/java/org/springframework/data/neo4j/test/Neo4jIntegrationTest.java b/src/test/java/org/springframework/data/neo4j/test/Neo4jIntegrationTest.java index 359e6e4e7b..5ee14fe231 100644 --- a/src/test/java/org/springframework/data/neo4j/test/Neo4jIntegrationTest.java +++ b/src/test/java/org/springframework/data/neo4j/test/Neo4jIntegrationTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -25,12 +25,12 @@ import org.springframework.test.context.junit.jupiter.SpringExtension; /** - * This annotations triggers the {@link Neo4jExtension}, that provides a driver instance for Neo4j integration tests. + * This annotation triggers the {@link Neo4jExtension}, that provides a driver instance for Neo4j integration tests. * The important point here is that the extension possibly dirties a Spring context by closing the driver instance, so * it has been meta annotated with {@link DirtiesContext}. That issue happens mostly when one and the same integration * tests is run several times via an IDE: Spring will detect that the context configuration is the same and reuse the * old context based on contextual information from the first run. The Neo4j extension will dutiful create a new - * connection and driver instance, but Spring won't never use it. + * connection and driver instance, but Spring won't ever use it. * * @author Michael J. Simons */ diff --git a/src/test/java/org/springframework/data/neo4j/test/Neo4jReactiveTestConfiguration.java b/src/test/java/org/springframework/data/neo4j/test/Neo4jReactiveTestConfiguration.java new file mode 100644 index 0000000000..ca33ba39aa --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/test/Neo4jReactiveTestConfiguration.java @@ -0,0 +1,30 @@ +/* + * Copyright 2011-2023 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.test; + +import org.neo4j.cypherdsl.core.renderer.Configuration; +import org.springframework.data.neo4j.config.AbstractReactiveNeo4jConfig; + +/** + * @author Gerrit Meier + */ +public abstract class Neo4jReactiveTestConfiguration extends AbstractReactiveNeo4jConfig implements Neo4jTestConfiguration { + + @Override + public Configuration cypherDslConfiguration() { + return getConfiguration(); + } +} diff --git a/src/test/java/org/springframework/data/neo4j/test/Neo4jTestConfiguration.java b/src/test/java/org/springframework/data/neo4j/test/Neo4jTestConfiguration.java new file mode 100644 index 0000000000..e0b9574398 --- /dev/null +++ b/src/test/java/org/springframework/data/neo4j/test/Neo4jTestConfiguration.java @@ -0,0 +1,35 @@ +/* + * Copyright 2011-2023 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.test; + +import org.neo4j.cypherdsl.core.renderer.Configuration; +import org.neo4j.cypherdsl.core.renderer.Dialect; + +/** + * @author Gerrit Meier + */ +public interface Neo4jTestConfiguration { + + boolean isCypher5Compatible(); + + default Configuration getConfiguration() { + if (isCypher5Compatible()) { + return Configuration.newConfig().withDialect(Dialect.NEO4J_5).build(); + } + + return Configuration.defaultConfig(); + } +} diff --git a/src/test/java/org/springframework/data/neo4j/types/GeographicPoint2dTest.java b/src/test/java/org/springframework/data/neo4j/types/GeographicPoint2dTest.java index 765c23a7e7..c5c915ec73 100644 --- a/src/test/java/org/springframework/data/neo4j/types/GeographicPoint2dTest.java +++ b/src/test/java/org/springframework/data/neo4j/types/GeographicPoint2dTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/java/org/springframework/data/neo4j/types/GeographicPoint3dTest.java b/src/test/java/org/springframework/data/neo4j/types/GeographicPoint3dTest.java index 4be84d3500..496d7198c8 100644 --- a/src/test/java/org/springframework/data/neo4j/types/GeographicPoint3dTest.java +++ b/src/test/java/org/springframework/data/neo4j/types/GeographicPoint3dTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/kotlin/org/springframework/data/neo4j/core/Neo4jClientExtensionsTest.kt b/src/test/kotlin/org/springframework/data/neo4j/core/Neo4jClientExtensionsTest.kt index 11297ff8eb..9eb8f4cf91 100644 --- a/src/test/kotlin/org/springframework/data/neo4j/core/Neo4jClientExtensionsTest.kt +++ b/src/test/kotlin/org/springframework/data/neo4j/core/Neo4jClientExtensionsTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/kotlin/org/springframework/data/neo4j/core/Neo4jOperationsExtensionsTest.kt b/src/test/kotlin/org/springframework/data/neo4j/core/Neo4jOperationsExtensionsTest.kt index ff5d5a5e64..9cee62f4d2 100644 --- a/src/test/kotlin/org/springframework/data/neo4j/core/Neo4jOperationsExtensionsTest.kt +++ b/src/test/kotlin/org/springframework/data/neo4j/core/Neo4jOperationsExtensionsTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/kotlin/org/springframework/data/neo4j/core/PreparedQueryExtensionsTest.kt b/src/test/kotlin/org/springframework/data/neo4j/core/PreparedQueryExtensionsTest.kt index bbf275e60c..08f48b24b7 100644 --- a/src/test/kotlin/org/springframework/data/neo4j/core/PreparedQueryExtensionsTest.kt +++ b/src/test/kotlin/org/springframework/data/neo4j/core/PreparedQueryExtensionsTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/kotlin/org/springframework/data/neo4j/core/ReactiveNeo4jClientExtensionsTest.kt b/src/test/kotlin/org/springframework/data/neo4j/core/ReactiveNeo4jClientExtensionsTest.kt index e1b7d608bf..2ea04640ef 100644 --- a/src/test/kotlin/org/springframework/data/neo4j/core/ReactiveNeo4jClientExtensionsTest.kt +++ b/src/test/kotlin/org/springframework/data/neo4j/core/ReactiveNeo4jClientExtensionsTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/kotlin/org/springframework/data/neo4j/core/ReactiveNeo4jOperationsExtensionsTest.kt b/src/test/kotlin/org/springframework/data/neo4j/core/ReactiveNeo4jOperationsExtensionsTest.kt index 0307a22fc6..c779a472e3 100644 --- a/src/test/kotlin/org/springframework/data/neo4j/core/ReactiveNeo4jOperationsExtensionsTest.kt +++ b/src/test/kotlin/org/springframework/data/neo4j/core/ReactiveNeo4jOperationsExtensionsTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/kotlin/org/springframework/data/neo4j/core/cypher/ParametersTest.kt b/src/test/kotlin/org/springframework/data/neo4j/core/cypher/ParametersTest.kt index 8cefb80606..e6ad424fa1 100644 --- a/src/test/kotlin/org/springframework/data/neo4j/core/cypher/ParametersTest.kt +++ b/src/test/kotlin/org/springframework/data/neo4j/core/cypher/ParametersTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/kotlin/org/springframework/data/neo4j/core/mapping/KotlinPostLoad.kt b/src/test/kotlin/org/springframework/data/neo4j/core/mapping/KotlinPostLoad.kt new file mode 100644 index 0000000000..01fbd36e19 --- /dev/null +++ b/src/test/kotlin/org/springframework/data/neo4j/core/mapping/KotlinPostLoad.kt @@ -0,0 +1,39 @@ +package org.springframework.data.neo4j.core.mapping + +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.PostLoad + +interface KotlinBase { + var baseName: String? + + fun bar(); +} + +interface KotlinA : KotlinBase { + var ownAttr: String? +} + +@Node("Base") +class KotlinBaseImpl : KotlinBase { + @Id + @GeneratedValue + val id: Long? = null + + override var baseName: String? = null + + @PostLoad + override fun bar() { + baseName = "someValue" + } +} + +@Node("A") +class KotlinAImpl : KotlinA, KotlinBase by KotlinBaseImpl() { + @Id + @GeneratedValue + val id: Long? = null + + override var ownAttr: String? = null +} diff --git a/src/test/kotlin/org/springframework/data/neo4j/integration/imperative/ImmutableRelationshipsIT.kt b/src/test/kotlin/org/springframework/data/neo4j/integration/imperative/ImmutableRelationshipsIT.kt index a7c379b155..fc9c1a0e08 100644 --- a/src/test/kotlin/org/springframework/data/neo4j/integration/imperative/ImmutableRelationshipsIT.kt +++ b/src/test/kotlin/org/springframework/data/neo4j/integration/imperative/ImmutableRelationshipsIT.kt @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/kotlin/org/springframework/data/neo4j/integration/imperative/KotlinInheritanceIT.kt b/src/test/kotlin/org/springframework/data/neo4j/integration/imperative/KotlinInheritanceIT.kt index aa337ae7e3..c541595d4e 100644 --- a/src/test/kotlin/org/springframework/data/neo4j/integration/imperative/KotlinInheritanceIT.kt +++ b/src/test/kotlin/org/springframework/data/neo4j/integration/imperative/KotlinInheritanceIT.kt @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/kotlin/org/springframework/data/neo4j/integration/imperative/KotlinProjectionIT.kt b/src/test/kotlin/org/springframework/data/neo4j/integration/imperative/KotlinProjectionIT.kt index 38eaeee5f9..d9f62f7788 100644 --- a/src/test/kotlin/org/springframework/data/neo4j/integration/imperative/KotlinProjectionIT.kt +++ b/src/test/kotlin/org/springframework/data/neo4j/integration/imperative/KotlinProjectionIT.kt @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/kotlin/org/springframework/data/neo4j/integration/imperative/Neo4jClientKotlinInteropIT.kt b/src/test/kotlin/org/springframework/data/neo4j/integration/imperative/Neo4jClientKotlinInteropIT.kt index 0c400d3b35..6e7ec9b1f6 100644 --- a/src/test/kotlin/org/springframework/data/neo4j/integration/imperative/Neo4jClientKotlinInteropIT.kt +++ b/src/test/kotlin/org/springframework/data/neo4j/integration/imperative/Neo4jClientKotlinInteropIT.kt @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/kotlin/org/springframework/data/neo4j/integration/imperative/Neo4jListContainsTest.kt b/src/test/kotlin/org/springframework/data/neo4j/integration/imperative/Neo4jListContainsTest.kt index 8b8be626eb..fcc3c5ac76 100644 --- a/src/test/kotlin/org/springframework/data/neo4j/integration/imperative/Neo4jListContainsTest.kt +++ b/src/test/kotlin/org/springframework/data/neo4j/integration/imperative/Neo4jListContainsTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -46,7 +46,7 @@ class Neo4jListContainsTest { @BeforeAll @JvmStatic fun prepareDatabase(@Autowired driver: Driver, @Autowired bookmarkCapture: BookmarkCapture) { - driver.session().use { session -> + driver.session(bookmarkCapture.createSessionConfig()).use { session -> session.run("MATCH (n) DETACH DELETE n").consume() session.run("CREATE (testNode:GH2444{id: 1, items: ['item 1', 'item 2', 'item 3'], description: 'desc 1'})").consume(); bookmarkCapture.seedWith(session.lastBookmark()) diff --git a/src/test/kotlin/org/springframework/data/neo4j/integration/reactive/ReactiveNeo4jClientKotlinInteropIT.kt b/src/test/kotlin/org/springframework/data/neo4j/integration/reactive/ReactiveNeo4jClientKotlinInteropIT.kt index 3f8b246349..0172ab5602 100644 --- a/src/test/kotlin/org/springframework/data/neo4j/integration/reactive/ReactiveNeo4jClientKotlinInteropIT.kt +++ b/src/test/kotlin/org/springframework/data/neo4j/integration/reactive/ReactiveNeo4jClientKotlinInteropIT.kt @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. @@ -29,12 +29,13 @@ 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.config.AbstractReactiveNeo4jConfig import org.springframework.data.neo4j.core.* import org.springframework.data.neo4j.core.cypher.asParam +import org.springframework.data.neo4j.integration.issues.gh2526.GH2526IT import org.springframework.data.neo4j.test.Neo4jExtension import org.springframework.data.neo4j.test.Neo4jExtension.NEEDS_REACTIVE_SUPPORT import org.springframework.data.neo4j.test.Neo4jIntegrationTest +import org.springframework.data.neo4j.test.Neo4jReactiveTestConfiguration import org.springframework.transaction.annotation.EnableTransactionManagement import reactor.test.StepVerifier @@ -133,11 +134,15 @@ class ReactiveNeo4jClientKotlinInteropIT @Autowired constructor( @Configuration @EnableTransactionManagement - open class Config : AbstractReactiveNeo4jConfig() { + open class Config : Neo4jReactiveTestConfiguration() { @Bean override fun driver(): Driver { return neo4jConnectionSupport.driver } + + override fun isCypher5Compatible(): Boolean { + return neo4jConnectionSupport.isCypher5SyntaxCompatible + } } } diff --git a/src/test/kotlin/org/springframework/data/neo4j/integration/shared/common/ImmutableRelationships.kt b/src/test/kotlin/org/springframework/data/neo4j/integration/shared/common/ImmutableRelationships.kt index 43cd9063aa..21aad95c6a 100644 --- a/src/test/kotlin/org/springframework/data/neo4j/integration/shared/common/ImmutableRelationships.kt +++ b/src/test/kotlin/org/springframework/data/neo4j/integration/shared/common/ImmutableRelationships.kt @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/kotlin/org/springframework/data/neo4j/integration/shared/common/KotlinInheritance.kt b/src/test/kotlin/org/springframework/data/neo4j/integration/shared/common/KotlinInheritance.kt index aa3c49b665..af1fa705db 100644 --- a/src/test/kotlin/org/springframework/data/neo4j/integration/shared/common/KotlinInheritance.kt +++ b/src/test/kotlin/org/springframework/data/neo4j/integration/shared/common/KotlinInheritance.kt @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/kotlin/org/springframework/data/neo4j/integration/shared/common/KotlinPerson.kt b/src/test/kotlin/org/springframework/data/neo4j/integration/shared/common/KotlinPerson.kt index 837e7b5332..bf84b7ce28 100644 --- a/src/test/kotlin/org/springframework/data/neo4j/integration/shared/common/KotlinPerson.kt +++ b/src/test/kotlin/org/springframework/data/neo4j/integration/shared/common/KotlinPerson.kt @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/kotlin/org/springframework/data/neo4j/integration/shared/common/KotlinRepository.kt b/src/test/kotlin/org/springframework/data/neo4j/integration/shared/common/KotlinRepository.kt index 0a4964a4e0..60e4f69368 100644 --- a/src/test/kotlin/org/springframework/data/neo4j/integration/shared/common/KotlinRepository.kt +++ b/src/test/kotlin/org/springframework/data/neo4j/integration/shared/common/KotlinRepository.kt @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/kotlin/org/springframework/data/neo4j/integration/shared/common/TestNode.kt b/src/test/kotlin/org/springframework/data/neo4j/integration/shared/common/TestNode.kt index 2a421af3fe..bbf490a8b7 100644 --- a/src/test/kotlin/org/springframework/data/neo4j/integration/shared/common/TestNode.kt +++ b/src/test/kotlin/org/springframework/data/neo4j/integration/shared/common/TestNode.kt @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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. diff --git a/src/test/kotlin/org/springframework/data/neo4j/integration/shared/common/TestPersonEntity.kt b/src/test/kotlin/org/springframework/data/neo4j/integration/shared/common/TestPersonEntity.kt index 4d64dc9a3e..82c9cc194b 100644 --- a/src/test/kotlin/org/springframework/data/neo4j/integration/shared/common/TestPersonEntity.kt +++ b/src/test/kotlin/org/springframework/data/neo4j/integration/shared/common/TestPersonEntity.kt @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 2011-2023 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.