Skip to content

Commit 93485e1

Browse files
committed
Add generic JSON decoding
1 parent 3300b67 commit 93485e1

File tree

1 file changed

+43
-0
lines changed

1 file changed

+43
-0
lines changed

src/Data/Argonaut/Decode/Class.purs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,15 @@ import Data.List (List(..), (:), fromFoldable)
1313
import Data.Map as M
1414
import Data.Maybe (maybe, Maybe(..))
1515
import Data.String (CodePoint, codePointAt)
16+
import Data.Symbol (class IsSymbol, SProxy(..), reflectSymbol)
1617
import Data.Traversable (traverse)
1718
import Data.TraversableWithIndex (traverseWithIndex)
1819
import Data.Tuple (Tuple(..))
1920
import Foreign.Object as FO
21+
import Prim.Row as Row
22+
import Prim.RowList as RL
23+
import Record as Record
24+
import Type.Data.RowList (RLProxy(..))
2025

2126
class DecodeJson a where
2227
decodeJson :: Json -> Either String a
@@ -98,3 +103,41 @@ decodeJArray = maybe (Left "Value is not an Array") Right <<< toArray
98103

99104
decodeJObject :: Json -> Either String (FO.Object Json)
100105
decodeJObject = maybe (Left "Value is not an Object") Right <<< toObject
106+
107+
108+
instance decodeRecord :: (GDecodeJson row list, RL.RowToList row list) => DecodeJson (Record row) where
109+
decodeJson json =
110+
case toObject json of
111+
Just object -> gDecodeJson object (RLProxy :: RLProxy list)
112+
Nothing -> Left "Could not convert JSON to object"
113+
114+
class GDecodeJson (row :: # Type) (list :: RL.RowList) | list -> row where
115+
gDecodeJson :: FO.Object Json -> RLProxy list -> Either String (Record row)
116+
117+
instance gDecodeJsonNil :: GDecodeJson () RL.Nil where
118+
gDecodeJson _ _ = Right {}
119+
120+
instance gDecodeJsonCons
121+
:: ( DecodeJson value
122+
, GDecodeJson rowTail tail
123+
, IsSymbol field
124+
, Row.Cons field value rowTail row
125+
, Row.Lacks field rowTail
126+
)
127+
=> GDecodeJson row (RL.Cons field value tail) where
128+
129+
gDecodeJson object _ = do
130+
let sProxy :: SProxy field
131+
sProxy = SProxy
132+
133+
fieldName = reflectSymbol sProxy
134+
135+
rest <- gDecodeJson object (RLProxy :: RLProxy tail)
136+
137+
case FO.lookup fieldName object of
138+
Just jsonVal -> do
139+
val <- decodeJson jsonVal
140+
Right $ Record.insert sProxy val rest
141+
142+
Nothing ->
143+
Left $ "JSON was missing expected field: " <> fieldName

0 commit comments

Comments
 (0)