ron-rdt-0.11: lib/RON/Data/GTree.hs
{-# LANGUAGE DisambiguateRecordFields #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ImportQualifiedPost #-}
{-# LANGUAGE NamedFieldPuns #-}
-- | Experimental!
module RON.Data.GTree (GTree, insert, loadForest) where
import RON.Prelude
import Data.HashMap.Strict qualified as HashMap
import Data.HashSet (HashSet)
import Data.HashSet qualified as HashSet
import Data.Tree (Forest, Tree (Node))
import RON.Error (MonadE)
import RON.Event (ReplicaClock, advanceToUuid, getEventUuid)
import RON.Store (MonadStore, appendPatch, loadSubObjectLog)
import RON.Types (Op (..), OpenFrame, UUID)
import RON.Types.Experimental (Patch (..), Ref (..))
-- | Grow-only tree
data GTree
type GTreeState = HashMap UUID (HashSet Op)
readFrame :: UUID -> OpenFrame -> GTreeState
readFrame object ops =
HashMap.fromListWith
(<>)
[ (refId, HashSet.singleton op)
| op@Op{opId, refId} <- ops
, opId /= object
]
toForest :: UUID -> GTreeState -> Forest Op
toForest object children = go object
where
go i =
[ Node op $ go opId
| op@Op{opId} <- toList $ HashMap.lookupDefault mempty i children
]
loadForest :: (MonadE m, MonadStore m) => Ref GTree -> m (Forest Op)
loadForest ref@(Ref oid _) =
toForest oid . readFrame oid <$> loadSubObjectLog ref mempty
insert :: (MonadStore m, ReplicaClock m) => Ref GTree -> UUID -> m ()
insert (Ref object prefix) parent = do
advanceToUuid object
opId <- getEventUuid
appendPatch
Patch{object, log = Op{opId, refId = parent, payload = prefix} :| []}