1
1
module Data.Codec.Argonaut.Sum
2
2
( Encoding (..)
3
3
, FlatEncoding
4
+ , Err
4
5
, class GCases
5
6
, class GFields
6
7
, class GFlatCases
@@ -22,7 +23,6 @@ module Data.Codec.Argonaut.Sum
22
23
23
24
import Prelude
24
25
25
- import Control.Alt ((<|>))
26
26
import Data.Argonaut.Core (Json )
27
27
import Data.Argonaut.Core (Json , fromString ) as J
28
28
import Data.Array (catMaybes )
@@ -138,17 +138,26 @@ sumWith ∷ ∀ r rep a. GCases r rep ⇒ Generic a rep ⇒ Encoding → String
138
138
sumWith encoding name r =
139
139
dimap from to $ codec' decode encode
140
140
where
141
- decode = gCasesDecode encoding r >>> ( lmap $ Named name)
141
+ decode = gCasesDecode encoding r >>> lmap (finalizeError name)
142
142
encode = gCasesEncode encoding r
143
143
144
+ finalizeError ∷ String → Err → JsonDecodeError
145
+ finalizeError name err =
146
+ Named name $
147
+ case err of
148
+ UnmatchedCase → TypeMismatch " No case matched"
149
+ JErr jerr → jerr
150
+
151
+ data Err = UnmatchedCase | JErr JsonDecodeError
152
+
144
153
-- ------------------------------------------------------------------------------
145
154
146
155
class GCases ∷ Row Type → Type → Constraint
147
156
class
148
157
GCases r rep
149
158
where
150
159
gCasesEncode ∷ Encoding → Record r → rep → Json
151
- gCasesDecode ∷ Encoding → Record r → Json → Either JsonDecodeError rep
160
+ gCasesDecode ∷ Encoding → Record r → Json → Either Err rep
152
161
153
162
instance gCasesConstructorNoArgs ∷
154
163
( Row.Cons name Unit () r
@@ -162,7 +171,7 @@ instance gCasesConstructorNoArgs ∷
162
171
in
163
172
encodeSumCase encoding name []
164
173
165
- gCasesDecode ∷ Encoding → Record r → Json → Either JsonDecodeError (Constructor name NoArguments )
174
+ gCasesDecode ∷ Encoding → Record r → Json → Either Err (Constructor name NoArguments )
166
175
gCasesDecode encoding _ json = do
167
176
let name = reflectSymbol @name Proxy ∷ String
168
177
@@ -182,13 +191,13 @@ else instance gCasesConstructorSingleArg ∷
182
191
in
183
192
encodeSumCase encoding name [ CA .encode codec x ]
184
193
185
- gCasesDecode ∷ Encoding → Record r → Json → Either JsonDecodeError (Constructor name (Argument a ))
194
+ gCasesDecode ∷ Encoding → Record r → Json → Either Err (Constructor name (Argument a ))
186
195
gCasesDecode encoding r json = do
187
196
let name = reflectSymbol @name Proxy ∷ String
188
197
189
198
field ← parseSingleField encoding json name ∷ _ Json
190
199
let codec = Record .get (Proxy @name) r ∷ JsonCodec a
191
- result ← CA .decode codec field ∷ _ a
200
+ result ← lmap JErr $ CA .decode codec field ∷ _ a
192
201
pure $ Constructor (Argument result)
193
202
194
203
else instance gCasesConstructorManyArgs ∷
@@ -206,13 +215,13 @@ else instance gCasesConstructorManyArgs ∷
206
215
in
207
216
encodeSumCase encoding name jsons
208
217
209
- gCasesDecode ∷ Encoding → Record r → Json → Either JsonDecodeError (Constructor name args )
218
+ gCasesDecode ∷ Encoding → Record r → Json → Either Err (Constructor name args )
210
219
gCasesDecode encoding r json = do
211
220
let name = reflectSymbol @name Proxy ∷ String
212
221
213
222
jsons ← parseManyFields encoding json name ∷ _ (Array Json )
214
223
let codecs = Record .get (Proxy @name) r ∷ codecs
215
- result ← gFieldsDecode encoding codecs jsons ∷ _ args
224
+ result ← lmap JErr $ gFieldsDecode encoding codecs jsons ∷ _ args
216
225
pure $ Constructor result
217
226
218
227
instance gCasesSum ∷
@@ -236,16 +245,19 @@ instance gCasesSum ∷
236
245
Inl lhs → gCasesEncode encoding r1 lhs
237
246
Inr rhs → gCasesEncode encoding r2 rhs
238
247
239
- gCasesDecode ∷ Encoding → Record r → Json → Either JsonDecodeError (Sum (Constructor name lhs ) rhs )
248
+ gCasesDecode ∷ Encoding → Record r → Json → Either Err (Sum (Constructor name lhs ) rhs )
240
249
gCasesDecode encoding r tagged = do
241
250
let
242
251
codec = Record .get (Proxy @name) r ∷ codec
243
252
r1 = Record .insert (Proxy @name) codec {} ∷ Record r1
244
253
r2 = Record .delete (Proxy @name) r ∷ Record r2
245
254
let
246
- lhs = gCasesDecode encoding r1 tagged ∷ _ (Constructor name lhs )
247
- rhs = gCasesDecode encoding r2 tagged ∷ _ rhs
248
- (Inl <$> lhs) <|> (Inr <$> rhs)
255
+ lhs _ = gCasesDecode encoding r1 tagged ∷ _ (Constructor name lhs )
256
+ rhs _ = gCasesDecode encoding r2 tagged ∷ _ rhs
257
+ case lhs unit of
258
+ Left UnmatchedCase → Inr <$> (rhs unit)
259
+ Left (JErr err) → Left (JErr err)
260
+ Right val → Right (Inl val)
249
261
250
262
-- ------------------------------------------------------------------------------
251
263
@@ -292,97 +304,99 @@ instance gFieldsProduct ∷
292
304
293
305
-- ------------------------------------------------------------------------------
294
306
295
- checkTag ∷ String → Object Json → String → Either JsonDecodeError Unit
307
+ checkTag ∷ String → Object Json → String → Either Err Unit
296
308
checkTag tagKey obj expectedTag = do
297
309
val ←
298
310
( Obj .lookup tagKey obj
299
311
# note (TypeMismatch (" Expecting a tag property `" <> tagKey <> " `" ))
312
+ # lmap JErr
300
313
) ∷ _ Json
301
- tag ← CA .decode CA .string val ∷ _ String
302
- unless (tag == expectedTag)
303
- $ Left
304
- $ TypeMismatch (" Expecting tag `" <> expectedTag <> " `, got `" <> tag <> " `" )
314
+ tag ← CA .decode CA .string val # lmap JErr ∷ _ String
315
+ when (tag /= expectedTag)
316
+ (Left UnmatchedCase )
305
317
306
- parseNoFields ∷ Encoding → Json → String → Either JsonDecodeError Unit
318
+ parseNoFields ∷ Encoding → Json → String → Either Err Unit
307
319
parseNoFields encoding json expectedTagRaw =
308
320
case encoding of
309
321
EncodeNested { mapTag } → do
310
322
let expectedTag = mapTag expectedTagRaw ∷ String
311
- obj ← CA .decode jobject json
323
+ obj ← lmap JErr $ CA .decode jobject json
312
324
val ←
313
- ( Obj .lookup expectedTag obj # note ( TypeMismatch ( " Expecting a property ` " <> expectedTag <> " ` " ))
325
+ ( Obj .lookup expectedTag obj # note UnmatchedCase
314
326
) ∷ _ Json
315
- fields ← CA .decode CA .jarray val ∷ _ (Array Json )
327
+ fields ← lmap JErr $ CA .decode CA .jarray val ∷ _ (Array Json )
316
328
when (fields /= [] )
317
329
$ Left
318
- $ TypeMismatch " Expecting an empty array"
330
+ (JErr $ TypeMismatch " Expecting an empty array" )
331
+ pure unit
319
332
320
333
EncodeTagged { tagKey, valuesKey, omitEmptyArguments, mapTag } → do
321
334
let expectedTag = mapTag expectedTagRaw ∷ String
322
- obj ← CA .decode jobject json
335
+ obj ← lmap JErr $ CA .decode jobject json
323
336
checkTag tagKey obj expectedTag
324
337
when (not omitEmptyArguments) do
325
338
val ←
326
339
( Obj .lookup valuesKey obj
327
- # note (TypeMismatch (" Expecting a value property `" <> valuesKey <> " `" ))
340
+ # note (JErr $ TypeMismatch (" Expecting a value property `" <> valuesKey <> " `" ))
328
341
) ∷ _ Json
329
- fields ← CA .decode CA .jarray val ∷ _ (Array Json )
342
+ fields ← lmap JErr $ CA .decode CA .jarray val ∷ _ (Array Json )
330
343
when (fields /= [] )
331
344
$ Left
332
- $ TypeMismatch " Expecting an empty array"
345
+ (JErr $ TypeMismatch " Expecting an empty array" )
346
+ pure unit
333
347
334
- parseSingleField ∷ Encoding → Json → String → Either JsonDecodeError Json
348
+ parseSingleField ∷ Encoding → Json → String → Either Err Json
335
349
parseSingleField encoding json expectedTagRaw = case encoding of
336
350
EncodeNested { unwrapSingleArguments, mapTag } → do
337
351
let expectedTag = mapTag expectedTagRaw ∷ String
338
- obj ← CA .decode jobject json
352
+ obj ← lmap JErr $ CA .decode jobject json
339
353
val ←
340
- ( Obj .lookup expectedTag obj # note ( TypeMismatch ( " Expecting a property ` " <> expectedTag <> " ` " ))
354
+ ( Obj .lookup expectedTag obj # note UnmatchedCase
341
355
) ∷ _ Json
342
356
if unwrapSingleArguments then
343
357
pure val
344
358
else do
345
- fields ← CA .decode CA .jarray val
359
+ fields ← lmap JErr $ CA .decode CA .jarray val
346
360
case fields of
347
361
[ head ] → pure head
348
- _ → Left $ TypeMismatch " Expecting exactly one element"
362
+ _ → Left $ JErr $ TypeMismatch " Expecting exactly one element"
349
363
350
364
EncodeTagged { tagKey, valuesKey, unwrapSingleArguments, mapTag } → do
351
365
let expectedTag = mapTag expectedTagRaw ∷ String
352
- obj ← CA .decode jobject json
366
+ obj ← lmap JErr $ CA .decode jobject json
353
367
checkTag tagKey obj expectedTag
354
368
val ←
355
369
( Obj .lookup valuesKey obj
356
- # note (TypeMismatch (" Expecting a value property `" <> valuesKey <> " `" ))
370
+ # note (JErr $ TypeMismatch (" Expecting a value property `" <> valuesKey <> " `" ))
357
371
) ∷ _ Json
358
372
if unwrapSingleArguments then
359
373
pure val
360
374
else do
361
- fields ← CA .decode CA .jarray val
375
+ fields ← lmap JErr $ CA .decode CA .jarray val
362
376
case fields of
363
377
[ head ] → pure head
364
- _ → Left $ TypeMismatch " Expecting exactly one element"
378
+ _ → Left $ JErr $ TypeMismatch " Expecting exactly one element"
365
379
366
- parseManyFields ∷ Encoding → Json → String → Either JsonDecodeError (Array Json )
380
+ parseManyFields ∷ Encoding → Json → String → Either Err (Array Json )
367
381
parseManyFields encoding json expectedTagRaw =
368
382
case encoding of
369
383
EncodeNested { mapTag } → do
370
384
let expectedTag = mapTag expectedTagRaw ∷ String
371
- obj ← CA .decode jobject json
385
+ obj ← lmap JErr $ CA .decode jobject json
372
386
val ←
373
- ( Obj .lookup expectedTag obj # note ( TypeMismatch ( " Expecting a property ` " <> expectedTag <> " ` " ))
387
+ ( Obj .lookup expectedTag obj # note UnmatchedCase
374
388
) ∷ _ Json
375
- CA .decode CA .jarray val
389
+ lmap JErr $ CA .decode CA .jarray val
376
390
377
391
EncodeTagged { tagKey, valuesKey, mapTag } → do
378
392
let expectedTag = mapTag expectedTagRaw ∷ String
379
- obj ← CA .decode jobject json
393
+ obj ← lmap JErr $ CA .decode jobject json
380
394
checkTag tagKey obj expectedTag
381
395
val ←
382
396
( Obj .lookup valuesKey obj
383
- # note (TypeMismatch (" Expecting a value property `" <> valuesKey <> " `" ))
397
+ # note (JErr $ TypeMismatch (" Expecting a value property `" <> valuesKey <> " `" ))
384
398
) ∷ _ Json
385
- CA .decode CA .jarray val
399
+ lmap JErr $ CA .decode CA .jarray val
386
400
387
401
encodeSumCase ∷ Encoding → String → Array Json → Json
388
402
encodeSumCase encoding rawTag jsons =
@@ -431,15 +445,15 @@ sumFlatWith ∷ ∀ @tag r rep a. GFlatCases tag r rep ⇒ Generic a rep ⇒ Fla
431
445
sumFlatWith encoding name r =
432
446
dimap from to $ codec' dec enc
433
447
where
434
- dec = gFlatCasesDecode @tag encoding r >>> (lmap $ Named name)
448
+ dec = gFlatCasesDecode @tag encoding r >>> (lmap $ finalizeError name)
435
449
enc = gFlatCasesEncode @tag encoding r
436
450
437
451
class GFlatCases ∷ Symbol → Row Type → Type → Constraint
438
452
class
439
453
GFlatCases tag r rep
440
454
where
441
455
gFlatCasesEncode ∷ FlatEncoding tag → Record r → rep → Json
442
- gFlatCasesDecode ∷ FlatEncoding tag → Record r → Json → Either JsonDecodeError rep
456
+ gFlatCasesDecode ∷ FlatEncoding tag → Record r → Json → Either Err rep
443
457
444
458
instance gFlatCasesConstructorNoArg ∷
445
459
( Row.Cons name Unit () rc
@@ -460,23 +474,20 @@ instance gFlatCasesConstructorNoArg ∷
460
474
in
461
475
CA .encode codecWithTag rcWithTag
462
476
463
- gFlatCasesDecode ∷ FlatEncoding tag → Record rc → Json → Either JsonDecodeError (Constructor name NoArguments )
477
+ gFlatCasesDecode ∷ FlatEncoding tag → Record rc → Json → Either Err (Constructor name NoArguments )
464
478
gFlatCasesDecode { mapTag } _ json = do
465
479
let
466
480
nameRaw = reflectSymbol (Proxy @name) ∷ String
467
481
name = mapTag nameRaw ∷ String
468
- propCodec = CAR .record {} ∷ JPropCodec { }
469
- propCodecWithTag = CA .recordProp (Proxy @tag) CA .string propCodec ∷ JPropCodec (Record rf )
470
- codecWithTag = CA .object (" case " <> name) propCodecWithTag ∷ JsonCodec (Record rf )
471
- r ← CA .decode codecWithTag json ∷ _ (Record rf )
472
- let actualTag = Record .get (Proxy @tag) r ∷ String
482
+ tag = reflectSymbol (Proxy @tag) ∷ String
483
+
484
+ obj ← lmap JErr $ CA .decode jobject json
473
485
474
- when (actualTag /= name)
475
- $ Left
476
- $ TypeMismatch (" Expecting tag `" <> name <> " `, got `" <> actualTag <> " `" )
486
+ checkTag tag obj name
477
487
478
488
pure (Constructor NoArguments )
479
489
490
+
480
491
instance gFlatCasesConstructorSingleArg ∷
481
492
( Row.Cons name (JPropCodec (Record rf )) () rc
482
493
, Row.Lacks tag rf
@@ -497,23 +508,26 @@ instance gFlatCasesConstructorSingleArg ∷
497
508
in
498
509
CA .encode codecWithTag rcWithTag
499
510
500
- gFlatCasesDecode ∷ FlatEncoding tag → Record rc → Json → Either JsonDecodeError (Constructor name (Argument (Record rf )))
511
+
512
+ gFlatCasesDecode ∷ FlatEncoding tag → Record rc → Json → Either Err (Constructor name (Argument (Record rf )))
501
513
gFlatCasesDecode { mapTag } rc json = do
502
514
let
503
515
nameRaw = reflectSymbol (Proxy @name) ∷ String
504
516
name = mapTag nameRaw ∷ String
517
+ tag = reflectSymbol (Proxy @tag) ∷ String
518
+
519
+
520
+ obj ← lmap JErr $ CA .decode jobject json
521
+
522
+ checkTag tag obj name
523
+
524
+ let
505
525
propCodec = Record .get (Proxy @name) rc ∷ JPropCodec (Record rf )
506
- propCodecWithTag = CA .recordProp (Proxy @tag) CA .string propCodec ∷ JPropCodec (Record rf' )
507
- codecWithTag = CA .object (" case " <> name) propCodecWithTag ∷ JsonCodec (Record rf' )
508
- r ← CA .decode codecWithTag json ∷ _ (Record rf' )
526
+ codec = CA .object (" case " <> name) propCodec ∷ JsonCodec (Record rf )
509
527
510
- let actualTag = Record .get (Proxy @tag) r ∷ String
511
- when (actualTag /= name)
512
- $ Left
513
- $ TypeMismatch (" Expecting tag `" <> name <> " `, got `" <> actualTag <> " `" )
528
+ r ← lmap JErr $ CA .decode codec json ∷ _ (Record rf )
514
529
515
- let r' = Record .delete (Proxy @tag) r ∷ Record rf
516
- pure (Constructor (Argument r'))
530
+ pure (Constructor (Argument r))
517
531
518
532
instance gFlatCasesSum ∷
519
533
( GFlatCases tag r1 (Constructor name lhs )
@@ -536,16 +550,19 @@ instance gFlatCasesSum ∷
536
550
Inl lhs → gFlatCasesEncode @tag encoding r1 lhs
537
551
Inr rhs → gFlatCasesEncode @tag encoding r2 rhs
538
552
539
- gFlatCasesDecode ∷ FlatEncoding tag → Record r → Json → Either JsonDecodeError (Sum (Constructor name lhs ) rhs )
553
+ gFlatCasesDecode ∷ FlatEncoding tag -> Record r → Json → Either Err (Sum (Constructor name lhs ) rhs )
540
554
gFlatCasesDecode encoding r tagged = do
541
555
let
542
556
codec = Record .get (Proxy @name) r ∷ codec
543
557
r1 = Record .insert (Proxy @name) codec {} ∷ Record r1
544
558
r2 = Record .delete (Proxy @name) r ∷ Record r2
545
559
let
546
- lhs = gFlatCasesDecode @tag encoding r1 tagged ∷ _ (Constructor name lhs )
547
- rhs = gFlatCasesDecode @tag encoding r2 tagged ∷ _ rhs
548
- (Inl <$> lhs) <|> (Inr <$> rhs)
560
+ lhs _ = gFlatCasesDecode @tag encoding r1 tagged ∷ _ (Constructor name lhs )
561
+ rhs _ = gFlatCasesDecode @tag encoding r2 tagged ∷ _ rhs
562
+ case lhs unit of
563
+ Left UnmatchedCase → Inr <$> rhs unit
564
+ Left (JErr err) → Left (JErr err)
565
+ Right val → Right (Inl val)
549
566
550
567
-- ------------------------------------------------------------------------------
551
568
0 commit comments