Skip to content

Commit

Permalink
#202 Introducing snapshotting event sourced aggregate - draft 2
Browse files Browse the repository at this point in the history
  • Loading branch information
idugalic committed Jun 10, 2023
1 parent b7b7323 commit 7fb2444
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 86 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ fun <C, S, E, I> I.handle(command: C): Flow<E> where I : StateComputation<C, S,
}

/**
* Extension function - Handles the command message of type [C] to the locking state stored aggregate, optimistically
* Extension function - Handles the command message of type [C] to the snapshotting, locking event sourced aggregate, optimistically
*
* @param command Command message of type [C]
* @return State of type [Pair]<[S], [V]>, in which [V] is the type of the Version (optimistic locking)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,22 +73,6 @@ interface EventOrchestratingComputation<C, S, E> : ISaga<E, C>, IDecider<C, S, E
*/
interface EventSourcingAggregate<C, S, E> : EventComputation<C, S, E>, EventRepository<C, E>

/**
* Event sourcing snapshotting aggregate is using/delegating a `decider` of type [IDecider]<[C], [S], [E]>/ [EventComputation]<[C], [S], [E]> to handle commands and produce events.
* In order to handle the command, aggregate needs to fetch the current state (represented as a list of events) via [EventSnapshottingRepository.fetchEvents] function, and then delegate the command to the `decider` which can produce new event(s) as a result.
* Produced events are then stored via [EventSnapshottingRepository.save] suspending function.
*
* [EventSourcingAggregate] extends [EventComputation] and [EventSnapshottingRepository] interfaces,
* clearly communicating that it is composed out of these two behaviours.
*
* @param C Commands of type [C] that this aggregate can handle
* @param S Aggregate state of type [S]
* @param E Events of type [E] that this aggregate can publish
*
* @author Иван Дугалић / Ivan Dugalic / @idugalic
*/
interface EventSourcingSnapshottingAggregate<C, S, E> : EventComputation<C, S, E>, EventSnapshottingRepository<C, S, E>

/**
* Locking Event sourcing aggregate is using/delegating a `decider` of type [IDecider]<[C], [S], [E]>/ [EventComputation]<[C], [S], [E]> to handle commands and produce events.
* In order to handle the command, aggregate needs to fetch the current state (represented as a list of events) via [EventLockingRepository.fetchEvents] function, and then delegate the command to the `decider` which can produce new event(s) as a result.
Expand All @@ -111,29 +95,6 @@ interface EventSourcingSnapshottingAggregate<C, S, E> : EventComputation<C, S, E
*/
interface EventSourcingLockingAggregate<C, S, E, V> : EventComputation<C, S, E>, EventLockingRepository<C, E, V>

/**
* Locking Event sourcing aggregate is using/delegating a `decider` of type [IDecider]<[C], [S], [E]>/ [EventComputation]<[C], [S], [E]> to handle commands and produce events.
* In order to handle the command, aggregate needs to fetch the current state (represented as a list of events) via [EventSnapshottingLockingRepository.fetchEvents] function, and then delegate the command to the `decider` which can produce new event(s) as a result.
* Produced events are then stored via [EventSnapshottingLockingRepository.save] suspending function.
*
* Locking Event sourcing aggregate enables `optimistic locking` mechanism more explicitly.
* If you fetch events from a storage, the application records the `version` number of that event stream.
* You can append new events, but only if the `version` number in the storage has not changed.
* If there is a `version` mismatch, it means that someone else has added the event(s) before you did.
*
* [EventSourcingLockingAggregate] extends [EventComputation] and [EventSnapshottingLockingRepository] interfaces,
* clearly communicating that it is composed out of these two behaviours.
*
* @param C Commands of type [C] that this aggregate can handle
* @param S Aggregate state of type [S]
* @param E Events of type [E] that this aggregate can publish
* @param V Version
*
* @author Иван Дугалић / Ivan Dugalic / @idugalic
*/
interface EventSourcingSnapshottingLockingAggregate<C, S, E, V> : EventComputation<C, S, E>,
EventSnapshottingLockingRepository<C, S, E, V>

/**
* Orchestrating Event sourcing aggregate is using/delegating a `decider` of type [IDecider]<[C], [S], [E]> to handle commands and produce events.
* In order to handle the command, aggregate needs to fetch the current state (represented as a list of events) via [EventRepository.fetchEvents] function, and then delegate the command to the `decider` which can produce new event(s) as a result.
Expand Down Expand Up @@ -226,28 +187,6 @@ fun <C, S, E> EventSourcingAggregate(
EventRepository<C, E> by eventRepository,
IDecider<C, S, E> by decider {}

/**
* Event Sourced Snapshotting aggregate constructor-like function.
*
* The Delegation pattern has proven to be a good alternative to implementation inheritance, and Kotlin supports it natively requiring zero boilerplate code.
*
* @param C Commands of type [C] that this aggregate can handle
* @param S Aggregate state of type [S]
* @param E Events of type [E] that are used internally to build/fold new state
* @param decider A decider component of type [IDecider]<[C], [S], [E]>
* @param eventRepository An aggregate event repository of type [EventSnapshottingRepository]<[C], [S], [E]>
* @return An object/instance of type [EventSourcingSnapshottingAggregate]<[C], [S], [E]>
*
* @author Иван Дугалић / Ivan Dugalic / @idugalic
*/
fun <C, S, E> EventSourcingSnapshottingAggregate(
decider: IDecider<C, S, E>,
eventRepository: EventSnapshottingRepository<C, S, E>
): EventSourcingAggregate<C, S, E> =
object : EventSourcingAggregate<C, S, E>,
EventSnapshottingRepository<C, S, E> by eventRepository,
IDecider<C, S, E> by decider {}

/**
* Event Sourced Locking aggregate factory function.
*
Expand All @@ -269,10 +208,12 @@ fun <C, S, E> EventSourcingSnapshottingAggregate(
)
fun <C, S, E, V> eventSourcingLockingAggregate(
decider: IDecider<C, S, E>,
eventRepository: EventLockingRepository<C, E, V>
eventRepository: EventLockingRepository<C, E, V>,
stateRepository: StateRepository<C, S>
): EventSourcingLockingAggregate<C, S, E, V> =
object : EventSourcingLockingAggregate<C, S, E, V>,
EventLockingRepository<C, E, V> by eventRepository,
StateRepository<C, S> by stateRepository,
IDecider<C, S, E> by decider {}

/**
Expand All @@ -298,29 +239,6 @@ fun <C, S, E, V> EventSourcingLockingAggregate(
EventLockingRepository<C, E, V> by eventRepository,
IDecider<C, S, E> by decider {}

/**
* Event Sourced Snapshotting and Locking aggregate constructor-like function.
*
* The Delegation pattern has proven to be a good alternative to implementation inheritance, and Kotlin supports it natively requiring zero boilerplate code.
*
* @param C Commands of type [C] that this aggregate can handle
* @param S Aggregate state of type [S]
* @param E Events of type [E] that are used internally to build/fold new state
* @param V Version
* @param decider A decider component of type [IDecider]<[C], [S], [E]>
* @param eventRepository An aggregate event repository of type [EventSnapshottingLockingRepository]<[C], [S], [E], [V]>
* @return An object/instance of type [EventSourcingSnapshottingLockingAggregate]<[C], [S], [E], [V]>
*
* @author Иван Дугалић / Ivan Dugalic / @idugalic
*/
fun <C, S, E, V> EventSourcingSnapshottingLockingAggregate(
decider: IDecider<C, S, E>,
eventRepository: EventSnapshottingLockingRepository<C, S, E, V>
): EventSourcingSnapshottingLockingAggregate<C, S, E, V> =
object : EventSourcingSnapshottingLockingAggregate<C, S, E, V>,
EventSnapshottingLockingRepository<C, S, E, V> by eventRepository,
IDecider<C, S, E> by decider {}

/**
* Event Sourced Orchestrating aggregate factory function.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/*
* Copyright (c) 2023 Fraktalio D.O.O. All rights reserved.
*
* 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
*
* http://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.fraktalio.fmodel.application

import com.fraktalio.fmodel.domain.IDecider


/**
* Event sourced, snapshotting aggregate is using/delegating a `decider` of type [IDecider]<[C], [S], [E]>/ [EventComputation]<[C], [S], [E]> to handle commands and produce events.
* In order to handle the command, aggregate needs to fetch the current state (represented as a list of events) via [EventSnapshottingRepository.fetchEvents] function, and then delegate the command to the `decider` which can produce new event(s) as a result.
* Produced events are then stored via [EventSnapshottingRepository.save] suspending function.
*
* Additionally, Event sourcing aggregate enables `snapshotting` mechanism by using [StateComputation] and [StateRepository] interfaces to store and fetch the current state of the aggregate from time to time, removing the need to always fetch the full list of events.
*
* [EventSourcingSnapshottingAggregate] extends [EventComputation], [StateComputation], [StateRepository] and [EventSnapshottingRepository] interfaces,
* clearly communicating that it is composed out of these behaviours.
*
* @param C Commands of type [C] that this aggregate can handle
* @param S Aggregate state of type [S]
* @param E Events of type [E] that this aggregate can publish
*
* @author Иван Дугалић / Ivan Dugalic / @idugalic
*/
interface EventSourcingSnapshottingAggregate<C, S, E> :
EventComputation<C, S, E>,
StateComputation<C, S, E>,
EventSnapshottingRepository<C, S, E>,
StateRepository<C, S>

/**
* Event sourced, snapshotting, locking aggregate is using/delegating a `decider` of type [IDecider]<[C], [S], [E]>/ [EventComputation]<[C], [S], [E]> to handle commands and produce events.
* In order to handle the command, aggregate needs to fetch the current state (represented as a list of events) via [EventSnapshottingLockingRepository.fetchEvents] function, and then delegate the command to the `decider` which can produce new event(s) as a result.
* Produced events are then stored via [EventSnapshottingLockingRepository.save] suspending function.
*
* Additionally, Event sourcing aggregate enables `snapshotting` mechanism by using [StateComputation] and [StateRepository] interfaces to store and fetch the current state of the aggregate from time to time, removing the need to always fetch the full list of events.
*
* Locking Event sourcing aggregate enables `optimistic locking` mechanism more explicitly.
* If you fetch events from a storage, the application records the `version` number of that event stream.
* You can append new events, but only if the `version` number in the storage has not changed.
* If there is a `version` mismatch, it means that someone else has added the event(s) before you did.
*
* [EventSourcingSnapshottingLockingAggregate] extends [EventComputation], [StateComputation], [StateLockingRepository] and [EventSnapshottingLockingRepository] interfaces,
* clearly communicating that it is composed out of these behaviours.
*
* @param C Commands of type [C] that this aggregate can handle
* @param S Aggregate state of type [S]
* @param E Events of type [E] that this aggregate can publish
* @param V Version
*
* @author Иван Дугалић / Ivan Dugalic / @idugalic
*/
interface EventSourcingSnapshottingLockingAggregate<C, S, E, V> :
EventComputation<C, S, E>,
StateComputation<C, S, E>,
EventSnapshottingLockingRepository<C, S, E, V>,
StateLockingRepository<C, S, V>

/**
* Event Sourced Snapshotting aggregate constructor-like function.
*
* The Delegation pattern has proven to be a good alternative to implementation inheritance, and Kotlin supports it natively requiring zero boilerplate code.
*
* @param C Commands of type [C] that this aggregate can handle
* @param S Aggregate state of type [S]
* @param E Events of type [E] that are used internally to build/fold new state
* @param decider A decider component of type [IDecider]<[C], [S], [E]>
* @param eventRepository An aggregate event repository of type [EventSnapshottingRepository]<[C], [S], [E]>
* @return An object/instance of type [EventSourcingSnapshottingAggregate]<[C], [S], [E]>
*
* @author Иван Дугалић / Ivan Dugalic / @idugalic
*/
fun <C, S, E> EventSourcingSnapshottingAggregate(
decider: IDecider<C, S, E>,
eventRepository: EventSnapshottingRepository<C, S, E>,
stateRepository: StateRepository<C, S>
): EventSourcingAggregate<C, S, E> =
object : EventSourcingAggregate<C, S, E>,
EventSnapshottingRepository<C, S, E> by eventRepository,
StateRepository<C, S> by stateRepository,
IDecider<C, S, E> by decider {}


/**
* Event Sourced Snapshotting and Locking aggregate constructor-like function.
*
* The Delegation pattern has proven to be a good alternative to implementation inheritance, and Kotlin supports it natively requiring zero boilerplate code.
*
* @param C Commands of type [C] that this aggregate can handle
* @param S Aggregate state of type [S]
* @param E Events of type [E] that are used internally to build/fold new state
* @param V Version
* @param decider A decider component of type [IDecider]<[C], [S], [E]>
* @param eventRepository An aggregate event repository of type [EventSnapshottingLockingRepository]<[C], [S], [E], [V]>
* @return An object/instance of type [EventSourcingSnapshottingLockingAggregate]<[C], [S], [E], [V]>
*
* @author Иван Дугалић / Ivan Dugalic / @idugalic
*/
fun <C, S, E, V> EventSourcingSnapshottingLockingAggregate(
decider: IDecider<C, S, E>,
eventRepository: EventSnapshottingLockingRepository<C, S, E, V>,
stateRepository: StateLockingRepository<C, S, V>
): EventSourcingSnapshottingLockingAggregate<C, S, E, V> =
object : EventSourcingSnapshottingLockingAggregate<C, S, E, V>,
EventSnapshottingLockingRepository<C, S, E, V> by eventRepository,
StateLockingRepository<C, S, V> by stateRepository,
IDecider<C, S, E> by decider {}

0 comments on commit 7fb2444

Please sign in to comment.