1
1
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
+ -- )
22
22
where
23
23
24
24
import Prelude
@@ -36,6 +36,7 @@ import Data.Codec.Argonaut as CA
36
36
import Data.Codec.Argonaut.Record as CAR
37
37
import Data.Either (Either (..), note )
38
38
import Data.Generic.Rep (class Generic , Argument (..), Constructor (..), NoArguments (..), Product (..), Sum (..), from , to )
39
+ import Data.Int (Parity )
39
40
import Data.Maybe (Maybe (..), maybe )
40
41
import Data.Profunctor (dimap )
41
42
import Data.Symbol (class IsSymbol , reflectSymbol )
@@ -135,17 +136,26 @@ sumWith ∷ ∀ r rep a. GCases r rep ⇒ Generic a rep ⇒ Encoding → String
135
136
sumWith encoding name r =
136
137
dimap from to $ codec' decode encode
137
138
where
138
- decode = gCasesDecode encoding r >>> ( lmap $ Named name)
139
+ decode = gCasesDecode encoding r >>> lmap (finalizeError name)
139
140
encode = gCasesEncode encoding r
140
141
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
+
141
151
-- ------------------------------------------------------------------------------
142
152
143
153
class GCases ∷ Row Type → Type → Constraint
144
154
class
145
155
GCases r rep
146
156
where
147
157
gCasesEncode ∷ Encoding → Record r → rep → Json
148
- gCasesDecode ∷ Encoding → Record r → Json → Either JsonDecodeError rep
158
+ gCasesDecode ∷ Encoding → Record r → Json → Either Err rep
149
159
150
160
instance gCasesConstructorNoArgs ∷
151
161
( Row.Cons name Unit () r
@@ -159,7 +169,7 @@ instance gCasesConstructorNoArgs ∷
159
169
in
160
170
encodeSumCase encoding name []
161
171
162
- gCasesDecode ∷ Encoding → Record r → Json → Either JsonDecodeError (Constructor name NoArguments )
172
+ gCasesDecode ∷ Encoding → Record r → Json → Either Err (Constructor name NoArguments )
163
173
gCasesDecode encoding _ json = do
164
174
let name = reflectSymbol @name Proxy ∷ String
165
175
@@ -179,13 +189,13 @@ else instance gCasesConstructorSingleArg ∷
179
189
in
180
190
encodeSumCase encoding name [ CA .encode codec x ]
181
191
182
- gCasesDecode ∷ Encoding → Record r → Json → Either JsonDecodeError (Constructor name (Argument a ))
192
+ gCasesDecode ∷ Encoding → Record r → Json → Either Err (Constructor name (Argument a ))
183
193
gCasesDecode encoding r json = do
184
194
let name = reflectSymbol @name Proxy ∷ String
185
195
186
196
field ← parseSingleField encoding json name ∷ _ Json
187
197
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
189
199
pure $ Constructor (Argument result)
190
200
191
201
else instance gCasesConstructorManyArgs ∷
@@ -203,13 +213,13 @@ else instance gCasesConstructorManyArgs ∷
203
213
in
204
214
encodeSumCase encoding name jsons
205
215
206
- gCasesDecode ∷ Encoding → Record r → Json → Either JsonDecodeError (Constructor name args )
216
+ gCasesDecode ∷ Encoding → Record r → Json → Either Err (Constructor name args )
207
217
gCasesDecode encoding r json = do
208
218
let name = reflectSymbol @name Proxy ∷ String
209
219
210
220
jsons ← parseManyFields encoding json name ∷ _ (Array Json )
211
221
let codecs = Record .get (Proxy @name) r ∷ codecs
212
- result ← gFieldsDecode encoding codecs jsons ∷ _ args
222
+ result ← lmap JErr $ gFieldsDecode encoding codecs jsons ∷ _ args
213
223
pure $ Constructor result
214
224
215
225
instance gCasesSum ∷
@@ -233,16 +243,19 @@ instance gCasesSum ∷
233
243
Inl lhs → gCasesEncode encoding r1 lhs
234
244
Inr rhs → gCasesEncode encoding r2 rhs
235
245
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 )
237
247
gCasesDecode encoding r tagged = do
238
248
let
239
249
codec = Record .get (Proxy @name) r ∷ codec
240
250
r1 = Record .insert (Proxy @name) codec {} ∷ Record r1
241
251
r2 = Record .delete (Proxy @name) r ∷ Record r2
242
252
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)
246
259
247
260
-- ------------------------------------------------------------------------------
248
261
@@ -289,91 +302,95 @@ instance gFieldsProduct ∷
289
302
290
303
-- ------------------------------------------------------------------------------
291
304
292
- checkTag ∷ String → Object Json → String → Either JsonDecodeError Unit
305
+ checkTag ∷ String → Object Json → String → Either Err Unit
293
306
checkTag tagKey obj expectedTag = do
294
307
val ←
295
308
( Obj .lookup tagKey obj
296
309
# note (TypeMismatch (" Expecting a tag property `" <> tagKey <> " `" ))
310
+ # lmap JErr
297
311
) ∷ _ 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)
300
314
$ Left
301
- $ TypeMismatch ( " Expecting tag ` " <> expectedTag <> " `, got ` " <> tag <> " ` " )
315
+ $ NoCase
302
316
303
- parseNoFields ∷ Encoding → Json → String → Either JsonDecodeError Unit
317
+ parseNoFields ∷ Encoding → Json → String → Either Err Unit
304
318
parseNoFields encoding json expectedTag =
305
319
case encoding of
306
320
EncodeNested {} → do
307
- obj ← CA .decode jobject json
321
+ obj ← lmap JErr $ CA .decode jobject json
308
322
val ←
309
- ( Obj .lookup expectedTag obj # note (TypeMismatch (" Expecting a property `" <> expectedTag <> " `" ))
323
+ ( Obj .lookup expectedTag obj # note (JErr $ TypeMismatch (" Expecting a property `" <> expectedTag <> " `" ))
310
324
) ∷ _ Json
311
- fields ← CA .decode CA .jarray val ∷ _ (Array Json )
325
+ fields ← lmap JErr $ CA .decode CA .jarray val ∷ _ (Array Json )
312
326
when (fields /= [] )
313
327
$ Left
314
- $ TypeMismatch " Expecting an empty array"
328
+ (JErr $ TypeMismatch " Expecting an empty array" )
329
+ pure unit
315
330
316
331
EncodeTagged { tagKey, valuesKey, omitEmptyArguments } → do
317
- obj ← CA .decode jobject json
332
+ obj ← lmap JErr $ CA .decode jobject json
318
333
checkTag tagKey obj expectedTag
319
334
when (not omitEmptyArguments) do
320
335
val ←
321
336
( Obj .lookup valuesKey obj
322
- # note (TypeMismatch (" Expecting a value property `" <> valuesKey <> " `" ))
337
+ # note (JErr $ TypeMismatch (" Expecting a value property `" <> valuesKey <> " `" ))
323
338
) ∷ _ Json
324
- fields ← CA .decode CA .jarray val ∷ _ (Array Json )
339
+ fields ← lmap JErr $ CA .decode CA .jarray val ∷ _ (Array Json )
325
340
when (fields /= [] )
326
341
$ Left
327
- $ TypeMismatch " Expecting an empty array"
342
+ (JErr $ TypeMismatch " Expecting an empty array" )
343
+ pure unit
328
344
329
- parseSingleField ∷ Encoding → Json → String → Either JsonDecodeError Json
345
+ parseSingleField ∷ Encoding → Json → String → Either Err Json
330
346
parseSingleField encoding json expectedTag = case encoding of
331
347
EncodeNested { unwrapSingleArguments } → do
332
- obj ← CA .decode jobject json
348
+ obj ← lmap JErr $ CA .decode jobject json
333
349
val ←
334
- ( Obj .lookup expectedTag obj # note (TypeMismatch (" Expecting a property `" <> expectedTag <> " `" ))
350
+ ( Obj .lookup expectedTag obj # note (JErr $ TypeMismatch (" Expecting a property `" <> expectedTag <> " `" ))
335
351
) ∷ _ Json
336
352
if unwrapSingleArguments then
337
353
pure val
338
354
else do
339
- fields ← CA .decode CA .jarray val
355
+ fields ← lmap JErr $ CA .decode CA .jarray val
340
356
case fields of
341
357
[ head ] → pure head
342
- _ → Left $ TypeMismatch " Expecting exactly one element"
358
+ _ → Left $ JErr $ TypeMismatch " Expecting exactly one element"
343
359
344
360
EncodeTagged { tagKey, valuesKey, unwrapSingleArguments } → do
345
- obj ← CA .decode jobject json
361
+ obj ← lmap JErr $ CA .decode jobject json
346
362
checkTag tagKey obj expectedTag
347
363
val ←
348
364
( Obj .lookup valuesKey obj
349
- # note (TypeMismatch (" Expecting a value property `" <> valuesKey <> " `" ))
365
+ # note (JErr $ TypeMismatch (" Expecting a value property `" <> valuesKey <> " `" ))
350
366
) ∷ _ Json
351
367
if unwrapSingleArguments then
352
368
pure val
353
369
else do
354
- fields ← CA .decode CA .jarray val
370
+ fields ← lmap JErr $ CA .decode CA .jarray val
355
371
case fields of
356
372
[ head ] → pure head
357
- _ → Left $ TypeMismatch " Expecting exactly one element"
373
+ _ → Left $ JErr $ TypeMismatch " Expecting exactly one element"
358
374
359
- parseManyFields ∷ Encoding → Json → String → Either JsonDecodeError (Array Json )
375
+ parseManyFields ∷ Encoding → Json → String → Either Err (Array Json )
360
376
parseManyFields encoding json expectedTag =
361
377
case encoding of
362
378
EncodeNested {} → do
363
- obj ← CA .decode jobject json
379
+ obj ← lmap JErr $ CA .decode jobject json
364
380
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 <> " `" ))
366
383
) ∷ _ Json
367
- CA .decode CA .jarray val
384
+ lmap JErr $ CA .decode CA .jarray val
368
385
369
386
EncodeTagged { tagKey, valuesKey } → do
370
- obj ← CA .decode jobject json
387
+ obj ← lmap JErr $ CA .decode jobject json
371
388
checkTag tagKey obj expectedTag
372
389
val ←
373
390
( Obj .lookup valuesKey obj
374
- # note (TypeMismatch (" Expecting a value property `" <> valuesKey <> " `" ))
391
+ # note (JErr $ TypeMismatch (" Expecting a value property `" <> valuesKey <> " `" ))
375
392
) ∷ _ Json
376
- CA .decode CA .jarray val
393
+ lmap JErr $ CA .decode CA .jarray val
377
394
378
395
encodeSumCase ∷ Encoding → String → Array Json → Json
379
396
encodeSumCase encoding tag jsons =
@@ -412,19 +429,19 @@ defaultFlatEncoding = { tag: Proxy }
412
429
sumFlat ∷ ∀ r rep a . GFlatCases " tag" r rep ⇒ Generic a rep ⇒ String → Record r → JsonCodec a
413
430
sumFlat = sumFlatWith defaultFlatEncoding
414
431
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
416
433
sumFlatWith _ name r =
417
434
dimap from to $ codec' dec enc
418
435
where
419
- dec = gFlatCasesDecode @tag r >>> (lmap $ Named name)
436
+ dec = gFlatCasesDecode @tag r >>> (lmap $ finalizeError name)
420
437
enc = gFlatCasesEncode @tag r
421
438
422
439
class GFlatCases ∷ Symbol → Row Type → Type → Constraint
423
440
class
424
441
GFlatCases tag r rep
425
442
where
426
443
gFlatCasesEncode ∷ Record r → rep → Json
427
- gFlatCasesDecode ∷ Record r → Json → Either JsonDecodeError rep
444
+ gFlatCasesDecode ∷ Record r → Json → Either Err rep
428
445
429
446
instance gFlatCasesConstructorNoArg ∷
430
447
( Row.Cons name Unit () rc
@@ -444,20 +461,20 @@ instance gFlatCasesConstructorNoArg ∷
444
461
in
445
462
CA .encode codecWithTag rcWithTag
446
463
447
- gFlatCasesDecode ∷ Record rc → Json → Either JsonDecodeError (Constructor name NoArguments )
464
+ gFlatCasesDecode ∷ Record rc → Json → Either Err (Constructor name NoArguments )
448
465
gFlatCasesDecode _ json = do
449
466
let
450
467
name = reflectSymbol (Proxy @name) ∷ String
451
468
452
469
propCodec = CAR .record {} ∷ JPropCodec { }
453
470
propCodecWithTag = CA .recordProp (Proxy @tag) CA .string propCodec ∷ JPropCodec (Record rf )
454
471
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 )
456
473
let actualTag = Record .get (Proxy @tag) r ∷ String
457
474
458
475
when (actualTag /= name)
459
476
$ Left
460
- $ TypeMismatch (" Expecting tag `" <> name <> " `, got `" <> actualTag <> " `" )
477
+ ( JErr $ TypeMismatch (" Expecting tag `" <> name <> " `, got `" <> actualTag <> " `" ) )
461
478
462
479
pure (Constructor NoArguments )
463
480
@@ -480,19 +497,19 @@ instance gFlatCasesConstructorSingleArg ∷
480
497
in
481
498
CA .encode codecWithTag rcWithTag
482
499
483
- gFlatCasesDecode ∷ Record rc → Json → Either JsonDecodeError (Constructor name (Argument (Record rf )))
500
+ gFlatCasesDecode ∷ Record rc → Json → Either Err (Constructor name (Argument (Record rf )))
484
501
gFlatCasesDecode rc json = do
485
502
let
486
503
name = reflectSymbol (Proxy @name) ∷ String
487
504
propCodec = Record .get (Proxy @name) rc ∷ JPropCodec (Record rf )
488
505
propCodecWithTag = CA .recordProp (Proxy @tag) CA .string propCodec ∷ JPropCodec (Record rf' )
489
506
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' )
491
508
492
509
let actualTag = Record .get (Proxy @tag) r ∷ String
493
510
when (actualTag /= name)
494
511
$ Left
495
- $ TypeMismatch (" Expecting tag `" <> name <> " `, got `" <> actualTag <> " `" )
512
+ ( JErr $ TypeMismatch (" Expecting tag `" <> name <> " `, got `" <> actualTag <> " `" ) )
496
513
497
514
let r' = Record .delete (Proxy @tag) r ∷ Record rf
498
515
pure (Constructor (Argument r'))
@@ -518,16 +535,19 @@ instance gFlatCasesSum ∷
518
535
Inl lhs → gFlatCasesEncode @tag r1 lhs
519
536
Inr rhs → gFlatCasesEncode @tag r2 rhs
520
537
521
- gFlatCasesDecode ∷ Record r → Json → Either JsonDecodeError (Sum (Constructor name lhs ) rhs )
538
+ gFlatCasesDecode ∷ Record r → Json → Either Err (Sum (Constructor name lhs ) rhs )
522
539
gFlatCasesDecode r tagged = do
523
540
let
524
541
codec = Record .get (Proxy @name) r ∷ codec
525
542
r1 = Record .insert (Proxy @name) codec {} ∷ Record r1
526
543
r2 = Record .delete (Proxy @name) r ∷ Record r2
527
544
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)
531
551
532
552
-- | Same as `Record.delete` but deleting only happens at the type level
533
553
-- | and the value is left untouched.
0 commit comments