{-| Metadata functions.

-}
module Shikensu.Metadata
    ( transposeMetadata
    , transposeToMetadata
    ) where

import Flow
import Shikensu.Internal.Types

import qualified Data.Aeson as Aeson (FromJSON, Result(..), ToJSON, fromJSON, toJSON)
import qualified Data.Aeson.KeyMap as KeyMap (empty, fromList)


{-| Transpose metadata.

Transpose our metadata object to a given type
which implements the Aeson.FromJSON instance.

> data Example =
>     Example { some :: Text }
>     deriving (Generic, FromJSON)
>
> keyMap      = KeyMap.fromList [ ("some", "metadata") ]
> defaultEx   = Example { some = "default" }
> example     = transposeMetadata keyMap defaultEx :: Example

-}
transposeMetadata :: Aeson.FromJSON a => Metadata -> a -> a
transposeMetadata :: Metadata -> a -> a
transposeMetadata Metadata
keyMap a
fallback =
    let
        result :: Result a
result = Metadata
keyMap
            Metadata -> (Metadata -> Value) -> Value
forall a b. a -> (a -> b) -> b
|> Metadata -> Value
forall a. ToJSON a => a -> Value
Aeson.toJSON
            Value -> (Value -> Result b) -> Result b
forall a b. a -> (a -> b) -> b
|> Value -> Result b
forall a. FromJSON a => Value -> Result a
Aeson.fromJSON :: Aeson.FromJSON b => Aeson.Result b
    in
        case Result a
result of
            Aeson.Success a
x -> a
x
            Aeson.Error String
_   -> a
fallback


{-| Inverse of `transposeMetadata`.
-}
transposeToMetadata :: (Aeson.ToJSON a) => a -> Metadata
transposeToMetadata :: a -> Metadata
transposeToMetadata a
generic =
    let
        result :: Result Metadata
result = a
generic
            a -> (a -> Value) -> Value
forall a b. a -> (a -> b) -> b
|> a -> Value
forall a. ToJSON a => a -> Value
Aeson.toJSON
            Value -> (Value -> Result b) -> Result b
forall a b. a -> (a -> b) -> b
|> Value -> Result b
forall a. FromJSON a => Value -> Result a
Aeson.fromJSON :: Aeson.FromJSON b => Aeson.Result b
    in
        case Result Metadata
result of
            Aeson.Success Metadata
x -> Metadata
x
            Aeson.Error String
_   -> Metadata
forall v. KeyMap v
KeyMap.empty