Skip to content

Commit 64e882f

Browse files
committed
add optionalWith
1 parent 78b0171 commit 64e882f

File tree

2 files changed

+82
-6
lines changed

2 files changed

+82
-6
lines changed

src/Data/Codec/Argonaut.purs

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ module Data.Codec.Argonaut
2323
, record
2424
, recordProp
2525
, recordPropOptional
26+
, recordPropOptionalWith
2627
, fix
2728
, named
2829
, coercible
@@ -32,6 +33,7 @@ module Data.Codec.Argonaut
3233

3334
import Prelude
3435

36+
import Data.Argonaut.Core (Json)
3537
import Data.Argonaut.Core as J
3638
import Data.Array as A
3739
import Data.Bifunctor (bimap, lmap)
@@ -41,7 +43,7 @@ import Data.Codec (Codec(..), Codec', codec, codec', decode, encode, hoist, iden
4143
import Data.Either (Either(..), note)
4244
import Data.Generic.Rep (class Generic)
4345
import Data.Int as I
44-
import Data.List ((:))
46+
import Data.List (List, (:))
4547
import Data.List as L
4648
import Data.Maybe (Maybe(..), maybe)
4749
import Data.String as S
@@ -52,7 +54,8 @@ import Data.Tuple (Tuple(..))
5254
import Foreign.Object as FO
5355
import Prim.Coerce (class Coercible)
5456
import Prim.Row as Row
55-
import Record.Unsafe as Record
57+
import Record as Record
58+
import Record.Unsafe as RecordUnsafe
5659
import Safe.Coerce (coerce)
5760
import Type.Proxy (Proxy)
5861
import Unsafe.Coerce (unsafeCoerce)
@@ -264,11 +267,11 @@ recordProp p codecA codecR =
264267
a ← BF.lmap (AtKey key) case FO.lookup key obj of
265268
Just val → Codec.decode codecA val
266269
NothingLeft MissingValue
267-
pure $ Record.unsafeSet key a r
270+
pure $ RecordUnsafe.unsafeSet key a r
268271

269272
enc' String Record r' L.List (Tuple String J.Json)
270273
enc' key val =
271-
Tuple key (Codec.encode codecA (Record.unsafeGet key val))
274+
Tuple key (Codec.encode codecA (RecordUnsafe.unsafeGet key val))
272275
: Codec.encode codecR (unsafeForget val)
273276

274277
unsafeForget Record r' Record r
@@ -300,18 +303,58 @@ recordPropOptional p codecA codecR = Codec.codec dec' enc'
300303
a ← BF.lmap (AtKey key) case FO.lookup key obj of
301304
Just val → Just <$> Codec.decode codecA val
302305
_ → Right Nothing
303-
pure $ Record.unsafeSet key a r
306+
pure $ RecordUnsafe.unsafeSet key a r
304307

305308
enc' Record r' L.List (Tuple String J.Json)
306309
enc' val = do
307310
let w = Codec.encode codecR (unsafeForget val)
308-
case Record.unsafeGet key val of
311+
case RecordUnsafe.unsafeGet key val of
309312
Just a → Tuple key (Codec.encode codecA a) : w
310313
Nothing → w
311314

312315
unsafeForget Record r' Record r
313316
unsafeForget = unsafeCoerce
314317

318+
recordPropOptionalWith
319+
p a b r r'
320+
. IsSymbol p
321+
Row.Cons p b r r'
322+
Row.Lacks p r
323+
Proxy p
324+
(Maybe a b)
325+
(b a)
326+
JsonCodec a
327+
JPropCodec (Record r)
328+
JPropCodec (Record r')
329+
recordPropOptionalWith p normalize denormalize codecA codecR = Codec.codec dec' enc'
330+
where
331+
key String
332+
key = reflectSymbol p
333+
334+
dec' FO.Object J.Json Either JsonDecodeError (Record r')
335+
dec' obj = do
336+
r Record rCodec.decode codecR obj
337+
b bBF.lmap (AtKey key) case FO.lookup key obj of
338+
Just j do
339+
ret aCodec.decode codecA j
340+
pure $ normalize (Just ret)
341+
Nothing pure $ normalize Nothing
342+
pure $ Record.insert p b r
343+
344+
enc' Record r' L.List (Tuple String J.Json)
345+
enc' val = do
346+
let
347+
w List (Tuple String Json)
348+
w = Codec.encode codecR (unsafeForget val)
349+
350+
b b
351+
b = Record.get p val
352+
353+
Tuple key (Codec.encode codecA $ denormalize b) : w
354+
355+
unsafeForget Record r' Record r
356+
unsafeForget = unsafeCoerce
357+
315358
jsonPrimCodec a. String (J.Json Maybe a) (a J.Json) JsonCodec a
316359
jsonPrimCodec ty f = Codec.codec' (maybe (Left (TypeMismatch ty)) pure <<< f)
317360

src/Data/Codec/Argonaut/Record.purs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,24 @@ record = rowListCodec (Proxy ∷ Proxy rl)
4848
-- | The property will be omitted when encoding and the value is `Nothing`.
4949
newtype Optional a = Optional (CA.JsonCodec a)
5050

51+
-- | Like `Optional`, but allows you to provide a function to transform the
52+
-- | `Maybe a` value into a different type `b`. This is useful when you want to
53+
-- | provide a default value or perform some other transformation when the
54+
-- | property is not present in the JSON object.
55+
newtype OptionalWith a b = OptionalWith
56+
{ normalize Maybe a b
57+
, denormalize b a
58+
, codec CA.JsonCodec a
59+
}
60+
5161
-- | A lowercase alias for `Optional`, provided for stylistic reasons only.
5262
optional a. CA.JsonCodec a Optional a
5363
optional = Optional
5464

65+
-- | A lowercase alias for `OptionalWith`, provided for stylistic reasons only.
66+
optionalWith a b. (Maybe a b) (b a) CA.JsonCodec a OptionalWith a b
67+
optionalWith normalize denormalize codec = OptionalWith { normalize, denormalize, codec }
68+
5569
-- | The class used to enable the building of `Record` codecs by providing a
5670
-- | record of codecs.
5771
class RowListCodec (rlRL.RowList Type) (riRow Type) (roRow Type) | rl ri ro where
@@ -76,6 +90,25 @@ instance rowListCodecConsOptional ∷
7690
tail CA.JPropCodec (Record ro')
7791
tail = rowListCodec (Proxy Proxy rs) ((unsafeCoerce Record ri Record ri') codecs)
7892

93+
else instance rowListCodecConsOptionalWith
94+
( RowListCodec rs ri' ro'
95+
, R.Cons sym (OptionalWith a b) ri' ri
96+
, R.Cons sym b ro' ro
97+
, R.Lacks sym ro'
98+
, R.Lacks sym ri'
99+
, IsSymbol sym
100+
)
101+
RowListCodec (RL.Cons sym (OptionalWith a b) rs) ri ro where
102+
rowListCodec _ codecs =
103+
CA.recordPropOptionalWith (Proxy Proxy sym) ret.normalize ret.denormalize ret.codec tail
104+
105+
where
106+
ret { normalize Maybe a b, denormalize b a, codec CA.JsonCodec a }
107+
ret = coerce (Rec.get (Proxy Proxy sym) codecs OptionalWith a b)
108+
109+
tail CA.JPropCodec (Record ro')
110+
tail = rowListCodec (Proxy Proxy rs) ((unsafeCoerce Record ri Record ri') codecs)
111+
79112
else instance rowListCodecCons
80113
( RowListCodec rs ri' ro'
81114
, R.Cons sym (CA.JsonCodec a) ri' ri

0 commit comments

Comments
 (0)