hmemdb-0.2.0.4: src/Data/HMemDb/Persistence.hs
module Data.HMemDb.Persistence (fillTable, putTable) where
import Control.Applicative (Applicative(pure, (<*>)), (<$>))
import Control.Concurrent.STM (STM, TVar, readTVar, writeTVar)
import Control.Monad.Trans.Cont (Cont, runCont, cont)
import Control.Monad.Trans.Maybe (MaybeT(runMaybeT))
import Data.Binary (Binary(get, put))
import Data.Foldable (for_)
import qualified Data.Map as M (toAscList)
import Data.HMemDb.Bin (Bin (binGet, binPut))
import Data.HMemDb.Binary (GS, SP)
import Data.HMemDb.Tables
(PreTable(tabContent, tabCount, tabRefs), Table(Table), insertRefIntoTable)
import Data.HMemDb.Utils
(bindO, enumElem, fixArray, oBind, liftPure, pureO, replicateO)
-- serialization
putTVar :: TVar a -> Cont SP a
putTVar tv = cont $ bindO $ readTVar tv
readValue :: (a, TVar (Maybe b)) -> STM (Maybe (a, b))
readValue (n, tv) = fmap ((,) n) <$> readTVar tv
putPreTable :: Bin r -> PreTable r a -> Cont SP ()
putPreTable b pt =
do tC <- putTVar $ tabCount pt
liftPure $ put tC
mp <- putTVar $ tabContent pt
pairs <- fixArray (M.toAscList mp) readValue
liftPure $ put $ length pairs
~(n, r) <- enumElem pairs
liftPure $ put n >> binPut b r
putTable :: Table a -> SP
-- ^ This function saves the table to the ByteString.
-- Note that it doesn't really matter if the type of values in the table
-- are serializable.
--
-- NB: if any index used to access the values in this table depended on any foreign keys,
-- and targets of these keys have changed,
-- the index could be different after storing and restoring the table.
putTable (Table b pt) = runCont (putPreTable b pt) pure
-- deserialization
fillTable :: Table a -> GS ()
-- ^ This function reads the table from the ByteString.
fillTable (Table b pt) = genPairs `oBind` insPairs where
genPair = (,) <$> pureO get <*> binGet b (tabRefs pt)
genPairs = (,) <$> pureO get <*> (get `bindO` replicateO genPair)
insPairs ~(counter, pairs) =
do writeTVar (tabCount pt) counter
for_ pairs $ runMaybeT . insertRefIntoTable pt