diff options
author | Giacomo Cavalieri <giacomo.cavalieri@icloud.com> | 2023-04-21 15:04:50 +0200 |
---|---|---|
committer | Louis Pilfold <louis@lpil.uk> | 2023-04-29 14:33:18 +0100 |
commit | 54b22b142d17f0fd893ec2465e53b92109aadb48 (patch) | |
tree | c7a6bba9e1c1f35e0285570cda7e4468eb9283b0 | |
parent | 8924398359342ad33e99d707a3c8a7fb44d99da0 (diff) | |
download | gleam_stdlib-54b22b142d17f0fd893ec2465e53b92109aadb48.tar.gz gleam_stdlib-54b22b142d17f0fd893ec2465e53b92109aadb48.zip |
Fix `dynamic.field` behaviour
-rw-r--r-- | src/gleam/dynamic.gleam | 21 | ||||
-rw-r--r-- | src/gleam_stdlib.erl | 10 | ||||
-rw-r--r-- | src/gleam_stdlib.mjs | 19 | ||||
-rw-r--r-- | test/gleam/dynamic_test.gleam | 14 |
4 files changed, 44 insertions, 20 deletions
diff --git a/src/gleam/dynamic.gleam b/src/gleam/dynamic.gleam index a845b1c..4f0708f 100644 --- a/src/gleam/dynamic.gleam +++ b/src/gleam/dynamic.gleam @@ -474,20 +474,29 @@ if javascript { /// pub fn field(named name: a, of inner_type: Decoder(t)) -> Decoder(t) { fn(value) { - value - |> decode_field(name) - |> result.try(inner_type) - |> map_errors(push_path(_, name)) + case decode_field(value, name) { + Error(not_a_map_errors) -> Error(not_a_map_errors) + Ok(dynamic_field_result) -> + dynamic_field_result + |> result.try(inner_type) + |> map_errors(push_path(_, name)) + } } } if erlang { - external fn decode_field(Dynamic, name) -> Result(Dynamic, DecodeErrors) = + external fn decode_field( + Dynamic, + name, + ) -> Result(Result(Dynamic, DecodeErrors), DecodeErrors) = "gleam_stdlib" "decode_field" } if javascript { - external fn decode_field(Dynamic, name) -> Result(Dynamic, DecodeErrors) = + external fn decode_field( + Dynamic, + name, + ) -> Result(Result(Dynamic, DecodeErrors), DecodeErrors) = "../gleam_stdlib.mjs" "decode_field" } diff --git a/src/gleam_stdlib.erl b/src/gleam_stdlib.erl index 33c9609..4c59893 100644 --- a/src/gleam_stdlib.erl +++ b/src/gleam_stdlib.erl @@ -78,12 +78,14 @@ decode_bool(Data) -> decode_error_msg(<<"Bool">>, Data). decode_list(Data) when is_list(Data) -> {ok, Data}; decode_list(Data) -> decode_error_msg(<<"List">>, Data). -decode_field(Data, Key) -> +decode_field(Data, Key) when is_map(Data) -> case Data of - #{Key := Value} -> {ok, Value}; + #{Key := Value} -> {ok, {ok, Value}}; _ -> - decode_error(<<"field"/utf8>>, <<"nothing"/utf8>>) - end. + {ok, decode_error(<<"field"/utf8>>, <<"nothing"/utf8>>)} + end; +decode_field(Data, _) -> + decode_error_msg(<<"Map">>, Data). size_of_tuple(Data) -> tuple_size(Data). diff --git a/src/gleam_stdlib.mjs b/src/gleam_stdlib.mjs index 2b0a6e1..52fbc89 100644 --- a/src/gleam_stdlib.mjs +++ b/src/gleam_stdlib.mjs @@ -663,14 +663,23 @@ export function decode_option(data, decoder) { } export function decode_field(value, name) { - let error = () => decoder_error_no_classify("field", "nothing"); - if (value instanceof PMap) { + let missing_field_error = () => decoder_error_no_classify("field", "nothing"); + let not_a_map_error = () => decoder_error("Map", value); + + if (value instanceof PMap || value instanceof WeakMap || value instanceof Map) { let entry = map_get(value, name); - return entry.isOk() ? entry : error(); + return new Ok(entry.isOk() ? entry : missing_field_error()); + } else if (Object.getPrototypeOf(value) == Object.prototype) { + return try_get_field(value, name, () => new Ok(missing_field_error())); + } else { + return try_get_field(value, name, not_a_map_error); } +} + +function try_get_field(value, field, or_else) { try { - return name in value ? new Ok(value[name]) : error(); + return field in value ? new Ok(new Ok(value[field])) : or_else(); } catch { - return error(); + return or_else(); } } diff --git a/test/gleam/dynamic_test.gleam b/test/gleam/dynamic_test.gleam index a220e6e..3937ac8 100644 --- a/test/gleam/dynamic_test.gleam +++ b/test/gleam/dynamic_test.gleam @@ -300,7 +300,7 @@ if javascript { |> dynamic.from |> dynamic.field("Nope", dynamic.int) |> should.equal(Error([ - DecodeError(expected: "field", found: "nothing", path: ["Nope"]), + DecodeError(expected: "Map", found: "Result", path: []), ])) } } @@ -343,15 +343,19 @@ pub fn field_test() { 1 |> dynamic.from |> dynamic.field("ok", dynamic.int) - |> should.equal(Error([ - DecodeError(expected: "field", found: "nothing", path: ["ok"]), - ])) + |> should.equal(Error([DecodeError(expected: "Map", found: "Int", path: [])])) [] |> dynamic.from |> dynamic.field("ok", dynamic.int) + |> should.equal(Error([DecodeError(expected: "Map", found: "List", path: [])])) + + map.new() + |> map.insert("ok", 1) + |> dynamic.from + |> dynamic.field("ok", dynamic.field("not_a_field", dynamic.int)) |> should.equal(Error([ - DecodeError(expected: "field", found: "nothing", path: ["ok"]), + DecodeError(expected: "Map", found: "Int", path: ["ok"]), ])) } |