{-# LANGUAGE CPP #-}
module Composite.Aeson.Record
  ( ToJsonField(..), FromJsonField(..), JsonField(..)
  , field, field', fromField, fromField', toField, toField'
  , optionalField, optionalField', fromOptionalField, fromOptionalField', toOptionalField, toOptionalField'
  , JsonFormatRecord, ToJsonFormatRecord, FromJsonFormatRecord, zipJsonFormatRecord, toJsonFormatRecord, fromJsonFormatRecord
  , DefaultJsonFormatRecord, defaultJsonFormatRecord
  , RecordToJsonObject, recordToJsonObject, recordToJson
  , RecordFromJson, recordFromJson
  , recordJsonFormat
  ) where

import Composite.Aeson.Base
  ( JsonProfunctor(JsonProfunctor)
  , JsonFormat(JsonFormat)
  , wrappedJsonFormat
  )
import Composite.Aeson.Formats.Default (DefaultJsonFormat(defaultJsonFormat))
import Composite.Record ((:->))
import Control.Lens (Wrapped(type Unwrapped, _Wrapped'), from, review, view)
import Control.Monad (join)
import qualified Data.Aeson as Aeson
import qualified Data.Aeson.BetterErrors as ABE
#if MIN_VERSION_aeson(2,0,0)
import qualified Data.Aeson.Key as Aeson.Key
import qualified Data.Aeson.KeyMap as Aeson.KeyMap
#else
import qualified Data.HashMap.Strict as HM
#endif
import Data.Functor.Contravariant (Contravariant, contramap)
import Data.Functor.Identity (Identity(Identity))
import Data.Proxy (Proxy(Proxy))
import Data.Text (Text, pack)
import Data.Vinyl (RApply, RMap, Rec((:&), RNil), rmap, rzipWith)
import GHC.TypeLits (KnownSymbol, symbolVal)

-- |Function to encode a single field of a record, possibly choosing to elide the field with @Nothing@.
newtype ToJsonField a = ToJsonField { forall a. ToJsonField a -> a -> Maybe Value
unToJsonField :: a -> Maybe Aeson.Value }

instance Contravariant ToJsonField where
  contramap :: forall a' a. (a' -> a) -> ToJsonField a -> ToJsonField a'
contramap a' -> a
f (ToJsonField a -> Maybe Value
g) = forall a. (a -> Maybe Value) -> ToJsonField a
ToJsonField (a -> Maybe Value
g forall b c a. (b -> c) -> (a -> b) -> a -> c
. a' -> a
f)

-- |Function to decode a single field of a record.
newtype FromJsonField e a = FromJsonField { forall e a. FromJsonField e a -> Text -> Parse e a
unFromJsonField :: Text -> ABE.Parse e a }

instance Functor (FromJsonField e) where
  fmap :: forall a b. (a -> b) -> FromJsonField e a -> FromJsonField e b
fmap a -> b
f (FromJsonField Text -> Parse e a
g) = forall e a. (Text -> Parse e a) -> FromJsonField e a
FromJsonField (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> b
f forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Parse e a
g)

-- |Descriptor of how to handle a single record field with functions to parse and emit the field which can handle missing fields on parse and elide fields on
-- encode.
data JsonField e a = JsonField (a -> Maybe Aeson.Value) (Text -> ABE.Parse e a)

-- |Given a 'JsonFormat' for some type @a@, produce a 'JsonField' for fields of type @a@ which fails if the field is missing and never elides the field.
field :: (Wrapped a', Unwrapped a' ~ a) => JsonFormat e a -> JsonField e a'
field :: forall a' a e.
(Wrapped a', Unwrapped a' ~ a) =>
JsonFormat e a -> JsonField e a'
field JsonFormat e a
fmt = forall e a. JsonFormat e a -> JsonField e a
field' (forall a e.
Wrapped a =>
JsonFormat e (Unwrapped a) -> JsonFormat e a
wrappedJsonFormat JsonFormat e a
fmt)

-- |Given a 'JsonFormat' for some type @a@, produce a 'JsonField' for fields of type @a@ which fails if the field is missing and never elides the field.
field' :: JsonFormat e a -> JsonField e a
field' :: forall e a. JsonFormat e a -> JsonField e a
field' (JsonFormat (JsonProfunctor a -> Value
o Parse e a
i)) = forall e a.
(a -> Maybe Value) -> (Text -> Parse e a) -> JsonField e a
JsonField (forall a. a -> Maybe a
Just forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Value
o) (forall (m :: * -> *) err a.
(Functor m, Monad m) =>
Text -> ParseT err m a -> ParseT err m a
`ABE.key` Parse e a
i)

-- |Given a parser for @'Unwrapped' a@, produce a @'FromField' e a@.
fromField :: Wrapped a => ABE.Parse e (Unwrapped a) -> FromJsonField e a
fromField :: forall a e. Wrapped a => Parse e (Unwrapped a) -> FromJsonField e a
fromField = forall e a. (Text -> Parse e a) -> FromJsonField e a
FromJsonField forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b c. (a -> b -> c) -> b -> a -> c
flip forall (m :: * -> *) err a.
(Functor m, Monad m) =>
Text -> ParseT err m a -> ParseT err m a
ABE.key forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall b (m :: * -> *) t. MonadReader b m => AReview t b -> m t
review forall s. Wrapped s => Iso' s (Unwrapped s)
_Wrapped')

-- |Given a parser for @a@, produce a @'FromField' e a@.
fromField' :: ABE.Parse e a -> FromJsonField e a
fromField' :: forall e a. Parse e a -> FromJsonField e a
fromField' = forall e a. (Text -> Parse e a) -> FromJsonField e a
FromJsonField forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b c. (a -> b -> c) -> b -> a -> c
flip forall (m :: * -> *) err a.
(Functor m, Monad m) =>
Text -> ParseT err m a -> ParseT err m a
ABE.key

-- |Given a parser for @'Unwrapped' a@, produce a @'FromField' e a@.
toField :: (Wrapped a', Unwrapped a' ~ a) => (a -> Aeson.Value) -> ToJsonField a'
toField :: forall a' a.
(Wrapped a', Unwrapped a' ~ a) =>
(a -> Value) -> ToJsonField a'
toField a -> Value
o = forall a. (a -> Maybe Value) -> ToJsonField a
ToJsonField forall a b. (a -> b) -> a -> b
$ forall a. a -> Maybe a
Just forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Value
o forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view forall s. Wrapped s => Iso' s (Unwrapped s)
_Wrapped'

-- |Given a parser for @a@, produce a @'ToField' a@.
toField' :: (a -> Aeson.Value) -> ToJsonField a
toField' :: forall a. (a -> Value) -> ToJsonField a
toField' = forall a. (a -> Maybe Value) -> ToJsonField a
ToJsonField forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. a -> Maybe a
Just

-- |Given a 'JsonFormat' for some type @a@, produce a 'JsonField' for fields of type @Maybe a@ which substitutes @Nothing@ for either @null@ or missing field,
-- and which elides the field on @Nothing@.
optionalField :: (Wrapped a', Unwrapped a' ~ Maybe a) => JsonFormat e a -> JsonField e a'
optionalField :: forall a' a e.
(Wrapped a', Unwrapped a' ~ Maybe a) =>
JsonFormat e a -> JsonField e a'
optionalField (JsonFormat (JsonProfunctor a -> Value
o Parse e a
i)) =
  forall e a.
(a -> Maybe Value) -> (Text -> Parse e a) -> JsonField e a
JsonField
    (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> Value
o forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view forall s. Wrapped s => Iso' s (Unwrapped s)
_Wrapped')
    (\ Text
k -> forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view (forall s t a b. AnIso s t a b -> Iso b a t s
from forall s. Wrapped s => Iso' s (Unwrapped s)
_Wrapped') forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a. Monad m => m (m a) -> m a
join forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *) err a.
(Functor m, Monad m) =>
Text -> ParseT err m a -> ParseT err m (Maybe a)
ABE.keyMay Text
k (forall (m :: * -> *) err a.
(Functor m, Monad m) =>
ParseT err m a -> ParseT err m (Maybe a)
ABE.perhaps Parse e a
i))

-- |Given a 'JsonFormat' for some type @a@, produce a 'JsonField' for fields of type @Maybe a@ which substitutes @Nothing@ for either @null@ or missing field,
-- and which elides the field on @Nothing@.
optionalField' :: JsonFormat e a -> JsonField e (Maybe a)
optionalField' :: forall e a. JsonFormat e a -> JsonField e (Maybe a)
optionalField' (JsonFormat (JsonProfunctor a -> Value
o Parse e a
i)) =
  forall e a.
(a -> Maybe Value) -> (Text -> Parse e a) -> JsonField e a
JsonField
    (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> Value
o)
    (\ Text
k -> forall (m :: * -> *) a. Monad m => m (m a) -> m a
join forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *) err a.
(Functor m, Monad m) =>
Text -> ParseT err m a -> ParseT err m (Maybe a)
ABE.keyMay Text
k (forall (m :: * -> *) err a.
(Functor m, Monad m) =>
ParseT err m a -> ParseT err m (Maybe a)
ABE.perhaps Parse e a
i))

-- |Given a parser for @a@, produce a @'FromField' e b@ where @b@ is a 'Wrapped' around @Maybe a@.
fromOptionalField :: (Wrapped a', Unwrapped a' ~ Maybe a) => ABE.Parse e a -> FromJsonField e a'
fromOptionalField :: forall a' a e.
(Wrapped a', Unwrapped a' ~ Maybe a) =>
Parse e a -> FromJsonField e a'
fromOptionalField Parse e a
i = forall e a. (Text -> Parse e a) -> FromJsonField e a
FromJsonField Text -> ParseT e Identity a'
f
  where
    f :: Text -> ParseT e Identity a'
f Text
k = forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view (forall s t a b. AnIso s t a b -> Iso b a t s
from forall s. Wrapped s => Iso' s (Unwrapped s)
_Wrapped') forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a. Monad m => m (m a) -> m a
join forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *) err a.
(Functor m, Monad m) =>
Text -> ParseT err m a -> ParseT err m (Maybe a)
ABE.keyMay Text
k (forall (m :: * -> *) err a.
(Functor m, Monad m) =>
ParseT err m a -> ParseT err m (Maybe a)
ABE.perhaps Parse e a
i)

-- |Given a parser for @a@, produce a @'FromField' e (Maybe a)@ which represents an optional field.
fromOptionalField' :: ABE.Parse e a -> FromJsonField e (Maybe a)
fromOptionalField' :: forall e a. Parse e a -> FromJsonField e (Maybe a)
fromOptionalField' Parse e a
i = forall e a. (Text -> Parse e a) -> FromJsonField e a
FromJsonField Text -> ParseT e Identity (Maybe a)
f
  where
    f :: Text -> ParseT e Identity (Maybe a)
f Text
k = forall (m :: * -> *) a. Monad m => m (m a) -> m a
join forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *) err a.
(Functor m, Monad m) =>
Text -> ParseT err m a -> ParseT err m (Maybe a)
ABE.keyMay Text
k (forall (m :: * -> *) err a.
(Functor m, Monad m) =>
ParseT err m a -> ParseT err m (Maybe a)
ABE.perhaps Parse e a
i)

-- |Given an encoding function for some type @a@, produce a 'ToField' for fields of type @Maybe a@ which elides the field on @Nothing@.
toOptionalField :: (Wrapped a', Unwrapped a' ~ Maybe a) => (a -> Aeson.Value) -> ToJsonField a'
toOptionalField :: forall a' a.
(Wrapped a', Unwrapped a' ~ Maybe a) =>
(a -> Value) -> ToJsonField a'
toOptionalField a -> Value
o = forall a. (a -> Maybe Value) -> ToJsonField a
ToJsonField (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> Value
o forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view forall s. Wrapped s => Iso' s (Unwrapped s)
_Wrapped')

-- |Given an encoding function for some type @a@, produce a 'ToField' for fields of type @Maybe a@ which elides the field on @Nothing@.
toOptionalField' :: (a -> Aeson.Value) -> ToJsonField (Maybe a)
toOptionalField' :: forall a. (a -> Value) -> ToJsonField (Maybe a)
toOptionalField' a -> Value
o = forall a. (a -> Maybe Value) -> ToJsonField a
ToJsonField (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> Value
o)

-- |Type of a Vinyl record which describes how to map fields of a record to JSON and back.
--
--
-- This record type has the same field names and types as a regular record with 'Identity' but instead of 'Identity' uses 'JsonFormat e'.
--
-- For example, given:
--
-- > type FId   = "id"   :-> Int
-- > type FName = "name" :-> Text
-- > type User = '[FId, FName]
--
-- A 'JsonFormatRecord' for @User@ might be:
--
-- @
--   userFormatRec :: 'JsonFormatRecord' e User
--   userFormatRec = 'field' 'Composite.Aeson.Default.integralJsonFormat'
--                :& 'field' 'Composite.Aeson.Default.textJsonFormat'
--                :& RNil
-- @
--
-- Or, using the default mappings for each field type:
--
-- @
--   userFormatRec :: 'JsonFormatRecord' e User
--   userFormatRec = 'defaultJsonFormatRecord'
-- @
--
-- Such a record is a first-class value like any other record, so can be composed into larger records, modified, etc. This is particularly useful in
-- combination with 'defaultJsonFormatRecord', where you can automatically derive a format record for all fields you want defaults for and then extend or
-- override formats for particular fields, e.g.
--
-- @
--   fId :: Proxy FId
--   fId = Proxy
--
--   userFormatRec :: 'JsonFormatRecord' e User
--   userFormatRec = 'Control.Lens.over' ('Frames.rlens' fId) ('Composite.Aeson.Base.dimapJsonFormat (+10) (subtract 10)) 'defaultJsonFormatRecord'
-- @
--
-- Would use the same JSON schema as the other examples, but the @id@ field would be encoded in JSON as 10 higher.
--
-- Once you've produced an appropriate 'JsonFormatRecord' for your case, use 'recordJsonFormat' to make a @'JsonFormat' e (Record '[…])@ of it.
type JsonFormatRecord e rs = Rec (JsonField e) rs

-- |Zip up a matching 'FromJsonFormatRecord' and 'ToJsonFormatRecord' into a 'JsonFormatRecord'.
--
-- Reverse operation of 'fromJsonFormatRecord' and 'toJsonFormatRecord'.
zipJsonFormatRecord :: (RMap rs, RApply rs) => ToJsonFormatRecord rs -> FromJsonFormatRecord e rs -> JsonFormatRecord e rs
zipJsonFormatRecord :: forall (rs :: [*]) e.
(RMap rs, RApply rs) =>
ToJsonFormatRecord rs
-> FromJsonFormatRecord e rs -> JsonFormatRecord e rs
zipJsonFormatRecord = forall {u} (xs :: [u]) (f :: u -> *) (g :: u -> *) (h :: u -> *).
(RMap xs, RApply xs) =>
(forall (x :: u). f x -> g x -> h x)
-> Rec f xs -> Rec g xs -> Rec h xs
rzipWith (\ (ToJsonField x -> Maybe Value
o) (FromJsonField Text -> Parse e x
i) -> forall e a.
(a -> Maybe Value) -> (Text -> Parse e a) -> JsonField e a
JsonField x -> Maybe Value
o Text -> Parse e x
i)

-- |Type of a Vinyl record which describes how to map fields of a record from a JSON object.
--
-- 'fromJsonFrmaOnce you've produced an appropriate 'FromJsonFormatRecord' for your case, use recordFromJson' to make a @'FromJson' e (Record '[…])@ of it.
type FromJsonFormatRecord e rs = Rec (FromJsonField e) rs

-- |Given a @'JsonFormatRecord' rs@ which describes how to encode or decode a record, produce a @'FromJsonFormatRecord' rs@ which describes
-- only how to decode the record.
fromJsonFormatRecord :: RMap rs => JsonFormatRecord e rs -> FromJsonFormatRecord e rs
fromJsonFormatRecord :: forall (rs :: [*]) e.
RMap rs =>
JsonFormatRecord e rs -> FromJsonFormatRecord e rs
fromJsonFormatRecord = forall {u} (rs :: [u]) (f :: u -> *) (g :: u -> *).
RMap rs =>
(forall (x :: u). f x -> g x) -> Rec f rs -> Rec g rs
rmap (\ (JsonField x -> Maybe Value
_ Text -> Parse e x
i) -> forall e a. (Text -> Parse e a) -> FromJsonField e a
FromJsonField Text -> Parse e x
i)

-- |Type of a Vinyl record which describes how to map fields of a record from a JSON object.
--
-- Once you've produced an appropriate 'ToJsonFormatRecord' for your case, use recordToJson' to make a @'ToJson' (Record '[…])@ of it.
type ToJsonFormatRecord rs = Rec ToJsonField rs

-- |Given a @'Rec' ('JsonField' e) rs@ which describes how to encode or decode a record, produce a @'Rec' 'ToField' rs@ which describes
-- only how to encode the record.
toJsonFormatRecord :: RMap rs => JsonFormatRecord e rs -> ToJsonFormatRecord rs
toJsonFormatRecord :: forall (rs :: [*]) e.
RMap rs =>
JsonFormatRecord e rs -> ToJsonFormatRecord rs
toJsonFormatRecord = forall {u} (rs :: [u]) (f :: u -> *) (g :: u -> *).
RMap rs =>
(forall (x :: u). f x -> g x) -> Rec f rs -> Rec g rs
rmap (\ (JsonField x -> Maybe Value
o Text -> Parse e x
_) -> forall a. (a -> Maybe Value) -> ToJsonField a
ToJsonField x -> Maybe Value
o)

-- |Helper class which induces over the structure of a record, reflecting the name of each field and applying each 'ToJson' to its corresponding value to
-- produce JSON.
class RecordToJsonObject rs where
  -- |Given a record of 'ToField' functions for each field in @rs@, convert an 'Identity' record to 'Aeson.Object'.
  recordToJsonObject :: Rec ToJsonField rs -> Rec Identity rs -> Aeson.Object

instance RecordToJsonObject '[] where
  recordToJsonObject :: Rec ToJsonField '[] -> Rec Identity '[] -> Object
recordToJsonObject Rec ToJsonField '[]
_ = forall a b. a -> b -> a
const forall a. Monoid a => a
mempty

instance forall s a rs. (KnownSymbol s, RecordToJsonObject rs) => RecordToJsonObject (s :-> a ': rs) where
  recordToJsonObject :: Rec ToJsonField ((s :-> a) : rs)
-> Rec Identity ((s :-> a) : rs) -> Object
recordToJsonObject (ToJsonField r -> Maybe Value
aToField :& Rec ToJsonField rs
fs) (Identity r
a :& Rec Identity rs
as) =
#if MIN_VERSION_aeson(2,0,0)
    forall b a. b -> (a -> b) -> Maybe a -> b
maybe forall a. a -> a
id (forall v. Key -> v -> KeyMap v -> KeyMap v
Aeson.KeyMap.insert (String -> Key
Aeson.Key.fromString forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (n :: Symbol) (proxy :: Symbol -> *).
KnownSymbol n =>
proxy n -> String
symbolVal forall a b. (a -> b) -> a -> b
$ (forall {k} (t :: k). Proxy t
Proxy :: Proxy s))) (r -> Maybe Value
aToField r
a) forall a b. (a -> b) -> a -> b
$
#else
    maybe id (HM.insert (pack . symbolVal $ (Proxy :: Proxy s))) (aToField a) $
#endif
      forall (rs :: [*]).
RecordToJsonObject rs =>
Rec ToJsonField rs -> Rec Identity rs -> Object
recordToJsonObject Rec ToJsonField rs
fs Rec Identity rs
as

-- |Given a record of 'ToField' functions for each field in @rs@, convert an 'Identity' record to JSON. Equivalent to @Aeson.Object . 'recordToJsonObject' fmt@
recordToJson :: RecordToJsonObject rs => Rec ToJsonField rs -> Rec Identity rs -> Aeson.Value
recordToJson :: forall (rs :: [*]).
RecordToJsonObject rs =>
Rec ToJsonField rs -> Rec Identity rs -> Value
recordToJson = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Object -> Value
Aeson.Object forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (rs :: [*]).
RecordToJsonObject rs =>
Rec ToJsonField rs -> Rec Identity rs -> Object
recordToJsonObject

-- |Class which induces over the structure of a record, parsing fields using a record of 'FromJson' and assembling an 'Identity' record.
class RecordFromJson rs where
  -- |Given a record of 'FromJson' parsers for each field in @rs@, produce an 'ABE.Parse' to make an 'Identity' record.
  recordFromJson :: Rec (FromJsonField e) rs -> ABE.Parse e (Rec Identity rs)

instance RecordFromJson '[] where
  recordFromJson :: forall e. Rec (FromJsonField e) '[] -> Parse e (Rec Identity '[])
recordFromJson Rec (FromJsonField e) '[]
_ = forall (f :: * -> *) a. Applicative f => a -> f a
pure forall {u} (a :: u -> *). Rec a '[]
RNil

instance forall s a rs. (KnownSymbol s, RecordFromJson rs) => RecordFromJson (s :-> a ': rs) where
  recordFromJson :: forall e.
Rec (FromJsonField e) ((s :-> a) : rs)
-> Parse e (Rec Identity ((s :-> a) : rs))
recordFromJson (FromJsonField Text -> Parse e r
aFromField :& Rec (FromJsonField e) rs
fs) =
    forall {u} (a :: u -> *) (r :: u) (rs :: [u]).
a r -> Rec a rs -> Rec a (r : rs)
(:&)
      forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (forall a. a -> Identity a
Identity forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Text -> Parse e r
aFromField (String -> Text
pack forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (n :: Symbol) (proxy :: Symbol -> *).
KnownSymbol n =>
proxy n -> String
symbolVal forall a b. (a -> b) -> a -> b
$ (forall {k} (t :: k). Proxy t
Proxy :: Proxy s)))
      forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall (rs :: [*]) e.
RecordFromJson rs =>
Rec (FromJsonField e) rs -> Parse e (Rec Identity rs)
recordFromJson Rec (FromJsonField e) rs
fs

-- |Take a 'JsonFormatRecord' describing how to map a record with field @rs@ to and from JSON and produce a @'JsonFormat' e (Record rs)@.
--
-- See 'JsonFormatRecord' for more.
recordJsonFormat :: (RMap rs, RecordToJsonObject rs, RecordFromJson rs) => JsonFormatRecord e rs -> JsonFormat e (Rec Identity rs)
recordJsonFormat :: forall (rs :: [*]) e.
(RMap rs, RecordToJsonObject rs, RecordFromJson rs) =>
JsonFormatRecord e rs -> JsonFormat e (Rec Identity rs)
recordJsonFormat JsonFormatRecord e rs
formatRec =
  forall e a. JsonProfunctor e a a -> JsonFormat e a
JsonFormat forall a b. (a -> b) -> a -> b
$ forall e a b. (a -> Value) -> Parse e b -> JsonProfunctor e a b
JsonProfunctor
    (forall (rs :: [*]).
RecordToJsonObject rs =>
Rec ToJsonField rs -> Rec Identity rs -> Value
recordToJson   forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (rs :: [*]) e.
RMap rs =>
JsonFormatRecord e rs -> ToJsonFormatRecord rs
toJsonFormatRecord   forall a b. (a -> b) -> a -> b
$ JsonFormatRecord e rs
formatRec)
    (forall (rs :: [*]) e.
RecordFromJson rs =>
Rec (FromJsonField e) rs -> Parse e (Rec Identity rs)
recordFromJson forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (rs :: [*]) e.
RMap rs =>
JsonFormatRecord e rs -> FromJsonFormatRecord e rs
fromJsonFormatRecord forall a b. (a -> b) -> a -> b
$ JsonFormatRecord e rs
formatRec)

-- |Class to make a 'JsonFormatRecord' with 'defaultJsonFormat' for each field.
class DefaultJsonFormatRecord rs where
  -- |Produce a 'JsonFormatRecord' for a record with fields @rs@ by using the default 'JsonFormat' for each field in @rs@, as provided by 'DefaultJsonFormat'.
  defaultJsonFormatRecord :: JsonFormatRecord e rs

instance (KnownSymbol s, DefaultJsonFormat a, DefaultJsonFormatRecord rs) => DefaultJsonFormatRecord (s :-> a ': rs) where
  defaultJsonFormatRecord :: forall e. JsonFormatRecord e ((s :-> a) : rs)
defaultJsonFormatRecord = forall a' a e.
(Wrapped a', Unwrapped a' ~ a) =>
JsonFormat e a -> JsonField e a'
field forall a e. DefaultJsonFormat a => JsonFormat e a
defaultJsonFormat forall {u} (a :: u -> *) (r :: u) (rs :: [u]).
a r -> Rec a rs -> Rec a (r : rs)
:& forall (rs :: [*]) e.
DefaultJsonFormatRecord rs =>
JsonFormatRecord e rs
defaultJsonFormatRecord

instance DefaultJsonFormatRecord '[] where
  defaultJsonFormatRecord :: forall e. JsonFormatRecord e '[]
defaultJsonFormatRecord = forall {u} (a :: u -> *). Rec a '[]
RNil