-- | Event store functions.
module Data.CQRS.Internal.EventStore
       ( EventStore(..)
       , enumerateEventStore
       , retrieveEvents
       , storeEvents
       ) where

-- External imports
import           Data.ByteString (ByteString)
import           Data.Conduit (ResourceT, Source, ($=))
import qualified Data.Conduit.List as CL
-- Internal imports
import           Data.CQRS.EventStore.Backend
import           Data.CQRS.GUID
import           Data.CQRS.Serializable
import           Data.CQRS.PersistedEvent (PersistedEvent(..))

-- Provide a type alias.
data EventStore e b = EventStore { esBackend :: b }

enumerateEventStore :: forall e b . (Serializable e, EventStoreBackend b) => EventStore e b -> Source (ResourceT IO) [PersistedEvent e]
enumerateEventStore es =
  esbEnumerateAllEvents (esBackend es) $= CL.map (\re -> [fmap deserialize' re])

storeEvents :: (Serializable e, EventStoreBackend b) => EventStore e b -> GUID -> Int -> [PersistedEvent e] -> IO ()
storeEvents (EventStore esb) guid v0 evs = do
  esbStoreEvents esb guid v0 $ (map $ fmap $ serialize) evs

retrieveEvents :: (Serializable e, EventStoreBackend b) => EventStore e b -> GUID -> Int -> Source (ResourceT IO) (PersistedEvent e)
retrieveEvents (EventStore esb) guid v0 = (esbRetrieveEvents esb guid v0) $= (CL.map (fmap deserialize'))

deserialize' :: Serializable e => ByteString -> e
deserialize' s =
    case deserialize s of
      Nothing -> error "Could not deserialize event -- event deserialization MUST NOT fail"
      Just e -> e