Skip to content

Commit 45de025

Browse files
authored
Merge pull request #43 from joneshf/parse-json-null-as-nothing
Support null values when parsing optional fields
2 parents ee3090d + b897f8e commit 45de025

8 files changed

+106
-6
lines changed

README.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,15 @@ We can give that a spin with some different JSON values:
330330
331331
> parse """{"name": "Pat", "title": "Dr."}"""
332332
(Right (Option.fromRecord { name: "Pat", title: "Dr." }))
333+
334+
> parse """{ "name": null }"""
335+
Right (Option.fromRecord {})
336+
337+
> parse """{ "title": null }"""
338+
Right (Option.fromRecord {})
339+
340+
> parse """{ "name": null, "title": null }"""
341+
Right (Option.fromRecord {})
333342
```
334343

335344
We can also produce some different JSON values:
@@ -531,6 +540,15 @@ We can give that a spin with some different JSON values:
531540
532541
> parse """{"name": "Pat", "title": "Dr."}"""
533542
(Right (Option.fromRecord { name: "Pat", title: "Dr." }))
543+
544+
> parse """{ "name": null }"""
545+
Right (Option.fromRecord {})
546+
547+
> parse """{ "title": null }"""
548+
Right (Option.fromRecord {})
549+
550+
> parse """{ "name": null, "title": null }"""
551+
Right (Option.fromRecord {})
534552
```
535553

536554
We can also produce some different JSON values:
@@ -828,6 +846,15 @@ We can give that a spin with some different JSON values:
828846
829847
> readJSON """{"name": "Pat", "title": "Dr."}"""
830848
(Right (Option.fromRecord { name: "Pat", title: "Dr." }))
849+
850+
> readJSON """{ "name": null }"""
851+
Right (Option.fromRecord {})
852+
853+
> readJSON """{ "title": null }"""
854+
Right (Option.fromRecord {})
855+
856+
> readJSON """{ "name": null, "title": null }"""
857+
Right (Option.fromRecord {})
831858
```
832859

833860
We can also produce some different JSON values:
@@ -947,6 +974,9 @@ We can give that a spin with some different JSON values:
947974
948975
> parse """{"name": "Pat", "title": "Dr."}"""
949976
(Right (Option.recordFromRecord { name: "Pat", title: "Dr." }))
977+
978+
> parse """{ "name": "Pat", "title": null }"""
979+
Right (Option.recordFromRecord { name: "Pat" })
950980
```
951981

952982
We can also produce some different JSON values:
@@ -1162,6 +1192,9 @@ We can give that a spin with some different JSON values:
11621192
11631193
> parse """{"name": "Pat", "title": "Dr."}"""
11641194
(Right (Option.recordFromRecord { name: "Pat", title: "Dr." }))
1195+
1196+
> parse """{ "name": "Pat", "title": null }"""
1197+
Right (Option.recordFromRecord { name: "Pat" })
11651198
```
11661199

11671200
Notice that we have to supply a `"name"` field in the JSON input otherwise it will not parse.
@@ -1474,6 +1507,9 @@ We can give that a spin with some different JSON values:
14741507
14751508
> parse """{"name": "Pat", "title": "Dr."}"""
14761509
(Right (Option.recordFromRecord { name: "Pat", title: "Dr." }))
1510+
1511+
> parse """{ "name": "Pat", "title": null }"""
1512+
Right (Option.recordFromRecord { name: "Pat" })
14771513
```
14781514

14791515
We can also produce some different JSON values:

src/Option.purs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ import Data.Argonaut.Decode.Error as Data.Argonaut.Decode.Error
133133
import Data.Argonaut.Encode.Class as Data.Argonaut.Encode.Class
134134
import Data.Codec as Data.Codec
135135
import Data.Codec.Argonaut as Data.Codec.Argonaut
136+
import Data.Codec.Argonaut.Compat as Data.Codec.Argonaut.Compat
136137
import Data.Either as Data.Either
137138
import Data.List as Data.List
138139
import Data.Maybe as Data.Maybe
@@ -605,9 +606,11 @@ else instance decodeJsonOptionCons ::
605606
Data.Either.Either Data.Argonaut.Decode.Error.JsonDecodeError (Option option)
606607
decodeJsonOption _ object' = case Foreign.Object.lookup key object' of
607608
Data.Maybe.Just json -> do
608-
value <- Data.Argonaut.Decode.Class.decodeJson json
609+
value' <- Data.Argonaut.Decode.Class.decodeJson json
609610
option <- option'
610-
Data.Either.Right (insert label value option)
611+
case value' of
612+
Data.Maybe.Just value -> Data.Either.Right (insert label value option)
613+
Data.Maybe.Nothing -> Data.Either.Right (insertField label option)
611614
Data.Maybe.Nothing -> do
612615
option <- option'
613616
Data.Either.Right (insertField label option)
@@ -1509,9 +1512,11 @@ else instance jsonCodecOptionCons ::
15091512
decode object' = do
15101513
option <- Data.Codec.Argonaut.decode option' object'
15111514
case Foreign.Object.lookup key object' of
1512-
Data.Maybe.Just json -> case Data.Codec.Argonaut.decode codec json of
1515+
Data.Maybe.Just json -> case Data.Codec.Argonaut.decode (Data.Codec.Argonaut.Compat.maybe codec) json of
15131516
Data.Either.Left error -> Data.Either.Left (Data.Codec.Argonaut.AtKey key error)
1514-
Data.Either.Right value -> Data.Either.Right (insert label value option)
1517+
Data.Either.Right value' -> case value' of
1518+
Data.Maybe.Just value -> Data.Either.Right (insert label value option)
1519+
Data.Maybe.Nothing -> Data.Either.Right (insertField label option)
15151520
Data.Maybe.Nothing -> Data.Either.Right (insertField label option)
15161521

15171522
encode ::
@@ -1833,9 +1838,11 @@ else instance readForeignOptionCons ::
18331838
true ->
18341839
Control.Monad.Except.except case Control.Monad.Except.runExcept (Foreign.Index.readProp key foreign') of
18351840
Data.Either.Left errors -> Data.Either.Left (map (Foreign.Index.errorAt key) errors)
1836-
Data.Either.Right value' -> case Control.Monad.Except.runExcept (Simple.JSON.readImpl value') of
1841+
Data.Either.Right value'' -> case Control.Monad.Except.runExcept (Simple.JSON.readImpl value'') of
18371842
Data.Either.Left errors -> Data.Either.Left (map (Foreign.Index.errorAt key) errors)
1838-
Data.Either.Right value -> Data.Either.Right (insert label value option)
1843+
Data.Either.Right value' -> case value' of
1844+
Data.Maybe.Just value -> Data.Either.Right (insert label value option)
1845+
Data.Maybe.Nothing -> Data.Either.Right (insertField label option)
18391846
false -> pure (insertField label option)
18401847
where
18411848
key :: String

test/HowTo.DecodeAndEncodeJSONWithOptionalValuesInPureScriptArgonaut.purs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,15 @@ spec_parse =
7979
Test.Spec.Assertions.shouldEqual
8080
(parse """{ "name": "Pat", "title": "Dr." }""")
8181
(Data.Either.Right (Option.fromRecord { name: "Pat", title: "Dr." }))
82+
Test.Spec.it "doesn't fail a null name" do
83+
Test.Spec.Assertions.shouldEqual
84+
(parse """{ "name": null }""")
85+
(Data.Either.Right (Option.fromRecord {}))
86+
Test.Spec.it "doesn't fail for a null title" do
87+
Test.Spec.Assertions.shouldEqual
88+
(parse """{ "title": null }""")
89+
(Data.Either.Right (Option.fromRecord {}))
90+
Test.Spec.it "doesn't fail for a null name or title" do
91+
Test.Spec.Assertions.shouldEqual
92+
(parse """{ "name": null, "title": null }""")
93+
(Data.Either.Right (Option.fromRecord {}))

test/HowTo.DecodeAndEncodeJSONWithOptionalValuesInPureScriptCodecArgonaut.purs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,15 @@ spec_parse =
8585
Test.Spec.Assertions.shouldEqual
8686
(parse """{ "name": "Pat", "title": "Dr." }""")
8787
(Data.Either.Right (Option.fromRecord { name: "Pat", title: "Dr." }))
88+
Test.Spec.it "doesn't fail a null name" do
89+
Test.Spec.Assertions.shouldEqual
90+
(parse """{ "name": null }""")
91+
(Data.Either.Right (Option.fromRecord {}))
92+
Test.Spec.it "doesn't fail for a null title" do
93+
Test.Spec.Assertions.shouldEqual
94+
(parse """{ "title": null }""")
95+
(Data.Either.Right (Option.fromRecord {}))
96+
Test.Spec.it "doesn't fail for a null name or title" do
97+
Test.Spec.Assertions.shouldEqual
98+
(parse """{ "name": null, "title": null }""")
99+
(Data.Either.Right (Option.fromRecord {}))

test/HowTo.DecodeAndEncodeJSONWithOptionalValuesInPureScriptSimpleJSON.purs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,27 @@ spec_readJSON =
5858
Test.Spec.Assertions.shouldEqual
5959
(readJSON json)
6060
(Data.Either.Right (Option.fromRecord { name: "Pat", title: "Dr." }))
61+
Test.Spec.it "doesn't fail a null name" do
62+
let
63+
json :: String
64+
json = """{ "name": null }"""
65+
Test.Spec.Assertions.shouldEqual
66+
(readJSON json)
67+
(Data.Either.Right (Option.fromRecord {}))
68+
Test.Spec.it "doesn't fail for a null title" do
69+
let
70+
json :: String
71+
json = """{ "title": null }"""
72+
Test.Spec.Assertions.shouldEqual
73+
(readJSON json)
74+
(Data.Either.Right (Option.fromRecord {}))
75+
Test.Spec.it "doesn't fail for a null name or title" do
76+
let
77+
json :: String
78+
json = """{ "name": null, "title": null }"""
79+
Test.Spec.Assertions.shouldEqual
80+
(readJSON json)
81+
(Data.Either.Right (Option.fromRecord {}))
6182

6283
spec_writeJSON :: Test.Spec.Spec Unit
6384
spec_writeJSON =

test/HowTo.DecodeAndEncodeJSONWithRequiredAndOptionalValuesInPureScriptArgonaut.purs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,7 @@ spec_parse =
7171
Test.Spec.Assertions.shouldEqual
7272
(parse """{ "name": "Pat", "title": "Dr." }""")
7373
(Data.Either.Right (Option.recordFromRecord { name: "Pat", title: "Dr." }))
74+
Test.Spec.it "doesn't fail for null fields" do
75+
Test.Spec.Assertions.shouldEqual
76+
(parse """{ "name": "Pat", "title": null }""")
77+
(Data.Either.Right (Option.recordFromRecord { name: "Pat" }))

test/HowTo.DecodeAndEncodeJSONWithRequiredAndOptionalValuesInPureScriptCodecArgonaut.purs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,7 @@ spec_parse =
7777
Test.Spec.Assertions.shouldEqual
7878
(parse """{ "name": "Pat", "title": "Dr." }""")
7979
(Data.Either.Right (Option.recordFromRecord { name: "Pat", title: "Dr." }))
80+
Test.Spec.it "doesn't fail for null fields" do
81+
Test.Spec.Assertions.shouldEqual
82+
(parse """{ "name": "Pat", "title": null }""")
83+
(Data.Either.Right (Option.recordFromRecord { name: "Pat" }))

test/HowTo.DecodeAndEncodeJSONWithRequiredAndOptionalValuesInPureScriptSimpleJSON.purs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ spec_parse =
5555
Test.Spec.Assertions.shouldEqual
5656
(parse """{ "name": "Pat", "title": "Dr." }""")
5757
(Data.Either.Right (Option.recordFromRecord { name: "Pat", title: "Dr." }))
58+
Test.Spec.it "doesn't fail for null fields" do
59+
Test.Spec.Assertions.shouldEqual
60+
(parse """{ "name": "Pat", "title": null }""")
61+
(Data.Either.Right (Option.recordFromRecord { name: "Pat" }))
5862

5963
spec_writeJSON :: Test.Spec.Spec Unit
6064
spec_writeJSON =

0 commit comments

Comments
 (0)