module Eventium.EventBus ( synchronousEventBusWrapper, storeAndPublishEvents, ) where import Eventium.Store.Class import Eventium.UUID -- | This function wraps an event store by sending events to event handlers -- after running 'storeEvents'. This is useful to quickly wire up event -- handlers in your application (like read models or process managers), and it -- is also useful for integration testing along with an in-memory event store. synchronousEventBusWrapper :: (Monad m) => VersionedEventStoreWriter m event -> [VersionedEventStoreWriter m event -> UUID -> event -> m ()] -> VersionedEventStoreWriter m event synchronousEventBusWrapper writer handlers = wrappedStore where -- NB: We need to use recursive let bindings so we can put wrappedStore -- inside the event handlers handlers' = map ($ wrappedStore) handlers wrappedStore = EventStoreWriter $ storeAndPublishEvents writer handlers' -- | Stores events in the store and then publishes them to the event handlers. -- This is used in the 'synchronousEventBusWrapper'. storeAndPublishEvents :: (Monad m) => VersionedEventStoreWriter m event -> [UUID -> event -> m ()] -> UUID -> ExpectedPosition EventVersion -> [event] -> m (Either (EventWriteError EventVersion) EventVersion) storeAndPublishEvents store handlers uuid expectedVersion events = do result <- storeEvents store uuid expectedVersion events case result of Left err -> return $ Left err Right vers -> do -- NB: If a handler stores events, then its events will be published -- before the events of the next handler. That is, we will be storing -- events generated by handlers in depth-first order. mapM_ (\handler -> mapM_ (handler uuid) events) handlers return $ Right vers