-- |
-- Module      : Data.Env
-- Description : Environment schema validation
--
-- This module provides functionality to validate environment variables against
-- a schema (a type that implements the `EnvSchema` class).
module Data.Env (EnvSchema(..)) where

import           Control.Monad.IO.Class
import           Data.Env.ExtractFields
import           Data.Env.RecordParser

-- | Type class for validating environment schemas.
class (ExtractFields a, RecordParser a) => EnvSchema a where
  -- | Validate the environment variables against the schema, transforming field
  -- names from camelCase to UPPER_SNAKE_CASE.
  validateEnv :: MonadIO m => m (Either String a)
  validateEnv = do
    Map String String
envRaw <- forall {k} (a :: k) (m :: * -> *).
(MonadIO m, ExtractFields a) =>
m (Map String String)
forall a (m :: * -> *).
(MonadIO m, ExtractFields a) =>
m (Map String String)
getEnvRawCamelCaseToUpperSnake @a
    Either String a -> m (Either String a)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Either String a -> m (Either String a))
-> Either String a -> m (Either String a)
forall a b. (a -> b) -> a -> b
$ Map String String -> Either String a
forall a. RecordParser a => Map String String -> Either String a
parseRecord Map String String
envRaw

  -- | Validate the environment variables against the schema, allowing for a
  -- cusutom transformation function to be applied to the field names to match
  -- with the environment variable names.
  validateEnvWith :: MonadIO m => (String -> String) -> m (Either String a)
  validateEnvWith String -> String
transform = do
    Map String String
envRaw <- forall {k} (a :: k) (m :: * -> *).
(MonadIO m, ExtractFields a) =>
(String -> String) -> m (Map String String)
forall a (m :: * -> *).
(MonadIO m, ExtractFields a) =>
(String -> String) -> m (Map String String)
getEnvRaw @a String -> String
transform
    Either String a -> m (Either String a)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Either String a -> m (Either String a))
-> Either String a -> m (Either String a)
forall a b. (a -> b) -> a -> b
$ Map String String -> Either String a
forall a. RecordParser a => Map String String -> Either String a
parseRecord Map String String
envRaw