{-# language StandaloneKindSignatures #-}

module Rel8.Type.JSONEncoded ( JSONEncoded(..) ) where

-- aeson
import Data.Aeson ( FromJSON, ToJSON, parseJSON, toJSON )
import Data.Aeson.Types ( parseEither )

-- base
import Data.Kind ( Type )
import Prelude

-- rel8
import Rel8.Type ( DBType(..) )
import Rel8.Type.Information ( parseTypeInformation )


-- | A deriving-via helper type for column types that store a Haskell value
-- using a JSON encoding described by @aeson@'s 'ToJSON' and 'FromJSON' type
-- classes.
type JSONEncoded :: Type -> Type
newtype JSONEncoded a = JSONEncoded { JSONEncoded a -> a
fromJSONEncoded :: a }


instance (FromJSON a, ToJSON a) => DBType (JSONEncoded a) where
  typeInformation :: TypeInformation (JSONEncoded a)
typeInformation = (Value -> Either String (JSONEncoded a))
-> (JSONEncoded a -> Value)
-> TypeInformation Value
-> TypeInformation (JSONEncoded a)
forall a b.
(a -> Either String b)
-> (b -> a) -> TypeInformation a -> TypeInformation b
parseTypeInformation Value -> Either String (JSONEncoded a)
f JSONEncoded a -> Value
g TypeInformation Value
forall a. DBType a => TypeInformation a
typeInformation
    where
      f :: Value -> Either String (JSONEncoded a)
f = (a -> JSONEncoded a)
-> Either String a -> Either String (JSONEncoded a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> JSONEncoded a
forall a. a -> JSONEncoded a
JSONEncoded (Either String a -> Either String (JSONEncoded a))
-> (Value -> Either String a)
-> Value
-> Either String (JSONEncoded a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Value -> Parser a) -> Value -> Either String a
forall a b. (a -> Parser b) -> a -> Either String b
parseEither Value -> Parser a
forall a. FromJSON a => Value -> Parser a
parseJSON
      g :: JSONEncoded a -> Value
g = a -> Value
forall a. ToJSON a => a -> Value
toJSON (a -> Value) -> (JSONEncoded a -> a) -> JSONEncoded a -> Value
forall b c a. (b -> c) -> (a -> b) -> a -> c
. JSONEncoded a -> a
forall a. JSONEncoded a -> a
fromJSONEncoded