Skip to content

Commit d0a621b

Browse files
committed
Code reuse
1 parent dc287c8 commit d0a621b

File tree

3 files changed

+61
-59
lines changed

3 files changed

+61
-59
lines changed

src/Data/Codec/Argonaut.purs

Lines changed: 5 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -288,45 +288,25 @@ recordPropOptional
288288
p a r r'
289289
. IsSymbol p
290290
Row.Cons p (Maybe a) r r'
291+
Row.Lacks p r
291292
Proxy p
292293
JsonCodec a
293294
JPropCodec (Record r)
294295
JPropCodec (Record r')
295-
recordPropOptional p codecA codecR = Codec.codec dec' enc'
296-
where
297-
key String
298-
key = reflectSymbol p
299-
300-
dec' FO.Object J.Json Either JsonDecodeError (Record r')
301-
dec' obj = do
302-
r ← Codec.decode codecR obj
303-
a ← BF.lmap (AtKey key) case FO.lookup key obj of
304-
Just val → Just <$> Codec.decode codecA val
305-
_ → Right Nothing
306-
pure $ RecordUnsafe.unsafeSet key a r
307-
308-
enc' Record r' L.List (Tuple String J.Json)
309-
enc' val = do
310-
let w = Codec.encode codecR (unsafeForget val)
311-
case RecordUnsafe.unsafeGet key val of
312-
Just a → Tuple key (Codec.encode codecA a) : w
313-
Nothing → w
314-
315-
unsafeForget Record r' Record r
316-
unsafeForget = unsafeCoerce
296+
recordPropOptional = recordPropOptionalWith identity identity
317297

318298
recordPropOptionalWith
319299
p a b r r'
320300
. IsSymbol p
321301
Row.Cons p b r r'
322302
Row.Lacks p r
323-
Proxy p
324-
(Maybe a b)
303+
(Maybe a b)
325304
(b Maybe a)
305+
Proxy p
326306
JsonCodec a
327307
JPropCodec (Record r)
328308
JPropCodec (Record r')
329-
recordPropOptionalWith p normalize denormalize codecA codecR = Codec.codec dec' enc'
309+
recordPropOptionalWith normalize denormalize p codecA codecR = Codec.codec dec' enc'
330310
where
331311
key String
332312
key = reflectSymbol p

src/Data/Codec/Argonaut/Record.purs

Lines changed: 23 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
1-
module Data.Codec.Argonaut.Record where
1+
module Data.Codec.Argonaut.Record
2+
( OptionalWith
3+
, class RowListCodec
4+
, object
5+
, optional
6+
, optionalWith
7+
, record
8+
, rowListCodec
9+
)
10+
where
211

312
import Data.Codec.Argonaut as CA
13+
import Data.Function (identity)
414
import Data.Maybe (Maybe)
515
import Data.Symbol (class IsSymbol)
616
import Prim.Row as R
@@ -39,30 +49,27 @@ record
3949
CA.JPropCodec (Record ro)
4050
record = rowListCodec (Proxy Proxy rl)
4151

52+
53+
newtype OptionalWith a b = OptionalWith
54+
{ normalize Maybe a b
55+
, denormalize b Maybe a
56+
, codec CA.JsonCodec a
57+
}
58+
4259
-- | Used to wrap codec values provided in `record` to indicate the field is optional.
4360
-- |
4461
-- | This will only decode the property as `Nothing` if the field does not exist
4562
-- | in the object - having a values such as `null` assigned will need handling
4663
-- | separately.
4764
-- |
4865
-- | The property will be omitted when encoding and the value is `Nothing`.
49-
newtype Optional a = Optional (CA.JsonCodec a)
66+
optional a. CA.JsonCodec a OptionalWith a (Maybe a)
67+
optional = optionalWith identity identity
5068

51-
-- | Like `Optional`, but allows you to provide a function to transform the
69+
-- | Like `Optional`, but more general. It allows you to provide a function to transform the
5270
-- | `Maybe a` value into a different type `b`. This is useful when you want to
5371
-- | provide a default value or perform some other transformation when the
5472
-- | property is not present in the JSON object.
55-
newtype OptionalWith a b = OptionalWith
56-
{ normalize Maybe a b
57-
, denormalize b Maybe a
58-
, codec CA.JsonCodec a
59-
}
60-
61-
-- | A lowercase alias for `Optional`, provided for stylistic reasons only.
62-
optional a. CA.JsonCodec a Optional a
63-
optional = Optional
64-
65-
-- | A lowercase alias for `OptionalWith`, provided for stylistic reasons only.
6673
optionalWith a b. (Maybe a b) (b Maybe a) CA.JsonCodec a OptionalWith a b
6774
optionalWith normalize denormalize codec = OptionalWith { normalize, denormalize, codec }
6875

@@ -74,23 +81,7 @@ class RowListCodec (rl ∷ RL.RowList Type) (ri ∷ Row Type) (ro ∷ Row Type)
7481
instance rowListCodecNilRowListCodec RL.Nil () () where
7582
rowListCodec _ _ = CA.record
7683

77-
instance rowListCodecConsOptional
78-
( RowListCodec rs ri' ro'
79-
, R.Cons sym (Optional a) ri' ri
80-
, R.Cons sym (Maybe a) ro' ro
81-
, IsSymbol sym
82-
)
83-
RowListCodec (RL.Cons sym (Optional a) rs) ri ro where
84-
rowListCodec _ codecs =
85-
CA.recordPropOptional (Proxy Proxy sym) codec tail
86-
where
87-
codec CA.JsonCodec a
88-
codec = coerce (Rec.get (Proxy Proxy sym) codecs Optional a)
89-
90-
tail CA.JPropCodec (Record ro')
91-
tail = rowListCodec (Proxy Proxy rs) ((unsafeCoerce Record ri Record ri') codecs)
92-
93-
else instance rowListCodecConsOptionalWith
84+
instance rowListCodecConsOptionalWith
9485
( RowListCodec rs ri' ro'
9586
, R.Cons sym (OptionalWith a b) ri' ri
9687
, R.Cons sym b ro' ro
@@ -100,7 +91,7 @@ else instance rowListCodecConsOptionalWith ∷
10091
)
10192
RowListCodec (RL.Cons sym (OptionalWith a b) rs) ri ro where
10293
rowListCodec _ codecs =
103-
CA.recordPropOptionalWith (Proxy Proxy sym) ret.normalize ret.denormalize ret.codec tail
94+
CA.recordPropOptionalWith ret.normalize ret.denormalize (Proxy Proxy sym) ret.codec tail
10495

10596
where
10697
ret { normalize Maybe a b, denormalize b Maybe a, codec CA.JsonCodec a }

test/Test/Record.purs

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ import Control.Monad.Gen.Common as GenC
77
import Data.Argonaut.Core (stringify)
88
import Data.Argonaut.Core as Json
99
import Data.Codec.Argonaut.Common as CA
10+
import Data.Codec.Argonaut.Common as Car
1011
import Data.Codec.Argonaut.Record as CAR
11-
import Data.Maybe (Maybe(..))
12+
import Data.Maybe (Maybe(..), fromMaybe)
1213
import Data.Newtype (class Newtype, unwrap, wrap)
1314
import Data.Profunctor (dimap)
1415
import Data.String.Gen (genAsciiString)
@@ -31,6 +32,11 @@ type InnerR =
3132
, o Maybe Boolean
3233
}
3334

35+
type Sample =
36+
{ p Int
37+
, q Boolean
38+
}
39+
3440
newtype Outer = Outer OuterR
3541

3642
derive instance newtypeOuterNewtype Outer _
@@ -59,10 +65,17 @@ innerCodec ∷ CA.JsonCodec InnerR
5965
innerCodec =
6066
CA.object "Inner" $ CAR.record
6167
{ n: CA.int
62-
, m: CA.boolean
68+
, m: Car.boolean
6369
, o: CAR.optional CA.boolean
6470
}
6571

72+
sampleCodec CA.JsonCodec Sample
73+
sampleCodec =
74+
CA.object "Sample" $ CAR.record
75+
{ p: CA.int
76+
, q: CAR.optionalWith (fromMaybe false) (if _ then Just true else Nothing) CA.boolean
77+
}
78+
6679
genOuter Gen OuterR
6780
genOuter = do
6881
a ← genInt
@@ -77,6 +90,12 @@ genInner = do
7790
o ← GenC.genMaybe Gen.chooseBool
7891
pure { n, m, o }
7992

93+
genSample Gen Sample
94+
genSample = do
95+
p ← genInt
96+
q ← Gen.chooseBool
97+
pure { p, q }
98+
8099
main Effect Unit
81100
main = do
82101
log "Checking record codec"
@@ -95,4 +114,16 @@ main = do
95114
let obj = Json.toObject $ CA.encode innerCodec (v { o = Just b })
96115
pure $ assertEquals (Just [ "m", "n", "o" ]) (Object.keys <$> obj)
97116

117+
log "Check `false` is not present in the json"
118+
quickCheckGen do
119+
v ← genSample
120+
let obj = Json.toObject $ CA.encode sampleCodec (v { q = false })
121+
pure $ assertEquals (Just [ "p" ]) (Object.keys <$> obj)
122+
123+
log "Check `true` is present in the json"
124+
quickCheckGen do
125+
v ← genSample
126+
let obj = Json.toObject $ CA.encode sampleCodec (v { q = true })
127+
pure $ assertEquals (Just [ "p", "q" ]) (Object.keys <$> obj)
128+
98129
pure unit

0 commit comments

Comments
 (0)