Skip to content

Commit 63a9679

Browse files
committed
Refactor errors
1 parent 368fc25 commit 63a9679

File tree

1 file changed

+93
-73
lines changed

1 file changed

+93
-73
lines changed

src/Data/Codec/Argonaut/Sum.purs

Lines changed: 93 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
11
module 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

2424
import Prelude
@@ -36,6 +36,7 @@ import Data.Codec.Argonaut as CA
3636
import Data.Codec.Argonaut.Record as CAR
3737
import Data.Either (Either(..), note)
3838
import Data.Generic.Rep (class Generic, Argument(..), Constructor(..), NoArguments(..), Product(..), Sum(..), from, to)
39+
import Data.Int (Parity)
3940
import Data.Maybe (Maybe(..), maybe)
4041
import Data.Profunctor (dimap)
4142
import Data.Symbol (class IsSymbol, reflectSymbol)
@@ -135,17 +136,26 @@ sumWith ∷ ∀ r rep a. GCases r rep ⇒ Generic a rep ⇒ Encoding → String
135136
sumWith 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+
NoCaseTypeMismatch "No case matched"
147+
JErr err → err
148+
149+
data Err = NoCase | JErr JsonDecodeError
150+
141151
--------------------------------------------------------------------------------
142152

143153
class GCasesRow Type Type Constraint
144154
class
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

150160
instance 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

191201
else 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

215225
instance 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 NoCaseInr <$> (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
293306
checkTag 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
304318
parseNoFields 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
330346
parseSingleField 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)
360376
parseManyFields 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

378395
encodeSumCase Encoding String Array Json Json
379396
encodeSumCase encoding tag jsons =
@@ -412,19 +429,19 @@ defaultFlatEncoding = { tag: Proxy }
412429
sumFlat r rep a. GFlatCases "tag" r rep Generic a rep String Record r JsonCodec a
413430
sumFlat = 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
416433
sumFlatWith _ 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

422439
class GFlatCasesSymbol Row Type Type Constraint
423440
class
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

429446
instance 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 NoCaseInr <$> 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

Comments
 (0)