11module Data.Codec.Argonaut.Sum
2- ( Encoding (..)
3- , FlatEncoding
4- , class GCases
5- , class GFields
6- , class GFlatCases
7- , defaultEncoding
8- , defaultFlatEncoding
9- , enumSum
10- , gCasesDecode
11- , gCasesEncode
12- , gFieldsDecode
13- , gFieldsEncode
14- , gFlatCasesDecode
15- , gFlatCasesEncode
16- , sum
17- , sumFlat
18- , sumFlatWith
19- , sumWith
20- , taggedSum
21- )
2+ -- ( Encoding(..)
3+ -- , FlatEncoding
4+ -- , class GCases
5+ -- , class GFields
6+ -- , class GFlatCases
7+ -- , defaultEncoding
8+ -- , defaultFlatEncoding
9+ -- , enumSum
10+ -- , gCasesDecode
11+ -- , gCasesEncode
12+ -- , gFieldsDecode
13+ -- , gFieldsEncode
14+ -- , gFlatCasesDecode
15+ -- , gFlatCasesEncode
16+ -- , sum
17+ -- , sumFlat
18+ -- , sumFlatWith
19+ -- , sumWith
20+ -- , taggedSum
21+ -- )
2222 where
2323
2424import Prelude
@@ -36,6 +36,7 @@ import Data.Codec.Argonaut as CA
3636import Data.Codec.Argonaut.Record as CAR
3737import Data.Either (Either (..), note )
3838import Data.Generic.Rep (class Generic , Argument (..), Constructor (..), NoArguments (..), Product (..), Sum (..), from , to )
39+ import Data.Int (Parity )
3940import Data.Maybe (Maybe (..), maybe )
4041import Data.Profunctor (dimap )
4142import Data.Symbol (class IsSymbol , reflectSymbol )
@@ -135,17 +136,26 @@ sumWith ∷ ∀ r rep a. GCases r rep ⇒ Generic a rep ⇒ Encoding → String
135136sumWith encoding name r =
136137 dimap from to $ codec' decode encode
137138 where
138- decode = gCasesDecode encoding r >>> ( lmap $ Named name)
139+ decode = gCasesDecode encoding r >>> lmap (finalizeError name)
139140 encode = gCasesEncode encoding r
140141
142+ finalizeError ∷ String → Err → JsonDecodeError
143+ finalizeError name err =
144+ Named name $
145+ case err of
146+ NoCase → TypeMismatch " No case matched"
147+ JErr err → err
148+
149+ data Err = NoCase | JErr JsonDecodeError
150+
141151-- ------------------------------------------------------------------------------
142152
143153class GCases ∷ Row Type → Type → Constraint
144154class
145155 GCases r rep
146156 where
147157 gCasesEncode ∷ Encoding → Record r → rep → Json
148- gCasesDecode ∷ Encoding → Record r → Json → Either JsonDecodeError rep
158+ gCasesDecode ∷ Encoding → Record r → Json → Either Err rep
149159
150160instance gCasesConstructorNoArgs ∷
151161 ( Row.Cons name Unit () r
@@ -159,7 +169,7 @@ instance gCasesConstructorNoArgs ∷
159169 in
160170 encodeSumCase encoding name []
161171
162- gCasesDecode ∷ Encoding → Record r → Json → Either JsonDecodeError (Constructor name NoArguments )
172+ gCasesDecode ∷ Encoding → Record r → Json → Either Err (Constructor name NoArguments )
163173 gCasesDecode encoding _ json = do
164174 let name = reflectSymbol @name Proxy ∷ String
165175
@@ -179,13 +189,13 @@ else instance gCasesConstructorSingleArg ∷
179189 in
180190 encodeSumCase encoding name [ CA .encode codec x ]
181191
182- gCasesDecode ∷ Encoding → Record r → Json → Either JsonDecodeError (Constructor name (Argument a ))
192+ gCasesDecode ∷ Encoding → Record r → Json → Either Err (Constructor name (Argument a ))
183193 gCasesDecode encoding r json = do
184194 let name = reflectSymbol @name Proxy ∷ String
185195
186196 field ← parseSingleField encoding json name ∷ _ Json
187197 let codec = Record .get (Proxy @name) r ∷ JsonCodec a
188- result ← CA .decode codec field ∷ _ a
198+ result ← lmap JErr $ CA .decode codec field ∷ _ a
189199 pure $ Constructor (Argument result)
190200
191201else instance gCasesConstructorManyArgs ∷
@@ -203,13 +213,13 @@ else instance gCasesConstructorManyArgs ∷
203213 in
204214 encodeSumCase encoding name jsons
205215
206- gCasesDecode ∷ Encoding → Record r → Json → Either JsonDecodeError (Constructor name args )
216+ gCasesDecode ∷ Encoding → Record r → Json → Either Err (Constructor name args )
207217 gCasesDecode encoding r json = do
208218 let name = reflectSymbol @name Proxy ∷ String
209219
210220 jsons ← parseManyFields encoding json name ∷ _ (Array Json )
211221 let codecs = Record .get (Proxy @name) r ∷ codecs
212- result ← gFieldsDecode encoding codecs jsons ∷ _ args
222+ result ← lmap JErr $ gFieldsDecode encoding codecs jsons ∷ _ args
213223 pure $ Constructor result
214224
215225instance gCasesSum ∷
@@ -233,16 +243,19 @@ instance gCasesSum ∷
233243 Inl lhs → gCasesEncode encoding r1 lhs
234244 Inr rhs → gCasesEncode encoding r2 rhs
235245
236- gCasesDecode ∷ Encoding → Record r → Json → Either JsonDecodeError (Sum (Constructor name lhs ) rhs )
246+ gCasesDecode ∷ Encoding → Record r → Json → Either Err (Sum (Constructor name lhs ) rhs )
237247 gCasesDecode encoding r tagged = do
238248 let
239249 codec = Record .get (Proxy @name) r ∷ codec
240250 r1 = Record .insert (Proxy @name) codec {} ∷ Record r1
241251 r2 = Record .delete (Proxy @name) r ∷ Record r2
242252 let
243- lhs = gCasesDecode encoding r1 tagged ∷ _ (Constructor name lhs )
244- rhs = gCasesDecode encoding r2 tagged ∷ _ rhs
245- (Inl <$> lhs) <|> (Inr <$> rhs)
253+ lhs _ = gCasesDecode encoding r1 tagged ∷ _ (Constructor name lhs )
254+ rhs _ = gCasesDecode encoding r2 tagged ∷ _ rhs
255+ case lhs unit of
256+ Left NoCase → Inr <$> (rhs unit)
257+ Left (JErr err) → Left (JErr err)
258+ Right val → Right (Inl val)
246259
247260-- ------------------------------------------------------------------------------
248261
@@ -289,91 +302,95 @@ instance gFieldsProduct ∷
289302
290303-- ------------------------------------------------------------------------------
291304
292- checkTag ∷ String → Object Json → String → Either JsonDecodeError Unit
305+ checkTag ∷ String → Object Json → String → Either Err Unit
293306checkTag tagKey obj expectedTag = do
294307 val ←
295308 ( Obj .lookup tagKey obj
296309 # note (TypeMismatch (" Expecting a tag property `" <> tagKey <> " `" ))
310+ # lmap JErr
297311 ) ∷ _ Json
298- tag ← CA .decode CA .string val ∷ _ String
299- unless (tag = = expectedTag)
312+ tag ← CA .decode CA .string val # lmap JErr ∷ _ String
313+ when (tag / = expectedTag)
300314 $ Left
301- $ TypeMismatch ( " Expecting tag ` " <> expectedTag <> " `, got ` " <> tag <> " ` " )
315+ $ NoCase
302316
303- parseNoFields ∷ Encoding → Json → String → Either JsonDecodeError Unit
317+ parseNoFields ∷ Encoding → Json → String → Either Err Unit
304318parseNoFields encoding json expectedTag =
305319 case encoding of
306320 EncodeNested {} → do
307- obj ← CA .decode jobject json
321+ obj ← lmap JErr $ CA .decode jobject json
308322 val ←
309- ( Obj .lookup expectedTag obj # note (TypeMismatch (" Expecting a property `" <> expectedTag <> " `" ))
323+ ( Obj .lookup expectedTag obj # note (JErr $ TypeMismatch (" Expecting a property `" <> expectedTag <> " `" ))
310324 ) ∷ _ Json
311- fields ← CA .decode CA .jarray val ∷ _ (Array Json )
325+ fields ← lmap JErr $ CA .decode CA .jarray val ∷ _ (Array Json )
312326 when (fields /= [] )
313327 $ Left
314- $ TypeMismatch " Expecting an empty array"
328+ (JErr $ TypeMismatch " Expecting an empty array" )
329+ pure unit
315330
316331 EncodeTagged { tagKey, valuesKey, omitEmptyArguments } → do
317- obj ← CA .decode jobject json
332+ obj ← lmap JErr $ CA .decode jobject json
318333 checkTag tagKey obj expectedTag
319334 when (not omitEmptyArguments) do
320335 val ←
321336 ( Obj .lookup valuesKey obj
322- # note (TypeMismatch (" Expecting a value property `" <> valuesKey <> " `" ))
337+ # note (JErr $ TypeMismatch (" Expecting a value property `" <> valuesKey <> " `" ))
323338 ) ∷ _ Json
324- fields ← CA .decode CA .jarray val ∷ _ (Array Json )
339+ fields ← lmap JErr $ CA .decode CA .jarray val ∷ _ (Array Json )
325340 when (fields /= [] )
326341 $ Left
327- $ TypeMismatch " Expecting an empty array"
342+ (JErr $ TypeMismatch " Expecting an empty array" )
343+ pure unit
328344
329- parseSingleField ∷ Encoding → Json → String → Either JsonDecodeError Json
345+ parseSingleField ∷ Encoding → Json → String → Either Err Json
330346parseSingleField encoding json expectedTag = case encoding of
331347 EncodeNested { unwrapSingleArguments } → do
332- obj ← CA .decode jobject json
348+ obj ← lmap JErr $ CA .decode jobject json
333349 val ←
334- ( Obj .lookup expectedTag obj # note (TypeMismatch (" Expecting a property `" <> expectedTag <> " `" ))
350+ ( Obj .lookup expectedTag obj # note (JErr $ TypeMismatch (" Expecting a property `" <> expectedTag <> " `" ))
335351 ) ∷ _ Json
336352 if unwrapSingleArguments then
337353 pure val
338354 else do
339- fields ← CA .decode CA .jarray val
355+ fields ← lmap JErr $ CA .decode CA .jarray val
340356 case fields of
341357 [ head ] → pure head
342- _ → Left $ TypeMismatch " Expecting exactly one element"
358+ _ → Left $ JErr $ TypeMismatch " Expecting exactly one element"
343359
344360 EncodeTagged { tagKey, valuesKey, unwrapSingleArguments } → do
345- obj ← CA .decode jobject json
361+ obj ← lmap JErr $ CA .decode jobject json
346362 checkTag tagKey obj expectedTag
347363 val ←
348364 ( Obj .lookup valuesKey obj
349- # note (TypeMismatch (" Expecting a value property `" <> valuesKey <> " `" ))
365+ # note (JErr $ TypeMismatch (" Expecting a value property `" <> valuesKey <> " `" ))
350366 ) ∷ _ Json
351367 if unwrapSingleArguments then
352368 pure val
353369 else do
354- fields ← CA .decode CA .jarray val
370+ fields ← lmap JErr $ CA .decode CA .jarray val
355371 case fields of
356372 [ head ] → pure head
357- _ → Left $ TypeMismatch " Expecting exactly one element"
373+ _ → Left $ JErr $ TypeMismatch " Expecting exactly one element"
358374
359- parseManyFields ∷ Encoding → Json → String → Either JsonDecodeError (Array Json )
375+ parseManyFields ∷ Encoding → Json → String → Either Err (Array Json )
360376parseManyFields encoding json expectedTag =
361377 case encoding of
362378 EncodeNested {} → do
363- obj ← CA .decode jobject json
379+ obj ← lmap JErr $ CA .decode jobject json
364380 val ←
365- ( Obj .lookup expectedTag obj # note (TypeMismatch (" Expecting a property `" <> expectedTag <> " `" ))
381+ ( Obj .lookup expectedTag obj
382+ # note (JErr $ TypeMismatch (" Expecting a property `" <> expectedTag <> " `" ))
366383 ) ∷ _ Json
367- CA .decode CA .jarray val
384+ lmap JErr $ CA .decode CA .jarray val
368385
369386 EncodeTagged { tagKey, valuesKey } → do
370- obj ← CA .decode jobject json
387+ obj ← lmap JErr $ CA .decode jobject json
371388 checkTag tagKey obj expectedTag
372389 val ←
373390 ( Obj .lookup valuesKey obj
374- # note (TypeMismatch (" Expecting a value property `" <> valuesKey <> " `" ))
391+ # note (JErr $ TypeMismatch (" Expecting a value property `" <> valuesKey <> " `" ))
375392 ) ∷ _ Json
376- CA .decode CA .jarray val
393+ lmap JErr $ CA .decode CA .jarray val
377394
378395encodeSumCase ∷ Encoding → String → Array Json → Json
379396encodeSumCase encoding tag jsons =
@@ -412,19 +429,19 @@ defaultFlatEncoding = { tag: Proxy }
412429sumFlat ∷ ∀ r rep a . GFlatCases " tag" r rep ⇒ Generic a rep ⇒ String → Record r → JsonCodec a
413430sumFlat = sumFlatWith defaultFlatEncoding
414431
415- sumFlatWith ∷ ∀ @tag r rep a . GFlatCases tag r rep ⇒ Generic a rep ⇒ FlatEncoding tag -> String → Record r → JsonCodec a
432+ sumFlatWith ∷ ∀ @tag r rep a . GFlatCases tag r rep ⇒ Generic a rep ⇒ FlatEncoding tag → String → Record r → JsonCodec a
416433sumFlatWith _ name r =
417434 dimap from to $ codec' dec enc
418435 where
419- dec = gFlatCasesDecode @tag r >>> (lmap $ Named name)
436+ dec = gFlatCasesDecode @tag r >>> (lmap $ finalizeError name)
420437 enc = gFlatCasesEncode @tag r
421438
422439class GFlatCases ∷ Symbol → Row Type → Type → Constraint
423440class
424441 GFlatCases tag r rep
425442 where
426443 gFlatCasesEncode ∷ Record r → rep → Json
427- gFlatCasesDecode ∷ Record r → Json → Either JsonDecodeError rep
444+ gFlatCasesDecode ∷ Record r → Json → Either Err rep
428445
429446instance gFlatCasesConstructorNoArg ∷
430447 ( Row.Cons name Unit () rc
@@ -444,20 +461,20 @@ instance gFlatCasesConstructorNoArg ∷
444461 in
445462 CA .encode codecWithTag rcWithTag
446463
447- gFlatCasesDecode ∷ Record rc → Json → Either JsonDecodeError (Constructor name NoArguments )
464+ gFlatCasesDecode ∷ Record rc → Json → Either Err (Constructor name NoArguments )
448465 gFlatCasesDecode _ json = do
449466 let
450467 name = reflectSymbol (Proxy @name) ∷ String
451468
452469 propCodec = CAR .record {} ∷ JPropCodec { }
453470 propCodecWithTag = CA .recordProp (Proxy @tag) CA .string propCodec ∷ JPropCodec (Record rf )
454471 codecWithTag = CA .object (" case " <> name) propCodecWithTag ∷ JsonCodec (Record rf )
455- r ← CA .decode codecWithTag json ∷ _ (Record rf )
472+ r ← lmap JErr $ CA .decode codecWithTag json ∷ _ (Record rf )
456473 let actualTag = Record .get (Proxy @tag) r ∷ String
457474
458475 when (actualTag /= name)
459476 $ Left
460- $ TypeMismatch (" Expecting tag `" <> name <> " `, got `" <> actualTag <> " `" )
477+ ( JErr $ TypeMismatch (" Expecting tag `" <> name <> " `, got `" <> actualTag <> " `" ) )
461478
462479 pure (Constructor NoArguments )
463480
@@ -480,19 +497,19 @@ instance gFlatCasesConstructorSingleArg ∷
480497 in
481498 CA .encode codecWithTag rcWithTag
482499
483- gFlatCasesDecode ∷ Record rc → Json → Either JsonDecodeError (Constructor name (Argument (Record rf )))
500+ gFlatCasesDecode ∷ Record rc → Json → Either Err (Constructor name (Argument (Record rf )))
484501 gFlatCasesDecode rc json = do
485502 let
486503 name = reflectSymbol (Proxy @name) ∷ String
487504 propCodec = Record .get (Proxy @name) rc ∷ JPropCodec (Record rf )
488505 propCodecWithTag = CA .recordProp (Proxy @tag) CA .string propCodec ∷ JPropCodec (Record rf' )
489506 codecWithTag = CA .object (" case " <> name) propCodecWithTag ∷ JsonCodec (Record rf' )
490- r ← CA .decode codecWithTag json ∷ _ (Record rf' )
507+ r ← lmap JErr $ CA .decode codecWithTag json ∷ _ (Record rf' )
491508
492509 let actualTag = Record .get (Proxy @tag) r ∷ String
493510 when (actualTag /= name)
494511 $ Left
495- $ TypeMismatch (" Expecting tag `" <> name <> " `, got `" <> actualTag <> " `" )
512+ ( JErr $ TypeMismatch (" Expecting tag `" <> name <> " `, got `" <> actualTag <> " `" ) )
496513
497514 let r' = Record .delete (Proxy @tag) r ∷ Record rf
498515 pure (Constructor (Argument r'))
@@ -518,16 +535,19 @@ instance gFlatCasesSum ∷
518535 Inl lhs → gFlatCasesEncode @tag r1 lhs
519536 Inr rhs → gFlatCasesEncode @tag r2 rhs
520537
521- gFlatCasesDecode ∷ Record r → Json → Either JsonDecodeError (Sum (Constructor name lhs ) rhs )
538+ gFlatCasesDecode ∷ Record r → Json → Either Err (Sum (Constructor name lhs ) rhs )
522539 gFlatCasesDecode r tagged = do
523540 let
524541 codec = Record .get (Proxy @name) r ∷ codec
525542 r1 = Record .insert (Proxy @name) codec {} ∷ Record r1
526543 r2 = Record .delete (Proxy @name) r ∷ Record r2
527544 let
528- lhs = gFlatCasesDecode @tag r1 tagged ∷ _ (Constructor name lhs )
529- rhs = gFlatCasesDecode @tag r2 tagged ∷ _ rhs
530- (Inl <$> lhs) <|> (Inr <$> rhs)
545+ lhs _ = gFlatCasesDecode @tag r1 tagged ∷ _ (Constructor name lhs )
546+ rhs _ = gFlatCasesDecode @tag r2 tagged ∷ _ rhs
547+ case lhs unit of
548+ Left NoCase → Inr <$> rhs unit
549+ Left (JErr err) → Left (JErr err)
550+ Right val → Right (Inl val)
531551
532552-- | Same as `Record.delete` but deleting only happens at the type level
533553-- | and the value is left untouched.
0 commit comments