Skip to content

Commit 9d4eaf2

Browse files
author
Poscat
committed
Implement deriveFromJSON for TaggedFlatObject
1 parent 4454d52 commit 9d4eaf2

File tree

1 file changed

+80
-4
lines changed

1 file changed

+80
-4
lines changed

Data/Aeson/TH.hs

Lines changed: 80 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -763,7 +763,8 @@ consFromJSON jc tName opts instTys cons = do
763763
case sumEncoding opts of
764764
TaggedObject {tagFieldName, contentsFieldName} ->
765765
parseObject $ parseTaggedObject tvMap tagFieldName contentsFieldName
766-
TaggedFlatObject {tagFieldName} -> error "unsupported"
766+
TaggedFlatObject {tagFieldName} ->
767+
parseObject $ parseTaggedFlatObject tvMap tagFieldName
767768
UntaggedValue -> error "UntaggedValue: Should be handled already"
768769
ObjectWithSingleField ->
769770
parseObject $ parseObjectWithSingleField tvMap
@@ -814,13 +815,88 @@ consFromJSON jc tName opts instTys cons = do
814815
, noBindS $ parseContents tvMap conKey (Left (valFieldName, obj)) 'conNotFoundFailTaggedObject
815816
]
816817

817-
parseTaggedFlatObject tvMap typFieldName obj = do
818+
parseTaggedFlatObject tvMap tagFieldName obj = do
818819
conKey <- newName "conKey"
819820
doE [ bindS (varP conKey)
820-
(infixApp (varE obj) [|(.:)|] ([|T.pack|] `appE` stringE typFieldName))
821-
, noBindS $ parseContents tvMap conKey (Right obj) 'conNotFoundFailTaggedObject
821+
(infixApp (varE obj) [|(.:)|] ([|T.pack|] `appE` stringE tagFieldName))
822+
, noBindS $
823+
caseE (varE conKey)
824+
[ match wildP
825+
( guardedB $
826+
[ do g <- normalG $ infixApp (varE conKey)
827+
[|(==)|]
828+
([|T.pack|] `appE`
829+
conNameExp opts con)
830+
argTys <- mapM resolveTypeSynonyms (constructorFields con)
831+
let conName = constructorName con
832+
e <- case constructorVariant con of
833+
RecordConstructor fields ->
834+
parseRecord jc tvMap argTys opts tName conName fields obj False
835+
_ ->
836+
parseNumRec tvMap argTys conName obj
837+
return (g, e)
838+
| con <- cons
839+
]
840+
++
841+
[ liftM2 (,)
842+
(normalG [e|otherwise|])
843+
( varE 'conNotFoundFailTaggedObject
844+
`appE` litE (stringL $ show tName)
845+
`appE` listE (map ( litE
846+
. stringL
847+
. constructorTagModifier opts
848+
. nameBase
849+
. constructorName
850+
) cons
851+
)
852+
`appE` ([|T.unpack|] `appE` varE conKey)
853+
)
854+
]
855+
)
856+
[]
857+
]
822858
]
823859

860+
parseNumRec :: TyVarMap
861+
-> [Type]
862+
-> Name
863+
-> Name
864+
-> ExpQ
865+
parseNumRec tvMap argTys conName obj =
866+
(if rejectUnknownFields opts
867+
then infixApp checkUnknownRecords [|(>>)|]
868+
else id) $
869+
if null argTys
870+
then [|pure|] `appE` conE conName
871+
else
872+
foldl' (\a b -> infixApp a [|(<*>)|] b)
873+
(infixApp (conE conName) [|(<$>)|] x)
874+
xs
875+
where
876+
fields = map (show :: Int -> String) $ take (length argTys) [1..]
877+
knownFields = appE [|H.fromList|] $ listE $
878+
map (\knownName -> tupE [appE [|T.pack|] $ litE $ stringL knownName, [|()|]]) fields
879+
checkUnknownRecords =
880+
caseE (appE [|H.keys|] $ infixApp (varE obj) [|H.difference|] knownFields)
881+
[ match (listP []) (normalB [|return ()|]) []
882+
, newName "unknownFields" >>=
883+
\unknownFields -> match (varP unknownFields)
884+
(normalB $ appE [|fail|] $ infixApp
885+
(litE (stringL "Unknown fields: "))
886+
[|(++)|]
887+
(appE [|show|] (varE unknownFields)))
888+
[]
889+
]
890+
x:xs = [ [|lookupField|]
891+
`appE` dispatchParseJSON jc conName tvMap argTy
892+
`appE` litE (stringL $ show tName)
893+
`appE` litE (stringL $ constructorTagModifier opts $ nameBase conName)
894+
`appE` varE obj
895+
`appE` ( [|T.pack|] `appE` stringE field
896+
)
897+
| (field, argTy) <- zip fields argTys
898+
]
899+
824900
parseUntaggedValue tvMap cons' conVal =
825901
foldr1 (\e e' -> infixApp e [|(<|>)|] e')
826902
(map (\x -> parseValue tvMap x conVal) cons')

0 commit comments

Comments
 (0)