module Eventful.Aggregate
( Aggregate (..)
, allAggregateStates
, commandStoredAggregate
, serializedAggregate
) where
import Data.Foldable (foldl')
import Data.List (scanl')
import Eventful.Projection
import Eventful.Serializer
import Eventful.Store.Class
import Eventful.UUID
data Aggregate state event command =
Aggregate
{ aggregateCommandHandler :: state -> command -> [event]
, aggregateProjection :: Projection state event
}
allAggregateStates
:: Aggregate state event command
-> [command]
-> [state]
allAggregateStates (Aggregate commandHandler (Projection seed eventHandler)) events =
scanl' go seed events
where
go state command = foldl' eventHandler state $ commandHandler state command
commandStoredAggregate
:: (Monad m)
=> EventStore serialized m
-> Aggregate state serialized command
-> UUID
-> command
-> m [serialized]
commandStoredAggregate store (Aggregate handler proj) uuid command = do
StreamProjection{..} <- getLatestProjection store (streamProjection proj uuid)
let events = handler streamProjectionState command
mError <- storeEvents store (ExactVersion streamProjectionVersion) uuid events
case mError of
(Just err) -> error $ "TODO: Create aggregate restart logic. " ++ show err
Nothing -> return events
serializedAggregate
:: Aggregate state event command
-> Serializer event serializedEvent
-> Serializer command serializedCommand
-> Aggregate state serializedEvent serializedCommand
serializedAggregate (Aggregate commandHandler projection) eventSerializer commandSerializer =
Aggregate serializedHandler serializedProjection'
where
serializedProjection' = serializedProjection projection eventSerializer
serializedHandler state = map (serialize eventSerializer) . maybe [] (commandHandler state) . deserialize commandSerializer