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

commonMain.dk.cachet.carp.common.domain.AggregateRoot.kt Maven / Gradle / Ivy

Go to download

Helper classes and base types relied upon by all subsystems. This library does not contain any domain logic.

The newest version!
package dk.cachet.carp.common.domain

import dk.cachet.carp.common.application.UUID
import kotlinx.datetime.Instant


/**
 * A root object with a unique [id] which ensures the integrity of underlying state as a whole,
 * tracks events raised from within, and for which an immutable 'snapshot' at any given moment in time can be obtained.
 */
abstract class AggregateRoot, TEvent : DomainEvent>(
    val id: UUID,
    /**
     * The date when this object was created.
     */
    val createdOn: Instant
)
{
    /**
     * If the aggregate root was loaded from a snapshot, its version; null otherwise.
     * On repository writes, this value should be used to verify whether the expected version is edited.
     */
    var fromSnapshotVersion: Int? = null
        private set

    /**
     * Specify that this aggregate root was loaded from [snapshot], which sets [fromSnapshotVersion] accordingly.
     */
    fun wasLoadedFromSnapshot( snapshot: TSnapshot )
    {
        check( fromSnapshotVersion == null )
            { "An aggregate root should only be loaded from a snapshot once." }
        check( events.size == 0 )
            { "The snapshot an aggregate root was loaded from should be set before executing any operations on it." }

        fromSnapshotVersion = snapshot.version
    }

    private val events: MutableList = mutableListOf()

    /**
     * Add an event triggered by this aggregate root to a queue.
     */
    protected fun event( event: TEvent ) = events.add( event )

    /**
     * In case the instance equals [value], [createEvent] and add it to the event queue of this aggregate root.
     */
    protected fun  TPredicate.eventIf( value: TPredicate, createEvent: () -> TEvent ): TPredicate =
        this.also { if ( this == value ) event( createEvent() ) }

    /**
     * Returns all tracked events on this aggregate root in the order they were triggered and clears the queue.
     */
    fun consumeEvents(): List
    {
        val toProcess = events.toList()
        events.clear()
        return toProcess
    }

    /**
     * Get an immutable snapshot of the current the state of this aggregate.
     */
    fun getSnapshot(): TSnapshot
    {
        val curSnapshotVersion = fromSnapshotVersion
        val newSnapshotVersion = if ( curSnapshotVersion == null ) 0 else curSnapshotVersion + events.size
        return getSnapshot( newSnapshotVersion )
    }

    /**
     * Get an immutable snapshot of the current state of this aggregate using the specified snapshot [version].
     */
    protected abstract fun getSnapshot( version: Int ): TSnapshot
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy