aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGiacomo Cavalieri <giacomo.cavalieri@icloud.com>2023-04-21 15:04:50 +0200
committerLouis Pilfold <louis@lpil.uk>2023-04-29 14:33:18 +0100
commit54b22b142d17f0fd893ec2465e53b92109aadb48 (patch)
treec7a6bba9e1c1f35e0285570cda7e4468eb9283b0
parent8924398359342ad33e99d707a3c8a7fb44d99da0 (diff)
downloadgleam_stdlib-54b22b142d17f0fd893ec2465e53b92109aadb48.tar.gz
gleam_stdlib-54b22b142d17f0fd893ec2465e53b92109aadb48.zip
Fix `dynamic.field` behaviour
-rw-r--r--src/gleam/dynamic.gleam21
-rw-r--r--src/gleam_stdlib.erl10
-rw-r--r--src/gleam_stdlib.mjs19
-rw-r--r--test/gleam/dynamic_test.gleam14
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"]),
]))
}