content: module Eventful.EventBus
    ( synchronousEventBusWrapper
    , storeAndPublishEvents
    ) where
  
  import Eventful.Store.Class
  import Eventful.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
  