All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.cultureamp.eventsourcing.CommandGateway.kt Maven / Gradle / Ivy

package com.cultureamp.eventsourcing

interface CommandGateway {
    companion object {
        operator fun  invoke(eventStore: EventStore, vararg routes: Route<*, *, M>) = EventStoreCommandGateway(eventStore, *routes)
    }
    fun dispatch(command: Command, metadata: M, retries: Int = 5): Either
}

class EventStoreCommandGateway(private val eventStore: EventStore, private vararg val routes: Route<*, *, M>) : CommandGateway {
    override tailrec fun dispatch(command: Command, metadata: M, retries: Int): Either {
        val result = createOrUpdate(command, metadata)
        return if (result is Left && result.error is RetriableError && retries > 0) {
            Thread.sleep(500L)
            dispatch(command, metadata, retries - 1)
        } else {
            result
        }
    }

    private fun createOrUpdate(command: Command, metadata: M): Either {
        val constructor = constructorFor(command) ?: return Left(NoConstructorForCommand)
        val events = eventStore.eventsFor(command.aggregateId)
        return if (events.isEmpty()) when (command) {
            is CreationCommand -> constructor.create(command, metadata, eventStore).map { Created }
            else -> Left(AggregateNotFound)
        } else when (command) {
            is UpdateCommand -> constructor.update(command, metadata, events, eventStore).map { Updated }
            else -> Left(AggregateAlreadyExists)
        }
    }

    @Suppress("UNCHECKED_CAST")
    private fun constructorFor(command: Command): AggregateConstructor>? {
        val route = routes.find { it.creationCommandClass.isInstance(command) || it.updateCommandClass.isInstance(command) }
        return route?.aggregateConstructor as AggregateConstructor>?
    }
}

sealed class SuccessStatus
object Created : SuccessStatus()
object Updated : SuccessStatus()

object NoConstructorForCommand : CommandError
object AggregateAlreadyExists : CommandError
object AggregateNotFound : CommandError




© 2015 - 2025 Weber Informatics LLC | Privacy Policy