module Eventful.Store.Class
(
EventStoreReader (..)
, EventStoreWriter (..)
, VersionedEventStoreReader
, GlobalEventStoreReader
, StreamEvent (..)
, VersionedStreamEvent
, GlobalStreamEvent
, ExpectedVersion (..)
, EventWriteError (..)
, runEventStoreReaderUsing
, runEventStoreWriterUsing
, module Eventful.Store.Queries
, serializedEventStoreReader
, serializedVersionedEventStoreReader
, serializedGlobalEventStoreReader
, serializedEventStoreWriter
, EventVersion (..)
, SequenceNumber (..)
, transactionalExpectedWriteHelper
) where
import Data.Aeson
import Data.Functor.Contravariant
import Data.Maybe (mapMaybe)
import Web.HttpApiData
import Web.PathPieces
import Eventful.Serializer
import Eventful.Store.Queries
import Eventful.UUID
newtype EventStoreReader key position m event = EventStoreReader { getEvents :: QueryRange key position -> m [event] }
instance (Functor m) => Functor (EventStoreReader key position m) where
fmap f (EventStoreReader reader) = EventStoreReader $ fmap (fmap f) <$> reader
type VersionedEventStoreReader m event = EventStoreReader UUID EventVersion m (VersionedStreamEvent event)
type GlobalEventStoreReader m event = EventStoreReader () SequenceNumber m (GlobalStreamEvent event)
newtype EventStoreWriter m event = EventStoreWriter { storeEvents :: ExpectedVersion -> UUID -> [event] -> m (Maybe EventWriteError) }
instance Contravariant (EventStoreWriter m) where
contramap f (EventStoreWriter writer) = EventStoreWriter $ \vers uuid -> writer vers uuid . fmap f
data StreamEvent key position event
= StreamEvent
{ streamEventKey :: !key
, streamEventPosition :: !position
, streamEventEvent :: !event
} deriving (Show, Eq, Functor, Foldable, Traversable)
type VersionedStreamEvent event = StreamEvent UUID EventVersion event
type GlobalStreamEvent event = StreamEvent () SequenceNumber (VersionedStreamEvent event)
data ExpectedVersion
= AnyVersion
| NoStream
| StreamExists
| ExactVersion EventVersion
deriving (Show, Eq)
data EventWriteError
= EventStreamNotAtExpectedVersion EventVersion
deriving (Show, Eq)
transactionalExpectedWriteHelper
:: (Monad m)
=> (UUID -> m EventVersion)
-> (UUID -> [event] -> m ())
-> ExpectedVersion -> UUID -> [event] -> m (Maybe EventWriteError)
transactionalExpectedWriteHelper getLatestVersion' storeEvents' expected =
go expected getLatestVersion' storeEvents'
where
go AnyVersion = transactionalExpectedWriteHelper' Nothing
go NoStream = transactionalExpectedWriteHelper' (Just $ (==) (1))
go StreamExists = transactionalExpectedWriteHelper' (Just (> (1)))
go (ExactVersion vers) = transactionalExpectedWriteHelper' (Just $ (==) vers)
transactionalExpectedWriteHelper'
:: (Monad m)
=> Maybe (EventVersion -> Bool)
-> (UUID -> m EventVersion)
-> (UUID -> [event] -> m ())
-> UUID -> [event] -> m (Maybe EventWriteError)
transactionalExpectedWriteHelper' Nothing _ storeEvents' uuid events =
storeEvents' uuid events >> return Nothing
transactionalExpectedWriteHelper' (Just f) getLatestVersion' storeEvents' uuid events = do
latestVersion <- getLatestVersion' uuid
if f latestVersion
then storeEvents' uuid events >> return Nothing
else return $ Just $ EventStreamNotAtExpectedVersion latestVersion
runEventStoreReaderUsing
:: (Monad m, Monad mstore)
=> (forall a. mstore a -> m a)
-> EventStoreReader key position mstore event
-> EventStoreReader key position m event
runEventStoreReaderUsing runStore (EventStoreReader f) = EventStoreReader (runStore . f)
runEventStoreWriterUsing
:: (Monad m, Monad mstore)
=> (forall a. mstore a -> m a)
-> EventStoreWriter mstore event
-> EventStoreWriter m event
runEventStoreWriterUsing runStore (EventStoreWriter f) =
EventStoreWriter $ \vers uuid events -> runStore $ f vers uuid events
serializedEventStoreReader
:: (Monad m)
=> Serializer event serialized
-> EventStoreReader key position m serialized
-> EventStoreReader key position m event
serializedEventStoreReader Serializer{..} (EventStoreReader reader) =
EventStoreReader $ fmap (mapMaybe deserialize) . reader
serializedVersionedEventStoreReader
:: (Monad m)
=> Serializer event serialized
-> VersionedEventStoreReader m serialized
-> VersionedEventStoreReader m event
serializedVersionedEventStoreReader serializer = serializedEventStoreReader (traverseSerializer serializer)
serializedGlobalEventStoreReader
:: (Monad m)
=> Serializer event serialized
-> GlobalEventStoreReader m serialized
-> GlobalEventStoreReader m event
serializedGlobalEventStoreReader serializer = serializedEventStoreReader (traverseSerializer (traverseSerializer serializer))
serializedEventStoreWriter
:: (Monad m)
=> Serializer event serialized
-> EventStoreWriter m serialized
-> EventStoreWriter m event
serializedEventStoreWriter Serializer{..} = contramap serialize
newtype EventVersion = EventVersion { unEventVersion :: Int }
deriving (Show, Read, Ord, Eq, Enum, Num, FromJSON, ToJSON)
newtype SequenceNumber = SequenceNumber { unSequenceNumber :: Int }
deriving (Show, Read, Ord, Eq, Enum, Num, FromJSON, ToJSON,
PathPiece, ToHttpApiData, FromHttpApiData)