create EventStreamInPostgresql
This commit is contained in:
@@ -3,7 +3,7 @@ package eventDemo.libs.event
|
||||
import io.github.oshai.kotlinlogging.withLoggingContext
|
||||
|
||||
interface EventStore<E : Event<ID>, ID : AggregateId> {
|
||||
fun getStream(aggregateId: ID): EventStream<E>
|
||||
fun getStream(aggregateId: ID): EventStream<E, ID>
|
||||
|
||||
fun publish(event: E) =
|
||||
withLoggingContext("event" to event.toString()) {
|
||||
|
||||
@@ -4,8 +4,8 @@ import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.concurrent.ConcurrentMap
|
||||
|
||||
class EventStoreInMemory<E : Event<ID>, ID : AggregateId> : EventStore<E, ID> {
|
||||
private val streams: ConcurrentMap<ID, EventStream<E>> = ConcurrentHashMap()
|
||||
private val streams: ConcurrentMap<ID, EventStream<E, ID>> = ConcurrentHashMap()
|
||||
|
||||
override fun getStream(aggregateId: ID): EventStream<E> =
|
||||
override fun getStream(aggregateId: ID): EventStream<E, ID> =
|
||||
streams.computeIfAbsent(aggregateId) { EventStreamInMemory(aggregateId) }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package eventDemo.libs.event
|
||||
|
||||
import javax.sql.DataSource
|
||||
|
||||
class EventStoreInPostgresql<E : Event<ID>, ID : AggregateId>(
|
||||
private val dataSource: DataSource,
|
||||
private val objectToString: (E) -> String,
|
||||
private val stringToObject: (String) -> E,
|
||||
) : EventStore<E, ID> {
|
||||
override fun getStream(aggregateId: ID): EventStream<E, ID> =
|
||||
EventStreamInPostgresql(aggregateId, dataSource, objectToString, stringToObject)
|
||||
}
|
||||
@@ -6,7 +6,9 @@ import io.github.oshai.kotlinlogging.withLoggingContext
|
||||
/**
|
||||
* Interface representing an event stream for publishing and reading domain events
|
||||
*/
|
||||
interface EventStream<E : Event<*>> {
|
||||
interface EventStream<E : Event<ID>, ID : AggregateId> {
|
||||
val aggregateId: ID
|
||||
|
||||
/** Publishes a single event to the event stream */
|
||||
fun publish(event: E)
|
||||
|
||||
|
||||
@@ -10,8 +10,8 @@ import java.util.concurrent.ConcurrentLinkedQueue
|
||||
* All methods are implemented.
|
||||
*/
|
||||
class EventStreamInMemory<E : Event<ID>, ID : AggregateId>(
|
||||
val aggregateId: ID,
|
||||
) : EventStream<E> {
|
||||
override val aggregateId: ID,
|
||||
) : EventStream<E, ID> {
|
||||
private val logger = KotlinLogging.logger {}
|
||||
private val events: Queue<E> = ConcurrentLinkedQueue()
|
||||
|
||||
|
||||
105
src/main/kotlin/eventDemo/libs/event/EventStreamInPostgresql.kt
Normal file
105
src/main/kotlin/eventDemo/libs/event/EventStreamInPostgresql.kt
Normal file
@@ -0,0 +1,105 @@
|
||||
package eventDemo.libs.event
|
||||
|
||||
import io.github.oshai.kotlinlogging.KotlinLogging
|
||||
import org.postgresql.util.PGobject
|
||||
import javax.sql.DataSource
|
||||
|
||||
/**
|
||||
* An In-Memory implementation of an event stream.
|
||||
*
|
||||
* All methods are implemented.
|
||||
*/
|
||||
class EventStreamInPostgresql<E : Event<ID>, ID : AggregateId>(
|
||||
override val aggregateId: ID,
|
||||
private val dataSource: DataSource,
|
||||
private val objectToString: (E) -> String,
|
||||
private val stringToObject: (String) -> E,
|
||||
) : EventStream<E, ID> {
|
||||
private val logger = KotlinLogging.logger {}
|
||||
|
||||
override fun publish(event: E) {
|
||||
if (event.aggregateId != aggregateId) {
|
||||
throw EventStreamPublishException(
|
||||
"You cannot publish this event in this stream because it has a different aggregateId!",
|
||||
)
|
||||
}
|
||||
dataSource.connection.use { connection ->
|
||||
connection
|
||||
.prepareStatement(
|
||||
"""
|
||||
insert into event_stream(id, aggregate_id, version, data)
|
||||
values (?, ?, ?, ?)
|
||||
""".trimIndent(),
|
||||
).use {
|
||||
it.setObject(1, event.eventId)
|
||||
it.setObject(2, event.aggregateId.id)
|
||||
it.setInt(3, event.version)
|
||||
it.setObject(4, PGJsonb(objectToString(event)))
|
||||
it.executeUpdate()
|
||||
}
|
||||
}
|
||||
logger.info { "Event published" }
|
||||
}
|
||||
|
||||
override fun readAll(): Set<E> =
|
||||
dataSource.connection.use { connection ->
|
||||
connection
|
||||
.prepareStatement(
|
||||
"""
|
||||
select data
|
||||
from event_stream
|
||||
where aggregate_id = ?
|
||||
order by version asc
|
||||
""".trimIndent(),
|
||||
).use {
|
||||
it.setObject(1, aggregateId.id)
|
||||
it.executeQuery().use { resultSet ->
|
||||
buildSet {
|
||||
while (resultSet.next()) {
|
||||
resultSet
|
||||
.getString("data")
|
||||
.let(stringToObject)
|
||||
.let { add(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun readVersionBetween(version: IntRange): Set<E> =
|
||||
dataSource.connection.use { connection ->
|
||||
connection
|
||||
.prepareStatement(
|
||||
"""
|
||||
select data
|
||||
from event_stream
|
||||
where version between ? and ?
|
||||
and aggregate_id = ?
|
||||
order by version asc
|
||||
""".trimIndent(),
|
||||
).use { stmt ->
|
||||
stmt.setInt(1, version.first)
|
||||
stmt.setInt(2, version.last)
|
||||
stmt.setObject(3, aggregateId.id)
|
||||
stmt.executeQuery().use { resultSet ->
|
||||
buildSet {
|
||||
while (resultSet.next()) {
|
||||
resultSet
|
||||
.getString("data")
|
||||
.let(stringToObject)
|
||||
.let { add(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class PGJsonb(
|
||||
value: String,
|
||||
) : PGobject() {
|
||||
init {
|
||||
this.value = value
|
||||
this.type = "jsonb"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user