aws-secrets-0.0.0.0: library/AWS/Secrets/Reader.hs
module AWS.Secrets.Reader
( -- * Type
SecretReader (..),
bind,
-- * Examples
text,
string,
scientific,
boundedInteger,
)
where
import AWS.Secrets.Key (SecretKey, getSecretKeyText)
import Control.Applicative (Applicative, pure)
import qualified Data.Aeson as JSON
import qualified Data.Aeson.Key as JSON.Key
import Data.Function (($), (.))
import Data.Functor (Functor, fmap)
import Data.Functor.Compose (Compose (..))
import qualified Data.Aeson.KeyMap as KeyMap
import Data.Maybe (Maybe (..), maybe)
import Data.Scientific (Scientific)
import qualified Data.Scientific as Scientific
import Data.Semigroup ((<>))
import Data.Sequence (Seq)
import Data.String (String)
import Data.Text (Text)
import qualified Data.Text as Text
import Data.Validation (Validation (..), bindValidation)
import Prelude (Bounded, Integral)
newtype SecretReader a = SecretReader
{ apply :: JSON.Object -> Validation (Seq Text) a
}
deriving
(Functor, Applicative)
via Compose ((->) JSON.Object) (Validation (Seq Text))
bind :: SecretReader a -> (a -> SecretReader b) -> SecretReader b
bind (SecretReader f) g = SecretReader \o ->
f o `bindValidation` (($ o) . apply . g)
---
text :: SecretKey -> SecretReader Text
text k = SecretReader \o ->
orFail ["Missing: " <> getSecretKeyText k] (KeyMap.lookup (key k) o)
`bindValidation` \txt -> orFail ["Not a string: " <> getSecretKeyText k] (castJsonString txt)
string :: SecretKey -> SecretReader String
string = fmap Text.unpack . text
scientific :: SecretKey -> SecretReader Scientific
scientific k = SecretReader \o ->
orFail ["Missing: " <> getSecretKeyText k] (KeyMap.lookup (key k) o)
`bindValidation` \txt -> orFail ["Not a string: " <> getSecretKeyText k] (castJsonNumber txt)
boundedInteger :: (Integral i, Bounded i) => SecretKey -> SecretReader i
boundedInteger k =
scientific k `bind` \s -> SecretReader \_ -> case Scientific.toBoundedInteger s of
Nothing -> Failure ["Not an integer or not within bounds: " <> getSecretKeyText k]
Just i -> pure i
---
key :: SecretKey -> JSON.Key
key = JSON.Key.fromText . getSecretKeyText
castJsonString :: JSON.Value -> Maybe Text
castJsonString = \case JSON.String x -> Just x; _ -> Nothing
castJsonNumber :: JSON.Value -> Maybe Scientific
castJsonNumber = \case JSON.Number x -> Just x; _ -> Nothing
orFail :: Seq Text -> Maybe a -> Validation (Seq Text) a
orFail err = maybe (Failure err) Success