Current section
Files
Jump to
Current section
Files
src/pgl.erl
-module(pgl).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/pgl.gleam").
-export([application/2, host/2, port/2, username/2, password/2, database/2, connection_parameter/3, ssl/2, rows_as_dict/2, ip_version/2, pool_size/2, idle_interval/2, queue_target/2, new/1, with_connection/2, shutdown/1, start/1, supervised/1, sql/1, params/2, batch/2, 'query'/2, execute/2, 'begin'/1, commit/1, from_url/1, release_savepoint/1, rollback/1, transaction/2, savepoint/2]).
-export_type([config/0, ip_version/0, ssl/0, pgl_error/0, field/0, transaction_error/1, db/0, connection/0, queried/0, 'query'/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(" PostgreSQL database client\n").
-type config() :: {config,
binary(),
binary(),
integer(),
binary(),
binary(),
binary(),
list({binary(), binary()}),
ssl(),
boolean(),
ip_version(),
integer(),
integer(),
integer()}.
-type ip_version() :: ipv4 | ipv6.
-type ssl() :: ssl_disabled | ssl_verified | ssl_unverified.
-type pgl_error() :: {query_error, binary()} |
{connection_error, binary()} |
connection_timeout |
{authentication_error, binary()} |
{protocol_error, binary()} |
{socket_error, binary()} |
{postgres_error,
binary(),
binary(),
binary(),
gleam@dict:dict(field(), binary())}.
-type field() :: severity |
code |
message |
detail |
hint |
position |
internal_position |
internal_query |
where |
schema |
table |
column |
data_type |
constraint |
file |
line |
routine |
{other, bitstring()}.
-type transaction_error(MDW) :: {rollback_error, MDW} |
not_in_transaction |
{transaction_error, binary()}.
-opaque db() :: {db,
gleam@erlang@process:name(db_pool:message(connection(), pgl_error())),
pgl@internal@socket:factory(),
pgl@internal@type_cache:type_cache(),
pgl@internal@query_cache:query_cache(),
config()}.
-opaque connection() :: {connection,
pgl@internal@socket:socket(),
gleam@option:option(integer()),
pgl@internal@type_cache:type_cache(),
pgl@internal@query_cache:query_cache(),
boolean()}.
-type queried() :: {queried,
integer(),
list(binary()),
list(gleam@dynamic:dynamic_())}.
-type 'query'() :: {'query', binary(), list(pg_value:value())}.
-file("src/pgl.gleam", 94).
?DOC(" Name of the application connecting to the database.\n").
-spec application(config(), binary()) -> config().
application(Conf, Application) ->
{config,
Application,
erlang:element(3, Conf),
erlang:element(4, Conf),
erlang:element(5, Conf),
erlang:element(6, Conf),
erlang:element(7, Conf),
erlang:element(8, Conf),
erlang:element(9, Conf),
erlang:element(10, Conf),
erlang:element(11, Conf),
erlang:element(12, Conf),
erlang:element(13, Conf),
erlang:element(14, Conf)}.
-file("src/pgl.gleam", 99).
?DOC(" The database server hostname.\n").
-spec host(config(), binary()) -> config().
host(Conf, Host) ->
{config,
erlang:element(2, Conf),
Host,
erlang:element(4, Conf),
erlang:element(5, Conf),
erlang:element(6, Conf),
erlang:element(7, Conf),
erlang:element(8, Conf),
erlang:element(9, Conf),
erlang:element(10, Conf),
erlang:element(11, Conf),
erlang:element(12, Conf),
erlang:element(13, Conf),
erlang:element(14, Conf)}.
-file("src/pgl.gleam", 104).
?DOC(" The port on which the database server is listening.\n").
-spec port(config(), integer()) -> config().
port(Conf, Port) ->
{config,
erlang:element(2, Conf),
erlang:element(3, Conf),
Port,
erlang:element(5, Conf),
erlang:element(6, Conf),
erlang:element(7, Conf),
erlang:element(8, Conf),
erlang:element(9, Conf),
erlang:element(10, Conf),
erlang:element(11, Conf),
erlang:element(12, Conf),
erlang:element(13, Conf),
erlang:element(14, Conf)}.
-file("src/pgl.gleam", 109).
?DOC(" The username to connect to the database as.\n").
-spec username(config(), binary()) -> config().
username(Conf, Username) ->
{config,
erlang:element(2, Conf),
erlang:element(3, Conf),
erlang:element(4, Conf),
Username,
erlang:element(6, Conf),
erlang:element(7, Conf),
erlang:element(8, Conf),
erlang:element(9, Conf),
erlang:element(10, Conf),
erlang:element(11, Conf),
erlang:element(12, Conf),
erlang:element(13, Conf),
erlang:element(14, Conf)}.
-file("src/pgl.gleam", 114).
?DOC(" The password of the user.\n").
-spec password(config(), binary()) -> config().
password(Conf, Password) ->
{config,
erlang:element(2, Conf),
erlang:element(3, Conf),
erlang:element(4, Conf),
erlang:element(5, Conf),
Password,
erlang:element(7, Conf),
erlang:element(8, Conf),
erlang:element(9, Conf),
erlang:element(10, Conf),
erlang:element(11, Conf),
erlang:element(12, Conf),
erlang:element(13, Conf),
erlang:element(14, Conf)}.
-file("src/pgl.gleam", 119).
?DOC(" The name of the database to use.\n").
-spec database(config(), binary()) -> config().
database(Conf, Database) ->
{config,
erlang:element(2, Conf),
erlang:element(3, Conf),
erlang:element(4, Conf),
erlang:element(5, Conf),
erlang:element(6, Conf),
Database,
erlang:element(8, Conf),
erlang:element(9, Conf),
erlang:element(10, Conf),
erlang:element(11, Conf),
erlang:element(12, Conf),
erlang:element(13, Conf),
erlang:element(14, Conf)}.
-file("src/pgl.gleam", 124).
?DOC(" Sets other postgres connection parameters.\n").
-spec connection_parameter(config(), binary(), binary()) -> config().
connection_parameter(Conf, Name, Value) ->
Connection_parameters = gleam@list:prepend(
erlang:element(8, Conf),
{Name, Value}
),
{config,
erlang:element(2, Conf),
erlang:element(3, Conf),
erlang:element(4, Conf),
erlang:element(5, Conf),
erlang:element(6, Conf),
erlang:element(7, Conf),
Connection_parameters,
erlang:element(9, Conf),
erlang:element(10, Conf),
erlang:element(11, Conf),
erlang:element(12, Conf),
erlang:element(13, Conf),
erlang:element(14, Conf)}.
-file("src/pgl.gleam", 136).
?DOC(" Whether SSL should be used.\n").
-spec ssl(config(), ssl()) -> config().
ssl(Conf, Ssl) ->
{config,
erlang:element(2, Conf),
erlang:element(3, Conf),
erlang:element(4, Conf),
erlang:element(5, Conf),
erlang:element(6, Conf),
erlang:element(7, Conf),
erlang:element(8, Conf),
Ssl,
erlang:element(10, Conf),
erlang:element(11, Conf),
erlang:element(12, Conf),
erlang:element(13, Conf),
erlang:element(14, Conf)}.
-file("src/pgl.gleam", 141).
?DOC(" Configures rows to be returns as `Dict` rather than n-tuples.\n").
-spec rows_as_dict(config(), boolean()) -> config().
rows_as_dict(Conf, Rows_as_dict) ->
{config,
erlang:element(2, Conf),
erlang:element(3, Conf),
erlang:element(4, Conf),
erlang:element(5, Conf),
erlang:element(6, Conf),
erlang:element(7, Conf),
erlang:element(8, Conf),
erlang:element(9, Conf),
Rows_as_dict,
erlang:element(11, Conf),
erlang:element(12, Conf),
erlang:element(13, Conf),
erlang:element(14, Conf)}.
-file("src/pgl.gleam", 146).
?DOC(" Which IP version to use\n").
-spec ip_version(config(), ip_version()) -> config().
ip_version(Conf, Ip_version) ->
{config,
erlang:element(2, Conf),
erlang:element(3, Conf),
erlang:element(4, Conf),
erlang:element(5, Conf),
erlang:element(6, Conf),
erlang:element(7, Conf),
erlang:element(8, Conf),
erlang:element(9, Conf),
erlang:element(10, Conf),
Ip_version,
erlang:element(12, Conf),
erlang:element(13, Conf),
erlang:element(14, Conf)}.
-file("src/pgl.gleam", 151).
?DOC(" Sets the size of the connection pool.\n").
-spec pool_size(config(), integer()) -> config().
pool_size(Conf, Pool_size) ->
{config,
erlang:element(2, Conf),
erlang:element(3, Conf),
erlang:element(4, Conf),
erlang:element(5, Conf),
erlang:element(6, Conf),
erlang:element(7, Conf),
erlang:element(8, Conf),
erlang:element(9, Conf),
erlang:element(10, Conf),
erlang:element(11, Conf),
Pool_size,
erlang:element(13, Conf),
erlang:element(14, Conf)}.
-file("src/pgl.gleam", 156).
?DOC(" How often idle connections should ping the database server.\n").
-spec idle_interval(config(), integer()) -> config().
idle_interval(Conf, Idle_interval) ->
{config,
erlang:element(2, Conf),
erlang:element(3, Conf),
erlang:element(4, Conf),
erlang:element(5, Conf),
erlang:element(6, Conf),
erlang:element(7, Conf),
erlang:element(8, Conf),
erlang:element(9, Conf),
erlang:element(10, Conf),
erlang:element(11, Conf),
erlang:element(12, Conf),
Idle_interval,
erlang:element(14, Conf)}.
-file("src/pgl.gleam", 161).
?DOC(" How long it should take to check out a connection from the connection pool.\n").
-spec queue_target(config(), integer()) -> config().
queue_target(Conf, Queue_target) ->
{config,
erlang:element(2, Conf),
erlang:element(3, Conf),
erlang:element(4, Conf),
erlang:element(5, Conf),
erlang:element(6, Conf),
erlang:element(7, Conf),
erlang:element(8, Conf),
erlang:element(9, Conf),
erlang:element(10, Conf),
erlang:element(11, Conf),
erlang:element(12, Conf),
erlang:element(13, Conf),
Queue_target}.
-file("src/pgl.gleam", 188).
-spec apply_user_info(config(), gleam@uri:uri()) -> {ok, config()} |
{error, nil}.
apply_user_info(Conf, Uri) ->
_pipe = erlang:element(3, Uri),
_pipe@4 = gleam@option:map(
_pipe,
fun(User_info) -> case gleam@string:split(User_info, <<":"/utf8>>) of
[User] ->
{ok, username(Conf, User)};
[User@1, Pass] ->
_pipe@1 = Conf,
_pipe@2 = username(_pipe@1, User@1),
_pipe@3 = password(_pipe@2, Pass),
{ok, _pipe@3};
_ ->
{error, nil}
end end
),
gleam@option:unwrap(_pipe@4, {error, nil}).
-file("src/pgl.gleam", 205).
-spec apply_host(config(), gleam@uri:uri()) -> {ok, config()} | {error, nil}.
apply_host(Conf, Uri) ->
case erlang:element(4, Uri) of
{some, Val} ->
{ok, host(Conf, Val)};
none ->
{error, nil}
end.
-file("src/pgl.gleam", 212).
-spec apply_port(config(), gleam@uri:uri()) -> {ok, config()} | {error, nil}.
apply_port(Conf, Uri) ->
_pipe = erlang:element(5, Uri),
_pipe@1 = gleam@option:map(_pipe, fun(_capture) -> port(Conf, _capture) end),
_pipe@2 = gleam@option:unwrap(_pipe@1, Conf),
{ok, _pipe@2}.
-file("src/pgl.gleam", 219).
-spec apply_database(config(), gleam@uri:uri()) -> {ok, config()} | {error, nil}.
apply_database(Conf, Uri) ->
case gleam@string:split(erlang:element(6, Uri), <<"/"/utf8>>) of
[<<""/utf8>>, Db] ->
{ok, database(Conf, Db)};
_ ->
{error, nil}
end.
-file("src/pgl.gleam", 226).
-spec apply_ssl_mode(config(), gleam@uri:uri()) -> {ok, config()} | {error, nil}.
apply_ssl_mode(Conf, Uri) ->
_pipe = case erlang:element(7, Uri) of
none ->
{ok, ssl_disabled};
{some, Query} ->
gleam@result:'try'(
gleam_stdlib:parse_query(Query),
fun(Query@1) ->
gleam@result:'try'(
gleam@list:key_find(Query@1, <<"sslmode"/utf8>>),
fun(Sslmode) -> case Sslmode of
<<"require"/utf8>> ->
{ok, ssl_unverified};
<<"verify-ca"/utf8>> ->
{ok, ssl_verified};
<<"verify-full"/utf8>> ->
{ok, ssl_verified};
<<"disable"/utf8>> ->
{ok, ssl_disabled};
_ ->
{error, nil}
end end
)
end
)
end,
gleam@result:map(_pipe, fun(_capture) -> ssl(Conf, _capture) end).
-file("src/pgl.gleam", 313).
-spec field_from_bit_array(bitstring()) -> field().
field_from_bit_array(Field_type) ->
case Field_type of
<<"S"/utf8>> ->
severity;
<<"C"/utf8>> ->
code;
<<"M"/utf8>> ->
message;
<<"D"/utf8>> ->
detail;
<<"H"/utf8>> ->
hint;
<<"P"/utf8>> ->
position;
<<"p"/utf8>> ->
internal_position;
<<"q"/utf8>> ->
internal_query;
<<"W"/utf8>> ->
where;
<<"s"/utf8>> ->
schema;
<<"t"/utf8>> ->
table;
<<"c"/utf8>> ->
column;
<<"d"/utf8>> ->
data_type;
<<"n"/utf8>> ->
constraint;
<<"F"/utf8>> ->
file;
<<"L"/utf8>> ->
line;
<<"R"/utf8>> ->
routine;
Bits ->
{other, Bits}
end.
-file("src/pgl.gleam", 282).
-spec from_internal_error(pgl@internal:internal_error()) -> pgl_error().
from_internal_error(Err) ->
case Err of
{postgres_error, Code, Name, Message, Fields} ->
Fields@1 = begin
_pipe = begin
gleam@list:map(
maps:to_list(Fields),
fun(_use0) ->
{Field, Val} = _use0,
Field1 = field_from_bit_array(Field),
{Field1, Val}
end
)
end,
maps:from_list(_pipe)
end,
{postgres_error, Code, Name, Message, Fields@1};
{authentication_error, _, _} ->
_pipe@1 = Err,
_pipe@2 = pgl@internal:error_to_string(_pipe@1),
{authentication_error, _pipe@2};
{socket_error, _, _} ->
_pipe@3 = Err,
_pipe@4 = pgl@internal:error_to_string(_pipe@3),
{socket_error, _pipe@4};
{protocol_error, _, _} ->
_pipe@5 = Err,
_pipe@6 = pgl@internal:error_to_string(_pipe@5),
{protocol_error, _pipe@6}
end.
-file("src/pgl.gleam", 426).
-spec disconnect(connection()) -> {ok, nil} | {error, pgl_error()}.
disconnect(Conn) ->
_pipe = pgl@internal@socket:shutdown(erlang:element(2, Conn)),
gleam@result:map_error(_pipe, fun from_internal_error/1).
-file("src/pgl.gleam", 431).
-spec authenticated_connection(config(), pgl@internal@socket:factory()) -> {ok,
pgl@internal@socket:socket()} |
{error, nil}.
authenticated_connection(Config, Sockets) ->
Conf = begin
_pipe = {config,
<<""/utf8>>,
<<""/utf8>>,
<<""/utf8>>,
<<""/utf8>>,
[],
none},
_pipe@1 = pgl@internal@protocol:application(
_pipe,
erlang:element(2, Config)
),
_pipe@2 = pgl@internal@protocol:connection_parameters(
_pipe@1,
erlang:element(8, Config)
),
_pipe@3 = pgl@internal@protocol:username(
_pipe@2,
erlang:element(5, Config)
),
_pipe@4 = pgl@internal@protocol:password(
_pipe@3,
erlang:element(6, Config)
),
pgl@internal@protocol:database(_pipe@4, erlang:element(7, Config))
end,
_pipe@5 = Sockets,
_pipe@6 = pgl@internal@socket:connect(_pipe@5),
_pipe@7 = gleam@result:map_error(_pipe@6, fun(_) -> nil end),
gleam@result:'try'(
_pipe@7,
fun(Sock) -> _pipe@8 = pgl@internal@protocol:auth(Sock, Conf),
gleam@result:map_error(_pipe@8, fun(_) -> nil end) end
).
-file("src/pgl.gleam", 356).
?DOC(
" Creates a new `Db` record. This must be passed to `pgl.start` or\n"
" `pgl.supervised` before it can be used.\n"
).
-spec new(config()) -> db().
new(Config) ->
Sockets = begin
_pipe = pgl@internal@socket:new(),
_pipe@1 = pgl@internal@socket:host(_pipe, erlang:element(3, Config)),
_pipe@2 = pgl@internal@socket:port(_pipe@1, erlang:element(4, Config)),
_pipe@3 = pgl@internal@socket:ipv6(
_pipe@2,
(case erlang:element(11, Config) of
ipv4 ->
false;
ipv6 ->
true
end)
),
pgl@internal@socket:factory(_pipe@3)
end,
Pool = gleam_erlang_ffi:new_name(<<"pgl_pool"/utf8>>),
Query_cache = pgl@internal@query_cache:new(),
Type_cache = begin
_pipe@4 = pgl@internal@type_cache:new(),
pgl@internal@type_cache:on_connect(
_pipe@4,
fun() -> authenticated_connection(Config, Sockets) end
)
end,
{db, Pool, Sockets, Type_cache, Query_cache, Config}.
-file("src/pgl.gleam", 410).
-spec connect(db()) -> {ok, connection()} | {error, pgl_error()}.
connect(Db) ->
{db, _, Sockets, Type_cache, Query_cache, Config} = Db,
_pipe = authenticated_connection(Config, Sockets),
_pipe@1 = gleam@result:map(
_pipe,
fun(Sock) ->
{connection,
Sock,
none,
Type_cache,
Query_cache,
erlang:element(10, Config)}
end
),
gleam@result:map_error(
_pipe@1,
fun(_) -> {connection_error, <<"Failed to open connection"/utf8>>} end
).
-file("src/pgl.gleam", 478).
-spec pool_error_to_pgl_error(db_pool:pool_error(pgl_error())) -> pgl_error().
pool_error_to_pgl_error(Err) ->
case Err of
{connection_error, Err@1} ->
Err@1;
connection_timeout ->
connection_timeout
end.
-file("src/pgl.gleam", 463).
?DOC(
" Checks out a connection passes it to the provided function. After the provided\n"
" function returns, the connection is checked back in.\n"
"\n"
" Example:\n"
"\n"
" ```gleam\n"
" pgl.with_connection(db, fn(conn) {\n"
" pgl.query(sql, [], conn)\n"
" })\n"
" ```\n"
).
-spec with_connection(db(), fun((connection()) -> MET)) -> {ok, MET} |
{error, pgl_error()}.
with_connection(Db, Next) ->
Self = erlang:self(),
Pool = gleam@erlang@process:named_subject(erlang:element(2, Db)),
_pipe = db_pool:checkout(
Pool,
Self,
erlang:element(14, erlang:element(6, Db))
),
_pipe@1 = gleam@result:map_error(_pipe, fun pool_error_to_pgl_error/1),
gleam@result:map(
_pipe@1,
fun(Conn) ->
Res = Next(Conn),
db_pool:checkin(Pool, Conn, Self),
Res
end
).
-file("src/pgl.gleam", 486).
?DOC(" Shuts down the `Db`\n").
-spec shutdown(db()) -> {ok, nil} | {error, pgl_error()}.
shutdown(Db) ->
_pipe = erlang:element(2, Db),
_pipe@1 = gleam@erlang@process:named_subject(_pipe),
_pipe@2 = db_pool:shutdown(_pipe@1, 1000),
gleam@result:map_error(_pipe@2, fun pool_error_to_pgl_error/1).
-file("src/pgl.gleam", 493).
-spec ping(connection()) -> {ok, connection()} | {error, pgl_error()}.
ping(Conn) ->
_pipe = pgl@internal@protocol:ping(erlang:element(2, Conn)),
_pipe@1 = gleam@result:replace(_pipe, Conn),
gleam@result:map_error(_pipe@1, fun from_internal_error/1).
-file("src/pgl.gleam", 379).
-spec start(db()) -> {ok,
gleam@otp@actor:started(gleam@otp@static_supervisor:supervisor())} |
{error, gleam@otp@actor:start_error()}.
start(Db) ->
Pool = begin
_pipe = db_pool:new(),
_pipe@1 = db_pool:size(_pipe, erlang:element(12, erlang:element(6, Db))),
_pipe@2 = db_pool:interval(
_pipe@1,
erlang:element(13, erlang:element(6, Db))
),
_pipe@3 = db_pool:on_open(_pipe@2, fun() -> connect(Db) end),
_pipe@4 = db_pool:on_close(_pipe@3, fun disconnect/1),
db_pool:on_interval(
_pipe@4,
fun(Conn) ->
_ = ping(Conn),
nil
end
)
end,
_pipe@5 = gleam@otp@static_supervisor:new(one_for_one),
_pipe@6 = gleam@otp@static_supervisor:add(
_pipe@5,
pgl@internal@type_cache:supervised(erlang:element(4, Db))
),
_pipe@7 = gleam@otp@static_supervisor:add(
_pipe@6,
pgl@internal@query_cache:supervised(erlang:element(5, Db))
),
_pipe@8 = gleam@otp@static_supervisor:add(
_pipe@7,
pgl@internal@socket:supervised(erlang:element(3, Db))
),
_pipe@9 = gleam@otp@static_supervisor:add(
_pipe@8,
db_pool:supervised(Pool, erlang:element(2, Db), 1000)
),
gleam@otp@static_supervisor:start(_pipe@9).
-file("src/pgl.gleam", 400).
-spec supervised(db()) -> gleam@otp@supervision:child_specification(gleam@otp@static_supervisor:supervisor()).
supervised(Db) ->
Pool_supervisor = begin
_pipe = gleam@otp@supervision:supervisor(fun() -> start(Db) end),
gleam@otp@supervision:restart(_pipe, transient)
end,
_pipe@1 = gleam@otp@static_supervisor:new(one_for_one),
_pipe@2 = gleam@otp@static_supervisor:add(_pipe@1, Pool_supervisor),
gleam@otp@static_supervisor:supervised(_pipe@2).
-file("src/pgl.gleam", 527).
?DOC(" Returns a `Query` with the provided SQL string.\n").
-spec sql(binary()) -> 'query'().
sql(Sql) ->
{'query', Sql, []}.
-file("src/pgl.gleam", 532).
?DOC(" Sets a list of query parameters for the provided `Query`.\n").
-spec params('query'(), list(pg_value:value())) -> 'query'().
params(Q, Params) ->
{'query', erlang:element(2, Q), Params}.
-file("src/pgl.gleam", 593).
-spec rows_to_dicts(list(binary()), list(list(gleam@dynamic:dynamic_()))) -> {ok,
list(gleam@dynamic:dynamic_())} |
{error, nil}.
rows_to_dicts(Fields, Values) ->
gleam@result:map(
gleam@list:try_map(
Values,
fun(_capture) -> gleam@list:strict_zip(Fields, _capture) end
),
fun(Rows) ->
_pipe = begin
gleam@list:map(
Rows,
fun(Row) ->
gleam@list:map(
Row,
fun(_use0) ->
{Col, Val} = _use0,
{gleam_stdlib:identity(Col), Val}
end
)
end
)
end,
gleam@list:map(_pipe, fun gleam@dynamic:properties/1)
end
).
-file("src/pgl.gleam", 579).
-spec to_queried(pgl@internal@protocol:extended(pg_value:value()), boolean()) -> {ok,
queried()} |
{error, pgl_error()}.
to_queried(Ext, Rows_as_dict) ->
Values = lists:reverse(erlang:element(7, Ext)),
_pipe = case Rows_as_dict of
true ->
rows_to_dicts(erlang:element(6, Ext), Values);
false ->
{ok, gleam@list:map(Values, fun erlang:list_to_tuple/1)}
end,
_pipe@1 = gleam@result:map(
_pipe,
fun(_capture) ->
{queried, erlang:element(8, Ext), erlang:element(6, Ext), _capture}
end
),
gleam@result:map_error(
_pipe@1,
fun(_) -> {query_error, <<"Failed to process queried rows"/utf8>>} end
).
-file("src/pgl.gleam", 643).
-spec encode_from_cache(binary(), list(pg_value:value()), connection()) -> {ok,
pgl@internal@encode:'query'(pg_value:value(), pg_value@type_info:type_info())} |
{error, nil}.
encode_from_cache(Sql, Params, Conn) ->
gleam@result:'try'(
pgl@internal@query_cache:lookup(erlang:element(5, Conn), Sql),
fun(Oids) ->
gleam@result:map(
pgl@internal@type_cache:lookup(erlang:element(4, Conn), Oids),
fun(Info) ->
_pipe = pgl@internal@encode:cached(
Sql,
Params,
Info,
fun pg_value:encode/2
),
pgl@internal@encode:with_sync(_pipe)
end
)
end
).
-file("src/pgl.gleam", 655).
-spec on_param_description(
binary(),
list(pg_value:value()),
list(integer()),
connection()
) -> {ok, bitstring()} | {error, nil}.
on_param_description(Sql, Params, Oids, Conn) ->
gleam@result:'try'(
pgl@internal@query_cache:insert(erlang:element(5, Conn), Sql, Oids),
fun(_) ->
gleam@result:'try'(
pgl@internal@type_cache:lookup(erlang:element(4, Conn), Oids),
fun(Info) ->
_pipe = pgl@internal@encode:cached(
Sql,
Params,
Info,
fun pg_value:encode/2
),
_pipe@1 = pgl@internal@encode:with_sync(_pipe),
_pipe@2 = pgl@internal@encode:to_bit_array(_pipe@1),
gleam@result:map_error(_pipe@2, fun(_) -> nil end)
end
)
end
).
-file("src/pgl.gleam", 685).
-spec decode_row_values(list(bitstring()), list(pg_value@type_info:type_info())) -> {ok,
list(gleam@dynamic:dynamic_())} |
{error, pgl@internal:internal_error()}.
decode_row_values(Values, Infos) ->
_pipe = gleam@list:strict_zip(Values, Infos),
_pipe@2 = gleam@result:map_error(_pipe, fun(_) -> _pipe@1 = decoding_error,
{protocol_error, _pipe@1, <<"Mismatched values and infos"/utf8>>} end),
gleam@result:'try'(
_pipe@2,
fun(Vals_infos) ->
gleam@list:try_map(
Vals_infos,
fun(Val_info) ->
{Val, Info} = Val_info,
_pipe@3 = pg_value:decode(Val, Info),
gleam@result:map_error(
_pipe@3,
fun(_capture) ->
{protocol_error, decoding_error, _capture}
end
)
end
)
end
).
-file("src/pgl.gleam", 670).
-spec decode_row(list(bitstring()), list(integer()), connection()) -> {ok,
list(gleam@dynamic:dynamic_())} |
{error, pgl@internal:internal_error()}.
decode_row(Values, Oids, Conn) ->
_pipe = pgl@internal@type_cache:lookup(erlang:element(4, Conn), Oids),
_pipe@1 = gleam@result:map_error(
_pipe,
fun(_) ->
{protocol_error, decoding_error, <<"Failed to decode row"/utf8>>}
end
),
gleam@result:'try'(
_pipe@1,
fun(_capture) -> decode_row_values(Values, _capture) end
).
-file("src/pgl.gleam", 629).
-spec extended(connection()) -> pgl@internal@protocol:extended(pg_value:value()).
extended(Conn) ->
_pipe = pgl@internal@protocol:extended(),
_pipe@1 = pgl@internal@protocol:on_decode_row(
_pipe,
fun(Vals, Oids) -> decode_row(Vals, Oids, Conn) end
),
pgl@internal@protocol:on_param_description(
_pipe@1,
fun(Sql, Params, Oids@1) ->
_pipe@2 = on_param_description(Sql, Params, Oids@1, Conn),
gleam@result:map_error(
_pipe@2,
fun(_) ->
{protocol_error,
processing_error,
<<"Failed to describe statement parameters"/utf8>>}
end
)
end
).
-file("src/pgl.gleam", 549).
?DOC(
" Uses [pipelining][1] to send multiple queries to the database server without\n"
" waiting for previous queries to complete. Reduces the number of network\n"
" roundtrips needed for multiple queries.\n"
"\n"
" [1]: https://www.postgresql.org/docs/current/protocol-flow.html#PROTOCOL-FLOW-PIPELINING\n"
).
-spec batch(list('query'()), connection()) -> {ok, list(queried())} |
{error, pgl_error()}.
batch(Queries, Conn) ->
Messages = begin
_pipe = Queries,
_pipe@1 = gleam@list:try_map(
_pipe,
fun(Query) ->
{'query', Sql, Params} = Query,
gleam@result:'try'(
pgl@internal@query_cache:lookup(
erlang:element(5, Conn),
Sql
),
fun(Oids) ->
gleam@result:map(
pgl@internal@type_cache:lookup(
erlang:element(4, Conn),
Oids
),
fun(Info) ->
pgl@internal@encode:cached(
Sql,
Params,
Info,
fun pg_value:encode/2
)
end
)
end
)
end
),
gleam@result:lazy_unwrap(
_pipe@1,
fun() ->
gleam@list:map(
Queries,
fun(Q) ->
pgl@internal@encode:uncached(
erlang:element(2, Q),
erlang:element(3, Q)
)
end
)
end
)
end,
Ext = extended(Conn),
_pipe@2 = pgl@internal@protocol:pipeline(),
_pipe@3 = pgl@internal@protocol:batch_process(
_pipe@2,
Ext,
Messages,
erlang:element(2, Conn)
),
_pipe@4 = gleam@result:map_error(_pipe@3, fun from_internal_error/1),
gleam@result:'try'(
_pipe@4,
fun(Exts) ->
gleam@list:try_map(
Exts,
fun(Ext@1) -> to_queried(Ext@1, erlang:element(6, Conn)) end
)
end
).
-file("src/pgl.gleam", 616).
-spec extended_query(binary(), list(pg_value:value()), connection()) -> {ok,
pgl@internal@protocol:extended(pg_value:value())} |
{error, pgl@internal:internal_error()}.
extended_query(Sql, Params, Conn) ->
Message = begin
_pipe = encode_from_cache(Sql, Params, Conn),
gleam@result:lazy_unwrap(
_pipe,
fun() -> pgl@internal@encode:uncached(Sql, Params) end
)
end,
_pipe@1 = extended(Conn),
pgl@internal@protocol:process(_pipe@1, Message, erlang:element(2, Conn)).
-file("src/pgl.gleam", 537).
?DOC(" Perform a query with the given SQL string and list of parameters.\n").
-spec 'query'('query'(), connection()) -> {ok, queried()} | {error, pgl_error()}.
'query'(Q, Conn) ->
_pipe = extended_query(erlang:element(2, Q), erlang:element(3, Q), Conn),
_pipe@1 = gleam@result:map_error(_pipe, fun from_internal_error/1),
gleam@result:'try'(
_pipe@1,
fun(_capture) -> to_queried(_capture, erlang:element(6, Conn)) end
).
-file("src/pgl.gleam", 610).
?DOC(
" Perform a query with the given SQL string. This function will send the\n"
" SQL string as is to the postgres database server.\n"
).
-spec execute(binary(), connection()) -> {ok, integer()} | {error, pgl_error()}.
execute(Sql, Conn) ->
_pipe = extended_query(Sql, [], Conn),
_pipe@1 = gleam@result:map(_pipe, fun(Rows) -> erlang:element(8, Rows) end),
gleam@result:map_error(_pipe@1, fun from_internal_error/1).
-file("src/pgl.gleam", 726).
?DOC(" Begins a transaction\n").
-spec 'begin'(connection()) -> {ok, connection()} |
{error, transaction_error(any())}.
'begin'(Conn) ->
Packet = pgl@internal@encode:'query'(<<"BEGIN"/utf8>>),
_pipe = pgl@internal@protocol:simple(Packet, erlang:element(2, Conn)),
_pipe@1 = gleam@result:replace(_pipe, Conn),
gleam@result:map_error(_pipe@1, fun(Err) -> _pipe@2 = Err,
_pipe@3 = pgl@internal:error_to_string(_pipe@2),
{transaction_error, _pipe@3} end).
-file("src/pgl.gleam", 739).
?DOC(" Commits a transaction\n").
-spec commit(connection()) -> {ok, connection()} |
{error, transaction_error(any())}.
commit(Conn) ->
Packet = pgl@internal@encode:'query'(<<"COMMIT"/utf8>>),
_pipe = pgl@internal@protocol:simple(Packet, erlang:element(2, Conn)),
_pipe@1 = gleam@result:replace(_pipe, Conn),
gleam@result:map_error(_pipe@1, fun(Err) -> _pipe@2 = Err,
_pipe@3 = pgl@internal:error_to_string(_pipe@2),
{transaction_error, _pipe@3} end).
-file("src/pgl.gleam", 817).
-spec set_savepoint(connection(), integer()) -> connection().
set_savepoint(Conn, Savepoint) ->
{connection,
erlang:element(2, Conn),
{some, Savepoint},
erlang:element(4, Conn),
erlang:element(5, Conn),
erlang:element(6, Conn)}.
-file("src/pgl.gleam", 177).
-spec options_from_uri(gleam@uri:uri()) -> {ok, config()} | {error, nil}.
options_from_uri(Uri) ->
_pipe = erlang:element(2, Uri),
_pipe@1 = gleam@option:map(_pipe, fun(Scheme) -> case Scheme of
<<"postgres"/utf8>> ->
{ok,
{config,
<<""/utf8>>,
<<"127.0.0.1"/utf8>>,
5432,
<<""/utf8>>,
<<""/utf8>>,
<<""/utf8>>,
[],
ssl_disabled,
false,
ipv4,
1,
1000,
50}};
<<"postgresql"/utf8>> ->
{ok,
{config,
<<""/utf8>>,
<<"127.0.0.1"/utf8>>,
5432,
<<""/utf8>>,
<<""/utf8>>,
<<""/utf8>>,
[],
ssl_disabled,
false,
ipv4,
1,
1000,
50}};
_ ->
{error, nil}
end end),
gleam@option:lazy_unwrap(_pipe@1, fun() -> {error, nil} end).
-file("src/pgl.gleam", 166).
?DOC(" Build a `Config` from a connection url\n").
-spec from_url(binary()) -> {ok, config()} | {error, nil}.
from_url(Url) ->
gleam@result:'try'(
gleam_stdlib:uri_parse(Url),
fun(Uri) ->
gleam@result:'try'(
options_from_uri(Uri),
fun(Conf) ->
gleam@result:'try'(
apply_user_info(Conf, Uri),
fun(Conf@1) ->
gleam@result:'try'(
apply_host(Conf@1, Uri),
fun(Conf@2) ->
gleam@result:'try'(
apply_port(Conf@2, Uri),
fun(Conf@3) ->
gleam@result:'try'(
apply_database(Conf@3, Uri),
fun(Conf@4) ->
apply_ssl_mode(Conf@4, Uri)
end
)
end
)
end
)
end
)
end
)
end
).
-file("src/pgl.gleam", 795).
-spec next_savepoint(connection()) -> {ok, connection()} |
{error, transaction_error(any())}.
next_savepoint(Conn) ->
Num@1 = case erlang:element(3, Conn) of
{some, Num} ->
Num;
none ->
0
end,
Statement = <<<<"SAVEPOINT "/utf8, "pgl_savepoint"/utf8>>/binary,
(erlang:integer_to_binary(Num@1))/binary>>,
Savepoint = Num@1 + 1,
Packet = pgl@internal@encode:'query'(Statement),
_pipe = pgl@internal@protocol:simple(Packet, erlang:element(2, Conn)),
_pipe@1 = gleam@result:map(
_pipe,
fun(_) -> set_savepoint(Conn, Savepoint) end
),
gleam@result:map_error(_pipe@1, fun(Err) -> _pipe@2 = Err,
_pipe@3 = pgl@internal:error_to_string(_pipe@2),
{transaction_error, _pipe@3} end).
-file("src/pgl.gleam", 822).
?DOC(" Releases a savepoint.\n").
-spec release_savepoint(connection()) -> {ok, connection()} |
{error, transaction_error(any())}.
release_savepoint(Conn) ->
case erlang:element(3, Conn) of
{some, Num} ->
Statement = <<<<"RELEASE SAVEPOINT "/utf8, "pgl_savepoint"/utf8>>/binary,
(erlang:integer_to_binary(Num - 1))/binary>>,
Packet = pgl@internal@encode:'query'(Statement),
_pipe = pgl@internal@protocol:simple(
Packet,
erlang:element(2, Conn)
),
_pipe@1 = gleam@result:replace(_pipe, Conn),
gleam@result:map_error(_pipe@1, fun(Err) -> _pipe@2 = Err,
_pipe@3 = pgl@internal:error_to_string(_pipe@2),
{transaction_error, _pipe@3} end);
none ->
{error, not_in_transaction}
end.
-file("src/pgl.gleam", 844).
-spec rollback_savepoint(integer(), connection()) -> {ok, connection()} |
{error, transaction_error(any())}.
rollback_savepoint(Num, Conn) ->
Savepoint = Num - 1,
Statement = <<<<<<"ROLLBACK TO SAVEPOINT "/utf8, "pgl_savepoint"/utf8>>/binary,
(erlang:integer_to_binary(Savepoint))/binary>>/binary,
";"/utf8>>,
Packet = pgl@internal@encode:'query'(Statement),
_pipe = pgl@internal@protocol:simple(Packet, erlang:element(2, Conn)),
_pipe@1 = gleam@result:replace(_pipe, Conn),
gleam@result:map_error(_pipe@1, fun(Err) -> _pipe@2 = Err,
_pipe@3 = pgl@internal:error_to_string(_pipe@2),
{transaction_error, _pipe@3} end).
-file("src/pgl.gleam", 752).
?DOC(" Rolls back a transaction\n").
-spec rollback(connection()) -> {ok, connection()} |
{error, transaction_error(any())}.
rollback(Conn) ->
case erlang:element(3, Conn) of
{some, Num} ->
rollback_savepoint(Num, Conn);
none ->
Packet = pgl@internal@encode:'query'(<<"ROLLBACK"/utf8>>),
_pipe = pgl@internal@protocol:simple(
Packet,
erlang:element(2, Conn)
),
_pipe@1 = gleam@result:replace(_pipe, Conn),
gleam@result:map_error(_pipe@1, fun(Err) -> _pipe@2 = Err,
_pipe@3 = pgl@internal:error_to_string(_pipe@2),
{transaction_error, _pipe@3} end)
end.
-file("src/pgl.gleam", 709).
?DOC(
" Starts a transaction and then calls the provided function, passing it the\n"
" transaction connection. If the given function throws an exception, the\n"
" transaction will be rolled back the exception propagated up.\n"
" If the given function returns an error result, the transaction will also\n"
" be rolled back and an error result returned.\n"
).
-spec transaction(connection(), fun((connection()) -> {ok, MGR} | {error, MGS})) -> {ok,
MGR} |
{error, transaction_error(MGS)}.
transaction(Conn, Next) ->
gleam@result:'try'(
'begin'(Conn),
fun(Tx) ->
_pipe = exception_ffi:on_crash(
fun() -> rollback(Tx) end,
fun() -> Next(Tx) end
),
_pipe@1 = gleam@result:map_error(
_pipe,
fun(Err) -> case rollback(Tx) of
{ok, _} ->
{rollback_error, Err};
{error, Err@1} ->
Err@1
end end
),
gleam@result:'try'(_pipe@1, fun(Res) -> _pipe@2 = commit(Tx),
gleam@result:replace(_pipe@2, Res) end)
end
).
-file("src/pgl.gleam", 786).
-spec rollback_and_release(connection()) -> {ok, connection()} |
{error, transaction_error(any())}.
rollback_and_release(Conn) ->
_pipe = rollback(Conn),
gleam@result:'try'(_pipe, fun release_savepoint/1).
-file("src/pgl.gleam", 770).
?DOC(" Creates a new savepoint.\n").
-spec savepoint(connection(), fun((connection()) -> {ok, MHK} | {error, MHL})) -> {ok,
MHK} |
{error, transaction_error(MHL)}.
savepoint(Conn, Next) ->
gleam@result:'try'(
next_savepoint(Conn),
fun(Conn1) ->
_pipe = exception_ffi:on_crash(
fun() -> rollback_and_release(Conn1) end,
fun() -> Next(Conn1) end
),
_pipe@1 = gleam@result:map_error(
_pipe,
fun(Err) -> case rollback_and_release(Conn1) of
{ok, _} ->
{rollback_error, Err};
{error, Err@1} ->
Err@1
end end
),
gleam@result:'try'(
_pipe@1,
fun(Res) -> _pipe@2 = release_savepoint(Conn1),
gleam@result:replace(_pipe@2, Res) end
)
end
).