diff --git a/gleam.toml b/gleam.toml index 462b640..65f78e5 100644 --- a/gleam.toml +++ b/gleam.toml @@ -26,7 +26,7 @@ allow_write = [ ] [dependencies] -gleam_stdlib = "~> 0.25" +gleam_stdlib = "~> 0.51" esqlite = "~> 0.8" [dev-dependencies] diff --git a/manifest.toml b/manifest.toml index e54da36..edae797 100644 --- a/manifest.toml +++ b/manifest.toml @@ -2,12 +2,12 @@ # You typically do not need to edit this file packages = [ - { name = "esqlite", version = "0.8.8", build_tools = ["rebar3"], requirements = [], otp_app = "esqlite", source = "hex", outer_checksum = "374902457C7D94DC9409C98D3BDD1CA0D50A60DC9F3BDF1FD8EB74C0DCDF02D6" }, - { name = "gleam_stdlib", version = "0.39.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "2D7DE885A6EA7F1D5015D1698920C9BAF7241102836CE0C3837A4F160128A9C4" }, + { name = "esqlite", version = "0.8.9", build_tools = ["rebar3"], requirements = [], otp_app = "esqlite", source = "hex", outer_checksum = "465AE9AE28AE4192EA54C829FDC90C320447D439A9B2E10946621672FC6A6F8C" }, + { name = "gleam_stdlib", version = "0.51.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "14AFA8D3DDD7045203D422715DBB822D1725992A31DF35A08D97389014B74B68" }, { name = "gleeunit", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "F7A7228925D3EE7D0813C922E062BFD6D7E9310F0BEE585D3A42F3307E3CFD13" }, ] [requirements] esqlite = { version = "~> 0.8" } -gleam_stdlib = { version = "~> 0.25" } +gleam_stdlib = { version = "~> 0.51" } gleeunit = { version = "~> 1.0" } diff --git a/src/sqlight.gleam b/src/sqlight.gleam index 2321c9c..0d6f238 100644 --- a/src/sqlight.gleam +++ b/src/sqlight.gleam @@ -1,4 +1,4 @@ -import gleam/dynamic.{type Decoder, type Dynamic} +import gleam/dynamic/decode.{type Decoder, type Dynamic} import gleam/list import gleam/option.{type Option, None, Some} import gleam/result @@ -383,7 +383,7 @@ pub fn query( ) -> Result(List(t), Error) { use rows <- result.then(run_query(sql, connection, arguments)) use rows <- result.then( - list.try_map(over: rows, with: decoder) + list.try_map(over: rows, with: fn(row) { decode.run(row, decoder) }) |> result.map_error(decode_error), ) Ok(rows) @@ -468,16 +468,17 @@ pub fn null() -> Value /// /// Decodes 0 as `False` and any other integer as `True`. /// -pub fn decode_bool(value: Dynamic) -> Result(Bool, List(dynamic.DecodeError)) { - case dynamic.int(value) { - Ok(0) -> Ok(False) - Ok(_) -> Ok(True) - Error(e) -> Error(e) +pub fn decode_bool() -> Decoder(Bool) { + use b <- decode.then(decode.int) + + case b { + 0 -> decode.success(False) + _ -> decode.success(True) } } -fn decode_error(errors: List(dynamic.DecodeError)) -> Error { - let assert [dynamic.DecodeError(expected, actual, path), ..] = errors +fn decode_error(errors: List(decode.DecodeError)) -> Error { + let assert [decode.DecodeError(expected, actual, path), ..] = errors let path = string.join(path, ".") let message = "Decoder failed, expected " diff --git a/test/sqlight_test.gleam b/test/sqlight_test.gleam index ced5a62..84757cb 100644 --- a/test/sqlight_test.gleam +++ b/test/sqlight_test.gleam @@ -1,4 +1,4 @@ -import gleam/dynamic +import gleam/dynamic/decode import gleam/list import gleam/option import gleeunit @@ -54,18 +54,23 @@ pub fn with_connection_test() { pub fn query_1_test() { use conn <- connect() let assert Ok([#(1, 2, 3), #(4, 5, 6)]) = - sqlight.query( - "select 1, 2, 3 union all select 4, 5, 6", - conn, - [], - dynamic.tuple3(dynamic.int, dynamic.int, dynamic.int), - ) + sqlight.query("select 1, 2, 3 union all select 4, 5, 6", conn, [], { + use one <- decode.field(0, decode.int) + use two <- decode.field(1, decode.int) + use three <- decode.field(2, decode.int) + decode.success(#(one, two, three)) + }) } pub fn query_2_test() { use conn <- connect() let assert Ok([1337]) = - sqlight.query("select 1337", conn, [], dynamic.element(0, dynamic.int)) + sqlight.query( + "select 1337", + conn, + [], + decode.field(0, decode.int, decode.success), + ) } pub fn bind_int_test() { @@ -75,7 +80,7 @@ pub fn bind_int_test() { "select ?", conn, [sqlight.int(12_345)], - dynamic.element(0, dynamic.int), + decode.field(0, decode.int, decode.success), ) } @@ -86,7 +91,7 @@ pub fn bind_float_test() { "select ?", conn, [sqlight.float(12_345.6789)], - dynamic.element(0, dynamic.float), + decode.field(0, decode.float, decode.success), ) } @@ -97,19 +102,18 @@ pub fn bind_text_test() { "select ?", conn, [sqlight.text("hello")], - dynamic.element(0, dynamic.string), + decode.field(0, decode.string, decode.success), ) } pub fn bind_blob_test() { use conn <- connect() let assert Ok([#(<<123, 0>>, "blob")]) = - sqlight.query( - "select ?1, typeof(?1)", - conn, - [sqlight.blob(<<123, 0>>)], - dynamic.tuple2(dynamic.bit_array, dynamic.string), - ) + sqlight.query("select ?1, typeof(?1)", conn, [sqlight.blob(<<123, 0>>)], { + use ary <- decode.field(0, decode.bit_array) + use str <- decode.field(1, decode.string) + decode.success(#(ary, str)) + }) } pub fn bind_null_test() { @@ -119,7 +123,7 @@ pub fn bind_null_test() { "select ?", conn, [sqlight.null()], - dynamic.element(0, dynamic.optional(dynamic.int)), + decode.field(0, decode.optional(decode.int), decode.success), ) } @@ -130,7 +134,7 @@ pub fn bind_bool_test() { "select ?", conn, [sqlight.bool(True)], - dynamic.element(0, sqlight.decode_bool), + decode.field(0, sqlight.decode_bool(), decode.success), ) } @@ -144,7 +148,7 @@ pub fn exec_test() { "select name from cats", conn, [], - dynamic.element(0, dynamic.string), + decode.field(0, decode.string, decode.success), ) } @@ -157,7 +161,11 @@ pub fn exec_fail_test() { pub fn readme_example_test() { use conn <- sqlight.with_connection(":memory:") - let cat_decoder = dynamic.tuple2(dynamic.string, dynamic.int) + let cat_decoder = { + use name <- decode.field(0, decode.string) + use age <- decode.field(1, decode.int) + decode.success(#(name, age)) + } let sql = " @@ -242,7 +250,13 @@ pub fn decode_error_test() { sqlight.GenericError, "Decoder failed, expected String, got Int in 0", -1, - )) = sqlight.query("select 1", conn, [], dynamic.element(0, dynamic.string)) + )) = + sqlight.query( + "select 1", + conn, + [], + decode.field(0, decode.string, decode.success), + ) } pub fn query_error_test() { @@ -253,7 +267,7 @@ pub fn query_error_test() { "this isn't a valid query", conn, [], - dynamic.element(0, dynamic.int), + decode.field(0, decode.int, decode.success), ) } @@ -265,7 +279,7 @@ pub fn bind_nullable_test() { "select ?", conn, [sqlight.nullable(sqlight.int, option.Some(12_345))], - dynamic.element(0, dynamic.optional(dynamic.int)), + decode.field(0, decode.optional(decode.int), decode.success), ) let assert Ok([option.None]) = @@ -273,6 +287,6 @@ pub fn bind_nullable_test() { "select ?", conn, [sqlight.nullable(sqlight.int, option.None)], - dynamic.element(0, dynamic.optional(dynamic.int)), + decode.field(0, decode.optional(decode.int), decode.success), ) }