module Eventful.Projection
( Projection (..)
, latestProjection
, allProjections
, getLatestProjection
, getLatestGlobalProjection
, serializedProjection
)
where
import Data.Foldable (foldl')
import Data.List (scanl')
import Data.Maybe (fromMaybe)
import Eventful.Serializer
import Eventful.Store.Class
import Eventful.UUID
data Projection state event
= Projection
{ projectionSeed :: state
, projectionEventHandler :: state -> event -> state
}
latestProjection :: (Foldable t) => Projection state event -> t event -> state
latestProjection (Projection seed handler) = foldl' handler seed
allProjections :: Projection state event -> [event] -> [state]
allProjections (Projection seed handler) = scanl' handler seed
getLatestProjection
:: (Monad m)
=> EventStore serialized m
-> Projection proj serialized
-> UUID
-> m (proj, EventVersion)
getLatestProjection store proj uuid = do
events <- getEvents store uuid Nothing
let
latestVersion = maxEventVersion events
latestProj = latestProjection proj $ storedEventEvent <$> events
return (latestProj, latestVersion)
where
maxEventVersion [] = 1
maxEventVersion es = maximum $ storedEventVersion <$> es
getLatestGlobalProjection
:: (Monad m)
=> GloballyOrderedEventStore serialized m
-> Projection proj (ProjectionEvent serialized)
-> Maybe (proj, SequenceNumber)
-> m (proj, SequenceNumber)
getLatestGlobalProjection store proj mCurrentState = do
let
currentState = fromMaybe (projectionSeed proj) $ fst <$> mCurrentState
startingSequenceNumber = maybe 0 (+1) $ snd <$> mCurrentState
events <- getSequencedEvents store startingSequenceNumber
let
projectionEvents = globallyOrderedEventToProjectionEvent <$> events
latestState = foldl' (projectionEventHandler proj) currentState projectionEvents
latestSeq =
case events of
[] -> startingSequenceNumber
_ -> globallyOrderedEventSequenceNumber $ last events
return (latestState, latestSeq)
serializedProjection
:: Projection state event
-> Serializer event serialized
-> Projection state serialized
serializedProjection (Projection seed eventHandler) Serializer{..} =
Projection seed serializedHandler
where
serializedHandler state = maybe state (eventHandler state) . deserialize