GH-301 - Polishing.
Formatting, visibility. Some refactorings in Neo4jEventPublicationRepository.
This commit is contained in:
@@ -1,58 +1,58 @@
|
|||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
<modelVersion>4.0.0</modelVersion>
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>org.springframework.modulith</groupId>
|
<groupId>org.springframework.modulith</groupId>
|
||||||
<artifactId>spring-modulith-events</artifactId>
|
<artifactId>spring-modulith-events</artifactId>
|
||||||
<version>1.1.0-SNAPSHOT</version>
|
<version>1.1.0-SNAPSHOT</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<name>Spring Modulith - Events - Neo4j-based repository</name>
|
<name>Spring Modulith - Events - Neo4j-based repository</name>
|
||||||
<artifactId>spring-modulith-events-neo4j</artifactId>
|
<artifactId>spring-modulith-events-neo4j</artifactId>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<module.name>org.springframework.modulith.events.neo4j</module.name>
|
<module.name>org.springframework.modulith.events.neo4j</module.name>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>${project.groupId}</groupId>
|
<groupId>${project.groupId}</groupId>
|
||||||
<artifactId>spring-modulith-events-core</artifactId>
|
<artifactId>spring-modulith-events-core</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.data</groupId>
|
<groupId>org.springframework.data</groupId>
|
||||||
<artifactId>spring-data-neo4j</artifactId>
|
<artifactId>spring-data-neo4j</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-test</artifactId>
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-data-neo4j</artifactId>
|
<artifactId>spring-boot-starter-data-neo4j</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.testcontainers</groupId>
|
<groupId>org.testcontainers</groupId>
|
||||||
<artifactId>neo4j</artifactId>
|
<artifactId>neo4j</artifactId>
|
||||||
<version>1.19.0</version>
|
<scope>test</scope>
|
||||||
<scope>test</scope>
|
</dependency>
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.testcontainers</groupId>
|
<groupId>org.testcontainers</groupId>
|
||||||
<artifactId>junit-jupiter</artifactId>
|
<artifactId>junit-jupiter</artifactId>
|
||||||
<version>1.19.0</version>
|
<scope>test</scope>
|
||||||
<scope>test</scope>
|
</dependency>
|
||||||
</dependency>
|
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -1,15 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* 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 org.springframework.modulith.events.neo4j;
|
package org.springframework.modulith.events.neo4j;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* The event publication entity definition.
|
* The event publication entity definition.
|
||||||
*
|
*
|
||||||
* @author Gerrit Meier
|
* @author Gerrit Meier
|
||||||
|
* @since 1.1
|
||||||
*/
|
*/
|
||||||
public class Neo4jEventPublication {
|
class Neo4jEventPublication {
|
||||||
|
|
||||||
public final UUID identifier;
|
public final UUID identifier;
|
||||||
public final Instant publicationDate;
|
public final Instant publicationDate;
|
||||||
@@ -19,12 +34,13 @@ public class Neo4jEventPublication {
|
|||||||
|
|
||||||
public Instant completionDate;
|
public Instant completionDate;
|
||||||
|
|
||||||
public Neo4jEventPublication(UUID identifier, Instant publicationDate, String listenerId, Object event, String eventHash) {
|
public Neo4jEventPublication(UUID identifier, Instant publicationDate, String listenerId, Object event,
|
||||||
|
String eventHash) {
|
||||||
|
|
||||||
this.identifier = identifier;
|
this.identifier = identifier;
|
||||||
this.publicationDate = publicationDate;
|
this.publicationDate = publicationDate;
|
||||||
this.listenerId = listenerId;
|
this.listenerId = listenerId;
|
||||||
this.event = event;
|
this.event = event;
|
||||||
this.eventHash = eventHash;
|
this.eventHash = eventHash;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,14 +12,19 @@ import org.springframework.modulith.events.config.EventPublicationConfigurationE
|
|||||||
import org.springframework.modulith.events.core.EventSerializer;
|
import org.springframework.modulith.events.core.EventSerializer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Auto-configuration to register a {@link Neo4jEventPublicationRepository}, a default {@link Configuration} and a
|
||||||
|
* {@link Neo4jIndexInitializer} if enabled.
|
||||||
|
*
|
||||||
* @author Gerrit Meier
|
* @author Gerrit Meier
|
||||||
|
* @since 1.1
|
||||||
*/
|
*/
|
||||||
@AutoConfiguration
|
@AutoConfiguration
|
||||||
@AutoConfigureBefore(EventPublicationAutoConfiguration.class)
|
@AutoConfigureBefore(EventPublicationAutoConfiguration.class)
|
||||||
public class Neo4jEventPublicationAutoConfiguration implements EventPublicationConfigurationExtension {
|
class Neo4jEventPublicationAutoConfiguration implements EventPublicationConfigurationExtension {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
Neo4jEventPublicationRepository neo4jEventPublicationRepository(Neo4jClient neo4jClient, Configuration cypherDslConfiguration, EventSerializer eventSerializer) {
|
Neo4jEventPublicationRepository neo4jEventPublicationRepository(Neo4jClient neo4jClient,
|
||||||
|
Configuration cypherDslConfiguration, EventSerializer eventSerializer) {
|
||||||
return new Neo4jEventPublicationRepository(neo4jClient, cypherDslConfiguration, eventSerializer);
|
return new Neo4jEventPublicationRepository(neo4jClient, cypherDslConfiguration, eventSerializer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* 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 org.springframework.modulith.events.neo4j;
|
package org.springframework.modulith.events.neo4j;
|
||||||
|
|
||||||
import org.neo4j.cypherdsl.core.Cypher;
|
|
||||||
import org.neo4j.cypherdsl.core.Node;
|
|
||||||
import org.neo4j.cypherdsl.core.Statement;
|
|
||||||
import org.neo4j.cypherdsl.core.renderer.Configuration;
|
|
||||||
import org.neo4j.cypherdsl.core.renderer.Renderer;
|
|
||||||
import org.neo4j.driver.Values;
|
|
||||||
import org.neo4j.driver.types.TypeSystem;
|
|
||||||
import org.springframework.data.neo4j.core.Neo4jClient;
|
|
||||||
import org.springframework.modulith.events.core.EventPublicationRepository;
|
|
||||||
import org.springframework.modulith.events.core.EventSerializer;
|
|
||||||
import org.springframework.modulith.events.core.PublicationTargetIdentifier;
|
|
||||||
import org.springframework.modulith.events.core.TargetEventPublication;
|
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
import org.springframework.util.DigestUtils;
|
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.ZoneOffset;
|
import java.time.ZoneOffset;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -24,6 +23,30 @@ import java.util.Objects;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.neo4j.cypherdsl.core.Cypher;
|
||||||
|
import org.neo4j.cypherdsl.core.Node;
|
||||||
|
import org.neo4j.cypherdsl.core.ResultStatement;
|
||||||
|
import org.neo4j.cypherdsl.core.Statement;
|
||||||
|
import org.neo4j.cypherdsl.core.renderer.Configuration;
|
||||||
|
import org.neo4j.cypherdsl.core.renderer.Renderer;
|
||||||
|
import org.neo4j.driver.Values;
|
||||||
|
import org.neo4j.driver.types.TypeSystem;
|
||||||
|
import org.springframework.data.neo4j.core.Neo4jClient;
|
||||||
|
import org.springframework.lang.Nullable;
|
||||||
|
import org.springframework.modulith.events.core.EventPublicationRepository;
|
||||||
|
import org.springframework.modulith.events.core.EventSerializer;
|
||||||
|
import org.springframework.modulith.events.core.PublicationTargetIdentifier;
|
||||||
|
import org.springframework.modulith.events.core.TargetEventPublication;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.util.DigestUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link Neo4jClient} based implementation of {@link EventPublicationRepository}.
|
||||||
|
*
|
||||||
|
* @author Gerrit Meier
|
||||||
|
* @since 1.1
|
||||||
|
*/
|
||||||
@Transactional
|
@Transactional
|
||||||
class Neo4jEventPublicationRepository implements EventPublicationRepository {
|
class Neo4jEventPublicationRepository implements EventPublicationRepository {
|
||||||
|
|
||||||
@@ -35,20 +58,75 @@ class Neo4jEventPublicationRepository implements EventPublicationRepository {
|
|||||||
private static final String PUBLICATION_DATE = "publicationDate";
|
private static final String PUBLICATION_DATE = "publicationDate";
|
||||||
private static final String COMPLETION_DATE = "completionDate";
|
private static final String COMPLETION_DATE = "completionDate";
|
||||||
|
|
||||||
private static final Node eventPublicationNode = Cypher.node("Neo4jEventPublication").named("neo4jEventPublication");
|
private static final Node EVENT_PUBLICATION_NODE = Cypher.node("Neo4jEventPublication")
|
||||||
|
.named("neo4jEventPublication");
|
||||||
|
|
||||||
|
private static final Statement INCOMPLETE_BY_EVENT_AND_TARGET_IDENTIFIER_STATEMENT = Cypher
|
||||||
|
.match(EVENT_PUBLICATION_NODE)
|
||||||
|
.where(EVENT_PUBLICATION_NODE.property(EVENT_HASH).eq(Cypher.parameter(EVENT_HASH)))
|
||||||
|
.and(EVENT_PUBLICATION_NODE.property(LISTENER_ID).eq(Cypher.parameter(LISTENER_ID)))
|
||||||
|
.and(EVENT_PUBLICATION_NODE.property(COMPLETION_DATE).isNull())
|
||||||
|
.returning(EVENT_PUBLICATION_NODE)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
private static final Statement DELETE_BY_ID_STATEMENT = Cypher.match(EVENT_PUBLICATION_NODE)
|
||||||
|
.where(EVENT_PUBLICATION_NODE.property(ID).in(Cypher.parameter(ID)))
|
||||||
|
.delete(EVENT_PUBLICATION_NODE)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
private static final Statement DELETE_COMPLETED_STATEMENT = Cypher.match(EVENT_PUBLICATION_NODE)
|
||||||
|
.where(EVENT_PUBLICATION_NODE.property(COMPLETION_DATE).isNotNull())
|
||||||
|
.delete(EVENT_PUBLICATION_NODE)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
private static final Statement DELETE_COMPLETED_BEFORE_STATEMENT = Cypher.match(EVENT_PUBLICATION_NODE)
|
||||||
|
.where(EVENT_PUBLICATION_NODE.property(PUBLICATION_DATE).lt(Cypher.parameter(PUBLICATION_DATE)))
|
||||||
|
.and(EVENT_PUBLICATION_NODE.property(COMPLETION_DATE).isNotNull())
|
||||||
|
.delete(EVENT_PUBLICATION_NODE)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
private static final Statement INCOMPLETE_PUBLISHED_BEFORE_STATEMENT = Cypher
|
||||||
|
.match(EVENT_PUBLICATION_NODE)
|
||||||
|
.where(EVENT_PUBLICATION_NODE.property(PUBLICATION_DATE).lt(Cypher.parameter(PUBLICATION_DATE)))
|
||||||
|
.and(EVENT_PUBLICATION_NODE.property(COMPLETION_DATE).isNull())
|
||||||
|
.returning(EVENT_PUBLICATION_NODE)
|
||||||
|
.orderBy(EVENT_PUBLICATION_NODE.property(PUBLICATION_DATE))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
private static final Statement CREATE_STATEMENT = Cypher.create(EVENT_PUBLICATION_NODE)
|
||||||
|
.set(EVENT_PUBLICATION_NODE.property(ID).to(Cypher.parameter(ID)))
|
||||||
|
.set(EVENT_PUBLICATION_NODE.property(EVENT_SERIALIZED).to(Cypher.parameter(EVENT_SERIALIZED)))
|
||||||
|
.set(EVENT_PUBLICATION_NODE.property(EVENT_HASH).to(Cypher.parameter(EVENT_HASH)))
|
||||||
|
.set(EVENT_PUBLICATION_NODE.property(EVENT_TYPE).to(Cypher.parameter(EVENT_TYPE)))
|
||||||
|
.set(EVENT_PUBLICATION_NODE.property(LISTENER_ID).to(Cypher.parameter(LISTENER_ID)))
|
||||||
|
.set(EVENT_PUBLICATION_NODE.property(PUBLICATION_DATE).to(Cypher.parameter(PUBLICATION_DATE)))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
private static final Statement COMPLETE_STATEMENT = Cypher.match(EVENT_PUBLICATION_NODE)
|
||||||
|
.where(EVENT_PUBLICATION_NODE.property(EVENT_HASH).eq(Cypher.parameter(EVENT_HASH)))
|
||||||
|
.and(EVENT_PUBLICATION_NODE.property(LISTENER_ID).eq(Cypher.parameter(LISTENER_ID)))
|
||||||
|
.set(EVENT_PUBLICATION_NODE.property(COMPLETION_DATE).to(Cypher.parameter(COMPLETION_DATE)))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
private static final ResultStatement INCOMPLETE_STATEMENT = Cypher.match(EVENT_PUBLICATION_NODE)
|
||||||
|
.where(EVENT_PUBLICATION_NODE.property(COMPLETION_DATE).isNull())
|
||||||
|
.returning(EVENT_PUBLICATION_NODE)
|
||||||
|
.orderBy(EVENT_PUBLICATION_NODE.property(PUBLICATION_DATE))
|
||||||
|
.build();
|
||||||
|
|
||||||
private final Neo4jClient neo4jClient;
|
private final Neo4jClient neo4jClient;
|
||||||
private final Configuration cypherDslConfiguration;
|
private final Renderer renderer;
|
||||||
private final EventSerializer eventSerializer;
|
private final EventSerializer eventSerializer;
|
||||||
|
|
||||||
Neo4jEventPublicationRepository(Neo4jClient neo4jClient, Configuration cypherDslConfiguration, EventSerializer eventSerializer) {
|
Neo4jEventPublicationRepository(Neo4jClient neo4jClient, Configuration cypherDslConfiguration,
|
||||||
|
EventSerializer eventSerializer) {
|
||||||
|
|
||||||
Assert.notNull(neo4jClient, "Neo4jClient must not be null!");
|
Assert.notNull(neo4jClient, "Neo4jClient must not be null!");
|
||||||
Assert.notNull(cypherDslConfiguration, "CypherDSL configuration must not be null!");
|
Assert.notNull(cypherDslConfiguration, "CypherDSL configuration must not be null!");
|
||||||
Assert.notNull(eventSerializer, "EventSerializer must not be null!");
|
Assert.notNull(eventSerializer, "EventSerializer must not be null!");
|
||||||
|
|
||||||
this.neo4jClient = neo4jClient;
|
this.neo4jClient = neo4jClient;
|
||||||
this.cypherDslConfiguration = cypherDslConfiguration;
|
this.renderer = Renderer.getRenderer(cypherDslConfiguration);
|
||||||
this.eventSerializer = eventSerializer;
|
this.eventSerializer = eventSerializer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,28 +144,18 @@ class Neo4jEventPublicationRepository implements EventPublicationRepository {
|
|||||||
var event = publication.getEvent();
|
var event = publication.getEvent();
|
||||||
var eventType = event.getClass().getName();
|
var eventType = event.getClass().getName();
|
||||||
|
|
||||||
var eventSerialized = (String) eventSerializer.serialize(event);
|
var eventSerialized = eventSerializer.serialize(event).toString();
|
||||||
var eventHash = DigestUtils.md5DigestAsHex(eventSerialized.getBytes());
|
var eventHash = DigestUtils.md5DigestAsHex(eventSerialized.getBytes());
|
||||||
|
|
||||||
var createStatement = Cypher.create(eventPublicationNode)
|
neo4jClient.query(renderer.render(CREATE_STATEMENT))
|
||||||
.set(eventPublicationNode.property(ID).to(Cypher.parameter(ID)))
|
.bindAll(Map.of(
|
||||||
.set(eventPublicationNode.property(EVENT_SERIALIZED).to(Cypher.parameter(EVENT_SERIALIZED)))
|
ID, Values.value(identifier.toString()),
|
||||||
.set(eventPublicationNode.property(EVENT_HASH).to(Cypher.parameter(EVENT_HASH)))
|
EVENT_SERIALIZED, eventSerialized,
|
||||||
.set(eventPublicationNode.property(EVENT_TYPE).to(Cypher.parameter(EVENT_TYPE)))
|
EVENT_HASH, eventHash,
|
||||||
.set(eventPublicationNode.property(LISTENER_ID).to(Cypher.parameter(LISTENER_ID)))
|
EVENT_TYPE, eventType,
|
||||||
.set(eventPublicationNode.property(PUBLICATION_DATE).to(Cypher.parameter(PUBLICATION_DATE)))
|
LISTENER_ID, listenerId,
|
||||||
.build();
|
PUBLICATION_DATE, Values.value(publicationDate.atOffset(ZoneOffset.UTC))))
|
||||||
|
.run();
|
||||||
neo4jClient.query(renderStatement(createStatement))
|
|
||||||
.bindAll(Map.of(
|
|
||||||
ID, Values.value(identifier.toString()),
|
|
||||||
EVENT_SERIALIZED, eventSerialized,
|
|
||||||
EVENT_HASH, eventHash,
|
|
||||||
EVENT_TYPE, eventType,
|
|
||||||
LISTENER_ID, listenerId,
|
|
||||||
PUBLICATION_DATE, Values.value(publicationDate.atOffset(ZoneOffset.UTC))
|
|
||||||
))
|
|
||||||
.run();
|
|
||||||
|
|
||||||
return publication;
|
return publication;
|
||||||
}
|
}
|
||||||
@@ -99,19 +167,14 @@ class Neo4jEventPublicationRepository implements EventPublicationRepository {
|
|||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public void markCompleted(Object event, PublicationTargetIdentifier identifier, Instant completionDate) {
|
public void markCompleted(Object event, PublicationTargetIdentifier identifier, Instant completionDate) {
|
||||||
var eventHash = DigestUtils.md5DigestAsHex(((String) eventSerializer.serialize(event)).getBytes());
|
|
||||||
|
|
||||||
var completeStatement = Cypher.match(eventPublicationNode)
|
var eventHash = DigestUtils.md5DigestAsHex(eventSerializer.serialize(event).toString().getBytes());
|
||||||
.where(eventPublicationNode.property(EVENT_HASH).eq(Cypher.parameter(EVENT_HASH)))
|
|
||||||
.and(eventPublicationNode.property(LISTENER_ID).eq(Cypher.parameter(LISTENER_ID)))
|
|
||||||
.set(eventPublicationNode.property(COMPLETION_DATE).to(Cypher.parameter(COMPLETION_DATE)))
|
|
||||||
.build();
|
|
||||||
|
|
||||||
neo4jClient.query(renderStatement(completeStatement))
|
neo4jClient.query(renderer.render(COMPLETE_STATEMENT))
|
||||||
.bind(eventHash).to(EVENT_HASH)
|
.bind(eventHash).to(EVENT_HASH)
|
||||||
.bind(identifier.getValue()).to(LISTENER_ID)
|
.bind(identifier.getValue()).to(LISTENER_ID)
|
||||||
.bind(Values.value(completionDate.atOffset(ZoneOffset.UTC))).to(COMPLETION_DATE)
|
.bind(Values.value(completionDate.atOffset(ZoneOffset.UTC))).to(COMPLETION_DATE)
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -122,99 +185,85 @@ class Neo4jEventPublicationRepository implements EventPublicationRepository {
|
|||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
public List<TargetEventPublication> findIncompletePublications() {
|
public List<TargetEventPublication> findIncompletePublications() {
|
||||||
|
|
||||||
var findIncompleteStatement = Cypher.match(eventPublicationNode)
|
return List.copyOf(neo4jClient.query(renderer.render(INCOMPLETE_STATEMENT))
|
||||||
.where(eventPublicationNode.property(COMPLETION_DATE).isNull())
|
.fetchAs(TargetEventPublication.class)
|
||||||
.returning(eventPublicationNode)
|
.mappedBy(this::mapRecordToPublication)
|
||||||
.orderBy(eventPublicationNode.property(PUBLICATION_DATE))
|
.all());
|
||||||
.build();
|
|
||||||
|
|
||||||
return List.copyOf(neo4jClient.query(renderStatement(findIncompleteStatement))
|
|
||||||
.fetchAs(TargetEventPublication.class)
|
|
||||||
.mappedBy(this::mapRecordToPublication)
|
|
||||||
.all());
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.modulith.events.core.EventPublicationRepository#findIncompletePublicationsPublishedBefore(java.time.Instant)
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
public List<TargetEventPublication> findIncompletePublicationsPublishedBefore(Instant instant) {
|
public List<TargetEventPublication> findIncompletePublicationsPublishedBefore(Instant instant) {
|
||||||
var findIncompleteStatement = Cypher.match(eventPublicationNode)
|
|
||||||
.where(eventPublicationNode.property(PUBLICATION_DATE).lt(Cypher.parameter(PUBLICATION_DATE)))
|
|
||||||
.and(eventPublicationNode.property(COMPLETION_DATE).isNull())
|
|
||||||
.returning(eventPublicationNode)
|
|
||||||
.orderBy(eventPublicationNode.property(PUBLICATION_DATE))
|
|
||||||
.build();
|
|
||||||
|
|
||||||
return List.copyOf(neo4jClient.query(renderStatement(findIncompleteStatement))
|
|
||||||
.bind(Values.value(instant.atOffset(ZoneOffset.UTC))).to(PUBLICATION_DATE)
|
|
||||||
.fetchAs(TargetEventPublication.class)
|
|
||||||
.mappedBy(this::mapRecordToPublication)
|
|
||||||
.all());
|
|
||||||
|
|
||||||
|
return List.copyOf(neo4jClient.query(renderer.render(INCOMPLETE_PUBLISHED_BEFORE_STATEMENT))
|
||||||
|
.bind(Values.value(instant.atOffset(ZoneOffset.UTC))).to(PUBLICATION_DATE)
|
||||||
|
.fetchAs(TargetEventPublication.class)
|
||||||
|
.mappedBy(this::mapRecordToPublication)
|
||||||
|
.all());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.modulith.events.core.EventPublicationRepository#findIncompletePublicationsByEventAndTargetIdentifier(java.lang.Object, org.springframework.modulith.events.core.PublicationTargetIdentifier)
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
public Optional<TargetEventPublication> findIncompletePublicationsByEventAndTargetIdentifier(Object event, PublicationTargetIdentifier targetIdentifier) {
|
public Optional<TargetEventPublication> findIncompletePublicationsByEventAndTargetIdentifier(Object event,
|
||||||
|
PublicationTargetIdentifier targetIdentifier) {
|
||||||
|
|
||||||
var eventHash = DigestUtils.md5DigestAsHex(((String) eventSerializer.serialize(event)).getBytes());
|
var eventHash = DigestUtils.md5DigestAsHex(((String) eventSerializer.serialize(event)).getBytes());
|
||||||
var listenerId = targetIdentifier.getValue();
|
var listenerId = targetIdentifier.getValue();
|
||||||
|
|
||||||
var statement = Cypher.match(eventPublicationNode)
|
return neo4jClient.query(renderer.render(INCOMPLETE_BY_EVENT_AND_TARGET_IDENTIFIER_STATEMENT))
|
||||||
.where(eventPublicationNode.property(EVENT_HASH).eq(Cypher.parameter(EVENT_HASH)))
|
.bindAll(Map.of(EVENT_HASH, eventHash, LISTENER_ID, listenerId))
|
||||||
.and(eventPublicationNode.property(LISTENER_ID).eq(Cypher.parameter(LISTENER_ID)))
|
.fetchAs(TargetEventPublication.class)
|
||||||
.and(eventPublicationNode.property(COMPLETION_DATE).isNull())
|
.mappedBy(this::mapRecordToPublication)
|
||||||
.returning(eventPublicationNode)
|
.one();
|
||||||
.build();
|
|
||||||
|
|
||||||
return neo4jClient.query(renderStatement(statement))
|
|
||||||
.bindAll(Map.of(EVENT_HASH, eventHash, LISTENER_ID, listenerId))
|
|
||||||
.fetchAs(TargetEventPublication.class)
|
|
||||||
.mappedBy(this::mapRecordToPublication)
|
|
||||||
.one();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.modulith.events.core.EventPublicationRepository#deletePublications(java.util.List)
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public void deletePublications(List<UUID> identifiers) {
|
public void deletePublications(List<UUID> identifiers) {
|
||||||
var deleteStatement = Cypher.match(eventPublicationNode)
|
|
||||||
.where(eventPublicationNode.property(ID).in(Cypher.parameter(ID)))
|
|
||||||
.delete(eventPublicationNode)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
neo4jClient.query(renderStatement(deleteStatement))
|
neo4jClient.query(renderer.render(DELETE_BY_ID_STATEMENT))
|
||||||
.bind(identifiers.stream().map(UUID::toString).toList()).to(ID)
|
.bind(identifiers.stream().map(UUID::toString).toList()).to(ID)
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.modulith.events.core.EventPublicationRepository#deleteCompletedPublications()
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public void deleteCompletedPublications() {
|
public void deleteCompletedPublications() {
|
||||||
var deleteStatement = Cypher.match(eventPublicationNode)
|
neo4jClient.query(renderer.render(DELETE_COMPLETED_STATEMENT)).run();
|
||||||
.where(eventPublicationNode.property(COMPLETION_DATE).isNotNull())
|
|
||||||
.delete(eventPublicationNode)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
neo4jClient.query(renderStatement(deleteStatement))
|
|
||||||
.run();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.modulith.events.core.EventPublicationRepository#deleteCompletedPublicationsBefore(java.time.Instant)
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public void deleteCompletedPublicationsBefore(Instant instant) {
|
public void deleteCompletedPublicationsBefore(Instant instant) {
|
||||||
var deleteStatement = Cypher.match(eventPublicationNode)
|
|
||||||
.where(eventPublicationNode.property(PUBLICATION_DATE).lt(Cypher.parameter(PUBLICATION_DATE)))
|
|
||||||
.and(eventPublicationNode.property(COMPLETION_DATE).isNotNull())
|
|
||||||
.delete(eventPublicationNode)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
neo4jClient.query(renderStatement(deleteStatement))
|
neo4jClient.query(renderer.render(DELETE_COMPLETED_BEFORE_STATEMENT))
|
||||||
.bind(Values.value(instant.atOffset(ZoneOffset.UTC))).to(PUBLICATION_DATE)
|
.bind(Values.value(instant.atOffset(ZoneOffset.UTC))).to(PUBLICATION_DATE)
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Neo4jEventPublicationAdapter mapRecordToPublication(TypeSystem typeSystem, org.neo4j.driver.Record record) {
|
private Neo4jEventPublicationAdapter mapRecordToPublication(TypeSystem typeSystem, org.neo4j.driver.Record record) {
|
||||||
var publicationNode = record.get(eventPublicationNode.getRequiredSymbolicName().getValue()).asNode();
|
|
||||||
|
var publicationNode = record.get(EVENT_PUBLICATION_NODE.getRequiredSymbolicName().getValue()).asNode();
|
||||||
var identifier = UUID.fromString(publicationNode.get(ID).asString());
|
var identifier = UUID.fromString(publicationNode.get(ID).asString());
|
||||||
var publicationDate = publicationNode.get(PUBLICATION_DATE).asZonedDateTime().toInstant();
|
var publicationDate = publicationNode.get(PUBLICATION_DATE).asZonedDateTime().toInstant();
|
||||||
var listenerId = publicationNode.get(LISTENER_ID).asString();
|
var listenerId = publicationNode.get(LISTENER_ID).asString();
|
||||||
@@ -223,21 +272,19 @@ class Neo4jEventPublicationRepository implements EventPublicationRepository {
|
|||||||
var eventType = publicationNode.get(EVENT_TYPE).asString();
|
var eventType = publicationNode.get(EVENT_TYPE).asString();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Object event = eventSerializer.deserialize(eventSerialized, Class.forName(eventType));
|
|
||||||
Neo4jEventPublication publication = new Neo4jEventPublication(identifier, publicationDate, listenerId, event, eventHash);
|
var event = eventSerializer.deserialize(eventSerialized, Class.forName(eventType));
|
||||||
|
var publication = new Neo4jEventPublication(identifier, publicationDate, listenerId, event,
|
||||||
|
eventHash);
|
||||||
|
|
||||||
return new Neo4jEventPublicationAdapter(publication);
|
return new Neo4jEventPublicationAdapter(publication);
|
||||||
|
|
||||||
} catch (ClassNotFoundException e) {
|
} catch (ClassNotFoundException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String renderStatement(Statement statement) {
|
private static class Neo4jEventPublicationAdapter implements TargetEventPublication {
|
||||||
return Renderer.getRenderer(cypherDslConfiguration).render(statement);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static class Neo4jEventPublicationAdapter implements TargetEventPublication {
|
|
||||||
|
|
||||||
private final Neo4jEventPublication delegate;
|
private final Neo4jEventPublication delegate;
|
||||||
|
|
||||||
@@ -285,7 +332,7 @@ class Neo4jEventPublicationRepository implements EventPublicationRepository {
|
|||||||
* @see java.lang.Object#equals(java.lang.Object)
|
* @see java.lang.Object#equals(java.lang.Object)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(@Nullable Object obj) {
|
||||||
|
|
||||||
if (this == obj) {
|
if (this == obj) {
|
||||||
return true;
|
return true;
|
||||||
@@ -307,4 +354,4 @@ class Neo4jEventPublicationRepository implements EventPublicationRepository {
|
|||||||
return Objects.hash(delegate);
|
return Objects.hash(delegate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* 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 org.springframework.modulith.events.neo4j;
|
package org.springframework.modulith.events.neo4j;
|
||||||
|
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
import org.springframework.data.neo4j.core.Neo4jClient;
|
import org.springframework.data.neo4j.core.Neo4jClient;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Automatically creates an index on the {@link Neo4jEventPublication#eventHash} field.
|
||||||
|
*
|
||||||
* @author Gerrit Meier
|
* @author Gerrit Meier
|
||||||
|
* @since 1.1
|
||||||
*/
|
*/
|
||||||
public class Neo4jIndexInitializer implements InitializingBean {
|
class Neo4jIndexInitializer implements InitializingBean {
|
||||||
|
|
||||||
private final Neo4jClient neo4jClient;
|
private final Neo4jClient neo4jClient;
|
||||||
|
|
||||||
public Neo4jIndexInitializer(Neo4jClient neo4jClient) {
|
Neo4jIndexInitializer(Neo4jClient neo4jClient) {
|
||||||
this.neo4jClient = neo4jClient;
|
this.neo4jClient = neo4jClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void afterPropertiesSet() throws Exception {
|
public void afterPropertiesSet() throws Exception {
|
||||||
|
|
||||||
neo4jClient
|
neo4jClient
|
||||||
.query("CREATE INDEX eventHashIndex IF NOT EXISTS FOR (n:`Neo4jEventPublication`) ON (n.eventHash)")
|
.query("CREATE INDEX eventHashIndex IF NOT EXISTS FOR (n:`Neo4jEventPublication`) ON (n.eventHash)")
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
/**
|
||||||
|
* Neo4j integration for {@link org.springframework.modulith.events.core.EventPublicationRepository}.
|
||||||
|
*/
|
||||||
|
@org.springframework.lang.NonNullApi
|
||||||
|
package org.springframework.modulith.events.neo4j;
|
||||||
@@ -1,13 +1,21 @@
|
|||||||
package org.springframework.modulith.events.neo4j;
|
package org.springframework.modulith.events.neo4j;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.*;
|
||||||
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
import lombok.Value;
|
import lombok.Value;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.neo4j.cypherdsl.core.renderer.Dialect;
|
import org.neo4j.cypherdsl.core.renderer.Dialect;
|
||||||
import org.neo4j.driver.AuthTokens;
|
import org.neo4j.driver.AuthTokens;
|
||||||
import org.neo4j.driver.Driver;
|
import org.neo4j.driver.Driver;
|
||||||
import org.neo4j.driver.GraphDatabase;
|
import org.neo4j.driver.GraphDatabase;
|
||||||
import org.neo4j.driver.types.Node;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
@@ -24,14 +32,6 @@ import org.testcontainers.junit.jupiter.Container;
|
|||||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||||
import org.testcontainers.utility.DockerImageName;
|
import org.testcontainers.utility.DockerImageName;
|
||||||
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.time.temporal.ChronoUnit;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Gerrit Meier
|
* @author Gerrit Meier
|
||||||
*/
|
*/
|
||||||
@@ -39,23 +39,19 @@ import static org.mockito.Mockito.when;
|
|||||||
@Testcontainers(disabledWithoutDocker = true)
|
@Testcontainers(disabledWithoutDocker = true)
|
||||||
class Neo4jEventPublicationRepositoryTest {
|
class Neo4jEventPublicationRepositoryTest {
|
||||||
|
|
||||||
@Container
|
@Container //
|
||||||
private static Neo4jContainer<?> neo4jContainer = new Neo4jContainer<>(DockerImageName.parse("neo4j:5"))
|
static final Neo4jContainer<?> neo4jContainer = new Neo4jContainer<>(DockerImageName.parse("neo4j:5"))
|
||||||
.withRandomPassword();
|
.withRandomPassword();
|
||||||
|
|
||||||
static final PublicationTargetIdentifier TARGET_IDENTIFIER = PublicationTargetIdentifier.of("listener");
|
static final PublicationTargetIdentifier TARGET_IDENTIFIER = PublicationTargetIdentifier.of("listener");
|
||||||
|
|
||||||
@Autowired
|
@Autowired Neo4jEventPublicationRepository repository;
|
||||||
private Neo4jEventPublicationRepository repository;
|
@Autowired Driver driver;
|
||||||
|
@MockBean EventSerializer eventSerializer;
|
||||||
@Autowired
|
|
||||||
private Driver driver;
|
|
||||||
|
|
||||||
@MockBean
|
|
||||||
private EventSerializer eventSerializer;
|
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void clearDb() {
|
void clearDb() {
|
||||||
|
|
||||||
try (var session = driver.session()) {
|
try (var session = driver.session()) {
|
||||||
session.run("MATCH (n) detach delete n").consume();
|
session.run("MATCH (n) detach delete n").consume();
|
||||||
}
|
}
|
||||||
@@ -63,6 +59,7 @@ class Neo4jEventPublicationRepositoryTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void createEventPublication() {
|
void createEventPublication() {
|
||||||
|
|
||||||
var testEvent = new TestEvent("id");
|
var testEvent = new TestEvent("id");
|
||||||
var eventSerialized = "{\"eventId\":\"id\"}";
|
var eventSerialized = "{\"eventId\":\"id\"}";
|
||||||
var eventHash = DigestUtils.md5DigestAsHex(eventSerialized.getBytes());
|
var eventHash = DigestUtils.md5DigestAsHex(eventSerialized.getBytes());
|
||||||
@@ -71,22 +68,27 @@ class Neo4jEventPublicationRepositoryTest {
|
|||||||
var publication = repository.create(TargetEventPublication.of(testEvent, TARGET_IDENTIFIER));
|
var publication = repository.create(TargetEventPublication.of(testEvent, TARGET_IDENTIFIER));
|
||||||
|
|
||||||
try (var session = driver.session()) {
|
try (var session = driver.session()) {
|
||||||
var result = session.run("MATCH (p:Neo4jEventPublication) return p")
|
|
||||||
.single();
|
|
||||||
|
|
||||||
Node neo4jEventPublicationNode = result.get("p").asNode();
|
var result = session.run("MATCH (p:Neo4jEventPublication) return p")
|
||||||
assertThat(UUID.fromString(neo4jEventPublicationNode.get("identifier").asString())).isEqualTo(publication.getIdentifier());
|
.single();
|
||||||
assertThat(neo4jEventPublicationNode.get("publicationDate").asZonedDateTime().toInstant()).isEqualTo(publication.getPublicationDate());
|
|
||||||
assertThat(neo4jEventPublicationNode.get("listenerId").asString()).isEqualTo(publication.getTargetIdentifier().getValue());
|
var neo4jEventPublicationNode = result.get("p").asNode();
|
||||||
|
|
||||||
|
assertThat(UUID.fromString(neo4jEventPublicationNode.get("identifier").asString()))
|
||||||
|
.isEqualTo(publication.getIdentifier());
|
||||||
|
assertThat(neo4jEventPublicationNode.get("publicationDate").asZonedDateTime().toInstant())
|
||||||
|
.isEqualTo(publication.getPublicationDate());
|
||||||
|
assertThat(neo4jEventPublicationNode.get("listenerId").asString())
|
||||||
|
.isEqualTo(publication.getTargetIdentifier().getValue());
|
||||||
assertThat(neo4jEventPublicationNode.get("completionDate").isNull()).isTrue();
|
assertThat(neo4jEventPublicationNode.get("completionDate").isNull()).isTrue();
|
||||||
assertThat(neo4jEventPublicationNode.get("eventSerialized").asString()).isEqualTo(eventSerialized);
|
assertThat(neo4jEventPublicationNode.get("eventSerialized").asString()).isEqualTo(eventSerialized);
|
||||||
assertThat(neo4jEventPublicationNode.get("eventHash").asString()).isEqualTo(eventHash);
|
assertThat(neo4jEventPublicationNode.get("eventHash").asString()).isEqualTo(eventHash);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void updateEventPublication() {
|
void updateEventPublication() {
|
||||||
|
|
||||||
var testEvent1 = new TestEvent("id1");
|
var testEvent1 = new TestEvent("id1");
|
||||||
var event1Serialized = "{\"eventId\":\"id1\"}";
|
var event1Serialized = "{\"eventId\":\"id1\"}";
|
||||||
var testEvent2 = new TestEvent("id2");
|
var testEvent2 = new TestEvent("id2");
|
||||||
@@ -103,12 +105,13 @@ class Neo4jEventPublicationRepositoryTest {
|
|||||||
repository.markCompleted(event1, now);
|
repository.markCompleted(event1, now);
|
||||||
|
|
||||||
assertThat(repository.findIncompletePublications()).hasSize(1)
|
assertThat(repository.findIncompletePublications()).hasSize(1)
|
||||||
.element(0)
|
.element(0)
|
||||||
.extracting(TargetEventPublication::getEvent).isEqualTo(event2.getEvent());
|
.extracting(TargetEventPublication::getEvent).isEqualTo(event2.getEvent());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void findInCompletePastPublications() {
|
void findInCompletePastPublications() {
|
||||||
|
|
||||||
var testEvent = new TestEvent("id");
|
var testEvent = new TestEvent("id");
|
||||||
var eventSerialized = "{\"eventId\":\"id\"}";
|
var eventSerialized = "{\"eventId\":\"id\"}";
|
||||||
|
|
||||||
@@ -121,14 +124,15 @@ class Neo4jEventPublicationRepositoryTest {
|
|||||||
var older = Instant.now().minus(1L, ChronoUnit.MINUTES);
|
var older = Instant.now().minus(1L, ChronoUnit.MINUTES);
|
||||||
|
|
||||||
assertThat(repository.findIncompletePublicationsPublishedBefore(newer)).hasSize(1)
|
assertThat(repository.findIncompletePublicationsPublishedBefore(newer)).hasSize(1)
|
||||||
.element(0)
|
.element(0)
|
||||||
.extracting(TargetEventPublication::getEvent).isEqualTo(event.getEvent());
|
.extracting(TargetEventPublication::getEvent).isEqualTo(event.getEvent());
|
||||||
|
|
||||||
assertThat(repository.findIncompletePublicationsPublishedBefore(older)).hasSize(0);
|
assertThat(repository.findIncompletePublicationsPublishedBefore(older)).hasSize(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void findIncompleteByEventAndTargetIdentifier() {
|
void findIncompleteByEventAndTargetIdentifier() {
|
||||||
|
|
||||||
var testEvent = new TestEvent("id");
|
var testEvent = new TestEvent("id");
|
||||||
var eventSerialized = "{\"eventId\":\"id\"}";
|
var eventSerialized = "{\"eventId\":\"id\"}";
|
||||||
|
|
||||||
@@ -138,13 +142,15 @@ class Neo4jEventPublicationRepositoryTest {
|
|||||||
var event = repository.create(TargetEventPublication.of(testEvent, TARGET_IDENTIFIER));
|
var event = repository.create(TargetEventPublication.of(testEvent, TARGET_IDENTIFIER));
|
||||||
|
|
||||||
assertThat(repository.findIncompletePublicationsByEventAndTargetIdentifier(testEvent, event.getTargetIdentifier()))
|
assertThat(repository.findIncompletePublicationsByEventAndTargetIdentifier(testEvent, event.getTargetIdentifier()))
|
||||||
.isPresent();
|
.isPresent();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void deletePublicationById() {
|
void deletePublicationById() {
|
||||||
TestEvent testEvent = new TestEvent("id");
|
|
||||||
|
var testEvent = new TestEvent("id");
|
||||||
var eventSerialized = "{\"eventId\":\"id\"}";
|
var eventSerialized = "{\"eventId\":\"id\"}";
|
||||||
|
|
||||||
when(eventSerializer.serialize(testEvent)).thenReturn(eventSerialized);
|
when(eventSerializer.serialize(testEvent)).thenReturn(eventSerialized);
|
||||||
|
|
||||||
var event = repository.create(TargetEventPublication.of(testEvent, TARGET_IDENTIFIER));
|
var event = repository.create(TargetEventPublication.of(testEvent, TARGET_IDENTIFIER));
|
||||||
@@ -156,9 +162,10 @@ class Neo4jEventPublicationRepositoryTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void deleteCompletedPublications() {
|
void deleteCompletedPublications() {
|
||||||
TestEvent testEvent1 = new TestEvent("id1");
|
|
||||||
|
var testEvent1 = new TestEvent("id1");
|
||||||
var event1Serialized = "{\"eventId\":\"id1\"}";
|
var event1Serialized = "{\"eventId\":\"id1\"}";
|
||||||
TestEvent testEvent2 = new TestEvent("id2");
|
var testEvent2 = new TestEvent("id2");
|
||||||
var event2Serialized = "{\"eventId\":\"id2\"}";
|
var event2Serialized = "{\"eventId\":\"id2\"}";
|
||||||
|
|
||||||
when(eventSerializer.serialize(testEvent1)).thenReturn(event1Serialized);
|
when(eventSerializer.serialize(testEvent1)).thenReturn(event1Serialized);
|
||||||
@@ -173,16 +180,18 @@ class Neo4jEventPublicationRepositoryTest {
|
|||||||
repository.deleteCompletedPublications();
|
repository.deleteCompletedPublications();
|
||||||
|
|
||||||
try (var session = driver.session()) {
|
try (var session = driver.session()) {
|
||||||
var count = session.run("MATCH (n) WHERE n.completionDate is not null return count(n)").single().get("count(n)").asLong();
|
var count = session.run("MATCH (n) WHERE n.completionDate is not null return count(n)").single().get("count(n)")
|
||||||
|
.asLong();
|
||||||
assertThat(count).isEqualTo(0);
|
assertThat(count).isEqualTo(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void deleteCompletedPublicationsBefore() throws Exception {
|
void deleteCompletedPublicationsBefore() throws Exception {
|
||||||
TestEvent testEvent1 = new TestEvent("id1");
|
|
||||||
|
var testEvent1 = new TestEvent("id1");
|
||||||
var event1Serialized = "{\"eventId\":\"id1\"}";
|
var event1Serialized = "{\"eventId\":\"id1\"}";
|
||||||
TestEvent testEvent2 = new TestEvent("id2");
|
var testEvent2 = new TestEvent("id2");
|
||||||
var event2Serialized = "{\"eventId\":\"id2\"}";
|
var event2Serialized = "{\"eventId\":\"id2\"}";
|
||||||
|
|
||||||
when(eventSerializer.serialize(testEvent1)).thenReturn(event1Serialized);
|
when(eventSerializer.serialize(testEvent1)).thenReturn(event1Serialized);
|
||||||
@@ -203,27 +212,31 @@ class Neo4jEventPublicationRepositoryTest {
|
|||||||
assertThat(repository.findIncompletePublications()).hasSize(0);
|
assertThat(repository.findIncompletePublications()).hasSize(0);
|
||||||
|
|
||||||
try (var session = driver.session()) {
|
try (var session = driver.session()) {
|
||||||
|
|
||||||
var records = session.run("MATCH (n) WHERE n.completionDate is not null return n").list();
|
var records = session.run("MATCH (n) WHERE n.completionDate is not null return n").list();
|
||||||
|
|
||||||
assertThat(records.size()).isEqualTo(1);
|
assertThat(records.size()).isEqualTo(1);
|
||||||
assertThat(records.get(0).get("n").asNode().get("eventSerialized").asString()).contains("id2");
|
assertThat(records.get(0).get("n").asNode().get("eventSerialized").asString()).contains("id2");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Value
|
@Value
|
||||||
private static final class TestEvent {
|
static class TestEvent {
|
||||||
String eventId;
|
String eventId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Import({TestApplication.class})
|
@Import({ TestApplication.class })
|
||||||
@Configuration
|
@Configuration
|
||||||
static class Config {
|
static class Config {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public Driver driver() {
|
Driver driver() {
|
||||||
return GraphDatabase.driver(neo4jContainer.getBoltUrl(), AuthTokens.basic("neo4j", neo4jContainer.getAdminPassword()));
|
return GraphDatabase.driver(neo4jContainer.getBoltUrl(),
|
||||||
|
AuthTokens.basic("neo4j", neo4jContainer.getAdminPassword()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public org.neo4j.cypherdsl.core.renderer.Configuration cypherDslConfiguration() {
|
org.neo4j.cypherdsl.core.renderer.Configuration cypherDslConfiguration() {
|
||||||
return org.neo4j.cypherdsl.core.renderer.Configuration.newConfig().withDialect(Dialect.NEO4J_5).build();
|
return org.neo4j.cypherdsl.core.renderer.Configuration.newConfig().withDialect(Dialect.NEO4J_5).build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* 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 org.springframework.modulith.events.neo4j;
|
package org.springframework.modulith.events.neo4j;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.*;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Nested;
|
import org.junit.jupiter.api.Nested;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.neo4j.driver.AuthTokens;
|
import org.neo4j.driver.AuthTokens;
|
||||||
@@ -20,34 +39,28 @@ import org.testcontainers.junit.jupiter.Container;
|
|||||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||||
import org.testcontainers.utility.DockerImageName;
|
import org.testcontainers.utility.DockerImageName;
|
||||||
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Gerrit Meier
|
* @author Gerrit Meier
|
||||||
*/
|
*/
|
||||||
public class Neo4jIndexInitializerTest {
|
class Neo4jIndexInitializerTest {
|
||||||
|
|
||||||
@ImportAutoConfiguration({Neo4jEventPublicationAutoConfiguration.class, TestBase.Config.class})
|
@ImportAutoConfiguration({ Neo4jEventPublicationAutoConfiguration.class, TestBase.Config.class })
|
||||||
@Testcontainers(disabledWithoutDocker = true)
|
@Testcontainers(disabledWithoutDocker = true)
|
||||||
@ContextConfiguration(classes = TestApplication.class)
|
@ContextConfiguration(classes = TestApplication.class)
|
||||||
static class TestBase {
|
static class TestBase {
|
||||||
|
|
||||||
@Container
|
@Container private static Neo4jContainer<?> neo4jContainer = new Neo4jContainer<>(DockerImageName.parse("neo4j:5"))
|
||||||
private static Neo4jContainer<?> neo4jContainer = new Neo4jContainer<>(DockerImageName.parse("neo4j:5"))
|
.withRandomPassword();
|
||||||
.withRandomPassword();
|
|
||||||
|
|
||||||
@MockBean
|
|
||||||
EventSerializer eventSerializer;
|
|
||||||
|
|
||||||
|
@MockBean EventSerializer eventSerializer;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
static class Config {
|
static class Config {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
Driver driver() {
|
Driver driver() {
|
||||||
return GraphDatabase.driver(neo4jContainer.getBoltUrl(), AuthTokens.basic("neo4j", neo4jContainer.getAdminPassword()));
|
return GraphDatabase.driver(neo4jContainer.getBoltUrl(),
|
||||||
|
AuthTokens.basic("neo4j", neo4jContainer.getAdminPassword()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -55,11 +68,9 @@ public class Neo4jIndexInitializerTest {
|
|||||||
@Nested
|
@Nested
|
||||||
@DataNeo4jTest(properties = "spring.modulith.events.neo4j.event-index.enabled=true")
|
@DataNeo4jTest(properties = "spring.modulith.events.neo4j.event-index.enabled=true")
|
||||||
class WithIndexEnabled extends TestBase {
|
class WithIndexEnabled extends TestBase {
|
||||||
@Autowired
|
|
||||||
Neo4jClient neo4jClient;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired Neo4jClient neo4jClient;
|
||||||
Optional<Neo4jIndexInitializer> neo4jIndexInitializer;
|
@Autowired Optional<Neo4jIndexInitializer> neo4jIndexInitializer;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void indexInitializerBeanIsPresent() {
|
void indexInitializerBeanIsPresent() {
|
||||||
@@ -69,19 +80,17 @@ public class Neo4jIndexInitializerTest {
|
|||||||
@Test
|
@Test
|
||||||
void indexWasCreated() {
|
void indexWasCreated() {
|
||||||
assertThat(neo4jClient.query("SHOW INDEX YIELD name")
|
assertThat(neo4jClient.query("SHOW INDEX YIELD name")
|
||||||
.fetchAs(String.class)
|
.fetchAs(String.class)
|
||||||
.all()).contains("eventHashIndex");
|
.all()).contains("eventHashIndex");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
@DataNeo4jTest(properties = "spring.modulith.events.neo4j.event-index.enabled=false")
|
@DataNeo4jTest(properties = "spring.modulith.events.neo4j.event-index.enabled=false")
|
||||||
class WithoutIndexEnabled extends TestBase {
|
class WithoutIndexEnabled extends TestBase {
|
||||||
@Autowired
|
|
||||||
Neo4jClient neo4jClient;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired Neo4jClient neo4jClient;
|
||||||
Optional<Neo4jIndexInitializer> neo4jIndexInitializer;
|
@Autowired Optional<Neo4jIndexInitializer> neo4jIndexInitializer;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void indexInitializerBeanIsNotPresent() {
|
void indexInitializerBeanIsNotPresent() {
|
||||||
@@ -91,9 +100,8 @@ public class Neo4jIndexInitializerTest {
|
|||||||
@Test
|
@Test
|
||||||
void indexWasNotCreated() {
|
void indexWasNotCreated() {
|
||||||
assertThat(neo4jClient.query("SHOW INDEX YIELD name")
|
assertThat(neo4jClient.query("SHOW INDEX YIELD name")
|
||||||
.fetchAs(String.class)
|
.fetchAs(String.class)
|
||||||
.all()).doesNotContain("eventHashIndex");
|
.all()).doesNotContain("eventHashIndex");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* 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 org.springframework.modulith.testapp;
|
package org.springframework.modulith.testapp;
|
||||||
|
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
@@ -6,5 +21,4 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
|
|||||||
* @author Gerrit Meier
|
* @author Gerrit Meier
|
||||||
*/
|
*/
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
public class TestApplication {
|
public class TestApplication {}
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,56 +1,58 @@
|
|||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>org.springframework.modulith</groupId>
|
<groupId>org.springframework.modulith</groupId>
|
||||||
<artifactId>spring-modulith-examples</artifactId>
|
<artifactId>spring-modulith-examples</artifactId>
|
||||||
<version>1.1.0-SNAPSHOT</version>
|
<version>1.1.0-SNAPSHOT</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>spring-modulith-example-epr-neo4j</artifactId>
|
<artifactId>spring-modulith-example-epr-neo4j</artifactId>
|
||||||
<name>Spring Modulith - Examples - EPR Neo4j Example</name>
|
<name>Spring Modulith - Examples - EPR Neo4j Example</name>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.modulith</groupId>
|
<groupId>org.springframework.modulith</groupId>
|
||||||
<artifactId>spring-modulith-starter-neo4j</artifactId>
|
<artifactId>spring-modulith-starter-neo4j</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- jMolecules -->
|
<!-- jMolecules -->
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jmolecules</groupId>
|
<groupId>org.jmolecules</groupId>
|
||||||
<artifactId>jmolecules-events</artifactId>
|
<artifactId>jmolecules-events</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- Persistence -->
|
<!-- Persistence -->
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-data-neo4j</artifactId>
|
<artifactId>spring-boot-starter-data-neo4j</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.testcontainers</groupId>
|
<groupId>org.testcontainers</groupId>
|
||||||
<artifactId>junit-jupiter</artifactId>
|
<artifactId>junit-jupiter</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.testcontainers</groupId>
|
<groupId>org.testcontainers</groupId>
|
||||||
<artifactId>neo4j</artifactId>
|
<artifactId>neo4j</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-testcontainers</artifactId>
|
<artifactId>spring-boot-testcontainers</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -17,6 +17,9 @@ package example;
|
|||||||
|
|
||||||
import example.inventory.InventoryUpdated;
|
import example.inventory.InventoryUpdated;
|
||||||
import example.order.OrderManagement;
|
import example.order.OrderManagement;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.neo4j.cypherdsl.core.renderer.Configuration;
|
import org.neo4j.cypherdsl.core.renderer.Configuration;
|
||||||
import org.neo4j.cypherdsl.core.renderer.Dialect;
|
import org.neo4j.cypherdsl.core.renderer.Dialect;
|
||||||
@@ -34,8 +37,6 @@ import org.springframework.modulith.test.Scenario;
|
|||||||
import org.testcontainers.containers.Neo4jContainer;
|
import org.testcontainers.containers.Neo4jContainer;
|
||||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Oliver Drotbohm
|
* @author Oliver Drotbohm
|
||||||
* @author Gerrit Meier
|
* @author Gerrit Meier
|
||||||
@@ -46,7 +47,7 @@ import java.util.Collection;
|
|||||||
class ApplicationIntegrationTests {
|
class ApplicationIntegrationTests {
|
||||||
|
|
||||||
@TestConfiguration
|
@TestConfiguration
|
||||||
static class MongoDbInfrastructureConfiguration {
|
static class InfrastructureConfiguration {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ServiceConnection
|
@ServiceConnection
|
||||||
@@ -55,12 +56,12 @@ class ApplicationIntegrationTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public Driver driver(Neo4jContainer<?> container) {
|
Driver driver(Neo4jContainer<?> container) {
|
||||||
return GraphDatabase.driver(container.getBoltUrl(), AuthTokens.basic("neo4j", container.getAdminPassword()));
|
return GraphDatabase.driver(container.getBoltUrl(), AuthTokens.basic("neo4j", container.getAdminPassword()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public Configuration cypherDslConfiguration() {
|
Configuration cypherDslConfiguration() {
|
||||||
return Configuration.newConfig().withDialect(Dialect.NEO4J_5).build();
|
return Configuration.newConfig().withDialect(Dialect.NEO4J_5).build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,54 +1,55 @@
|
|||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>org.springframework.modulith</groupId>
|
<groupId>org.springframework.modulith</groupId>
|
||||||
<artifactId>spring-modulith-starters</artifactId>
|
<artifactId>spring-modulith-starters</artifactId>
|
||||||
<version>1.1.0-SNAPSHOT</version>
|
<version>1.1.0-SNAPSHOT</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>spring-modulith-starter-neo4j</artifactId>
|
<artifactId>spring-modulith-starter-neo4j</artifactId>
|
||||||
<name>Spring Modulith - Starters - Starter Neo4j</name>
|
<name>Spring Modulith - Starters - Starter Neo4j</name>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<module.name>org.springframework.modulith.starter.neo4j</module.name>
|
<module.name>org.springframework.modulith.starter.neo4j</module.name>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.modulith</groupId>
|
<groupId>org.springframework.modulith</groupId>
|
||||||
<artifactId>spring-modulith-starter-core</artifactId>
|
<artifactId>spring-modulith-starter-core</artifactId>
|
||||||
<version>1.1.0-SNAPSHOT</version>
|
<version>1.1.0-SNAPSHOT</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- Events -->
|
<!-- Events -->
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.modulith</groupId>
|
|
||||||
<artifactId>spring-modulith-events-api</artifactId>
|
|
||||||
<version>1.1.0-SNAPSHOT</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.modulith</groupId>
|
|
||||||
<artifactId>spring-modulith-events-core</artifactId>
|
|
||||||
<version>1.1.0-SNAPSHOT</version>
|
|
||||||
<scope>runtime</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.modulith</groupId>
|
|
||||||
<artifactId>spring-modulith-events-jackson</artifactId>
|
|
||||||
<version>1.1.0-SNAPSHOT</version>
|
|
||||||
<scope>runtime</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.modulith</groupId>
|
|
||||||
<artifactId>spring-modulith-events-neo4j</artifactId>
|
|
||||||
<version>1.1.0-SNAPSHOT</version>
|
|
||||||
<scope>runtime</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
</dependencies>
|
<dependency>
|
||||||
|
<groupId>org.springframework.modulith</groupId>
|
||||||
|
<artifactId>spring-modulith-events-api</artifactId>
|
||||||
|
<version>1.1.0-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.modulith</groupId>
|
||||||
|
<artifactId>spring-modulith-events-core</artifactId>
|
||||||
|
<version>1.1.0-SNAPSHOT</version>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.modulith</groupId>
|
||||||
|
<artifactId>spring-modulith-events-jackson</artifactId>
|
||||||
|
<version>1.1.0-SNAPSHOT</version>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.modulith</groupId>
|
||||||
|
<artifactId>spring-modulith-events-neo4j</artifactId>
|
||||||
|
<version>1.1.0-SNAPSHOT</version>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
Reference in New Issue
Block a user