{-# LANGUAGE RecordWildCards     #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications    #-}
{-# LANGUAGE TypeOperators       #-}

-- | Generic conversion to/from JSON
module Data.Record.Generic.JSON (
    gtoJSON
  , gparseJSON
  ) where

import Data.Aeson
import Data.Aeson.Types
import Data.Proxy
import Data.String

import Data.Record.Generic
import qualified Data.Record.Generic.Rep as Rep

gtoJSON :: forall a. (Generic a, Constraints a ToJSON) => a -> Value
gtoJSON :: forall a. (Generic a, Constraints a ToJSON) => a -> Value
gtoJSON =
      [Pair] -> Value
object
    forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. Rep (K a) b -> [a]
Rep.collapse
    forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a (f :: * -> *) (g :: * -> *) (h :: * -> *).
Generic a =>
(forall x. f x -> g x -> h x) -> Rep f a -> Rep g a -> Rep h a
Rep.zipWith (forall {k1} {k2} {k3} a b c (d :: k1) (e :: k2) (f :: k3).
(a -> b -> c) -> K a d -> K b e -> K c f
mapKKK forall a b. (a -> b) -> a -> b
$ \String
n Value
x -> (forall a. IsString a => String -> a
fromString String
n, Value
x)) (forall a. Metadata a -> Rep (K String) a
recordFieldNames Metadata a
md)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a (c :: * -> Constraint) (f :: * -> *) (g :: * -> *).
(Generic a, Constraints a c) =>
Proxy c -> (forall x. c x => f x -> g x) -> Rep f a -> Rep g a
Rep.cmap (forall {k} (t :: k). Proxy t
Proxy @ToJSON) (forall k a (b :: k). a -> K a b
K forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. ToJSON a => a -> Value
toJSON forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. I a -> a
unI)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Generic a => a -> Rep I a
from
  where
    md :: Metadata a
md = forall a (proxy :: * -> *). Generic a => proxy a -> Metadata a
metadata (forall {k} (t :: k). Proxy t
Proxy @a)

gparseJSON :: forall a. (Generic a, Constraints a FromJSON) => Value -> Parser a
gparseJSON :: forall a. (Generic a, Constraints a FromJSON) => Value -> Parser a
gparseJSON =
    forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject (forall a. Metadata a -> String
recordName Metadata a
md) (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. Generic a => Rep I a -> a
to forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) (f :: * -> *) a.
Applicative m =>
Rep (m :.: f) a -> m (Rep f a)
Rep.sequenceA forall b c a. (b -> c) -> (a -> b) -> a -> c
. Object -> Rep (Parser :.: I) a
aux)
  where
    md :: Metadata a
md = forall a (proxy :: * -> *). Generic a => proxy a -> Metadata a
metadata (forall {k} (t :: k). Proxy t
Proxy @a)

    aux :: Object -> Rep (Parser :.: I) a
    aux :: Object -> Rep (Parser :.: I) a
aux Object
obj =
        forall a (c :: * -> Constraint) (f :: * -> *) (g :: * -> *).
(Generic a, Constraints a c) =>
Proxy c -> (forall x. c x => f x -> g x) -> Rep f a -> Rep g a
Rep.cmap
          (forall {k} (t :: k). Proxy t
Proxy @FromJSON)
          (\(K String
fld) -> forall l k (f :: l -> *) (g :: k -> l) (p :: k).
f (g p) -> (:.:) f g p
Comp (forall a. a -> I a
I forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall x. FromJSON x => String -> Parser x
getField String
fld))
          (forall a. Metadata a -> Rep (K String) a
recordFieldNames Metadata a
md)
      where
        getField :: FromJSON x => String -> Parser x
        getField :: forall x. FromJSON x => String -> Parser x
getField String
fld = Object
obj forall a. FromJSON a => Object -> Key -> Parser a
.: forall a. IsString a => String -> a
fromString String
fld