packages feed

ron-rdt-0.11: lib/RON/Store.hs

{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedRecordDot #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}

module RON.Store (
    MonadStore (..),
    loadSubObjectLog,
    newObject,
    readObject,
) where

import RON.Prelude

import Data.List (stripPrefix)
import RON.Data.VersionVector (VV)
import RON.Error (MonadE, errorContext)
import RON.Event (ReplicaClock, getEventUuid)
import RON.Experimental.Data (
    ReplicatedObject,
    baseType,
    baseTypeId,
    decodeObject,
    encodeObject,
 )
import RON.Store.Class (MonadStore (..))
import RON.Types (Op (..))
import RON.Types.Experimental (Patch (..), Ref (..))

newObject ::
    forall a m.
    (MonadStore m, ReplicaClock m, ReplicatedObject a) =>
    a ->
    m (Ref a)
newObject a = do
    objectId <- getEventUuid
    let typeId = baseTypeId $ baseType @a
    let initOp = Op{opId = objectId, refId = typeId, payload = []}
    appendPatch $ Patch objectId $ initOp :| []
    encodeObject objectId a
    pure $ Ref objectId []

-- | Nothing if object doesn't exist in the replica.
readObject ::
    (MonadE m, MonadStore m, ReplicatedObject a, Typeable a) =>
    Ref a ->
    m (Maybe a)
readObject object@(Ref objectId _) =
    errorContext ("readObject " <> show object) do
        ops <- loadSubObjectLog object mempty
        case ops of
            [] -> pure Nothing
            _ : _ -> fmap Just $ decodeObject objectId $ sortOn (.opId) ops

loadSubObjectLog ::
    (MonadE m, MonadStore m, Typeable a) => Ref a -> VV -> m [Op]
loadSubObjectLog object@(Ref objectId path) version =
    errorContext ("loadSubObjectLog " <> show object) do
        ops <- loadWholeObjectLog objectId version
        pure
            [ op{payload = payload'}
            | op@Op{opId, payload} <- ops
            , opId /= objectId
            , Just payload' <- [stripPrefix path payload]
            ]