-module(ducky). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/ducky.gleam"). -export([path/1, field/2, get/2, connect/1, close/1, with_connection/2, transaction/2, 'query'/2, query_params/3]). -export_type([error/0, value/0, row/0, data_frame/0, connection/0]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. ?MODULEDOC( " Native DuckDB driver for Gleam.\n" "\n" " ## Quick Start\n" "\n" " ```gleam\n" " import ducky\n" " import gleam/int\n" " import gleam/io\n" "\n" " pub fn main() {\n" " use conn <- ducky.with_connection(\":memory:\")\n" "\n" " // Create our duck pond\n" " let assert Ok(_) = ducky.query(conn, \"\n" " CREATE TABLE ducks (name TEXT, quack_volume INT, is_rubber BOOLEAN)\n" " \")\n" " let assert Ok(_) = ducky.query(conn, \"\n" " INSERT INTO ducks VALUES\n" " ('Sir Quacksalot', 95, false),\n" " ('Duck Norris', 100, false),\n" " ('Mallard Fillmore', 72, false),\n" " ('Squeaky', 0, true)\n" " \")\n" "\n" " // Find the loudest quacker\n" " let assert Ok(result) = ducky.query(conn, \"\n" " SELECT name, quack_volume FROM ducks\n" " WHERE is_rubber = false\n" " ORDER BY quack_volume DESC LIMIT 1\n" " \")\n" "\n" " case result.rows {\n" " [ducky.Row([ducky.Text(name), ducky.Integer(volume)])] ->\n" " io.println(name <> \" wins at \" <> int.to_string(volume) <> \" decibels!\")\n" " _ -> io.println(\"The pond is empty...\")\n" " }\n" " }\n" " // => Duck Norris wins at 100 decibels!\n" " ```\n" ). -type error() :: {connection_failed, binary()} | {query_syntax_error, binary()} | {timeout, integer()} | {type_mismatch, binary(), binary()} | {unsupported_parameter_type, binary()} | {database_error, binary()}. -type value() :: null | {boolean, boolean()} | {tiny_int, integer()} | {small_int, integer()} | {integer, integer()} | {big_int, integer()} | {float, float()} | {double, float()} | {decimal, binary()} | {text, binary()} | {blob, bitstring()} | {timestamp, integer()} | {date, integer()} | {time, integer()} | {interval, integer(), integer(), integer()} | {list, list(value())} | {array, list(value())} | {map, gleam@dict:dict(binary(), value())} | {struct, gleam@dict:dict(binary(), value())}. -type row() :: {row, list(value())}. -type data_frame() :: {data_frame, list(binary()), list(row())}. -opaque connection() :: {connection, ducky@internal@connection:connection()}. -file("src/ducky.gleam", 143). ?DOC(" Returns the database path for a connection.\n"). -spec path(connection()) -> binary(). path(Conn) -> ducky@internal@connection:path(erlang:element(2, Conn)). -file("src/ducky.gleam", 290). ?DOC( " Get a field value from a struct by field name.\n" "\n" " Returns None if the value is not a Struct or the field does not exist.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " let person = Struct(dict.from_list([#(\"name\", Text(\"Alice\")), #(\"age\", Integer(30))]))\n" " field(person, \"name\")\n" " // => Some(Text(\"Alice\"))\n" "\n" " field(person, \"unknown\")\n" " // => None\n" " ```\n" ). -spec field(value(), binary()) -> gleam@option:option(value()). field(Value, Name) -> case Value of {struct, Fields} -> _pipe = gleam_stdlib:map_get(Fields, Name), gleam@option:from_result(_pipe); _ -> none end. -file("src/ducky.gleam", 297). -spec list_at(list(DSQ), integer()) -> gleam@option:option(DSQ). list_at(Items, Index) -> case {Items, Index} of {[], _} -> none; {[First | _], 0} -> {some, First}; {[_ | Rest], N} when N > 0 -> list_at(Rest, N - 1); {_, _} -> none end. -file("src/ducky.gleam", 270). ?DOC( " Get a value from a row by column index.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " let row = Row([Integer(1), Text(\"Alice\")])\n" " get(row, 0)\n" " // => Some(Integer(1))\n" "\n" " get(row, 5)\n" " // => None\n" " ```\n" ). -spec get(row(), integer()) -> gleam@option:option(value()). get(Row, Index) -> case Row of {row, Values} -> list_at(Values, Index) end. -file("src/ducky.gleam", 307). ?DOC(" Creates a tagged tuple {tag, value} for NIF parameter encoding.\n"). -spec make_tagged(binary(), gleam@dynamic:dynamic_()) -> gleam@dynamic:dynamic_(). make_tagged(Tag, Value) -> erlang:list_to_tuple([erlang:binary_to_atom(Tag), Value]). -file("src/ducky.gleam", 312). ?DOC(" Creates an interval 4-tuple {interval, months, days, nanos}.\n"). -spec make_interval_tuple(integer(), integer(), integer()) -> gleam@dynamic:dynamic_(). make_interval_tuple(Months, Days, Nanos) -> erlang:list_to_tuple( [erlang:binary_to_atom(<<"interval"/utf8>>), gleam_stdlib:identity(Months), gleam_stdlib:identity(Days), gleam_stdlib:identity(Nanos)] ). -file("src/ducky.gleam", 322). ?DOC(" Converts a Value to a Dynamic for passing to the NIF.\n"). -spec value_to_dynamic(value()) -> {ok, gleam@dynamic:dynamic_()} | {error, error()}. value_to_dynamic(Value) -> case Value of null -> {ok, gleam@dynamic:nil()}; {boolean, B} -> {ok, gleam_stdlib:identity(B)}; {tiny_int, I} -> {ok, gleam_stdlib:identity(I)}; {small_int, I@1} -> {ok, gleam_stdlib:identity(I@1)}; {integer, I@2} -> {ok, gleam_stdlib:identity(I@2)}; {big_int, I@3} -> {ok, gleam_stdlib:identity(I@3)}; {float, F} -> {ok, gleam_stdlib:identity(F)}; {double, F@1} -> {ok, gleam_stdlib:identity(F@1)}; {text, S} -> {ok, gleam_stdlib:identity(S)}; {blob, Bits} -> {ok, gleam_stdlib:identity(Bits)}; {timestamp, Micros} -> {ok, make_tagged(<<"timestamp"/utf8>>, gleam_stdlib:identity(Micros))}; {date, Days} -> {ok, make_tagged(<<"date"/utf8>>, gleam_stdlib:identity(Days))}; {time, Micros@1} -> {ok, make_tagged(<<"time"/utf8>>, gleam_stdlib:identity(Micros@1))}; {interval, Months, Days@1, Nanos} -> {ok, make_interval_tuple(Months, Days@1, Nanos)}; {decimal, S@1} -> {ok, make_tagged(<<"decimal"/utf8>>, gleam_stdlib:identity(S@1))}; {list, _} -> {error, {unsupported_parameter_type, <<"List, Array, Map, and Struct types cannot be used as query parameters"/utf8>>}}; {array, _} -> {error, {unsupported_parameter_type, <<"List, Array, Map, and Struct types cannot be used as query parameters"/utf8>>}}; {map, _} -> {error, {unsupported_parameter_type, <<"List, Array, Map, and Struct types cannot be used as query parameters"/utf8>>}}; {struct, _} -> {error, {unsupported_parameter_type, <<"List, Array, Map, and Struct types cannot be used as query parameters"/utf8>>}} end. -file("src/ducky.gleam", 446). ?DOC(" Decodes a decimal tagged tuple {decimal, \"string\"}.\n"). -spec decode_decimal_value(gleam@dynamic:dynamic_()) -> value(). decode_decimal_value(Dyn) -> Decoder = begin gleam@dynamic@decode:subfield( [1], {decoder, fun gleam@dynamic@decode:decode_string/1}, fun(Value) -> gleam@dynamic@decode:success(Value) end ) end, case gleam@dynamic@decode:run(Dyn, Decoder) of {ok, Value@1} -> {decimal, Value@1}; {error, _} -> null end. -file("src/ducky.gleam", 498). ?DOC(" Decodes temporal tagged tuples (timestamp, date, time).\n"). -spec decode_temporal_tuple(gleam@dynamic:dynamic_()) -> value(). decode_temporal_tuple(Dyn) -> Decoder = begin gleam@dynamic@decode:subfield( [0], {decoder, fun gleam@dynamic@decode:decode_dynamic/1}, fun(Tag_dynamic) -> gleam@dynamic@decode:subfield( [1], {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(Value) -> Tag = case gleam_stdlib:classify_dynamic(Tag_dynamic) of <<"Atom"/utf8>> -> erlang:atom_to_binary(Tag_dynamic); <<"String"/utf8>> -> _pipe = gleam@dynamic@decode:run( Tag_dynamic, {decoder, fun gleam@dynamic@decode:decode_string/1} ), gleam@result:unwrap(_pipe, <<""/utf8>>); _ -> <<""/utf8>> end, gleam@dynamic@decode:success({Tag, Value}) end ) end ) end, case gleam@dynamic@decode:run(Dyn, Decoder) of {ok, {Tag@1, Value@1}} -> case Tag@1 of <<"timestamp"/utf8>> -> {timestamp, Value@1}; <<"date"/utf8>> -> {date, Value@1}; <<"time"/utf8>> -> {time, Value@1}; _ -> null end; {error, _} -> null end. -file("src/ducky.gleam", 527). ?DOC(" Decodes interval 4-tuple {interval, months, days, nanos}.\n"). -spec decode_interval_tuple(gleam@dynamic:dynamic_()) -> value(). decode_interval_tuple(Dyn) -> Decoder = begin gleam@dynamic@decode:subfield( [1], {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(Months) -> gleam@dynamic@decode:subfield( [2], {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(Days) -> gleam@dynamic@decode:subfield( [3], {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(Nanos) -> gleam@dynamic@decode:success( {Months, Days, Nanos} ) end ) end ) end ) end, case gleam@dynamic@decode:run(Dyn, Decoder) of {ok, {Months@1, Days@1, Nanos@1}} -> {interval, Months@1, Days@1, Nanos@1}; {error, _} -> null end. -file("src/ducky.gleam", 541). -spec error_from_tag(binary(), binary()) -> error(). error_from_tag(Tag, Message) -> case Tag of <<"connection_failed"/utf8>> -> {connection_failed, Message}; <<"query_syntax_error"/utf8>> -> {query_syntax_error, Message}; <<"unsupported_parameter_type"/utf8>> -> {unsupported_parameter_type, Message}; <<"database_error"/utf8>> -> {database_error, Message}; _ -> {database_error, <<<<<<"["/utf8, Tag/binary>>/binary, "] "/utf8>>/binary, Message/binary>>} end. -file("src/ducky.gleam", 551). -spec error_tuple_decoder() -> gleam@dynamic@decode:decoder({binary(), binary()}). error_tuple_decoder() -> gleam@dynamic@decode:subfield( [0], {decoder, fun gleam@dynamic@decode:decode_dynamic/1}, fun(Error_type_dyn) -> gleam@dynamic@decode:subfield( [1], {decoder, fun gleam@dynamic@decode:decode_string/1}, fun(Message) -> Error_type = case gleam_stdlib:classify_dynamic( Error_type_dyn ) of <<"Atom"/utf8>> -> erlang:atom_to_binary(Error_type_dyn); _ -> <<"unknown"/utf8>> end, gleam@dynamic@decode:success({Error_type, Message}) end ) end ). -file("src/ducky.gleam", 574). ?DOC(" Fallback decoder for unexpected error formats.\n"). -spec fallback_decode(gleam@dynamic:dynamic_()) -> error(). fallback_decode(Err) -> case gleam@dynamic@decode:run(Err, error_tuple_decoder()) of {ok, {Tag, Msg}} -> error_from_tag(Tag, Msg); {error, _} -> {database_error, <<"Unknown error: "/utf8, (gleam@string:inspect(Err))/binary>>} end. -file("src/ducky.gleam", 564). ?DOC(" Decodes an error from the NIF layer.\n"). -spec decode_nif_error(gleam@dynamic:dynamic_()) -> error(). decode_nif_error(Err) -> Decoder = gleam@dynamic@decode:at([1], error_tuple_decoder()), case gleam@dynamic@decode:run(Err, Decoder) of {ok, {Tag, Msg}} -> error_from_tag(Tag, Msg); {error, _} -> fallback_decode(Err) end. -file("src/ducky.gleam", 119). ?DOC( " Opens a connection to a DuckDB database.\n" "\n" " Must call `close()` when done. Use `with_connection()` instead\n" " for automatic cleanup.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " connect(\":memory:\")\n" " // => Ok(Connection(...))\n" "\n" " connect(\"data.duckdb\")\n" " // => Ok(Connection(...))\n" " ```\n" ). -spec connect(binary()) -> {ok, connection()} | {error, error()}. connect(Path) -> case Path of <<""/utf8>> -> {error, {connection_failed, <<"path cannot be empty"/utf8>>}}; _ -> _pipe = ducky@internal@connection:do_connect(Path), _pipe@1 = gleam@result:map( _pipe, fun(Internal) -> {connection, Internal} end ), gleam@result:map_error(_pipe@1, fun decode_nif_error/1) end. -file("src/ducky.gleam", 137). ?DOC( " Closes a database connection.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " let assert Ok(conn) = connect(\":memory:\")\n" " let assert Ok(_) = close(conn)\n" " ```\n" ). -spec close(connection()) -> {ok, nil} | {error, error()}. close(Conn) -> _pipe = ducky@internal@connection:do_close(erlang:element(2, Conn)), gleam@result:map_error(_pipe, fun decode_nif_error/1). -file("src/ducky.gleam", 157). ?DOC( " Executes operations with automatic connection cleanup.\n" "\n" " Connection closes automatically on success or error.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " use conn <- with_connection(\":memory:\")\n" " query(conn, \"SELECT 42\")\n" " ```\n" ). -spec with_connection( binary(), fun((connection()) -> {ok, DRZ} | {error, error()}) ) -> {ok, DRZ} | {error, error()}. with_connection(Db_path, Callback) -> gleam@result:'try'( connect(Db_path), fun(Conn) -> Res = Callback(Conn), _ = close(Conn), Res end ). -file("src/ducky.gleam", 179). ?DOC( " Executes operations within a transaction.\n" "\n" " Commits on success, rolls back on error.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " transaction(conn, fn(conn) {\n" " use _ <- result.try(query(conn, \"UPDATE accounts ...\"))\n" " query(conn, \"SELECT * FROM accounts\")\n" " })\n" " ```\n" ). -spec transaction( connection(), fun((connection()) -> {ok, DSE} | {error, error()}) ) -> {ok, DSE} | {error, error()}. transaction(Conn, Callback) -> gleam@result:'try'( begin _pipe = ducky@internal@connection:execute_raw( erlang:element(2, Conn), <<"BEGIN TRANSACTION"/utf8>> ), gleam@result:map_error(_pipe, fun decode_nif_error/1) end, fun(_) -> case Callback(Conn) of {ok, Value} -> gleam@result:'try'( begin _pipe@1 = ducky@internal@connection:execute_raw( erlang:element(2, Conn), <<"COMMIT"/utf8>> ), gleam@result:map_error( _pipe@1, fun decode_nif_error/1 ) end, fun(_) -> {ok, Value} end ); {error, Err} -> _ = ducky@internal@connection:execute_raw( erlang:element(2, Conn), <<"ROLLBACK"/utf8>> ), {error, Err} end end ). -file("src/ducky.gleam", 385). ?DOC(" Decodes a list with recursive element decoding.\n"). -spec decode_list(gleam@dynamic:dynamic_()) -> value(). decode_list(Dyn) -> Decoder = gleam@dynamic@decode:list( {decoder, fun gleam@dynamic@decode:decode_dynamic/1} ), case gleam@dynamic@decode:run(Dyn, Decoder) of {ok, Elements} -> Decoded_elements = gleam@list:map(Elements, fun decode_value/1), {list, Decoded_elements}; {error, _} -> null end. -file("src/ducky.gleam", 362). ?DOC(" Decodes a dynamic value from the NIF into a typed Value.\n"). -spec decode_value(gleam@dynamic:dynamic_()) -> value(). decode_value(Dyn) -> Classification = gleam_stdlib:classify_dynamic(Dyn), case Classification of <<"Atom"/utf8>> -> null; <<"Dict"/utf8>> -> decode_struct(Dyn); <<"List"/utf8>> -> decode_list(Dyn); <<"Array"/utf8>> -> decode_tagged_tuple(Dyn); _ -> Value_decoder = gleam@dynamic@decode:one_of( begin _pipe = {decoder, fun gleam@dynamic@decode:decode_bool/1}, gleam@dynamic@decode:map( _pipe, fun(Field@0) -> {boolean, Field@0} end ) end, [begin _pipe@1 = {decoder, fun gleam@dynamic@decode:decode_int/1}, gleam@dynamic@decode:map( _pipe@1, fun(Field@0) -> {integer, Field@0} end ) end, begin _pipe@2 = {decoder, fun gleam@dynamic@decode:decode_float/1}, gleam@dynamic@decode:map( _pipe@2, fun(Field@0) -> {double, Field@0} end ) end, begin _pipe@3 = {decoder, fun gleam@dynamic@decode:decode_string/1}, gleam@dynamic@decode:map( _pipe@3, fun(Field@0) -> {text, Field@0} end ) end, begin _pipe@4 = {decoder, fun gleam@dynamic@decode:decode_bit_array/1}, gleam@dynamic@decode:map( _pipe@4, fun(Field@0) -> {blob, Field@0} end ) end] ), _pipe@5 = gleam@dynamic@decode:run(Dyn, Value_decoder), gleam@result:unwrap(_pipe@5, null) end. -file("src/ducky.gleam", 348). ?DOC(" Decodes raw NIF result into a DataFrame.\n"). -spec decode_dataframe({list(binary()), list(list(gleam@dynamic:dynamic_()))}) -> data_frame(). decode_dataframe(Raw) -> {Columns, Rows} = Raw, Decoded_rows = begin _pipe = Rows, gleam@list:map( _pipe, fun(Row) -> Values = gleam@list:map(Row, fun decode_value/1), {row, Values} end ) end, {data_frame, Columns, Decoded_rows}. -file("src/ducky.gleam", 218). ?DOC( " Executes a SQL query and returns structured results.\n" "\n" " The query runs on a dirty scheduler to avoid blocking the BEAM.\n" " Results are loaded into memory. For large datasets, use LIMIT/OFFSET\n" " or filter in SQL to reduce memory usage.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " query(conn, \"SELECT id, name FROM users WHERE active = true\")\n" " // => Ok(DataFrame(columns: [\"id\", \"name\"], rows: [...]))\n" "\n" " // For large datasets, paginate:\n" " query(conn, \"SELECT * FROM users LIMIT 1000 OFFSET 0\")\n" " ```\n" ). -spec 'query'(connection(), binary()) -> {ok, data_frame()} | {error, error()}. 'query'(Conn, Sql) -> _pipe = ducky_nif:execute_query( ducky@internal@connection:native(erlang:element(2, Conn)), Sql, [] ), _pipe@1 = gleam@result:map(_pipe, fun decode_dataframe/1), gleam@result:map_error(_pipe@1, fun decode_nif_error/1). -file("src/ducky.gleam", 246). ?DOC( " Executes a parameterized SQL query with bound parameters to prevent SQL injection.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " query_params(conn, \"SELECT * FROM users WHERE id = ? AND age > ?\", [\n" " Integer(42),\n" " Integer(18),\n" " ])\n" " // => Ok(DataFrame(...))\n" " ```\n" "\n" " ## Security\n" "\n" " Always use this function when including user input in queries:\n" " ```gleam\n" " // UNSAFE - SQL injection risk\n" " query(conn, \"SELECT * FROM users WHERE name = '\" <> user_input <> \"'\")\n" "\n" " // SAFE - parameters are properly escaped\n" " query_params(conn, \"SELECT * FROM users WHERE name = ?\", [Text(user_input)])\n" " ```\n" ). -spec query_params(connection(), binary(), list(value())) -> {ok, data_frame()} | {error, error()}. query_params(Conn, Sql, Params) -> gleam@result:'try'( gleam@list:try_map(Params, fun value_to_dynamic/1), fun(Dynamic_params) -> _pipe = ducky_nif:execute_query( ducky@internal@connection:native(erlang:element(2, Conn)), Sql, Dynamic_params ), _pipe@1 = gleam@result:map(_pipe, fun decode_dataframe/1), gleam@result:map_error(_pipe@1, fun decode_nif_error/1) end ). -file("src/ducky.gleam", 398). ?DOC(" Decodes an Erlang map into a Struct with recursive value decoding.\n"). -spec decode_struct(gleam@dynamic:dynamic_()) -> value(). decode_struct(Dyn) -> Decoder = begin _pipe = gleam@dynamic@decode:dict( {decoder, fun gleam@dynamic@decode:decode_string/1}, {decoder, fun gleam@dynamic@decode:decode_dynamic/1} ), gleam@dynamic@decode:map( _pipe, fun(Fields) -> Decoded_fields = begin _pipe@1 = Fields, _pipe@2 = maps:to_list(_pipe@1), _pipe@3 = gleam@list:map( _pipe@2, fun(Pair) -> {Key, Val} = Pair, {Key, decode_value(Val)} end ), maps:from_list(_pipe@3) end, {struct, Decoded_fields} end ) end, _pipe@4 = gleam@dynamic@decode:run(Dyn, Decoder), gleam@result:unwrap(_pipe@4, null). -file("src/ducky.gleam", 458). ?DOC(" Decodes an array tagged tuple {array, [elements]}.\n"). -spec decode_array_value(gleam@dynamic:dynamic_()) -> value(). decode_array_value(Dyn) -> Decoder = begin gleam@dynamic@decode:subfield( [1], gleam@dynamic@decode:list( {decoder, fun gleam@dynamic@decode:decode_dynamic/1} ), fun(Elements) -> gleam@dynamic@decode:success(Elements) end ) end, case gleam@dynamic@decode:run(Dyn, Decoder) of {ok, Elements@1} -> Decoded_elements = gleam@list:map(Elements@1, fun decode_value/1), {array, Decoded_elements}; {error, _} -> null end. -file("src/ducky.gleam", 473). ?DOC(" Decodes a map tagged tuple {map, %{key => value}}.\n"). -spec decode_map_value(gleam@dynamic:dynamic_()) -> value(). decode_map_value(Dyn) -> Decoder = begin gleam@dynamic@decode:subfield( [1], gleam@dynamic@decode:dict( {decoder, fun gleam@dynamic@decode:decode_string/1}, {decoder, fun gleam@dynamic@decode:decode_dynamic/1} ), fun(Entries) -> gleam@dynamic@decode:success(Entries) end ) end, case gleam@dynamic@decode:run(Dyn, Decoder) of {ok, Entries@1} -> Decoded_entries = begin _pipe = Entries@1, _pipe@1 = maps:to_list(_pipe), _pipe@2 = gleam@list:map( _pipe@1, fun(Pair) -> {Key, Val} = Pair, {Key, decode_value(Val)} end ), maps:from_list(_pipe@2) end, {map, Decoded_entries}; {error, _} -> null end. -file("src/ducky.gleam", 419). ?DOC(" Decodes tagged tuples sent as Erlang arrays for various types.\n"). -spec decode_tagged_tuple(gleam@dynamic:dynamic_()) -> value(). decode_tagged_tuple(Dyn) -> Tag_decoder = begin gleam@dynamic@decode:subfield( [0], {decoder, fun gleam@dynamic@decode:decode_dynamic/1}, fun(Tag_dynamic) -> gleam@dynamic@decode:success(Tag_dynamic) end ) end, case gleam@dynamic@decode:run(Dyn, Tag_decoder) of {ok, Tag_dynamic@1} -> Tag = case gleam_stdlib:classify_dynamic(Tag_dynamic@1) of <<"Atom"/utf8>> -> erlang:atom_to_binary(Tag_dynamic@1); _ -> <<""/utf8>> end, case Tag of <<"decimal"/utf8>> -> decode_decimal_value(Dyn); <<"array"/utf8>> -> decode_array_value(Dyn); <<"map"/utf8>> -> decode_map_value(Dyn); <<"timestamp"/utf8>> -> decode_temporal_tuple(Dyn); <<"date"/utf8>> -> decode_temporal_tuple(Dyn); <<"time"/utf8>> -> decode_temporal_tuple(Dyn); <<"interval"/utf8>> -> decode_interval_tuple(Dyn); _ -> null end; {error, _} -> null end.