packages feed

eventium-memory-0.1.0: src/Eventium/ProjectionCache/Memory.hs

{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE RecordWildCards #-}

module Eventium.ProjectionCache.Memory
  ( ProjectionMap,
    emptyProjectionMap,
    projectionMapTVar,
    tvarProjectionCache,
    embeddedStateProjectionCache,
    module Eventium.ProjectionCache.Types,
  )
where

import Control.Concurrent.STM
import Control.Monad.State.Class hiding (state)
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import Eventium.ProjectionCache.Types

-- | A 'ProjectionMap' just stores the latest snapshot for each UUID.
type ProjectionMap key position serialized = Map key (position, serialized)

emptyProjectionMap :: ProjectionMap key position serialized
emptyProjectionMap = Map.empty

projectionMapTVar :: IO (TVar (ProjectionMap key position serialized))
projectionMapTVar = newTVarIO emptyProjectionMap

storeProjectionInMap ::
  (Ord key) =>
  key ->
  position ->
  serialized ->
  ProjectionMap key position serialized ->
  ProjectionMap key position serialized
storeProjectionInMap uuid version state = Map.insert uuid (version, state)

-- | A 'ProjectionCache' that uses a 'TVar' and runs in 'STM'.
tvarProjectionCache ::
  (Ord key) =>
  TVar (ProjectionMap key position serialized) ->
  ProjectionCache key position serialized STM
tvarProjectionCache tvar =
  let storeProjectionSnapshot uuid version projState = modifyTVar' tvar (storeProjectionInMap uuid version projState)
      loadProjectionSnapshot uuid = Map.lookup uuid <$> readTVar tvar
   in ProjectionCache {..}

-- | A 'ProjectionCache' for some 'MonadState' that contains a 'ProjectionMap'.
embeddedStateProjectionCache ::
  (MonadState s m, Ord key) =>
  (s -> ProjectionMap key position serialized) ->
  (s -> ProjectionMap key position serialized -> s) ->
  ProjectionCache key position serialized m
embeddedStateProjectionCache getMap setMap =
  let storeProjectionSnapshot uuid version projState = modify' (storeProjectionSnapshot' uuid version projState)
      loadProjectionSnapshot uuid = Map.lookup uuid <$> gets getMap
   in ProjectionCache {..}
  where
    storeProjectionSnapshot' uuid version projState state =
      setMap state $ storeProjectionInMap uuid version projState $ getMap state