Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 31 additions & 2 deletions src/Json/Decode.gren
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ module Json.Decode exposing
, maybe, oneOf
, decodeString, decodeValue, Value, Error(..), errorToString
, map, map2, map3, map4, map5, map6, map7, map8
, lazy, value, null, succeed, fail, andThen
, lazy, value, null, succeed, fail, andThen, andMap
)

{-| Turn JSON values into Gren values. We've inherited this from Elm. Definitely check out this [intro to
Expand Down Expand Up @@ -44,7 +44,7 @@ JSON decoders][guide] to get a feel for how this library works!

## Fancy Decoding

@docs lazy, value, null, succeed, fail, andThen
@docs lazy, value, null, succeed, fail, andThen, andMap

-}

Expand Down Expand Up @@ -716,6 +716,35 @@ andThen =
Gren.Kernel.Json.andThen


{-| Use andMap to incrementally decode a JSON object. Each andMap
provides a value that will be an argument to a type constructor.
For example:

-- The Type
type alias Info =
{ height : Float
, age : Int
}

-- The Constructor
makeInfo : Float -> Int -> Info
makeInfo height age =
{ height = height
, age = age
}

-- The Decoder
infoDecoder : Decoder Info
infoDecoder =
succeed makeInfo
|> andMap (field "height" float)
|> andMap (field "age" int)

-}
andMap : Decoder a -> Decoder (a -> b) -> Decoder b
andMap =
map2 (|>)

{-| Sometimes you have JSON with recursive structure, like nested comments.
You can use `lazy` to make sure your decoder unrolls lazily.

Expand Down
65 changes: 65 additions & 0 deletions tests/src/Test/Json.gren
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ tests =
describe "Json decode"
[ intTests
, customTests
, andMapTests
]


Expand Down Expand Up @@ -85,3 +86,67 @@ customTests =
++ Json.errorToString message
in
test "customDecoder preserves user error messages" <| \{} -> assertion

-- Used for testing andMap
type alias TestRecord1 =
{ stringField : String
, intField : Int
, boolField: Bool
, floatField: Float
, stringArrayField: Array String
}

-- The constructor for TestRecord1
mkTestRecord1: String -> Int -> Bool -> Float -> Array String -> TestRecord1
mkTestRecord1 s i b f sa =
{ stringField = s
, intField = i
, boolField = b
, floatField = f
, stringArrayField = sa
}

andMapTests : Test
andMapTests =
let
jsonString =
"""
{
"stringField": "bar",
"intField": 42,
"boolField": true,
"floatField": 1.5,
"stringArrayField": [ "a", "b" ]
}
"""

myDecoder =
Json.succeed mkTestRecord1
|> Json.andMap (Json.field "stringField" Json.string)
|> Json.andMap (Json.field "intField" Json.int)
|> Json.andMap (Json.field "boolField" Json.bool)
|> Json.andMap (Json.field "floatField" Json.float)
|> Json.andMap (Json.field "stringArrayField" (Json.array Json.string))

parse = Json.decodeString myDecoder jsonString

record = when parse is
Ok r -> r
Err _ -> mkTestRecord1 "" 0 False 0.0 []

in
describe "Json andMap "
[test "string field" <|
\{} -> Expect.equal record.stringField "bar"
, test "int field" <|
\{} -> Expect.equal record.intField 42
, test "bool field" <|
\{} -> Expect.equal record.boolField True
, test "float field" <|
\{} -> Expect.within (Expect.Relative 0.001) record.floatField 1.5
, test "string-array field" <|
\{} -> Expect.equalArrays record.stringArrayField [ "a", "b" ]
, test "parse error" <|
\{} -> Expect.ok parse

]
Loading