From cd5bcb25e68db6206abd818b2b314395af35c6df Mon Sep 17 00:00:00 2001 From: Lee Jarvis <lee@jrvs.uk> Date: Mon, 11 Nov 2024 14:53:01 +0000 Subject: [PATCH 1/3] Add basic parsing JSON example --- universal/test/formats/parsing_json.gleam | 40 +++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 universal/test/formats/parsing_json.gleam diff --git a/universal/test/formats/parsing_json.gleam b/universal/test/formats/parsing_json.gleam new file mode 100644 index 0000000..ce912ac --- /dev/null +++ b/universal/test/formats/parsing_json.gleam @@ -0,0 +1,40 @@ +//// # Parsing JSON +//// +//// The gleam_json library can be used to decode JSON. +//// +//// ## Dependencies +//// +//// - https://hex.pm/packages/gleam_json + +import gleam/dict +import gleam/dynamic +import gleam/json +import gleeunit/should + +type User(name, age, is_admin) { + User(name, age, is_admin) +} + +pub fn main_test() { + // Basic string key-value pair + "{\"name\": \"cookbook\"}" + |> json.decode(dynamic.dict(dynamic.string, dynamic.string)) + |> should.equal(Ok(dict.from_list([#("name", "cookbook")]))) + + // String key-value pair with list of integers + "{\"scores\": [1, 2, 3]}" + |> json.decode(dynamic.dict(dynamic.string, dynamic.list(of: dynamic.int))) + |> should.equal(Ok(dict.from_list([#("scores", [1, 2, 3])]))) + + // Custom decoder + let decoder = + dynamic.decode3( + User, + dynamic.field("name", dynamic.string), + dynamic.field("age", dynamic.int), + dynamic.field("is_admin", dynamic.bool), + ) + "{\"name\": \"Alice\", \"age\": 42, \"is_admin\": true}" + |> json.decode(decoder) + |> should.equal(Ok(User("Alice", 42, True))) +} From 8c61653d1c61901503fe971fe370a1e3826106be Mon Sep 17 00:00:00 2001 From: Lee Jarvis <lee@jrvs.uk> Date: Tue, 12 Nov 2024 10:58:49 +0000 Subject: [PATCH 2/3] Use decode/zero --- universal/gleam.toml | 1 + universal/manifest.toml | 2 ++ universal/test/formats/parsing_json.gleam | 44 +++++++++++++---------- 3 files changed, 28 insertions(+), 19 deletions(-) diff --git a/universal/gleam.toml b/universal/gleam.toml index daaff51..78e0511 100644 --- a/universal/gleam.toml +++ b/universal/gleam.toml @@ -22,6 +22,7 @@ lustre = ">= 4.4.4 and < 5.0.0" gleam_crypto = ">= 1.3.0 and < 2.0.0" tom = ">= 1.1.0 and < 2.0.0" envoy = ">= 1.0.2 and < 2.0.0" +decode = ">= 0.4.1" [dev-dependencies] gleeunit = ">= 1.0.0 and < 2.0.0" diff --git a/universal/manifest.toml b/universal/manifest.toml index 69ac9f9..225d20b 100644 --- a/universal/manifest.toml +++ b/universal/manifest.toml @@ -2,6 +2,7 @@ # You typically do not need to edit this file packages = [ + { name = "decode", version = "0.4.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "decode", source = "hex", outer_checksum = "90C83E830B380EAF64A0A20D0116C4C173AD753594AF1A37E692C1A699244244" }, { name = "envoy", version = "1.0.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "envoy", source = "hex", outer_checksum = "95FD059345AA982E89A0B6E2A3BF1CF43E17A7048DCD85B5B65D3B9E4E39D359" }, { name = "filepath", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "EFB6FF65C98B2A16378ABC3EE2B14124168C0CE5201553DE652E2644DCFDB594" }, { name = "gleam_crypto", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_crypto", source = "hex", outer_checksum = "ADD058DEDE8F0341F1ADE3AAC492A224F15700829D9A3A3F9ADF370F875C51B7" }, @@ -18,6 +19,7 @@ packages = [ ] [requirements] +decode = { version = ">= 0.4.1" } envoy = { version = ">= 1.0.2 and < 2.0.0" } gleam_crypto = { version = ">= 1.3.0 and < 2.0.0" } gleam_json = { version = ">= 1.0.1 and < 2.0.0" } diff --git a/universal/test/formats/parsing_json.gleam b/universal/test/formats/parsing_json.gleam index ce912ac..f2c1634 100644 --- a/universal/test/formats/parsing_json.gleam +++ b/universal/test/formats/parsing_json.gleam @@ -6,35 +6,41 @@ //// //// - https://hex.pm/packages/gleam_json -import gleam/dict -import gleam/dynamic +import decode/zero import gleam/json import gleeunit/should -type User(name, age, is_admin) { - User(name, age, is_admin) +pub type User { + User(name: String, age: Int, is_admin: Bool) } pub fn main_test() { - // Basic string key-value pair + // Simple types + let decoder = { + use name <- zero.field("name", zero.string) + zero.success(name) + } "{\"name\": \"cookbook\"}" - |> json.decode(dynamic.dict(dynamic.string, dynamic.string)) - |> should.equal(Ok(dict.from_list([#("name", "cookbook")]))) + |> json.decode(zero.run(_, decoder)) + |> should.equal(Ok("cookbook")) - // String key-value pair with list of integers + // Lists + let decoder = { + use scores <- zero.field("scores", zero.list(zero.int)) + zero.success(scores) + } "{\"scores\": [1, 2, 3]}" - |> json.decode(dynamic.dict(dynamic.string, dynamic.list(of: dynamic.int))) - |> should.equal(Ok(dict.from_list([#("scores", [1, 2, 3])]))) + |> json.decode(zero.run(_, decoder)) + |> should.equal(Ok([1, 2, 3])) - // Custom decoder - let decoder = - dynamic.decode3( - User, - dynamic.field("name", dynamic.string), - dynamic.field("age", dynamic.int), - dynamic.field("is_admin", dynamic.bool), - ) + // Records + let decoder = { + use name <- zero.field("name", zero.string) + use age <- zero.field("age", zero.int) + use is_admin <- zero.field("is_admin", zero.bool) + zero.success(User(name:, age:, is_admin:)) + } "{\"name\": \"Alice\", \"age\": 42, \"is_admin\": true}" - |> json.decode(decoder) + |> json.decode(zero.run(_, decoder)) |> should.equal(Ok(User("Alice", 42, True))) } From 5c76b8764ae88741bccd6e18f4e061b755ddb6c9 Mon Sep 17 00:00:00 2001 From: Lee Jarvis <lee@jrvs.uk> Date: Tue, 12 Nov 2024 11:27:47 +0000 Subject: [PATCH 3/3] Add optionals example --- universal/test/formats/parsing_json.gleam | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/universal/test/formats/parsing_json.gleam b/universal/test/formats/parsing_json.gleam index f2c1634..4e7ffc6 100644 --- a/universal/test/formats/parsing_json.gleam +++ b/universal/test/formats/parsing_json.gleam @@ -8,6 +8,7 @@ import decode/zero import gleam/json +import gleam/option import gleeunit/should pub type User { @@ -33,6 +34,18 @@ pub fn main_test() { |> json.decode(zero.run(_, decoder)) |> should.equal(Ok([1, 2, 3])) + // Optionals + let decoder = { + use name <- zero.field("name", zero.optional(zero.string)) + zero.success(name) + } + "{\"name\": \"cookbook\"}" + |> json.decode(zero.run(_, decoder)) + |> should.equal(Ok(option.Some("cookbook"))) + "{\"name\": null}" + |> json.decode(zero.run(_, decoder)) + |> should.equal(Ok(option.None)) + // Records let decoder = { use name <- zero.field("name", zero.string)