{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# OPTIONS_HADDOCK prune not-home #-}

{- |
Module      : KeyedVals.Handle.Typed
Copyright   : (c) 2022 Tim Emiola
Maintainer  : Tim Emiola <adetokunbo@emio.la>
SPDX-License-Identifier: BSD3

Provides typeclasses, data types and combinators that constrain the @types@ of
keys and values accessed in the key-value store, whilst also linking them to specific
storage paths.
-}
module KeyedVals.Handle.Typed (
  -- * How use this module
  -- $use

  -- * type-and-path-constrained Handle combinators
  TypedKVs,
  countKVs,
  loadFrom,
  loadKVs,
  loadSlice,
  mayLoadFrom,
  modKVs,
  saveTo,
  saveKVs,
  updateKVs,

  -- * link key-value collections to a path
  PathOf (..),
  VaryingPathOf (..),
  rawPath,
  expand,
  prepend,
  append,

  -- * unify @PathOf@/@VaryingPathOf@
  TypedPath (..),
  TypedKey,
  pathKey,
  pathOf,
  key,
  (//),

  -- * module re-exports
  module KeyedVals.Handle,
  module KeyedVals.Handle.Codec,
) where

import qualified Data.ByteString as B
import qualified Data.ByteString.Char8 as C8
import Data.Functor ((<&>))
import Data.List.NonEmpty (NonEmpty)
import Data.Map.Strict (Map)
import Data.Proxy (Proxy (Proxy))
import GHC.TypeLits (KnownSymbol, Symbol, symbolVal)
import KeyedVals.Handle (
  Handle,
  HandleErr (..),
  Key,
  Selection (..),
  close,
 )
import qualified KeyedVals.Handle as H
import KeyedVals.Handle.Codec
import Numeric.Natural


{- $use

 This section contains information on how to store data using this library.
 It starts with a preamble that shows the directives and imports used in the
 examples below

 > {\-# LANGUAGE DeriveGeneric #-\}
 > {\-# LANGUAGE DerivingVia #-\}
 > {\-# LANGUAGE OverloadedStrings #-\}
 > {\-# LANGUAGE StandaloneDeriving #-\}
 >
 > import Data.Aeson (FromJSON, ToJSON)
 > import Data.Text (Text)
 > import GHC.Generics (Generic)
 > import KeyedVals.Handle.Codec.Aeson (AesonOf(..))
 > import KeyedVals.Handle.Codec.HttpApiData (HttpApiDataOf(..))
 > import qualified KeyedVals.Handle.Mem as Mem
 > import KeyedVals.Handle.Typed
 > import Web.HttpApiData (FromHttpApiData, ToHttpApiData)

 Usage is fairly simple: 'PathOf' and possibly a 'VaryingPathOf' instance for
 storable data types are declared. They describe how the data type is encoded
 and decoded and where in the key-value store the data should be saved.

 For example, given this data type:

 > data Person = Person
 >   { name :: Text
 >   , age  :: Int
 >   } deriving (Eq, Show, Generic)

 Suppose each @Person@ is to be stored as JSON, via the @Generic@
 implementation, e.g,

 > instance FromJSON Person
 > instance ToJSON Person

 Also suppose each Person is stored with an Int key. To enable that, define a
 @newtype@ of @Int@, e.g,

 > newtype PersonID = PersonID Int
 >   deriving stock (Eq, Show)
 >   deriving (ToHttpApiData, FromHttpApiData, Num, Ord) via Int

 Also, suppose the collection of @Person@s keyed by @PersonID@ is stored at a
 specific fixed path in the key-value store. E.g, it is to be used as a runtime
 cache to speed up access to person data, so the path @/runtime/cache/persons@
 is used.

 To specify all this, first define @DecodeKV@ and @EncodeKV@ instances for
 @Person@:

 > deriving via (AesonOf Person) instance DecodeKV Person
 > deriving via (AesonOf Person) instance EncodeKV Person

 .. and do the same for @PersonID@:

 > deriving via (HttpApiDataOf Int) instance DecodeKV PersonID
 > deriving via (HttpApiDataOf Int) instance EncodeKV PersonID

 Then declare a @PathOf@ instance that binds the types together with the path:

 > instance PathOf Person where
 >   type KVPath Person = "/runtime/cache/persons"
 >   type KeyType Person = PersonID

 Note: the @DecodeKV@ and @EncodeKV@ deriving statements above were
 standalone for illustrative purposes. In most cases, they ought to be part
 of the deriving clause of the data type. E.g,

 > newtype AnotherID = AnotherID Int
 >   deriving stock (Eq, Show)
 >   deriving (ToHttpApiData, FromHttpApiData, Num, Ord) via Int
 >   deriving (DecodeKV, EncodeKV) via (HttpApiDataOf Int)

 Now one can load and fetch @Person@s from a storage backend using the functions
 in this module, e.g:

 > >>> handle <- Mem.new
 > >>> tim = Person { name = "Tim", age = 48 }
 > >>> saveTo handle (key 1) tim
 > Right ()
 > >>> loadFrom handle (key 1)
 > Right (Person { name = "Tim", age = 48 })

 Suppose that in addition to the main collection of @Person@s, it's necessary to
 store a distinct list of the friends of each @Person@. I.e, store a small keyed
 collection of @Person@s per person.

 One way to achieve is to store each such collection at a similar path, e.g
 suppose the friends for the person with @anID@ are stored at
 @/app/person/<anId>/friends@.

 This can be implemented using the existing types along with another newtype
 that has @PathOf@ and @VaryingPathOf@ instances as follows

 > newtype Friend = Friend Person
 >   deriving stock (Eq, Show)
 >   deriving (FromJSON, ToJSON, EncodeKV, DecodeKV) via Person
 >
 > instance PathOf Friend where
 >   type KVPath Friend = "/app/person/{}/friends"
 >   type KeyType Friend = FriendID -- as defined earlier
 >
 > instance VaryingPathOf Friend where
 >   type PathVar Friend = PersonID
 >   modifyPath _ = expand -- implements modifyPath by expanding the braces to PathVar

 This allows @Friends@ to be saved or fetched as follows:

 > >>> dave = Person { name = "Dave", age = 61 }
 > >>> saveTo handle (key 2) dave -- save in main person list
 > Right ()
 > >>> saveTo handle ( 1 // 2) (Friend dave) -- save as friend of tim (person 1)
 > Right ()
-}


-- | Obtains the path indicted by a 'TypedPath' as a 'Key'.
pathKey :: forall v. TypedPath v -> Key
pathKey :: forall v. TypedPath v -> ByteString
pathKey TypedPath v
Fixed = forall value. PathOf value => Proxy value -> ByteString
rawPath @v Proxy v
forall {k} (t :: k). Proxy t
Proxy
pathKey (Variable PathVar v
part) = forall value.
VaryingPathOf value =>
Proxy value -> PathVar value -> ByteString -> ByteString
modifyPath @v Proxy v
forall {k} (t :: k). Proxy t
Proxy PathVar v
part (ByteString -> ByteString) -> ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ forall value. PathOf value => Proxy value -> ByteString
rawPath @v Proxy v
forall {k} (t :: k). Proxy t
Proxy


-- | Derives the 'TypedPath' corresponding to a 'TypedKey'.
pathOf :: TypedKey v -> TypedPath v
pathOf :: forall v. TypedKey v -> TypedPath v
pathOf (ToKey KeyType v
_) = TypedPath v
forall v. PathOf v => TypedPath v
Fixed
pathOf (Extended PathVar v
part KeyType v
_) = PathVar v -> TypedPath v
forall v. VaryingPathOf v => PathVar v -> TypedPath v
Variable PathVar v
part


{- | Represents a related group of @values@ each stored using a key of type
 @'KeyType' <value type>@
-}
type TypedKVs value = Map (KeyType value) value


{- | Links the storage path of a group of key-values to the types of the key and
   value.
-}
class
  ( KnownSymbol (KVPath value)
  , EncodeKV (KeyType value)
  , DecodeKV (KeyType value)
  ) =>
  PathOf value
  where
  -- * the storage path where the key-values are saved
  type KVPath value :: Symbol


  -- * the type of keys in this group of key-values
  type KeyType value


{- | Allow the storage path specifed by @'PathOf'@ to vary so that related
  groups of key-values may be stored in similar, related paths.
-}
class PathOf value => VaryingPathOf value where
  -- * @PathVar@ is specified to modify the path
  type PathVar value


  -- * Combines the raw 'KVPath' and @PathVar to obtain a new path.
  modifyPath :: Proxy value -> PathVar value -> Key -> Key


-- | Supports implementation of 'modifyPath' via substitution of @{}@ within the 'KVPath'.
expand :: EncodeKV a => a -> Key -> Key
expand :: forall a. EncodeKV a => a -> ByteString -> ByteString
expand a
x ByteString
template =
  let (ByteString
prefix, ByteString
afterPre) = ByteString -> ByteString -> (ByteString, ByteString)
B.breakSubstring ByteString
braces ByteString
template
      suffix :: ByteString
suffix = Int -> ByteString -> ByteString
B.drop (ByteString -> Int
B.length ByteString
braces) ByteString
afterPre
      result :: ByteString
result = ByteString
prefix ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> a -> ByteString
forall a. EncodeKV a => a -> ByteString
encodeKV a
x ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
suffix
   in if ByteString -> ByteString -> Bool
B.isPrefixOf ByteString
braces ByteString
afterPre then ByteString
result else ByteString
template


{- | Supports implementation of 'modifyPath'

Intended for used within the 'KVPath' of instances of 'VaryingPathOf', indicates where
 a variable should be substituted
-}
braces :: B.ByteString
braces :: ByteString
braces = ByteString
"{}"


-- | Supports implementaton of 'modifyPath'.
append :: EncodeKV a => Key -> a -> Key -> Key
append :: forall a. EncodeKV a => ByteString -> a -> ByteString -> ByteString
append ByteString
sep a
x ByteString
template = ByteString
template ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
sep ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> a -> ByteString
forall a. EncodeKV a => a -> ByteString
encodeKV a
x


-- | Supports implementaton of 'modifyPath'
prepend :: EncodeKV a => Key -> a -> Key -> Key
prepend :: forall a. EncodeKV a => ByteString -> a -> ByteString -> ByteString
prepend ByteString
sep a
x ByteString
template = a -> ByteString
forall a. EncodeKV a => a -> ByteString
encodeKV a
x ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
sep ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
template


{- | A phantom type indicating either an instance of @'PathOf'@ or of
   @'VaryingPathOf'@.

 Allows combinators with similar behaviour for either to be defined just once,
 rather than separately for each typeclass.
-}
data TypedPath v where
  Fixed :: (PathOf v) => TypedPath v
  Variable :: (VaryingPathOf v) => PathVar v -> TypedPath v


-- | Similar to 'TypedPath', but includes an actual key along with the phantom type.
data TypedKey v where
  ToKey :: (PathOf v) => KeyType v -> TypedKey v
  Extended :: (VaryingPathOf v) => PathVar v -> KeyType v -> TypedKey v


-- | Constructs a simple 'TypedKey'.
key :: PathOf v => KeyType v -> TypedKey v
key :: forall v. PathOf v => KeyType v -> TypedKey v
key = KeyType v -> TypedKey v
forall v. PathOf v => KeyType v -> TypedKey v
ToKey


-- | Constructs an extended 'TypedKey'.
infixr 5 //


(//) :: VaryingPathOf v => PathVar v -> KeyType v -> TypedKey v
PathVar v
a // :: forall v. VaryingPathOf v => PathVar v -> KeyType v -> TypedKey v
// KeyType v
b = PathVar v -> KeyType v -> TypedKey v
forall v. VaryingPathOf v => PathVar v -> KeyType v -> TypedKey v
Extended PathVar v
a KeyType v
b


instance EncodeKV (TypedKey v) where
  encodeKV :: TypedKey v -> ByteString
encodeKV (ToKey KeyType v
x) = KeyType v -> ByteString
forall a. EncodeKV a => a -> ByteString
encodeKV KeyType v
x
  encodeKV (Extended PathVar v
_ KeyType v
x) = KeyType v -> ByteString
forall a. EncodeKV a => a -> ByteString
encodeKV KeyType v
x


-- | Obtain the raw path to key-values that implement 'PathOf'.
rawPath :: forall value. PathOf value => Proxy value -> Key
rawPath :: forall value. PathOf value => Proxy value -> ByteString
rawPath Proxy value
_ = String -> ByteString
C8.pack (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ forall (n :: Symbol) (proxy :: Symbol -> *).
KnownSymbol n =>
proxy n -> String
symbolVal @(KVPath value) Proxy (KVPath value)
forall {k} (t :: k). Proxy t
Proxy


-- | Like 'mayLoadFrom', but fails with 'Gone' if the value is missing.
loadFrom ::
  forall a m.
  (Monad m, DecodeKV a) =>
  Handle m ->
  TypedKey a ->
  m (Either HandleErr a)
loadFrom :: forall a (m :: * -> *).
(Monad m, DecodeKV a) =>
Handle m -> TypedKey a -> m (Either HandleErr a)
loadFrom Handle m
h TypedKey a
aKey =
  let outer :: ByteString
outer = TypedPath a -> ByteString
forall v. TypedPath v -> ByteString
pathKey (TypedPath a -> ByteString) -> TypedPath a -> ByteString
forall a b. (a -> b) -> a -> b
$ TypedKey a -> TypedPath a
forall v. TypedKey v -> TypedPath v
pathOf TypedKey a
aKey
      inner :: ByteString
inner = TypedKey a -> ByteString
forall a. EncodeKV a => a -> ByteString
encodeKV TypedKey a
aKey
      full :: ByteString
full = ByteString
outer ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
"//" ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
inner
   in Handle m
-> ByteString
-> ByteString
-> m (Either HandleErr (Maybe ByteString))
forall (m :: * -> *).
Handle m
-> ByteString
-> ByteString
-> m (Either HandleErr (Maybe ByteString))
H.loadFrom Handle m
h ByteString
outer ByteString
inner m (Either HandleErr (Maybe ByteString))
-> (Either HandleErr (Maybe ByteString) -> Either HandleErr a)
-> m (Either HandleErr a)
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> ByteString
-> Either HandleErr (Maybe ByteString) -> Either HandleErr a
forall b err.
(DecodeKV b, FromHandleErr err) =>
ByteString -> Either err (Maybe ByteString) -> Either err b
decodeOrGone' ByteString
full


{- | Like @'KeyedValues.Handle.loadVal'@ with the key, path and value
 constrained by @'TypedKey'@
-}
mayLoadFrom ::
  forall a m.
  (Monad m, DecodeKV a, PathOf a) =>
  Handle m ->
  TypedKey a ->
  m (Either HandleErr (Maybe a))
mayLoadFrom :: forall a (m :: * -> *).
(Monad m, DecodeKV a, PathOf a) =>
Handle m -> TypedKey a -> m (Either HandleErr (Maybe a))
mayLoadFrom Handle m
h TypedKey a
aKey =
  let outer :: ByteString
outer = TypedPath a -> ByteString
forall v. TypedPath v -> ByteString
pathKey (TypedPath a -> ByteString) -> TypedPath a -> ByteString
forall a b. (a -> b) -> a -> b
$ TypedKey a -> TypedPath a
forall v. TypedKey v -> TypedPath v
pathOf TypedKey a
aKey
      inner :: ByteString
inner = TypedKey a -> ByteString
forall a. EncodeKV a => a -> ByteString
encodeKV TypedKey a
aKey
   in Handle m
-> ByteString
-> ByteString
-> m (Either HandleErr (Maybe ByteString))
forall (m :: * -> *).
Handle m
-> ByteString
-> ByteString
-> m (Either HandleErr (Maybe ByteString))
H.loadFrom Handle m
h ByteString
outer ByteString
inner m (Either HandleErr (Maybe ByteString))
-> (Either HandleErr (Maybe ByteString)
    -> Either HandleErr (Maybe a))
-> m (Either HandleErr (Maybe a))
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> Either HandleErr (Maybe ByteString) -> Either HandleErr (Maybe a)
forall b err.
(DecodeKV b, FromHandleErr err) =>
Either err (Maybe ByteString) -> Either err (Maybe b)
decodeOr'


{- | Like @'KeyedValues.Handle.saveTo'@ with the key, path and value constrained
 by @'TypedKey'@
-}
saveTo ::
  (Monad m, EncodeKV a, PathOf a) =>
  Handle m ->
  TypedKey a ->
  a ->
  m (Either HandleErr ())
saveTo :: forall (m :: * -> *) a.
(Monad m, EncodeKV a, PathOf a) =>
Handle m -> TypedKey a -> a -> m (Either HandleErr ())
saveTo Handle m
h TypedKey a
aKey a
someKVs =
  let outer :: ByteString
outer = TypedPath a -> ByteString
forall v. TypedPath v -> ByteString
pathKey (TypedPath a -> ByteString) -> TypedPath a -> ByteString
forall a b. (a -> b) -> a -> b
$ TypedKey a -> TypedPath a
forall v. TypedKey v -> TypedPath v
pathOf TypedKey a
aKey
      inner :: ByteString
inner = TypedKey a -> ByteString
forall a. EncodeKV a => a -> ByteString
encodeKV TypedKey a
aKey
   in Handle m
-> ByteString
-> ByteString
-> ByteString
-> m (Either HandleErr ())
forall (m :: * -> *).
Handle m
-> ByteString
-> ByteString
-> ByteString
-> m (Either HandleErr ())
H.saveTo Handle m
h ByteString
outer ByteString
inner (ByteString -> m (Either HandleErr ()))
-> ByteString -> m (Either HandleErr ())
forall a b. (a -> b) -> a -> b
$ a -> ByteString
forall a. EncodeKV a => a -> ByteString
encodeKV a
someKVs


{- | Like @'KeyedValues.Handle.loadKVs'@ with the path and key values constrained
 by @'TypedPath'@
-}
loadKVs ::
  ( Monad m
  , DecodeKV a
  , DecodeKV (KeyType a)
  , Ord (KeyType a)
  ) =>
  Handle m ->
  TypedPath a ->
  m (Either HandleErr (TypedKVs a))
loadKVs :: forall (m :: * -> *) a.
(Monad m, DecodeKV a, DecodeKV (KeyType a), Ord (KeyType a)) =>
Handle m -> TypedPath a -> m (Either HandleErr (TypedKVs a))
loadKVs Handle m
h TypedPath a
k = Handle m -> ByteString -> m (Either HandleErr ValsByKey)
forall (m :: * -> *).
Handle m -> ByteString -> m (Either HandleErr ValsByKey)
H.loadKVs Handle m
h (TypedPath a -> ByteString
forall v. TypedPath v -> ByteString
pathKey TypedPath a
k) m (Either HandleErr ValsByKey)
-> (Either HandleErr ValsByKey
    -> m (Either HandleErr (Map (KeyType a) a)))
-> m (Either HandleErr (Map (KeyType a) a))
forall a b. m a -> (a -> m b) -> m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Either HandleErr (Map (KeyType a) a)
-> m (Either HandleErr (Map (KeyType a) a))
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either HandleErr (Map (KeyType a) a)
 -> m (Either HandleErr (Map (KeyType a) a)))
-> (Either HandleErr ValsByKey
    -> Either HandleErr (Map (KeyType a) a))
-> Either HandleErr ValsByKey
-> m (Either HandleErr (Map (KeyType a) a))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Either HandleErr ValsByKey -> Either HandleErr (Map (KeyType a) a)
forall a b.
(Ord a, DecodeKV a, DecodeKV b) =>
Either HandleErr ValsByKey -> Either HandleErr (Map a b)
orDecodeKVs


{- | Like @'KeyedValues.Handle.updateKVs'@ with the path and key-values
 constrained by @'TypedPath'@
-}
updateKVs ::
  (Monad m, EncodeKV a, EncodeKV (KeyType a), Ord (KeyType a)) =>
  Handle m ->
  TypedPath a ->
  TypedKVs a ->
  m (Either HandleErr ())
updateKVs :: forall (m :: * -> *) a.
(Monad m, EncodeKV a, EncodeKV (KeyType a), Ord (KeyType a)) =>
Handle m -> TypedPath a -> TypedKVs a -> m (Either HandleErr ())
updateKVs Handle m
h TypedPath a
aKey = Handle m
-> ByteString -> Map (KeyType a) a -> m (Either HandleErr ())
forall a b (m :: * -> *) err.
(Ord a, EncodeKV a, EncodeKV b, Monad m, FromHandleErr err) =>
Handle m -> ByteString -> Map a b -> m (Either err ())
updateEncodedKVs Handle m
h (ByteString -> Map (KeyType a) a -> m (Either HandleErr ()))
-> ByteString -> Map (KeyType a) a -> m (Either HandleErr ())
forall a b. (a -> b) -> a -> b
$ TypedPath a -> ByteString
forall v. TypedPath v -> ByteString
pathKey TypedPath a
aKey


{- | Like @'KeyedValues.Handle.savedKVs'@ with the path and key-values
 constrained by @'TypedPath'@
-}
saveKVs ::
  (Monad m, EncodeKV a, EncodeKV (KeyType a), Ord (KeyType a)) =>
  Handle m ->
  TypedPath a ->
  TypedKVs a ->
  m (Either HandleErr ())
saveKVs :: forall (m :: * -> *) a.
(Monad m, EncodeKV a, EncodeKV (KeyType a), Ord (KeyType a)) =>
Handle m -> TypedPath a -> TypedKVs a -> m (Either HandleErr ())
saveKVs Handle m
h TypedPath a
k = Handle m
-> ByteString -> Map (KeyType a) a -> m (Either HandleErr ())
forall a b (m :: * -> *) err.
(Ord a, EncodeKV a, EncodeKV b, Monad m, FromHandleErr err) =>
Handle m -> ByteString -> Map a b -> m (Either err ())
saveEncodedKVs Handle m
h (ByteString -> Map (KeyType a) a -> m (Either HandleErr ()))
-> ByteString -> Map (KeyType a) a -> m (Either HandleErr ())
forall a b. (a -> b) -> a -> b
$ TypedPath a -> ByteString
forall v. TypedPath v -> ByteString
pathKey TypedPath a
k


-- | Combines 'saveKVs' and 'loadKVs'
modKVs ::
  ( Monad m
  , EncodeKV a
  , EncodeKV (KeyType a)
  , DecodeKV a
  , DecodeKV (KeyType a)
  , Ord (KeyType a)
  ) =>
  (TypedKVs a -> TypedKVs a) ->
  Handle m ->
  TypedPath a ->
  m (Either HandleErr ())
modKVs :: forall (m :: * -> *) a.
(Monad m, EncodeKV a, EncodeKV (KeyType a), DecodeKV a,
 DecodeKV (KeyType a), Ord (KeyType a)) =>
(TypedKVs a -> TypedKVs a)
-> Handle m -> TypedPath a -> m (Either HandleErr ())
modKVs TypedKVs a -> TypedKVs a
modDict Handle m
h TypedPath a
aKey = do
  Handle m -> ByteString -> m (Either HandleErr ValsByKey)
forall (m :: * -> *).
Handle m -> ByteString -> m (Either HandleErr ValsByKey)
H.loadKVs Handle m
h (TypedPath a -> ByteString
forall v. TypedPath v -> ByteString
pathKey TypedPath a
aKey) m (Either HandleErr ValsByKey)
-> (Either HandleErr ValsByKey
    -> m (Either HandleErr (TypedKVs a)))
-> m (Either HandleErr (TypedKVs a))
forall a b. m a -> (a -> m b) -> m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (Either HandleErr (TypedKVs a) -> m (Either HandleErr (TypedKVs a))
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either HandleErr (TypedKVs a)
 -> m (Either HandleErr (TypedKVs a)))
-> (Either HandleErr ValsByKey -> Either HandleErr (TypedKVs a))
-> Either HandleErr ValsByKey
-> m (Either HandleErr (TypedKVs a))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Either HandleErr ValsByKey -> Either HandleErr (TypedKVs a)
forall a b.
(Ord a, DecodeKV a, DecodeKV b) =>
Either HandleErr ValsByKey -> Either HandleErr (Map a b)
orDecodeKVs) m (Either HandleErr (TypedKVs a))
-> (Either HandleErr (TypedKVs a) -> m (Either HandleErr ()))
-> m (Either HandleErr ())
forall a b. m a -> (a -> m b) -> m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
    Left HandleErr
err -> Either HandleErr () -> m (Either HandleErr ())
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either HandleErr () -> m (Either HandleErr ()))
-> Either HandleErr () -> m (Either HandleErr ())
forall a b. (a -> b) -> a -> b
$ HandleErr -> Either HandleErr ()
forall a b. a -> Either a b
Left HandleErr
err
    Right TypedKVs a
d -> Handle m -> TypedPath a -> TypedKVs a -> m (Either HandleErr ())
forall (m :: * -> *) a.
(Monad m, EncodeKV a, EncodeKV (KeyType a), Ord (KeyType a)) =>
Handle m -> TypedPath a -> TypedKVs a -> m (Either HandleErr ())
saveKVs Handle m
h TypedPath a
aKey (TypedKVs a -> m (Either HandleErr ()))
-> TypedKVs a -> m (Either HandleErr ())
forall a b. (a -> b) -> a -> b
$ TypedKVs a -> TypedKVs a
modDict TypedKVs a
d


{- | Like @'KeyedValues.Handle.loadSlice'@ with the path and key-values
 constrained by @'TypedPath'@
-}
loadSlice ::
  forall m a.
  ( Monad m
  , DecodeKV a
  , PathOf a
  , DecodeKV (KeyType a)
  , Ord (KeyType a)
  ) =>
  Handle m ->
  TypedPath a ->
  NonEmpty (KeyType a) ->
  m (Either HandleErr (TypedKVs a))
loadSlice :: forall (m :: * -> *) a.
(Monad m, DecodeKV a, PathOf a, DecodeKV (KeyType a),
 Ord (KeyType a)) =>
Handle m
-> TypedPath a
-> NonEmpty (KeyType a)
-> m (Either HandleErr (TypedKVs a))
loadSlice Handle m
h TypedPath a
aKey NonEmpty (KeyType a)
keys = do
  let selection :: Selection
selection = NonEmpty ByteString -> Selection
AllOf (NonEmpty ByteString -> Selection)
-> NonEmpty ByteString -> Selection
forall a b. (a -> b) -> a -> b
$ (KeyType a -> ByteString)
-> NonEmpty (KeyType a) -> NonEmpty ByteString
forall a b. (a -> b) -> NonEmpty a -> NonEmpty b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap KeyType a -> ByteString
forall a. EncodeKV a => a -> ByteString
encodeKV NonEmpty (KeyType a)
keys
  Handle m
-> ByteString -> Selection -> m (Either HandleErr ValsByKey)
forall (m :: * -> *).
Handle m
-> ByteString -> Selection -> m (Either HandleErr ValsByKey)
H.loadSlice Handle m
h (TypedPath a -> ByteString
forall v. TypedPath v -> ByteString
pathKey TypedPath a
aKey) Selection
selection m (Either HandleErr ValsByKey)
-> (Either HandleErr ValsByKey
    -> m (Either HandleErr (TypedKVs a)))
-> m (Either HandleErr (TypedKVs a))
forall a b. m a -> (a -> m b) -> m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Either HandleErr (TypedKVs a) -> m (Either HandleErr (TypedKVs a))
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either HandleErr (TypedKVs a)
 -> m (Either HandleErr (TypedKVs a)))
-> (Either HandleErr ValsByKey -> Either HandleErr (TypedKVs a))
-> Either HandleErr ValsByKey
-> m (Either HandleErr (TypedKVs a))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Either HandleErr ValsByKey -> Either HandleErr (TypedKVs a)
forall a b.
(Ord a, DecodeKV a, DecodeKV b) =>
Either HandleErr ValsByKey -> Either HandleErr (Map a b)
orDecodeKVs


orDecodeKVs ::
  (Ord a, DecodeKV a, DecodeKV b) =>
  Either HandleErr H.ValsByKey ->
  Either HandleErr (Map a b)
orDecodeKVs :: forall a b.
(Ord a, DecodeKV a, DecodeKV b) =>
Either HandleErr ValsByKey -> Either HandleErr (Map a b)
orDecodeKVs = (HandleErr -> Either HandleErr (Map a b))
-> (ValsByKey -> Either HandleErr (Map a b))
-> Either HandleErr ValsByKey
-> Either HandleErr (Map a b)
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either HandleErr -> Either HandleErr (Map a b)
forall a b. a -> Either a b
Left ValsByKey -> Either HandleErr (Map a b)
forall a b err.
(Ord a, DecodeKV a, DecodeKV b, FromHandleErr err) =>
ValsByKey -> Either err (Map a b)
decodeKVs


{- | Like @'KeyedValues.Handle.countKVs'@ with the path and key-values
 constrained by @'TypedPath'@
-}
countKVs ::
  forall a m.
  ( Monad m
  , Ord (KeyType a)
  ) =>
  Handle m ->
  TypedPath a ->
  m (Either HandleErr Natural)
countKVs :: forall a (m :: * -> *).
(Monad m, Ord (KeyType a)) =>
Handle m -> TypedPath a -> m (Either HandleErr Natural)
countKVs Handle m
h TypedPath a
k = Handle m -> ByteString -> m (Either HandleErr Natural)
forall (m :: * -> *).
Handle m -> ByteString -> m (Either HandleErr Natural)
H.countKVs Handle m
h (ByteString -> m (Either HandleErr Natural))
-> ByteString -> m (Either HandleErr Natural)
forall a b. (a -> b) -> a -> b
$ TypedPath a -> ByteString
forall v. TypedPath v -> ByteString
pathKey TypedPath a
k