Packages

A compile-time safe database library for Gleam - Ecto-inspired schemas, composable queries, and adapter-based persistence

Current section

Files

Jump to
cquill src cquill@adapter@postgres.erl
Raw

src/cquill@adapter@postgres.erl

-module(cquill@adapter@postgres).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/cquill/adapter/postgres.gleam").
-export([default_config/1, config_from_url/2, host/2, port/2, database/2, user/2, password/2, ssl/2, pool_size/2, default_timeout/2, idle_interval/2, start/1, named_connection/1, postgres_capabilities/0, postgres_adapter/0, with_transaction/2, execute_transaction/2, execute_transaction_with_user_error/2, execute_sql/3, execute_sql_mutation/3, create_savepoint/2, rollback_to_savepoint/2, release_savepoint/2, execute_savepoint/3, execute_savepoint_with_user_error/3, execute_sql_with_timeout/4, execute_sql_mutation_with_timeout/4, default_batch_config/0, batch_delete_all/4, batch_delete_all_returning/4, delete_all_rows/2, insert_all_with_config/5, insert_all/4, insert_all_returning/4, batch_update_all/5, batch_update_all_returning/5, decode_int/2, decode_string/2, decode_float/2, decode_bool/2, decode_optional/3]).
-export_type([postgres_config/0, postgres_connection/0, transaction_error/0, batch_config/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.
-type postgres_config() :: {postgres_config,
gleam@erlang@process:name(pog:message()),
binary(),
integer(),
binary(),
binary(),
gleam@option:option(binary()),
pog:ssl(),
integer(),
integer(),
integer()}.
-opaque postgres_connection() :: {postgres_connection, pog:connection()}.
-type transaction_error() :: {query_error, cquill@error:adapter_error()} |
{rolled_back, binary()}.
-type batch_config() :: {batch_config, integer(), boolean()}.
-file("src/cquill/adapter/postgres.gleam", 59).
?DOC(" Create a default configuration with a pool name.\n").
-spec default_config(gleam@erlang@process:name(pog:message())) -> postgres_config().
default_config(Pool_name) ->
{postgres_config,
Pool_name,
<<"127.0.0.1"/utf8>>,
5432,
<<"postgres"/utf8>>,
<<"postgres"/utf8>>,
none,
ssl_disabled,
10,
5000,
1000}.
-file("src/cquill/adapter/postgres.gleam", 76).
?DOC(
" Create configuration from a database URL.\n"
" URL format: postgresql://user:password@host:port/database\n"
).
-spec config_from_url(gleam@erlang@process:name(pog:message()), binary()) -> {ok,
postgres_config()} |
{error, nil}.
config_from_url(Pool_name, Url) ->
case pog:url_config(Pool_name, Url) of
{ok, Pog_config} ->
{ok,
{postgres_config,
erlang:element(2, Pog_config),
erlang:element(3, Pog_config),
erlang:element(4, Pog_config),
erlang:element(5, Pog_config),
erlang:element(6, Pog_config),
erlang:element(7, Pog_config),
erlang:element(8, Pog_config),
erlang:element(10, Pog_config),
5000,
erlang:element(13, Pog_config)}};
{error, _} ->
{error, nil}
end.
-file("src/cquill/adapter/postgres.gleam", 99).
?DOC(" Set the database host\n").
-spec host(postgres_config(), binary()) -> postgres_config().
host(Config, Host) ->
{postgres_config,
erlang:element(2, Config),
Host,
erlang:element(4, Config),
erlang:element(5, Config),
erlang:element(6, Config),
erlang:element(7, Config),
erlang:element(8, Config),
erlang:element(9, Config),
erlang:element(10, Config),
erlang:element(11, Config)}.
-file("src/cquill/adapter/postgres.gleam", 104).
?DOC(" Set the database port\n").
-spec port(postgres_config(), integer()) -> postgres_config().
port(Config, Port) ->
{postgres_config,
erlang:element(2, Config),
erlang:element(3, Config),
Port,
erlang:element(5, Config),
erlang:element(6, Config),
erlang:element(7, Config),
erlang:element(8, Config),
erlang:element(9, Config),
erlang:element(10, Config),
erlang:element(11, Config)}.
-file("src/cquill/adapter/postgres.gleam", 109).
?DOC(" Set the database name\n").
-spec database(postgres_config(), binary()) -> postgres_config().
database(Config, Database) ->
{postgres_config,
erlang:element(2, Config),
erlang:element(3, Config),
erlang:element(4, Config),
Database,
erlang:element(6, Config),
erlang:element(7, Config),
erlang:element(8, Config),
erlang:element(9, Config),
erlang:element(10, Config),
erlang:element(11, Config)}.
-file("src/cquill/adapter/postgres.gleam", 114).
?DOC(" Set the database user\n").
-spec user(postgres_config(), binary()) -> postgres_config().
user(Config, User) ->
{postgres_config,
erlang:element(2, Config),
erlang:element(3, Config),
erlang:element(4, Config),
erlang:element(5, Config),
User,
erlang:element(7, Config),
erlang:element(8, Config),
erlang:element(9, Config),
erlang:element(10, Config),
erlang:element(11, Config)}.
-file("src/cquill/adapter/postgres.gleam", 119).
?DOC(" Set the database password\n").
-spec password(postgres_config(), gleam@option:option(binary())) -> postgres_config().
password(Config, Password) ->
{postgres_config,
erlang:element(2, Config),
erlang:element(3, Config),
erlang:element(4, Config),
erlang:element(5, Config),
erlang:element(6, Config),
Password,
erlang:element(8, Config),
erlang:element(9, Config),
erlang:element(10, Config),
erlang:element(11, Config)}.
-file("src/cquill/adapter/postgres.gleam", 127).
?DOC(" Set SSL mode\n").
-spec ssl(postgres_config(), pog:ssl()) -> postgres_config().
ssl(Config, Ssl) ->
{postgres_config,
erlang:element(2, Config),
erlang:element(3, Config),
erlang:element(4, Config),
erlang:element(5, Config),
erlang:element(6, Config),
erlang:element(7, Config),
Ssl,
erlang:element(9, Config),
erlang:element(10, Config),
erlang:element(11, Config)}.
-file("src/cquill/adapter/postgres.gleam", 132).
?DOC(" Set the connection pool size\n").
-spec pool_size(postgres_config(), integer()) -> postgres_config().
pool_size(Config, Pool_size) ->
{postgres_config,
erlang:element(2, Config),
erlang:element(3, Config),
erlang:element(4, Config),
erlang:element(5, Config),
erlang:element(6, Config),
erlang:element(7, Config),
erlang:element(8, Config),
Pool_size,
erlang:element(10, Config),
erlang:element(11, Config)}.
-file("src/cquill/adapter/postgres.gleam", 139).
?DOC(
" Set the default query timeout in milliseconds.\n"
" Queries taking longer than this will be aborted with a Timeout error.\n"
" Default is 5000ms (5 seconds).\n"
).
-spec default_timeout(postgres_config(), integer()) -> postgres_config().
default_timeout(Config, Timeout_ms) ->
{postgres_config,
erlang:element(2, Config),
erlang:element(3, Config),
erlang:element(4, Config),
erlang:element(5, Config),
erlang:element(6, Config),
erlang:element(7, Config),
erlang:element(8, Config),
erlang:element(9, Config),
Timeout_ms,
erlang:element(11, Config)}.
-file("src/cquill/adapter/postgres.gleam", 150).
?DOC(
" Set the idle connection ping interval in milliseconds.\n"
" The database is pinged every idle_interval when the connection is idle.\n"
" This helps detect and recover from stale connections.\n"
" Default is 1000ms (1 second).\n"
).
-spec idle_interval(postgres_config(), integer()) -> postgres_config().
idle_interval(Config, Interval_ms) ->
{postgres_config,
erlang:element(2, Config),
erlang:element(3, Config),
erlang:element(4, Config),
erlang:element(5, Config),
erlang:element(6, Config),
erlang:element(7, Config),
erlang:element(8, Config),
erlang:element(9, Config),
erlang:element(10, Config),
Interval_ms}.
-file("src/cquill/adapter/postgres.gleam", 165).
?DOC(" Convert PostgresConfig to pog.Config\n").
-spec to_pog_config(postgres_config()) -> pog:config().
to_pog_config(Config) ->
_pipe = pog:default_config(erlang:element(2, Config)),
_pipe@1 = pog:host(_pipe, erlang:element(3, Config)),
_pipe@2 = pog:port(_pipe@1, erlang:element(4, Config)),
_pipe@3 = pog:database(_pipe@2, erlang:element(5, Config)),
_pipe@4 = pog:user(_pipe@3, erlang:element(6, Config)),
_pipe@5 = pog:password(_pipe@4, erlang:element(7, Config)),
_pipe@6 = pog:ssl(_pipe@5, erlang:element(8, Config)),
_pipe@7 = pog:pool_size(_pipe@6, erlang:element(9, Config)),
pog:idle_interval(_pipe@7, erlang:element(11, Config)).
-file("src/cquill/adapter/postgres.gleam", 179).
?DOC(
" Start a connection pool using the provided configuration.\n"
" Returns a PostgresConnection that can be used for queries.\n"
).
-spec start(postgres_config()) -> {ok, postgres_connection()} |
{error, gleam@otp@actor:start_error()}.
start(Config) ->
Pog_config = to_pog_config(Config),
case pog:start(Pog_config) of
{ok, {started, _, Connection}} ->
{ok, {postgres_connection, Connection}};
{error, Err} ->
{error, Err}
end.
-file("src/cquill/adapter/postgres.gleam", 192).
?DOC(
" Create a connection reference to a named pool.\n"
" Use this when you've started a pool with supervision and need to\n"
" reference it by name.\n"
).
-spec named_connection(gleam@erlang@process:name(pog:message())) -> postgres_connection().
named_connection(Name) ->
{postgres_connection, pog:named_connection(Name)}.
-file("src/cquill/adapter/postgres.gleam", 274).
?DOC(" Infer constraint type from common naming conventions\n").
-spec infer_from_constraint_name(binary()) -> binary().
infer_from_constraint_name(Constraint_lower) ->
case gleam_stdlib:contains_string(Constraint_lower, <<"_pkey"/utf8>>) of
true ->
<<"23505"/utf8>>;
false ->
case gleam_stdlib:contains_string(Constraint_lower, <<"_key"/utf8>>) of
true ->
<<"23505"/utf8>>;
false ->
case gleam_stdlib:contains_string(
Constraint_lower,
<<"_unique"/utf8>>
) of
true ->
<<"23505"/utf8>>;
false ->
case gleam_stdlib:contains_string(
Constraint_lower,
<<"_fkey"/utf8>>
) of
true ->
<<"23503"/utf8>>;
false ->
case gleam_stdlib:contains_string(
Constraint_lower,
<<"_check"/utf8>>
) of
true ->
<<"23514"/utf8>>;
false ->
case gleam_stdlib:contains_string(
Constraint_lower,
<<"_not_null"/utf8>>
) of
true ->
<<"23502"/utf8>>;
false ->
<<"23000"/utf8>>
end
end
end
end
end
end.
-file("src/cquill/adapter/postgres.gleam", 249).
?DOC(
" Infer PostgreSQL error code from constraint name and detail string\n"
"\n"
" Since pog's ConstraintViolated doesn't include the PostgreSQL error code,\n"
" we infer the constraint type from:\n"
" 1. The detail string patterns (most reliable)\n"
" 2. Common constraint naming conventions\n"
).
-spec infer_constraint_code(binary(), binary()) -> binary().
infer_constraint_code(Constraint, Detail) ->
Detail_lower = string:lowercase(Detail),
Constraint_lower = string:lowercase(Constraint),
case gleam_stdlib:contains_string(Detail_lower, <<"already exists"/utf8>>) of
true ->
<<"23505"/utf8>>;
false ->
case gleam_stdlib:contains_string(
Detail_lower,
<<"is not present"/utf8>>
) of
true ->
<<"23503"/utf8>>;
false ->
case gleam_stdlib:contains_string(
Detail_lower,
<<"is still referenced"/utf8>>
) of
true ->
<<"23503"/utf8>>;
false ->
infer_from_constraint_name(Constraint_lower)
end
end
end.
-file("src/cquill/adapter/postgres.gleam", 319).
?DOC(" Join a list of strings with a separator\n").
-spec join(list(binary()), binary()) -> binary().
join(Strings, Separator) ->
case Strings of
[] ->
<<""/utf8>>;
[First] ->
First;
[First@1 | Rest] ->
<<<<First@1/binary, Separator/binary>>/binary,
(join(Rest, Separator))/binary>>
end.
-file("src/cquill/adapter/postgres.gleam", 311).
-spec format_path(list(binary())) -> binary().
format_path(Path) ->
case Path of
[] ->
<<"root"/utf8>>;
Segments ->
join(Segments, <<"."/utf8>>)
end.
-file("src/cquill/adapter/postgres.gleam", 303).
?DOC(" Format decode errors for display\n").
-spec format_decode_errors(list(gleam@dynamic@decode:decode_error())) -> binary().
format_decode_errors(Errors) ->
_pipe = Errors,
_pipe@1 = gleam@list:map(
_pipe,
fun(Err) ->
<<<<<<"expected "/utf8, (erlang:element(2, Err))/binary>>/binary,
" at "/utf8>>/binary,
(format_path(erlang:element(4, Err)))/binary>>
end
),
join(_pipe@1, <<", "/utf8>>).
-file("src/cquill/adapter/postgres.gleam", 201).
?DOC(" Convert a pog.QueryError to cquill.AdapterError\n").
-spec map_query_error(pog:query_error()) -> cquill@error:adapter_error().
map_query_error(Err) ->
case Err of
{constraint_violated, Message, Constraint, Detail} ->
cquill@error:from_postgres_error(
infer_constraint_code(Constraint, Detail),
Message,
Detail
);
{postgresql_error, Code, _, Message@1} ->
cquill@error:from_postgres_error(Code, Message@1, <<""/utf8>>);
{unexpected_argument_count, Expected, Got} ->
{query_failed,
<<<<<<"Unexpected argument count: expected "/utf8,
(erlang:integer_to_binary(Expected))/binary>>/binary,
", got "/utf8>>/binary,
(erlang:integer_to_binary(Got))/binary>>,
none};
{unexpected_argument_type, Expected@1, Got@1} ->
{query_failed,
<<<<<<"Unexpected argument type: expected "/utf8,
Expected@1/binary>>/binary,
", got "/utf8>>/binary,
Got@1/binary>>,
none};
{unexpected_result_type, Decode_errors} ->
{decode_failed,
0,
<<"result"/utf8>>,
<<"expected type"/utf8>>,
format_decode_errors(Decode_errors)};
query_timeout ->
timeout;
connection_unavailable ->
{connection_failed, <<"Connection unavailable"/utf8>>}
end.
-file("src/cquill/adapter/postgres.gleam", 332).
?DOC(" Convert cquill QueryParam to pog.Value\n").
-spec param_to_value(cquill@adapter:query_param()) -> pog:value().
param_to_value(Param) ->
case Param of
{param_int, I} ->
pog_ffi:coerce(I);
{param_float, F} ->
pog_ffi:coerce(F);
{param_string, S} ->
pog_ffi:coerce(S);
{param_bool, B} ->
pog_ffi:coerce(B);
param_null ->
pog_ffi:null();
{param_bytes, Bytes} ->
pog_ffi:coerce(Bytes);
{param_custom, _, Value} ->
pog_ffi:coerce(Value)
end.
-file("src/cquill/adapter/postgres.gleam", 345).
?DOC(" Convert a list of QueryParams to pog.Values\n").
-spec params_to_values(list(cquill@adapter:query_param())) -> list(pog:value()).
params_to_values(Params) ->
gleam@list:map(Params, fun param_to_value/1).
-file("src/cquill/adapter/postgres.gleam", 373).
?DOC(" Wrap a dynamic row into a list format for consistency with adapter interface\n").
-spec wrap_row(gleam@dynamic:dynamic_()) -> list(gleam@dynamic:dynamic_()).
wrap_row(Row) ->
cquill_ffi:tuple_to_list(Row).
-file("src/cquill/adapter/postgres.gleam", 426).
?DOC(" Add parameters to a pog query\n").
-spec add_parameters(pog:'query'(PDO), list(pog:value())) -> pog:'query'(PDO).
add_parameters(Query, Values) ->
gleam@list:fold(Values, Query, fun(Q, V) -> pog:parameter(Q, V) end).
-file("src/cquill/adapter/postgres.gleam", 354).
?DOC(" Execute a query and return all rows as List(Dynamic)\n").
-spec execute_query(postgres_connection(), cquill@adapter:compiled_query()) -> {ok,
list(list(gleam@dynamic:dynamic_()))} |
{error, cquill@error:adapter_error()}.
execute_query(Conn, Compiled) ->
{postgres_connection, Pool} = Conn,
Values = params_to_values(erlang:element(3, Compiled)),
Query = begin
_pipe = pog:'query'(erlang:element(2, Compiled)),
_pipe@1 = add_parameters(_pipe, Values),
pog:returning(
_pipe@1,
{decoder, fun gleam@dynamic@decode:decode_dynamic/1}
)
end,
case pog:execute(Query, Pool) of
{ok, {returned, _, Rows}} ->
{ok, gleam@list:map(Rows, fun wrap_row/1)};
{error, Err} ->
{error, map_query_error(Err)}
end.
-file("src/cquill/adapter/postgres.gleam", 386).
?DOC(" Execute a mutation (INSERT/UPDATE/DELETE) and return affected count\n").
-spec execute_mutation(postgres_connection(), cquill@adapter:compiled_query()) -> {ok,
integer()} |
{error, cquill@error:adapter_error()}.
execute_mutation(Conn, Compiled) ->
{postgres_connection, Pool} = Conn,
Values = params_to_values(erlang:element(3, Compiled)),
Query = begin
_pipe = pog:'query'(erlang:element(2, Compiled)),
_pipe@1 = add_parameters(_pipe, Values),
pog:returning(
_pipe@1,
{decoder, fun gleam@dynamic@decode:decode_dynamic/1}
)
end,
case pog:execute(Query, Pool) of
{ok, {returned, Count, _}} ->
{ok, Count};
{error, Err} ->
{error, map_query_error(Err)}
end.
-file("src/cquill/adapter/postgres.gleam", 405).
?DOC(" Execute an INSERT with RETURNING clause\n").
-spec execute_returning(postgres_connection(), cquill@adapter:compiled_query()) -> {ok,
gleam@option:option(list(gleam@dynamic:dynamic_()))} |
{error, cquill@error:adapter_error()}.
execute_returning(Conn, Compiled) ->
{postgres_connection, Pool} = Conn,
Values = params_to_values(erlang:element(3, Compiled)),
Query = begin
_pipe = pog:'query'(erlang:element(2, Compiled)),
_pipe@1 = add_parameters(_pipe, Values),
pog:returning(
_pipe@1,
{decoder, fun gleam@dynamic@decode:decode_dynamic/1}
)
end,
case pog:execute(Query, Pool) of
{ok, {returned, _, [Row]}} ->
{ok, {some, wrap_row(Row)}};
{ok, {returned, _, []}} ->
{ok, none};
{ok, {returned, _, _}} ->
{ok, none};
{error, Err} ->
{error, map_query_error(Err)}
end.
-file("src/cquill/adapter/postgres.gleam", 437).
?DOC(
" Begin a transaction - pog handles this differently via pog.transaction\n"
" For the adapter interface, we return the same connection since pog\n"
" manages transaction state internally.\n"
).
-spec begin_transaction(postgres_connection()) -> {ok, postgres_connection()} |
{error, cquill@error:adapter_error()}.
begin_transaction(Conn) ->
{ok, Conn}.
-file("src/cquill/adapter/postgres.gleam", 447).
?DOC(" Commit a transaction\n").
-spec commit_transaction(postgres_connection()) -> {ok, nil} |
{error, cquill@error:adapter_error()}.
commit_transaction(_) ->
{ok, nil}.
-file("src/cquill/adapter/postgres.gleam", 453).
?DOC(" Rollback a transaction\n").
-spec rollback_transaction(postgres_connection()) -> {ok, nil} |
{error, cquill@error:adapter_error()}.
rollback_transaction(_) ->
{ok, nil}.
-file("src/cquill/adapter/postgres.gleam", 463).
?DOC(" PostgreSQL adapter capabilities - full SQL support\n").
-spec postgres_capabilities() -> cquill@adapter:adapter_capabilities().
postgres_capabilities() ->
{adapter_capabilities, true, true, true, true, {some, 65535}, true, true}.
-file("src/cquill/adapter/postgres.gleam", 477).
?DOC(
" Create a PostgreSQL adapter.\n"
" This implements the full adapter interface for PostgreSQL.\n"
).
-spec postgres_adapter() -> cquill@adapter:adapter(postgres_connection(), list(gleam@dynamic:dynamic_())).
postgres_adapter() ->
cquill@adapter:new(
<<"postgres"/utf8>>,
postgres_capabilities(),
fun execute_query/2,
fun execute_mutation/2,
fun execute_returning/2,
fun begin_transaction/1,
fun commit_transaction/1,
fun rollback_transaction/1
).
-file("src/cquill/adapter/postgres.gleam", 497).
?DOC(
" Run a function within a PostgreSQL transaction.\n"
" This uses pog's native transaction support which provides proper\n"
" transaction isolation and automatic commit/rollback.\n"
).
-spec with_transaction(
postgres_connection(),
fun((postgres_connection()) -> {ok, PEB} | {error, binary()})
) -> {ok, PEB} | {error, transaction_error()}.
with_transaction(Conn, Operation) ->
{postgres_connection, Pool} = Conn,
case pog:transaction(
Pool,
fun(Tx_pool) ->
Tx_conn = {postgres_connection, Tx_pool},
Operation(Tx_conn)
end
) of
{ok, Result} ->
{ok, Result};
{error, {transaction_query_error, Query_err}} ->
{error, {query_error, map_query_error(Query_err)}};
{error, {transaction_rolled_back, Reason}} ->
{error, {rolled_back, Reason}}
end.
-file("src/cquill/adapter/postgres.gleam", 527).
?DOC(
" Execute a transaction with automatic error handling.\n"
" This version uses the standard cquill TransactionError type.\n"
" - On success: commits and returns the result\n"
" - On adapter error (constraint violation, etc.): rolls back and returns AdapterTransactionError\n"
" - On pog query error during transaction: returns AdapterTransactionError\n"
).
-spec execute_transaction(
postgres_connection(),
fun((postgres_connection()) -> {ok, PEG} |
{error, cquill@error:adapter_error()})
) -> {ok, PEG} | {error, cquill@error:transaction_error(nil)}.
execute_transaction(Conn, Operation) ->
{postgres_connection, Pool} = Conn,
case pog:transaction(
Pool,
fun(Tx_pool) ->
Tx_conn = {postgres_connection, Tx_pool},
Operation(Tx_conn)
end
) of
{ok, Result} ->
{ok, Result};
{error, {transaction_query_error, Query_err}} ->
Adapter_err = map_query_error(Query_err),
case Query_err of
{postgresql_error, <<"40001"/utf8>>, _, _} ->
{error, serialization_failure};
query_timeout ->
{error, transaction_timeout};
_ ->
{error, {adapter_transaction_error, Adapter_err}}
end;
{error, {transaction_rolled_back, Adapter_err@1}} ->
{error, {adapter_transaction_error, Adapter_err@1}}
end.
-file("src/cquill/adapter/postgres.gleam", 561).
?DOC(
" Execute a transaction with a user error type.\n"
" This version allows the operation to return a custom error type.\n"
" - On success: commits and returns the result\n"
" - On user error: rolls back and returns UserError\n"
" - On pog query error during transaction: returns AdapterTransactionError\n"
).
-spec execute_transaction_with_user_error(
postgres_connection(),
fun((postgres_connection()) -> {ok, PEM} | {error, PEN})
) -> {ok, PEM} | {error, cquill@error:transaction_error(PEN)}.
execute_transaction_with_user_error(Conn, Operation) ->
{postgres_connection, Pool} = Conn,
case pog:transaction(
Pool,
fun(Tx_pool) ->
Tx_conn = {postgres_connection, Tx_pool},
Operation(Tx_conn)
end
) of
{ok, Result} ->
{ok, Result};
{error, {transaction_query_error, Query_err}} ->
Adapter_err = map_query_error(Query_err),
case Query_err of
{postgresql_error, <<"40001"/utf8>>, _, _} ->
{error, serialization_failure};
query_timeout ->
{error, transaction_timeout};
_ ->
{error, {adapter_transaction_error, Adapter_err}}
end;
{error, {transaction_rolled_back, User_error}} ->
{error, {user_error, User_error}}
end.
-file("src/cquill/adapter/postgres.gleam", 727).
?DOC(
" Escape a SQL identifier (table name, savepoint name, etc.)\n"
" to prevent SQL injection.\n"
).
-spec escape_identifier(binary()) -> binary().
escape_identifier(Name) ->
<<<<"\""/utf8,
(gleam@string:replace(Name, <<"\""/utf8>>, <<"\"\""/utf8>>))/binary>>/binary,
"\""/utf8>>.
-file("src/cquill/adapter/postgres.gleam", 739).
?DOC(
" Execute a raw SQL query with parameters.\n"
" Returns rows as List(Dynamic).\n"
).
-spec execute_sql(
postgres_connection(),
binary(),
list(cquill@adapter:query_param())
) -> {ok, list(list(gleam@dynamic:dynamic_()))} |
{error, cquill@error:adapter_error()}.
execute_sql(Conn, Sql, Params) ->
execute_query(Conn, {compiled_query, Sql, Params, 0}).
-file("src/cquill/adapter/postgres.gleam", 752).
?DOC(
" Execute a raw SQL mutation with parameters.\n"
" Returns the number of affected rows.\n"
).
-spec execute_sql_mutation(
postgres_connection(),
binary(),
list(cquill@adapter:query_param())
) -> {ok, integer()} | {error, cquill@error:adapter_error()}.
execute_sql_mutation(Conn, Sql, Params) ->
execute_mutation(Conn, {compiled_query, Sql, Params, 0}).
-file("src/cquill/adapter/postgres.gleam", 597).
?DOC(
" Create a savepoint with the given name.\n"
" Savepoints allow partial rollback within a transaction.\n"
" The connection must be within an active transaction.\n"
).
-spec create_savepoint(postgres_connection(), binary()) -> {ok, nil} |
{error, cquill@error:savepoint_error(nil)}.
create_savepoint(Conn, Name) ->
Sql = <<"SAVEPOINT "/utf8, (escape_identifier(Name))/binary>>,
case execute_sql_mutation(Conn, Sql, []) of
{ok, _} ->
{ok, nil};
{error, Adapter_err} ->
{error,
{savepoint_creation_failed,
cquill@error:format_error(Adapter_err)}}
end.
-file("src/cquill/adapter/postgres.gleam", 612).
?DOC(
" Rollback to a named savepoint.\n"
" All changes made after the savepoint was created are discarded.\n"
" The savepoint remains active and can be rolled back to again.\n"
).
-spec rollback_to_savepoint(postgres_connection(), binary()) -> {ok, nil} |
{error, cquill@error:savepoint_error(nil)}.
rollback_to_savepoint(Conn, Name) ->
Sql = <<"ROLLBACK TO SAVEPOINT "/utf8, (escape_identifier(Name))/binary>>,
case execute_sql_mutation(Conn, Sql, []) of
{ok, _} ->
{ok, nil};
{error, Adapter_err} ->
{error, {savepoint_adapter_error, Adapter_err}}
end.
-file("src/cquill/adapter/postgres.gleam", 626).
?DOC(
" Release a savepoint without rolling back.\n"
" This destroys the savepoint but keeps all changes made after it.\n"
" This is useful to free up resources when a savepoint is no longer needed.\n"
).
-spec release_savepoint(postgres_connection(), binary()) -> {ok, nil} |
{error, cquill@error:savepoint_error(nil)}.
release_savepoint(Conn, Name) ->
Sql = <<"RELEASE SAVEPOINT "/utf8, (escape_identifier(Name))/binary>>,
case execute_sql_mutation(Conn, Sql, []) of
{ok, _} ->
{ok, nil};
{error, Adapter_err} ->
{error,
{savepoint_release_failed,
cquill@error:format_error(Adapter_err)}}
end.
-file("src/cquill/adapter/postgres.gleam", 642).
?DOC(
" Execute a function within a savepoint.\n"
" If the function succeeds, the savepoint is released.\n"
" If the function fails, changes are rolled back to the savepoint.\n"
" This must be called within an active transaction.\n"
).
-spec execute_savepoint(
postgres_connection(),
binary(),
fun((postgres_connection()) -> {ok, PFC} |
{error, cquill@error:adapter_error()})
) -> {ok, PFC} | {error, cquill@error:savepoint_error(nil)}.
execute_savepoint(Conn, Name, Operation) ->
case create_savepoint(Conn, Name) of
{error, Err} ->
{error, Err};
{ok, _} ->
case Operation(Conn) of
{ok, Result} ->
case release_savepoint(Conn, Name) of
{ok, _} ->
{ok, Result};
{error, Err@1} ->
{error, Err@1}
end;
{error, Adapter_err} ->
_ = rollback_to_savepoint(Conn, Name),
{error, {savepoint_adapter_error, Adapter_err}}
end
end.
-file("src/cquill/adapter/postgres.gleam", 675).
?DOC(
" Execute a function within a savepoint, allowing user errors.\n"
" If the function succeeds, the savepoint is released.\n"
" If the function fails, changes are rolled back to the savepoint.\n"
).
-spec execute_savepoint_with_user_error(
postgres_connection(),
binary(),
fun((postgres_connection()) -> {ok, PFI} | {error, PFJ})
) -> {ok, PFI} | {error, cquill@error:savepoint_error(PFJ)}.
execute_savepoint_with_user_error(Conn, Name, Operation) ->
case create_savepoint(Conn, Name) of
{error, {savepoint_creation_failed, Reason}} ->
{error, {savepoint_creation_failed, Reason}};
{error, {savepoint_adapter_error, Adapter_err}} ->
{error, {savepoint_adapter_error, Adapter_err}};
{error, {savepoint_not_found, N}} ->
{error, {savepoint_not_found, N}};
{error, {savepoint_release_failed, R}} ->
{error, {savepoint_release_failed, R}};
{error, savepoint_no_transaction} ->
{error, savepoint_no_transaction};
{error, {savepoint_user_error, _}} ->
{error,
{savepoint_creation_failed, <<"Unexpected user error"/utf8>>}};
{ok, _} ->
case Operation(Conn) of
{ok, Result} ->
case release_savepoint(Conn, Name) of
{ok, _} ->
{ok, Result};
{error, {savepoint_release_failed, Reason@1}} ->
{error, {savepoint_release_failed, Reason@1}};
{error, {savepoint_adapter_error, Adapter_err@1}} ->
{error, {savepoint_adapter_error, Adapter_err@1}};
{error, {savepoint_not_found, N@1}} ->
{error, {savepoint_not_found, N@1}};
{error, {savepoint_creation_failed, R@1}} ->
{error, {savepoint_creation_failed, R@1}};
{error, savepoint_no_transaction} ->
{error, savepoint_no_transaction};
{error, {savepoint_user_error, _}} ->
{error,
{savepoint_release_failed,
<<"Unexpected user error"/utf8>>}}
end;
{error, User_err} ->
_ = rollback_to_savepoint(Conn, Name),
{error, {savepoint_user_error, User_err}}
end
end.
-file("src/cquill/adapter/postgres.gleam", 766).
?DOC(
" Execute a raw SQL query with a custom timeout.\n"
" The timeout is in milliseconds. Use this for queries that may take\n"
" longer than the default 5 second timeout.\n"
).
-spec execute_sql_with_timeout(
postgres_connection(),
binary(),
list(cquill@adapter:query_param()),
integer()
) -> {ok, list(list(gleam@dynamic:dynamic_()))} |
{error, cquill@error:adapter_error()}.
execute_sql_with_timeout(Conn, Sql, Params, Timeout_ms) ->
{postgres_connection, Pool} = Conn,
Values = params_to_values(Params),
Query = begin
_pipe = pog:'query'(Sql),
_pipe@1 = add_parameters(_pipe, Values),
_pipe@2 = pog:timeout(_pipe@1, Timeout_ms),
pog:returning(
_pipe@2,
{decoder, fun gleam@dynamic@decode:decode_dynamic/1}
)
end,
case pog:execute(Query, Pool) of
{ok, {returned, _, Rows}} ->
{ok, gleam@list:map(Rows, fun wrap_row/1)};
{error, Err} ->
{error, map_query_error(Err)}
end.
-file("src/cquill/adapter/postgres.gleam", 789).
?DOC(
" Execute a raw SQL mutation with a custom timeout.\n"
" The timeout is in milliseconds.\n"
).
-spec execute_sql_mutation_with_timeout(
postgres_connection(),
binary(),
list(cquill@adapter:query_param()),
integer()
) -> {ok, integer()} | {error, cquill@error:adapter_error()}.
execute_sql_mutation_with_timeout(Conn, Sql, Params, Timeout_ms) ->
{postgres_connection, Pool} = Conn,
Values = params_to_values(Params),
Query = begin
_pipe = pog:'query'(Sql),
_pipe@1 = add_parameters(_pipe, Values),
_pipe@2 = pog:timeout(_pipe@1, Timeout_ms),
pog:returning(
_pipe@2,
{decoder, fun gleam@dynamic@decode:decode_dynamic/1}
)
end,
case pog:execute(Query, Pool) of
{ok, {returned, Count, _}} ->
{ok, Count};
{error, Err} ->
{error, map_query_error(Err)}
end.
-file("src/cquill/adapter/postgres.gleam", 825).
?DOC(" Default batch configuration for Postgres\n").
-spec default_batch_config() -> batch_config().
default_batch_config() ->
{batch_config, 1000, true}.
-file("src/cquill/adapter/postgres.gleam", 948).
?DOC(" Build parameter placeholders ($1, $2, etc.)\n").
-spec build_placeholders(integer(), integer(), list(binary())) -> list(binary()).
build_placeholders(Count, Current_idx, Acc) ->
case Count of
0 ->
lists:reverse(Acc);
N ->
Placeholder = <<"$"/utf8,
(erlang:integer_to_binary(Current_idx))/binary>>,
build_placeholders(N - 1, Current_idx + 1, [Placeholder | Acc])
end.
-file("src/cquill/adapter/postgres.gleam", 1029).
?DOC(
" Adjust parameter indices in a WHERE clause\n"
" e.g., \"$1\" becomes \"$3\" if start_idx is 3\n"
).
-spec adjust_param_indices(binary(), integer()) -> binary().
adjust_param_indices(Where_clause, _) ->
Where_clause.
-file("src/cquill/adapter/postgres.gleam", 1061).
?DOC(
" Delete all rows matching a condition.\n"
" Returns the number of deleted rows.\n"
).
-spec batch_delete_all(
postgres_connection(),
binary(),
binary(),
list(cquill@adapter:query_param())
) -> {ok, integer()} | {error, cquill@error:adapter_error()}.
batch_delete_all(Conn, Table, Where_clause, Where_params) ->
Sql = <<<<<<"DELETE FROM "/utf8, (escape_identifier(Table))/binary>>/binary,
" WHERE "/utf8>>/binary,
Where_clause/binary>>,
execute_sql_mutation(Conn, Sql, Where_params).
-file("src/cquill/adapter/postgres.gleam", 1073).
?DOC(" Delete all rows matching a condition and return deleted rows.\n").
-spec batch_delete_all_returning(
postgres_connection(),
binary(),
binary(),
list(cquill@adapter:query_param())
) -> {ok, list(list(gleam@dynamic:dynamic_()))} |
{error, cquill@error:adapter_error()}.
batch_delete_all_returning(Conn, Table, Where_clause, Where_params) ->
Sql = <<<<<<<<"DELETE FROM "/utf8, (escape_identifier(Table))/binary>>/binary,
" WHERE "/utf8>>/binary,
Where_clause/binary>>/binary,
" RETURNING *"/utf8>>,
execute_sql(Conn, Sql, Where_params).
-file("src/cquill/adapter/postgres.gleam", 1090).
?DOC(
" Delete all rows in a table (truncate-like operation).\n"
" Returns the number of deleted rows.\n"
).
-spec delete_all_rows(postgres_connection(), binary()) -> {ok, integer()} |
{error, cquill@error:adapter_error()}.
delete_all_rows(Conn, Table) ->
Sql = <<"DELETE FROM "/utf8, (escape_identifier(Table))/binary>>,
execute_sql_mutation(Conn, Sql, []).
-file("src/cquill/adapter/postgres.gleam", 1103).
-spec do_chunk_list(list(PIO), integer(), list(PIO), list(list(PIO))) -> list(list(PIO)).
do_chunk_list(Items, Max_size, Current_chunk, Chunks) ->
case Items of
[] ->
case Current_chunk of
[] ->
lists:reverse(Chunks);
_ ->
lists:reverse([lists:reverse(Current_chunk) | Chunks])
end;
[Item | Rest] ->
New_chunk = [Item | Current_chunk],
case erlang:length(New_chunk) >= Max_size of
true ->
do_chunk_list(
Rest,
Max_size,
[],
[lists:reverse(New_chunk) | Chunks]
);
false ->
do_chunk_list(Rest, Max_size, New_chunk, Chunks)
end
end.
-file("src/cquill/adapter/postgres.gleam", 1099).
?DOC(" Chunk a list into sublists of max_size\n").
-spec chunk_list(list(PIK), integer()) -> list(list(PIK)).
chunk_list(Items, Max_size) ->
do_chunk_list(Items, Max_size, [], []).
-file("src/cquill/adapter/postgres.gleam", 1127).
?DOC(" Join a list of strings with a separator\n").
-spec join_strings(list(binary()), binary()) -> binary().
join_strings(Strings, Separator) ->
case Strings of
[] ->
<<""/utf8>>;
[First] ->
First;
[First@1 | Rest] ->
<<<<First@1/binary, Separator/binary>>/binary,
(join_strings(Rest, Separator))/binary>>
end.
-file("src/cquill/adapter/postgres.gleam", 937).
?DOC(" Build a single VALUES clause like ($1, $2, $3)\n").
-spec build_value_clause(
list(cquill@adapter:query_param()),
integer(),
integer()
) -> {binary(), integer()}.
build_value_clause(_, Column_count, Start_idx) ->
Placeholders = build_placeholders(Column_count, Start_idx, []),
Clause = <<<<"("/utf8, (join_strings(Placeholders, <<", "/utf8>>))/binary>>/binary,
")"/utf8>>,
{Clause, Start_idx + Column_count}.
-file("src/cquill/adapter/postgres.gleam", 909).
?DOC(" Build a multi-value INSERT statement\n").
-spec build_multi_value_insert(
binary(),
list(binary()),
list(list(cquill@adapter:query_param())),
integer()
) -> {binary(), list(cquill@adapter:query_param())}.
build_multi_value_insert(Table, Columns, Rows, Column_count) ->
Column_list = join_strings(Columns, <<", "/utf8>>),
Insert_prefix = <<<<<<<<"INSERT INTO "/utf8,
(escape_identifier(Table))/binary>>/binary,
" ("/utf8>>/binary,
Column_list/binary>>/binary,
") VALUES "/utf8>>,
{Values_clauses, All_params, _} = gleam@list:fold(
Rows,
{[], [], 1},
fun(Acc, Row) ->
{Clauses, Params, Param_idx} = Acc,
{Value_clause, New_idx} = build_value_clause(
Row,
Column_count,
Param_idx
),
{[Value_clause | Clauses], lists:append(Params, Row), New_idx}
end
),
Values_sql = join_strings(lists:reverse(Values_clauses), <<", "/utf8>>),
{<<Insert_prefix/binary, Values_sql/binary>>, All_params}.
-file("src/cquill/adapter/postgres.gleam", 896).
?DOC(" Insert a single chunk using multi-value INSERT\n").
-spec insert_single_chunk(
postgres_connection(),
binary(),
list(binary()),
list(list(cquill@adapter:query_param()))
) -> {ok, integer()} | {error, cquill@error:adapter_error()}.
insert_single_chunk(Conn, Table, Columns, Rows) ->
Column_count = erlang:length(Columns),
{Sql, All_params} = build_multi_value_insert(
Table,
Columns,
Rows,
Column_count
),
execute_sql_mutation(Conn, Sql, All_params).
-file("src/cquill/adapter/postgres.gleam", 878).
?DOC(" Insert multiple chunks sequentially\n").
-spec insert_chunks(
postgres_connection(),
binary(),
list(binary()),
list(list(list(cquill@adapter:query_param()))),
integer()
) -> {ok, integer()} | {error, cquill@error:adapter_error()}.
insert_chunks(Conn, Table, Columns, Chunks, Total) ->
case Chunks of
[] ->
{ok, Total};
[Chunk | Rest] ->
case insert_single_chunk(Conn, Table, Columns, Chunk) of
{error, E} ->
{error, E};
{ok, Count} ->
insert_chunks(Conn, Table, Columns, Rest, Total + Count)
end
end.
-file("src/cquill/adapter/postgres.gleam", 844).
?DOC(" Insert multiple rows with configuration options.\n").
-spec insert_all_with_config(
postgres_connection(),
binary(),
list(binary()),
list(list(cquill@adapter:query_param())),
batch_config()
) -> {ok, integer()} | {error, cquill@error:adapter_error()}.
insert_all_with_config(Conn, Table, Columns, Rows, Config) ->
case Rows of
[] ->
{ok, 0};
_ ->
Chunks = chunk_list(Rows, erlang:element(2, Config)),
case erlang:element(3, Config) of
true ->
case execute_transaction(
Conn,
fun(Tx_conn) ->
insert_chunks(Tx_conn, Table, Columns, Chunks, 0)
end
) of
{ok, Count} ->
{ok, Count};
{error, {adapter_transaction_error, E}} ->
{error, E};
{error, _} ->
{error,
{query_failed,
<<"Batch insert failed"/utf8>>,
none}}
end;
false ->
insert_chunks(Conn, Table, Columns, Chunks, 0)
end
end.
-file("src/cquill/adapter/postgres.gleam", 834).
?DOC(
" Insert multiple rows using a multi-value INSERT statement.\n"
" This is more efficient than individual inserts.\n"
"\n"
" Example SQL generated:\n"
" INSERT INTO users (email, name) VALUES ($1, $2), ($3, $4), ($5, $6)\n"
).
-spec insert_all(
postgres_connection(),
binary(),
list(binary()),
list(list(cquill@adapter:query_param()))
) -> {ok, integer()} | {error, cquill@error:adapter_error()}.
insert_all(Conn, Table, Columns, Rows) ->
insert_all_with_config(Conn, Table, Columns, Rows, default_batch_config()).
-file("src/cquill/adapter/postgres.gleam", 964).
?DOC(
" Insert multiple rows and return the inserted rows.\n"
" Uses RETURNING * to get all inserted data.\n"
).
-spec insert_all_returning(
postgres_connection(),
binary(),
list(binary()),
list(list(cquill@adapter:query_param()))
) -> {ok, list(list(gleam@dynamic:dynamic_()))} |
{error, cquill@error:adapter_error()}.
insert_all_returning(Conn, Table, Columns, Rows) ->
case Rows of
[] ->
{ok, []};
_ ->
Column_count = erlang:length(Columns),
{Base_sql, All_params} = build_multi_value_insert(
Table,
Columns,
Rows,
Column_count
),
Sql = <<Base_sql/binary, " RETURNING *"/utf8>>,
execute_sql(Conn, Sql, All_params)
end.
-file("src/cquill/adapter/postgres.gleam", 1011).
?DOC(" Build SET clause for UPDATE\n").
-spec build_set_clause(
list({binary(), cquill@adapter:query_param()}),
integer()
) -> {binary(), list(cquill@adapter:query_param()), integer()}.
build_set_clause(Clauses, Start_idx) ->
{Parts, Params, Idx} = gleam@list:fold(
Clauses,
{[], [], Start_idx},
fun(Acc, Clause) ->
{Sql_parts, Param_acc, Current_idx} = Acc,
{Column, Param} = Clause,
Sql_part = <<<<Column/binary, " = $"/utf8>>/binary,
(erlang:integer_to_binary(Current_idx))/binary>>,
{[Sql_part | Sql_parts], [Param | Param_acc], Current_idx + 1}
end
),
Sql = join_strings(lists:reverse(Parts), <<", "/utf8>>),
{Sql, lists:reverse(Params), Idx}.
-file("src/cquill/adapter/postgres.gleam", 988).
?DOC(
" Update all rows matching a condition.\n"
" Returns the number of updated rows.\n"
"\n"
" Example:\n"
" update_all(conn, \"users\", [#(\"active\", adapter.param_bool(False))],\n"
" \"created_at < $1\", [adapter.param_string(\"2024-01-01\")])\n"
).
-spec batch_update_all(
postgres_connection(),
binary(),
list({binary(), cquill@adapter:query_param()}),
binary(),
list(cquill@adapter:query_param())
) -> {ok, integer()} | {error, cquill@error:adapter_error()}.
batch_update_all(Conn, Table, Set_clauses, Where_clause, Where_params) ->
{Set_sql, Set_params, Next_idx} = build_set_clause(Set_clauses, 1),
Adjusted_where = adjust_param_indices(Where_clause, Next_idx),
Sql = <<<<<<<<<<"UPDATE "/utf8, (escape_identifier(Table))/binary>>/binary,
" SET "/utf8>>/binary,
Set_sql/binary>>/binary,
" WHERE "/utf8>>/binary,
Adjusted_where/binary>>,
All_params = lists:append(Set_params, Where_params),
execute_sql_mutation(Conn, Sql, All_params).
-file("src/cquill/adapter/postgres.gleam", 1036).
?DOC(" Update all rows matching a condition and return updated rows.\n").
-spec batch_update_all_returning(
postgres_connection(),
binary(),
list({binary(), cquill@adapter:query_param()}),
binary(),
list(cquill@adapter:query_param())
) -> {ok, list(list(gleam@dynamic:dynamic_()))} |
{error, cquill@error:adapter_error()}.
batch_update_all_returning(Conn, Table, Set_clauses, Where_clause, Where_params) ->
{Set_sql, Set_params, Next_idx} = build_set_clause(Set_clauses, 1),
Adjusted_where = adjust_param_indices(Where_clause, Next_idx),
Sql = <<<<<<<<<<<<"UPDATE "/utf8, (escape_identifier(Table))/binary>>/binary,
" SET "/utf8>>/binary,
Set_sql/binary>>/binary,
" WHERE "/utf8>>/binary,
Adjusted_where/binary>>/binary,
" RETURNING *"/utf8>>,
All_params = lists:append(Set_params, Where_params),
execute_sql(Conn, Sql, All_params).
-file("src/cquill/adapter/postgres.gleam", 1219).
-spec do_list_at(list(PJR), integer()) -> gleam@option:option(PJR).
do_list_at(List, Index) ->
case List of
[] ->
none;
[First | Rest] ->
case Index of
0 ->
{some, First};
_ ->
do_list_at(Rest, Index - 1)
end
end.
-file("src/cquill/adapter/postgres.gleam", 1212).
?DOC(" Get an element from a list by index\n").
-spec list_at(list(PJO), integer()) -> gleam@option:option(PJO).
list_at(List, Index) ->
case Index < 0 of
true ->
none;
false ->
do_list_at(List, Index)
end.
-file("src/cquill/adapter/postgres.gleam", 1148).
?DOC(" Decode a single integer value from a result row\n").
-spec decode_int(list(gleam@dynamic:dynamic_()), integer()) -> {ok, integer()} |
{error, nil}.
decode_int(Row, Index) ->
case list_at(Row, Index) of
{some, Value} ->
case gleam@dynamic@decode:run(
Value,
{decoder, fun gleam@dynamic@decode:decode_int/1}
) of
{ok, I} ->
{ok, I};
{error, _} ->
{error, nil}
end;
none ->
{error, nil}
end.
-file("src/cquill/adapter/postgres.gleam", 1160).
?DOC(" Decode a single string value from a result row\n").
-spec decode_string(list(gleam@dynamic:dynamic_()), integer()) -> {ok, binary()} |
{error, nil}.
decode_string(Row, Index) ->
case list_at(Row, Index) of
{some, Value} ->
case gleam@dynamic@decode:run(
Value,
{decoder, fun gleam@dynamic@decode:decode_string/1}
) of
{ok, S} ->
{ok, S};
{error, _} ->
{error, nil}
end;
none ->
{error, nil}
end.
-file("src/cquill/adapter/postgres.gleam", 1172).
?DOC(" Decode a single float value from a result row\n").
-spec decode_float(list(gleam@dynamic:dynamic_()), integer()) -> {ok, float()} |
{error, nil}.
decode_float(Row, Index) ->
case list_at(Row, Index) of
{some, Value} ->
case gleam@dynamic@decode:run(
Value,
{decoder, fun gleam@dynamic@decode:decode_float/1}
) of
{ok, F} ->
{ok, F};
{error, _} ->
{error, nil}
end;
none ->
{error, nil}
end.
-file("src/cquill/adapter/postgres.gleam", 1184).
?DOC(" Decode a single bool value from a result row\n").
-spec decode_bool(list(gleam@dynamic:dynamic_()), integer()) -> {ok, boolean()} |
{error, nil}.
decode_bool(Row, Index) ->
case list_at(Row, Index) of
{some, Value} ->
case gleam@dynamic@decode:run(
Value,
{decoder, fun gleam@dynamic@decode:decode_bool/1}
) of
{ok, B} ->
{ok, B};
{error, _} ->
{error, nil}
end;
none ->
{error, nil}
end.
-file("src/cquill/adapter/postgres.gleam", 1196).
?DOC(" Decode an optional value from a result row\n").
-spec decode_optional(
list(gleam@dynamic:dynamic_()),
integer(),
gleam@dynamic@decode:decoder(PJJ)
) -> {ok, gleam@option:option(PJJ)} | {error, nil}.
decode_optional(Row, Index, Decoder) ->
case list_at(Row, Index) of
{some, Value} ->
case gleam@dynamic@decode:run(
Value,
gleam@dynamic@decode:optional(Decoder)
) of
{ok, Opt} ->
{ok, Opt};
{error, _} ->
{error, nil}
end;
none ->
{error, nil}
end.