packages feed

polysemy-db-0.0.1.0: lib/Polysemy/Db/Interpreter/Store.hs

module Polysemy.Db.Interpreter.Store where

import Conc (interpretAtomic)
import qualified Data.Map.Strict as Map
import Exon (exon)
import Sqel.Data.Uid (Uid (Uid))

import qualified Polysemy.Db.Data.DbError as DbError
import Polysemy.Db.Data.DbError (DbError)
import Polysemy.Db.Effect.Store (QStore (..), Store)

newtype PureStore i a =
  PureStore { records :: Map i (Uid i a) }
  deriving stock (Eq, Show, Generic)
  deriving newtype (Default, Semigroup, Monoid)

pureStore ::
  Ord i =>
  [Uid i a] ->
  PureStore i a
pureStore =
  PureStore . Map.fromList . fmap \ a@(Uid i _) -> (i, a)

interpretStoreAtomicState ::
  ∀ i a r .
  Ord i =>
  Show i =>
  Member (AtomicState (PureStore i a)) r =>
  InterpreterFor (Store i a !! DbError) r
interpretStoreAtomicState =
  interpretResumable \case
    Insert a@(Uid i _) ->
      stopEither =<< atomicState' \ (PureStore records) ->
        let
          update = \case
            Just x -> (Left (DbError.Query [exon|'#{show i}' is already in the store|]), Just x)
            Nothing -> (Right (), Just a)
        in first PureStore (swap (Map.alterF update i records))
    Upsert a@(Uid i _) ->
      atomicModify' (#records %~ Map.insert i a)
    Delete i ->
      atomicState' \ (PureStore as) -> (PureStore (Map.delete i as), Map.lookup i as)
    DeleteAll ->
      atomicState' \ (PureStore as) -> (mempty, Map.elems as)
    Fetch i ->
      atomicGets \ (PureStore as) -> Map.lookup i as
    FetchAll ->
      atomicGets \ (PureStore as) -> Map.elems as

interpretStoreConc ::
  ∀ i a r .
  Ord i =>
  Show i =>
  Member (Embed IO) r =>
  PureStore i a ->
  InterpretersFor [Store i a !! DbError, AtomicState (PureStore i a)] r
interpretStoreConc initial =
  interpretAtomic initial .
  interpretStoreAtomicState

interpretStoreState ::
  ∀ i a r .
  Ord i =>
  Show i =>
  Member (State (PureStore i a)) r =>
  InterpreterFor (Store i a !! DbError) r
interpretStoreState =
  atomicStateToState .
  interpretStoreAtomicState .
  raiseUnder

interpretStoreLocal ::
  ∀ i a r .
  Ord i =>
  Show i =>
  PureStore i a ->
  InterpretersFor [Store i a !! DbError, State (PureStore i a)] r
interpretStoreLocal initial =
  evalState initial .
  interpretStoreState

interpretStoreNull ::
  InterpreterFor (Store i a !! e) r
interpretStoreNull =
  interpretResumable \case
    Insert _ ->
      unit
    Upsert _ ->
      unit
    Delete _ ->
      pure Nothing
    DeleteAll ->
      pure []
    Fetch _ ->
      pure Nothing
    FetchAll ->
      pure []