-- | -- This module exports instances of 'ToJSON' for all record types. module Record.Aeson where import BasePrelude import Record.Types import Record.Lens import Data.Aeson.Types import GHC.TypeLits import Language.Haskell.TH import Record.Aeson.TH -- -- Produce something in the spirit of the following: -- -- instance (KnownSymbol n1, KnownSymbol n2, ToJSON v1, ToJSON v2) => ToJSON (Record2 n1 v1 n2 v2) where -- toJSON x = -- object pairs -- where -- pairs = -- [ -- (undefined :: FieldName n1) & \n -> (fromString (symbolVal n), toJSON (view (fieldLens n) x)), -- (undefined :: FieldName n2) & \n -> (fromString (symbolVal n), toJSON (view (fieldLens n) x)) -- ] return $ do arity <- [1 .. 24] return $ let recordName = mkName $ showString "Record" $ show arity arityNumbers = enumFromTo 1 arity fieldNameVarNames = mkName . showString "n" . show <$> arityNumbers valueVarNames = mkName . showString "v" . show <$> arityNumbers instanceDec = InstanceD constraints headType decs where constraints = knownSymbolConstraints <> toJSONConstraints where knownSymbolConstraints = do varName <- fieldNameVarNames return $ mkClassP ''KnownSymbol [(VarT varName)] toJSONConstraints = do varName <- valueVarNames return $ mkClassP ''ToJSON [(VarT varName)] headType = AppT (ConT ''ToJSON) $ foldl' AppT (ConT recordName) $ map VarT $ interlace fieldNameVarNames valueVarNames where interlace a b = join (zipWith (\a b -> [a, b]) a b) decs = [toJSONDec] where toJSONDec = FunD 'toJSON [clause] where clause = Clause [pat] body [] where pat = ConP recordName varPats where varPats = map VarP valueVarNames body = NormalB exp where exp = AppE (VarE 'object) $ ListE $ do (valueVarName, fieldNameVarName) <- zip valueVarNames fieldNameVarNames let labelExp = AppE (VarE 'fromString) $ AppE (VarE 'symbolVal) $ SigE (VarE 'undefined) $ AppT (ConT ''FieldName) $ VarT fieldNameVarName valueExp = AppE (VarE 'toJSON) $ VarE valueVarName return $ TupE $ [labelExp, valueExp] in instanceDec