{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE StandaloneKindSignatures #-}
{-# LANGUAGE TypeOperators #-}
module Polysemy.FSKVStore
( FSKVStore,
runFSKVStoreRelBS,
runFSKVStoreAbsBS,
runFSKVStoreRelUtf8,
runFSKVStoreAbsUtf8,
)
where
import Data.ByteString (ByteString)
import qualified Data.ByteString as BS (readFile, writeFile)
import Data.Kind (Type)
import Path (Abs, Dir, File, Path, Rel, parent,
toFilePath, (</>))
import Polysemy (Embed, Members, Sem, embed, interpret)
import Polysemy.KVStore (KVStore (LookupKV, UpdateKV))
import RIO (Text, readFileUtf8, writeFileUtf8)
import qualified UnliftIO.Path.Directory as U
-- | Type synonym for a KVStore indexed by files.
type FSKVStore :: Type -> Type -> (Type -> Type) -> Type -> Type
type FSKVStore b a = KVStore (Path b File) a
-- | Run an `FSKVStore Rel ByteString` in the supplied directory in IO.
--
-- @since 0.1.0.0
runFSKVStoreRelBS ::
Members '[Embed IO] r =>
Path b Dir ->
Sem (KVStore (Path Rel File) ByteString ': r) a ->
Sem r a
runFSKVStoreRelBS d = interpret \case
LookupKV k -> embed $ do
z <- U.doesFileExist (d </> k)
if z
then fmap Just . BS.readFile $ toFilePath $ d </> k
else return Nothing
UpdateKV k v -> embed $ do
U.createDirectoryIfMissing True (d </> parent k)
case v of
Nothing -> pure ()
Just x -> BS.writeFile (toFilePath (d </> k)) x
-- | Run an `FSKVStore Abs ByteString` in IO.
--
-- @since 0.1.0.0
runFSKVStoreAbsBS ::
Members '[Embed IO] r =>
Sem (FSKVStore Abs ByteString ': r) a ->
Sem r a
runFSKVStoreAbsBS = interpret \case
LookupKV k -> embed $ do
z <- U.doesFileExist k
if z
then fmap Just . BS.readFile $ toFilePath k
else return Nothing
UpdateKV k v -> embed $ do
U.createDirectoryIfMissing True (parent k)
case v of
Nothing -> pure ()
Just x -> BS.writeFile (toFilePath k) x
{-# INLINE runFSKVStoreAbsBS #-}
-- | Run an `FSKVStore Rel Text` in the supplied directory in IO as UTF8.
--
-- @since 0.1.0.0
runFSKVStoreRelUtf8 ::
Members '[Embed IO] r =>
Path b Dir ->
Sem (FSKVStore Rel Text ': r) a ->
Sem r a
runFSKVStoreRelUtf8 d = interpret \case
LookupKV k -> do
z <- U.doesFileExist (d </> k)
if z
then fmap Just . readFileUtf8 $ toFilePath $ d </> k
else return Nothing
UpdateKV k v -> do
U.createDirectoryIfMissing True (d </> parent k)
case v of
Nothing -> pure ()
Just x -> writeFileUtf8 (toFilePath (d </> k)) x
{-# INLINE runFSKVStoreRelUtf8 #-}
-- | Run an `FSKVStore Abs Text` in IO as UTF8.
--
-- @since 0.1.0.0
runFSKVStoreAbsUtf8 ::
Members '[Embed IO] r =>
Sem (FSKVStore Abs Text ': r) a ->
Sem r a
runFSKVStoreAbsUtf8 = interpret \case
LookupKV k -> do
z <- U.doesFileExist k
if z
then fmap Just . readFileUtf8 $ toFilePath k
else return Nothing
UpdateKV k v -> do
U.createDirectoryIfMissing True (parent k)
case v of
Nothing -> pure ()
Just x -> writeFileUtf8 (toFilePath k) x
{-# INLINE runFSKVStoreAbsUtf8 #-}