Skip to content

Commit 5cc7520

Browse files
committed
add optional_index for use by optionally_at
Signed-off-by: James Hillyerd <[email protected]>
1 parent f59277c commit 5cc7520

File tree

2 files changed

+59
-1
lines changed

2 files changed

+59
-1
lines changed

Diff for: src/gleam/dynamic/decode.gleam

+41-1
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,46 @@ fn index(
423423
}
424424
}
425425

426+
// Indexes into a path similar to `index`, but treats Nil values as a miss
427+
// instead of an error.
428+
fn optional_index(
429+
path: List(a),
430+
position: List(a),
431+
inner: fn(Dynamic) -> #(b, List(DecodeError)),
432+
data: Dynamic,
433+
handle_miss: fn(Dynamic, List(a)) -> #(b, List(DecodeError)),
434+
) -> #(b, List(DecodeError)) {
435+
case path {
436+
[] -> {
437+
inner(data)
438+
|> push_path(list.reverse(position))
439+
}
440+
441+
[key, ..path] -> {
442+
case bare_index(data, key) {
443+
Ok(Some(data)) -> {
444+
optional_index(path, [key, ..position], inner, data, handle_miss)
445+
}
446+
Ok(None) -> {
447+
handle_miss(data, [key, ..position])
448+
}
449+
Error(kind) -> {
450+
case is_null(data) {
451+
True -> {
452+
handle_miss(data, [key, ..position])
453+
}
454+
False -> {
455+
let #(default, _) = inner(data)
456+
#(default, [DecodeError(kind, dynamic.classify(data), [])])
457+
|> push_path(list.reverse(position))
458+
}
459+
}
460+
}
461+
}
462+
}
463+
}
464+
}
465+
426466
@external(erlang, "gleam_stdlib_decode_ffi", "index")
427467
@external(javascript, "../../gleam_stdlib_decode_ffi.mjs", "index")
428468
fn bare_index(data: Dynamic, key: anything) -> Result(Option(Dynamic), String)
@@ -592,7 +632,7 @@ pub fn optionally_at(
592632
inner: Decoder(a),
593633
) -> Decoder(a) {
594634
Decoder(function: fn(data) {
595-
index(path, [], inner.function, data, fn(_, _) { #(default, []) })
635+
optional_index(path, [], inner.function, data, fn(_, _) { #(default, []) })
596636
})
597637
}
598638

Diff for: test/gleam/dynamic/decode_test.gleam

+18
Original file line numberDiff line numberDiff line change
@@ -923,6 +923,24 @@ pub fn optionally_at_nil_in_path_error_test() {
923923
|> should.equal(100)
924924
}
925925

926+
pub fn optionally_at_nil_target_error_test() {
927+
dynamic.from(
928+
dict.from_list([
929+
#(
930+
"first",
931+
dict.from_list([#("second", dict.from_list([#("third", Nil)]))]),
932+
),
933+
]),
934+
)
935+
|> decode.run(decode.optionally_at(
936+
["first", "second", "third"],
937+
100,
938+
decode.int,
939+
))
940+
|> should.be_error
941+
|> should.equal([DecodeError("Int", "Nil", ["first", "second", "third"])])
942+
}
943+
926944
@external(erlang, "maps", "from_list")
927945
@external(javascript, "../../gleam_stdlib_test_ffi.mjs", "object")
928946
fn make_object(items: List(#(String, t))) -> Dynamic

0 commit comments

Comments
 (0)