Polish "Add smoketests for relevant Neo4j features"
See gh-190
This commit is contained in:
@@ -361,8 +361,8 @@ h|nativeTest
|
||||
|
|
||||
|
||||
|data-neo4j
|
||||
|image:https://ci.spring.io/api/v1/teams/spring-aot-smoke-tests/pipelines/spring-aot-smoke-tests-3.2.x/jobs/data-neo4j-app-test/badge[link=https://ci.spring.io/teams/spring-aot-smoke-tests/pipelines/spring-aot-smoke-tests-3.2.x/jobs/data-neo4j-app-test]
|
||||
|image:https://ci.spring.io/api/v1/teams/spring-aot-smoke-tests/pipelines/spring-aot-smoke-tests-3.2.x/jobs/data-neo4j-native-app-test/badge[link=https://ci.spring.io/teams/spring-aot-smoke-tests/pipelines/spring-aot-smoke-tests-3.2.x/jobs/data-neo4j-native-app-test]
|
||||
|image:https://ci.spring.io/api/v1/teams/spring-aot-smoke-tests/pipelines/spring-aot-smoke-tests-3.0.x/jobs/data-neo4j-app-test/badge[link=https://ci.spring.io/teams/spring-aot-smoke-tests/pipelines/spring-aot-smoke-tests-3.0.x/jobs/data-neo4j-app-test]
|
||||
|image:https://ci.spring.io/api/v1/teams/spring-aot-smoke-tests/pipelines/spring-aot-smoke-tests-3.0.x/jobs/data-neo4j-native-app-test/badge[link=https://ci.spring.io/teams/spring-aot-smoke-tests/pipelines/spring-aot-smoke-tests-3.0.x/jobs/data-neo4j-native-app-test]
|
||||
|
|
||||
|
|
||||
|
||||
|
||||
@@ -30,18 +30,16 @@ class DataNeo4jApplicationAotTests {
|
||||
|
||||
@Test
|
||||
void annotatedTypesShouldHaveBeenRegistered(AssertableOutput output) {
|
||||
var expectedLines = List.of("All types are present: ChildNode",
|
||||
"Id has been populated from DB: \\w{8}-\\w{4}-\\w{4}-\\w{4}-\\w{12}");
|
||||
List<String> expectedLines = List.of("All types are present: ChildNode", "Id has been populated from DB: \\d+");
|
||||
|
||||
assertExpectedLines(output, expectedLines);
|
||||
}
|
||||
|
||||
@Test
|
||||
void externallyGeneratedFieldsShouldBePopulated(AssertableOutput output) {
|
||||
var expectedLines = List.of("Generated id is present: \\w{8}-\\w{4}-\\w{4}-\\w{4}-\\w{12}",
|
||||
"CreatedAt is present: true", "CreatedBy is present: true", "UpdatedAt is absent: false",
|
||||
"UpdatedBy is absent: false", "Version is 0", "UpdatedAt is now present: true",
|
||||
"UpdatedBy is now present: true", "Version is now 1");
|
||||
List<String> expectedLines = List.of("Generated id is present: \\d+", "CreatedAt is present: true",
|
||||
"CreatedBy is present: true", "UpdatedAt is absent: false", "UpdatedBy is absent: false",
|
||||
"Version is 0", "UpdatedAt is now present: true", "UpdatedBy is now present: true", "Version is now 1");
|
||||
|
||||
assertExpectedLines(output, expectedLines);
|
||||
}
|
||||
@@ -49,14 +47,14 @@ class DataNeo4jApplicationAotTests {
|
||||
@Test
|
||||
void internallyGeneratedIdsShouldBePopulated(AssertableOutput output) {
|
||||
Awaitility.await().atMost(Duration.ofSeconds(10)).untilAsserted(() -> {
|
||||
assertThat(output).hasLineMatching("Internal element id is present: \\d:[\\w\\-]+:\\d")
|
||||
.hasLineMatching("\\[Reactive\\] Internal element id is present: \\d:[\\w\\-]+:\\d");
|
||||
assertThat(output).hasLineMatching("Internal element id is present: \\d+")
|
||||
.hasLineMatching("\\[Reactive\\] Internal element id is present: \\d+");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void cypherDSLIntegrationShouldWork(AssertableOutput output) {
|
||||
var expectedLines = List.of("Loaded 1 movies", "With 1 actors, first named An Actor");
|
||||
List<String> expectedLines = List.of("Loaded 1 movies", "With 1 actors, first named An Actor");
|
||||
|
||||
assertExpectedLines(output, expectedLines);
|
||||
}
|
||||
@@ -70,11 +68,10 @@ class DataNeo4jApplicationAotTests {
|
||||
|
||||
@Test
|
||||
void qbeShouldWork(AssertableOutput output) {
|
||||
Awaitility.await().atMost(Duration.ofSeconds(10)).untilAsserted(() -> {
|
||||
assertThat(output).hasLineMatching("Found one movie by example with id \\w{8}-\\w{4}-\\w{4}-\\w{4}-\\w{12}")
|
||||
.hasLineMatching(
|
||||
"\\[Reactive\\] Found one movie by example with id \\w{8}-\\w{4}-\\w{4}-\\w{4}-\\w{12}");
|
||||
});
|
||||
Awaitility.await()
|
||||
.atMost(Duration.ofSeconds(10))
|
||||
.untilAsserted(() -> assertThat(output).hasLineMatching("Found one movie by example with id \\d+")
|
||||
.hasLineMatching("\\[Reactive\\] Found one movie by example with id \\d+"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
package com.example.data.neo4j;
|
||||
|
||||
import org.neo4j.driver.Driver;
|
||||
import org.neo4j.driver.Session;
|
||||
import org.neo4j.driver.Transaction;
|
||||
import org.springframework.context.SmartLifecycle;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -32,14 +34,14 @@ public class DatabaseInitializer implements SmartLifecycle {
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
if (running) {
|
||||
if (this.running) {
|
||||
return;
|
||||
}
|
||||
|
||||
try (var session = driver.session(); var tx = session.beginTransaction()) {
|
||||
try (Session session = this.driver.session(); Transaction tx = session.beginTransaction()) {
|
||||
tx.run("MATCH (n:ParentLabel:ChildLabel) DETACH DELETE n");
|
||||
tx.run("CREATE (:ParentLabel:ChildLabel {id: randomUuid(), name: 'BothLabelsMustBeManagedTypes'})");
|
||||
tx.run("CREATE (:Movie {id: randomUuid(), version: 0, title: 'A movie', updatedBy: 'A person', updatedAt: localdatetime()}) <-[:ACTED_IN]-(:Person {name: 'An Actor'})");
|
||||
tx.run("CREATE (:ParentLabel:ChildLabel {id: 1, name: 'BothLabelsMustBeManagedTypes'})");
|
||||
tx.run("CREATE (:Movie {id: 1, version: 0, title: 'A movie', updatedBy: 'A person', updatedAt: localdatetime()}) <-[:ACTED_IN]-(:Person {name: 'An Actor'})");
|
||||
tx.commit();
|
||||
this.running = true;
|
||||
}
|
||||
@@ -51,7 +53,7 @@ public class DatabaseInitializer implements SmartLifecycle {
|
||||
|
||||
@Override
|
||||
public boolean isRunning() {
|
||||
return running;
|
||||
return this.running;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,8 +17,10 @@ package com.example.data.neo4j;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.neo4j.cypherdsl.core.Cypher;
|
||||
import org.neo4j.cypherdsl.core.Property;
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.data.domain.Example;
|
||||
import org.springframework.data.neo4j.core.Neo4jTemplate;
|
||||
@@ -43,7 +45,6 @@ public class ImperativeTestRunner implements CommandLineRunner {
|
||||
|
||||
@Override
|
||||
public void run(String... args) {
|
||||
|
||||
annotatedTypesShouldHaveBeenRegistered();
|
||||
externallyGeneratedFieldsShouldBePopulated();
|
||||
internallyGeneratedIdsShouldBePopulated();
|
||||
@@ -52,19 +53,18 @@ public class ImperativeTestRunner implements CommandLineRunner {
|
||||
}
|
||||
|
||||
private void qbeShouldWork() {
|
||||
|
||||
log("---- Neo4j Query By Example (QBE) ----");
|
||||
var optionalMovie = movieRepository.findOne(Example.of(new Movie("A movie")));
|
||||
Optional<Movie> optionalMovie = this.movieRepository.findOne(Example.of(new Movie("A movie")));
|
||||
optionalMovie.ifPresent((movie) -> {
|
||||
log("Found one movie by example with id %s", movie.getId());
|
||||
});
|
||||
}
|
||||
|
||||
private void cypherDSLIntegrationShouldWork() {
|
||||
|
||||
log("---- Neo4j Cypher-DSL integration and relationship population ----");
|
||||
var title = Cypher.node("Movie").named("movie").property("title");
|
||||
var movies = new ArrayList<>(movieRepository.findAll(title.contains(Cypher.literalOf("A movie"))));
|
||||
Property title = Cypher.node("Movie").named("movie").property("title");
|
||||
ArrayList<Movie> movies = new ArrayList<>(
|
||||
this.movieRepository.findAll(title.contains(Cypher.literalOf("A movie"))));
|
||||
|
||||
log("Loaded %d movies", movies.size());
|
||||
if (!(movies.isEmpty() || movies.get(0).getActors().isEmpty())) {
|
||||
@@ -74,19 +74,17 @@ public class ImperativeTestRunner implements CommandLineRunner {
|
||||
}
|
||||
|
||||
private void internallyGeneratedIdsShouldBePopulated() {
|
||||
|
||||
log("---- Neo4j internally generated values ----");
|
||||
var person = new Person();
|
||||
Person person = new Person();
|
||||
person.setName("Jane Doe");
|
||||
person = neo4jTemplate.save(person);
|
||||
person = this.neo4jTemplate.save(person);
|
||||
log("Internal element id is present: %s", person.getId());
|
||||
}
|
||||
|
||||
private void externallyGeneratedFieldsShouldBePopulated() {
|
||||
|
||||
log("---- Neo4j externally generated values ----");
|
||||
var movie = transactionTemplate
|
||||
.execute(tx -> movieRepository.save(new Movie("One Flew Over the Cuckoos Nest")));
|
||||
Movie movie = this.transactionTemplate
|
||||
.execute(tx -> this.movieRepository.save(new Movie("One Flew Over the Cuckoos Nest")));
|
||||
|
||||
log("Generated id is present: %s", movie.getId());
|
||||
log("CreatedAt is present: %s", DataNeo4jApplication.FIXED_DATE.equals(movie.getCreatedAt()));
|
||||
@@ -96,7 +94,7 @@ public class ImperativeTestRunner implements CommandLineRunner {
|
||||
log("Version is %d", movie.getVersion());
|
||||
|
||||
movie.setTitle("One Flew Over the Cuckoo's Nest");
|
||||
var updatedMovie = transactionTemplate.execute(tx -> movieRepository.save(movie));
|
||||
Movie updatedMovie = this.transactionTemplate.execute(tx -> this.movieRepository.save(movie));
|
||||
|
||||
log("UpdatedAt is now present: %s", DataNeo4jApplication.FIXED_DATE.equals(updatedMovie.getUpdatedAt()));
|
||||
log("UpdatedBy is now present: %s", "Some person".equals(updatedMovie.getUpdatedBy()));
|
||||
@@ -104,10 +102,9 @@ public class ImperativeTestRunner implements CommandLineRunner {
|
||||
}
|
||||
|
||||
private void annotatedTypesShouldHaveBeenRegistered() {
|
||||
|
||||
log("---- Neo4j Managed types ----");
|
||||
|
||||
var optionalResult = this.neo4jTemplate.findOne("MATCH (t:ParentLabel {name: $name}) RETURN t",
|
||||
Optional<ParentNode> optionalResult = this.neo4jTemplate.findOne("MATCH (t:ParentLabel {name: $name}) RETURN t",
|
||||
Map.of("name", "BothLabelsMustBeManagedTypes"), ParentNode.class);
|
||||
optionalResult.ifPresent(node -> {
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@ package com.example.data.neo4j;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.springframework.data.annotation.CreatedBy;
|
||||
import org.springframework.data.annotation.CreatedDate;
|
||||
@@ -35,7 +34,7 @@ public class Movie {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private final UUID id;
|
||||
private final Long id;
|
||||
|
||||
@Version
|
||||
private final Long version;
|
||||
@@ -62,7 +61,7 @@ public class Movie {
|
||||
}
|
||||
|
||||
@PersistenceCreator
|
||||
Movie(UUID id, Long version, String title, List<Person> actors, LocalDateTime createdAt, String createdBy,
|
||||
Movie(Long id, Long version, String title, List<Person> actors, LocalDateTime createdAt, String createdBy,
|
||||
LocalDateTime updatedAt, String updatedBy) {
|
||||
this.id = id;
|
||||
this.version = version;
|
||||
@@ -74,16 +73,16 @@ public class Movie {
|
||||
this.updatedBy = updatedBy;
|
||||
}
|
||||
|
||||
public UUID getId() {
|
||||
return id;
|
||||
public Long getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public Long getVersion() {
|
||||
return version;
|
||||
return this.version;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
return this.title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
@@ -91,23 +90,39 @@ public class Movie {
|
||||
}
|
||||
|
||||
public List<Person> getActors() {
|
||||
return actors;
|
||||
return this.actors;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreatedAt() {
|
||||
return createdAt;
|
||||
return this.createdAt;
|
||||
}
|
||||
|
||||
public String getCreatedBy() {
|
||||
return createdBy;
|
||||
return this.createdBy;
|
||||
}
|
||||
|
||||
public LocalDateTime getUpdatedAt() {
|
||||
return updatedAt;
|
||||
return this.updatedAt;
|
||||
}
|
||||
|
||||
public String getUpdatedBy() {
|
||||
return updatedBy;
|
||||
return this.updatedBy;
|
||||
}
|
||||
|
||||
public void setCreatedAt(LocalDateTime createdAt) {
|
||||
this.createdAt = createdAt;
|
||||
}
|
||||
|
||||
public void setCreatedBy(String createdBy) {
|
||||
this.createdBy = createdBy;
|
||||
}
|
||||
|
||||
public void setUpdatedAt(LocalDateTime updatedAt) {
|
||||
this.updatedAt = updatedAt;
|
||||
}
|
||||
|
||||
public void setUpdatedBy(String updatedBy) {
|
||||
this.updatedBy = updatedBy;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,13 +15,11 @@
|
||||
*/
|
||||
package com.example.data.neo4j;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import org.springframework.data.neo4j.repository.Neo4jRepository;
|
||||
import org.springframework.data.neo4j.repository.support.CypherdslConditionExecutor;
|
||||
import org.springframework.data.repository.query.QueryByExampleExecutor;
|
||||
|
||||
public interface MovieRepository
|
||||
extends Neo4jRepository<Movie, UUID>, CypherdslConditionExecutor<Movie>, QueryByExampleExecutor<Movie> {
|
||||
extends Neo4jRepository<Movie, Long>, CypherdslConditionExecutor<Movie>, QueryByExampleExecutor<Movie> {
|
||||
|
||||
}
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
package com.example.data.neo4j;
|
||||
|
||||
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;
|
||||
@@ -32,11 +30,11 @@ public abstract sealed class ParentNode permits ParentNode.ChildNode {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private UUID id;
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
public UUID getId() {
|
||||
public Long getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,20 +22,20 @@ public class Person {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private String id;
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
public Long getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
|
||||
@@ -15,13 +15,11 @@
|
||||
*/
|
||||
package com.example.data.neo4j;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import org.springframework.data.neo4j.repository.ReactiveNeo4jRepository;
|
||||
import org.springframework.data.neo4j.repository.support.ReactiveCypherdslConditionExecutor;
|
||||
import org.springframework.data.repository.query.ReactiveQueryByExampleExecutor;
|
||||
|
||||
public interface ReactiveMovieRepository extends ReactiveNeo4jRepository<Movie, UUID>,
|
||||
public interface ReactiveMovieRepository extends ReactiveNeo4jRepository<Movie, Long>,
|
||||
ReactiveCypherdslConditionExecutor<Movie>, ReactiveQueryByExampleExecutor<Movie> {
|
||||
|
||||
}
|
||||
|
||||
@@ -15,9 +15,12 @@
|
||||
*/
|
||||
package com.example.data.neo4j;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.neo4j.cypherdsl.core.Cypher;
|
||||
import org.neo4j.cypherdsl.core.Property;
|
||||
import org.neo4j.driver.Driver;
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.data.domain.Example;
|
||||
@@ -29,25 +32,21 @@ import org.springframework.transaction.reactive.TransactionalOperator;
|
||||
@Component
|
||||
public class ReactiveTestRunner implements CommandLineRunner {
|
||||
|
||||
private final Driver driver;
|
||||
|
||||
private final ReactiveNeo4jTemplate neo4jTemplate;
|
||||
|
||||
private final TransactionalOperator transactionalOperator;
|
||||
|
||||
private final ReactiveMovieRepository movieRepository;
|
||||
|
||||
public ReactiveTestRunner(Driver driver, ReactiveNeo4jTemplate neo4jTemplate,
|
||||
public ReactiveTestRunner(ReactiveNeo4jTemplate neo4jTemplate,
|
||||
ReactiveTransactionManager reactiveTransactionManager, ReactiveMovieRepository movieRepository) {
|
||||
this.driver = driver;
|
||||
this.neo4jTemplate = neo4jTemplate;
|
||||
this.transactionalOperator = TransactionalOperator.create(reactiveTransactionManager);
|
||||
this.movieRepository = movieRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(String... args) throws Exception {
|
||||
|
||||
public void run(String... args) {
|
||||
annotatedTypesShouldHaveBeenRegistered();
|
||||
externallyGeneratedFieldsShouldBePopulated();
|
||||
internallyGeneratedIdsShouldBePopulated();
|
||||
@@ -56,19 +55,19 @@ public class ReactiveTestRunner implements CommandLineRunner {
|
||||
}
|
||||
|
||||
private void qbeShouldWork() {
|
||||
|
||||
log("---- [Reactive] Neo4j Query By Example (QBE) ----");
|
||||
var optionalMovie = movieRepository.findOne(Example.of(new Movie("A movie"))).blockOptional();
|
||||
Optional<Movie> optionalMovie = this.movieRepository.findOne(Example.of(new Movie("A movie"))).blockOptional();
|
||||
optionalMovie.ifPresent((movie) -> {
|
||||
log("[Reactive] Found one movie by example with id %s", movie.getId());
|
||||
});
|
||||
}
|
||||
|
||||
private void cypherDSLIntegrationShouldWork() {
|
||||
|
||||
log("---- [Reactive] Neo4j Cypher-DSL integration and relationship population ----");
|
||||
var title = Cypher.node("Movie").named("movie").property("title");
|
||||
var movies = movieRepository.findAll(title.contains(Cypher.literalOf("A movie"))).collectList().block();
|
||||
Property title = Cypher.node("Movie").named("movie").property("title");
|
||||
List<Movie> movies = this.movieRepository.findAll(title.contains(Cypher.literalOf("A movie")))
|
||||
.collectList()
|
||||
.block();
|
||||
|
||||
log("[Reactive] Loaded %d movies", movies.size());
|
||||
if (!(movies.isEmpty() || movies.get(0).getActors().isEmpty())) {
|
||||
@@ -78,19 +77,17 @@ public class ReactiveTestRunner implements CommandLineRunner {
|
||||
}
|
||||
|
||||
private void internallyGeneratedIdsShouldBePopulated() {
|
||||
|
||||
log("---- [Reactive] Neo4j internally generated values ----");
|
||||
var person = new Person();
|
||||
Person person = new Person();
|
||||
person.setName("Jane Doe");
|
||||
person = neo4jTemplate.save(person).block();
|
||||
person = this.neo4jTemplate.save(person).block();
|
||||
log("[Reactive] Internal element id is present: %s", person.getId());
|
||||
}
|
||||
|
||||
private void externallyGeneratedFieldsShouldBePopulated() {
|
||||
|
||||
log("---- [Reactive] Neo4j externally generated values ----");
|
||||
var movie = movieRepository.save(new Movie("One Flew Over the Cuckoos Nest"))
|
||||
.as(transactionalOperator::transactional)
|
||||
Movie movie = this.movieRepository.save(new Movie("One Flew Over the Cuckoos Nest"))
|
||||
.as(this.transactionalOperator::transactional)
|
||||
.block();
|
||||
|
||||
log("[Reactive] Generated id is present: %s", movie.getId());
|
||||
@@ -101,7 +98,7 @@ public class ReactiveTestRunner implements CommandLineRunner {
|
||||
log("[Reactive] Version is %d", movie.getVersion());
|
||||
|
||||
movie.setTitle("One Flew Over the Cuckoo's Nest");
|
||||
var updatedMovie = movieRepository.save(movie).as(transactionalOperator::transactional).block();
|
||||
Movie updatedMovie = this.movieRepository.save(movie).as(this.transactionalOperator::transactional).block();
|
||||
|
||||
log("[Reactive] UpdatedAt is now present: %s",
|
||||
DataNeo4jApplication.FIXED_DATE.equals(updatedMovie.getUpdatedAt()));
|
||||
@@ -110,10 +107,9 @@ public class ReactiveTestRunner implements CommandLineRunner {
|
||||
}
|
||||
|
||||
private void annotatedTypesShouldHaveBeenRegistered() {
|
||||
|
||||
log("---- [Reactive] Neo4j Managed types ----");
|
||||
|
||||
var optionalResult = this.neo4jTemplate
|
||||
Optional<ParentNode> optionalResult = this.neo4jTemplate
|
||||
.findOne("MATCH (t:ParentLabel {name: $name}) RETURN t", Map.of("name", "BothLabelsMustBeManagedTypes"),
|
||||
ParentNode.class)
|
||||
.blockOptional();
|
||||
@@ -124,15 +120,6 @@ public class ReactiveTestRunner implements CommandLineRunner {
|
||||
});
|
||||
}
|
||||
|
||||
private void initializeDatabase(String... args) {
|
||||
try (var session = driver.session(); var tx = session.beginTransaction()) {
|
||||
tx.run("MATCH (n:ParentLabel:ChildLabel) DETACH DELETE n");
|
||||
tx.run("CREATE (:ParentLabel:ChildLabel {id: randomUuid(), name: 'BothLabelsMustBeManagedTypes'})");
|
||||
tx.run("CREATE (:Movie {id: randomUuid(), version: 0, title: 'A movie', updatedBy: 'A person', updatedAt: localdatetime()}) <-[:ACTED_IN]-(:Person {name: 'An Actor'})");
|
||||
tx.commit();
|
||||
}
|
||||
}
|
||||
|
||||
private void log(Object value) {
|
||||
log(String.valueOf(value), new Object[0]);
|
||||
}
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023 the original author 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 com.example.data.neo4j;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.aot.hint.MemberCategory;
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.aot.hint.RuntimeHintsRegistrar;
|
||||
import org.springframework.aot.hint.TypeReference;
|
||||
import org.springframework.boot.autoconfigure.domain.EntityScanner;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.ImportRuntimeHints;
|
||||
import org.springframework.data.neo4j.aot.Neo4jManagedTypes;
|
||||
import org.springframework.data.neo4j.core.convert.Neo4jConversions;
|
||||
import org.springframework.data.neo4j.core.mapping.Neo4jMappingContext;
|
||||
import org.springframework.data.neo4j.core.schema.Node;
|
||||
import org.springframework.data.neo4j.core.schema.RelationshipProperties;
|
||||
import org.springframework.data.neo4j.repository.query.CypherdslConditionExecutorImpl;
|
||||
import org.springframework.data.neo4j.repository.query.ReactiveCypherdslConditionExecutorImpl;
|
||||
|
||||
/**
|
||||
* See https://github.com/spring-projects/spring-data-neo4j/issues/2798 Only needed until
|
||||
* https://github.com/spring-projects/spring-boot/pull/37574 is resolved Otherwise the
|
||||
* abscence of {@link ParentNode.ChildNode} will cause application startup failure
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ImportRuntimeHints(WorkaroundsForMissingTypeHintsAndSB37574Config.MissingRuntimeHints.class)
|
||||
public class WorkaroundsForMissingTypeHintsAndSB37574Config {
|
||||
|
||||
@Bean
|
||||
public Neo4jManagedTypes neo4jManagedTypes(ApplicationContext applicationContext) throws ClassNotFoundException {
|
||||
Set<Class<?>> initialEntityClasses = new EntityScanner(applicationContext).scan(Node.class,
|
||||
RelationshipProperties.class);
|
||||
return Neo4jManagedTypes.fromIterable(initialEntityClasses);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Neo4jMappingContext neo4jMappingContext(Neo4jManagedTypes managedTypes, Neo4jConversions neo4jConversions) {
|
||||
|
||||
Neo4jMappingContext context = new Neo4jMappingContext(neo4jConversions);
|
||||
context.setManagedTypes(managedTypes);
|
||||
return context;
|
||||
}
|
||||
|
||||
public static class MissingRuntimeHints implements RuntimeHintsRegistrar {
|
||||
|
||||
@Override
|
||||
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
|
||||
hints.reflection()
|
||||
.registerTypes(
|
||||
List.of(TypeReference.of(CypherdslConditionExecutorImpl.class),
|
||||
TypeReference.of(ReactiveCypherdslConditionExecutorImpl.class)),
|
||||
builder -> builder.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
|
||||
MemberCategory.INVOKE_PUBLIC_METHODS));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user