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, from_url/1, error_to_string/1, new/1, start/1, supervised/1, connection/1, shutdown/1, sql/1, values/2, 'query'/2, batch/2, execute/2, transaction/2, 'begin'/1, commit/1, rollback/1, 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").
-opaque 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 |
connection_unavailable |
{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(NTI) :: {rollback_error, NTI} |
not_in_transaction |
{transaction_error, binary()}.
-opaque db() :: {db,
gleam@erlang@process:name(db_pool:message(pgl@internal@socket:socket(), pgl_error())),
pgl@internal@socket:factory(),
pgl@internal@type_cache:type_cache(),
pgl@internal@query_cache:query_cache(),
config()}.
-opaque connection() :: {pool, db()} |
{connection, pgl@internal@conn:conn(), db()}.
-type queried() :: {queried,
integer(),
list(binary()),
list(gleam@dynamic:dynamic_())}.
-type 'query'() :: {'query', binary(), list(pg_value:value())}.
-file("src/pgl.gleam", 98).
?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", 103).
?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", 108).
?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", 113).
?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", 118).
?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", 123).
?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", 128).
?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", 140).
?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", 146).
?DOC(
" Configures rows to be returned as `Dict` rather than n-tuples.\n"
" The keys of the `Dict` are the queried column names.\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", 151).
?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", 156).
?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", 161).
?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", 166).
?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", 231).
-spec apply_ssl_mode(config(), gleam@uri:uri()) -> {ok, config()} | {error, nil}.
apply_ssl_mode(Conf, Uri) ->
Ssl_mode = case erlang:element(7, Uri) of
none ->
{ok, ssl_verified};
{some, Query} ->
case gleam_stdlib:parse_query(Query) of
{ok, Params} ->
case gleam@list:key_find(Params, <<"sslmode"/utf8>>) of
{ok, <<"require"/utf8>>} ->
{ok, ssl_unverified};
{ok, <<"verify-ca"/utf8>>} ->
{ok, ssl_verified};
{ok, <<"verify-full"/utf8>>} ->
{ok, ssl_verified};
{ok, <<"disable"/utf8>>} ->
{ok, ssl_disabled};
{ok, _} ->
{error, nil};
{error, _} ->
{ok, ssl_disabled}
end;
{error, _} ->
{error, nil}
end
end,
_pipe = Ssl_mode,
gleam@result:map(_pipe, fun(_capture) -> ssl(Conf, _capture) end).
-file("src/pgl.gleam", 224).
-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", 217).
-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", 210).
-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", 193).
-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", 182).
-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_verified,
false,
ipv4,
5,
1000,
50}};
<<"postgresql"/utf8>> ->
{ok,
{config,
<<""/utf8>>,
<<"127.0.0.1"/utf8>>,
5432,
<<""/utf8>>,
<<""/utf8>>,
<<""/utf8>>,
[],
ssl_verified,
false,
ipv4,
5,
1000,
50}};
_ ->
{error, nil}
end end),
gleam@option:lazy_unwrap(_pipe@1, fun() -> {error, nil} end).
-file("src/pgl.gleam", 171).
?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", 279).
?DOC(" Returns a formatted string representation of the provided error.\n").
-spec error_to_string(pgl_error()) -> binary().
error_to_string(Err) ->
case Err of
{query_error, Message} ->
pgl@internal:format_error(<<"QueryError"/utf8>>, Message);
{connection_error, Message@1} ->
pgl@internal:format_error(<<"ConnectionError"/utf8>>, Message@1);
connection_timeout ->
pgl@internal:format_error(<<"ConnectionTimeout"/utf8>>, <<""/utf8>>);
connection_unavailable ->
pgl@internal:format_error(
<<"ConnectionUnavailable"/utf8>>,
<<""/utf8>>
);
{authentication_error, Message@2} ->
pgl@internal:format_error(<<"AuthenticationError"/utf8>>, Message@2);
{protocol_error, Message@3} ->
pgl@internal:format_error(<<"ProtocolError"/utf8>>, Message@3);
{socket_error, Message@4} ->
pgl@internal:format_error(<<"SocketError"/utf8>>, Message@4);
{postgres_error, Code, Name, Message@5, _} ->
pgl@internal:format_error_with_values(
<<"PostgresError"/utf8>>,
<<""/utf8>>,
[{<<"code"/utf8>>, Code},
{<<"name"/utf8>>, Name},
{<<"message"/utf8>>, Message@5}],
fun gleam@function:identity/1
)
end.
-file("src/pgl.gleam", 358).
-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", 324).
-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, Kind, Message@1} ->
Message@2 = <<<<<<"["/utf8,
(pgl@internal:auth_error_to_string(Kind))/binary>>/binary,
"] "/utf8>>/binary,
Message@1/binary>>,
{authentication_error, Message@2};
{socket_error, Kind@1, Message@3} ->
Message@4 = <<<<<<"["/utf8,
(pgl@internal:socket_error_to_string(Kind@1))/binary>>/binary,
"] "/utf8>>/binary,
Message@3/binary>>,
{socket_error, Message@4};
{protocol_error, Kind@2, Message@5} ->
Message@6 = <<<<<<"["/utf8,
(pgl@internal:protocol_error_to_string(Kind@2))/binary>>/binary,
"] "/utf8>>/binary,
Message@5/binary>>,
{protocol_error, Message@6}
end.
-file("src/pgl.gleam", 471).
-spec authenticated_connection(config(), pgl@internal@socket:factory()) -> {ok,
pgl@internal@socket:socket()} |
{error, pgl@internal:internal_error()}.
authenticated_connection(Config, Sockets) ->
Ssl = case erlang:element(9, Config) of
ssl_disabled ->
ssl_disabled;
ssl_verified ->
ssl_verified;
ssl_unverified ->
ssl_unverified
end,
Conf = begin
_pipe = {config,
<<""/utf8>>,
<<""/utf8>>,
none,
<<""/utf8>>,
[],
ssl_verified},
_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)
),
_pipe@5 = pgl@internal@protocol:database(
_pipe@4,
erlang:element(7, Config)
),
pgl@internal@protocol:ssl(_pipe@5, Ssl)
end,
_pipe@6 = Sockets,
_pipe@7 = pgl@internal@socket:connect(_pipe@6),
_pipe@8 = gleam@result:map_error(
_pipe@7,
fun(_) ->
{socket_error,
{connect_error, <<"Failed to start socket connection"/utf8>>},
<<"Failed to start socket connection"/utf8>>}
end
),
gleam@result:'try'(
_pipe@8,
fun(Sock) -> pgl@internal@protocol:auth(Sock, Conf) end
).
-file("src/pgl.gleam", 405).
?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() -> _pipe@5 = authenticated_connection(Config, Sockets),
gleam@result:map_error(_pipe@5, fun(_) -> nil end) end
)
end,
{db, Pool, Sockets, Type_cache, Query_cache, Config}.
-file("src/pgl.gleam", 466).
-spec disconnect(pgl@internal@socket:socket()) -> {ok, nil} |
{error, pgl_error()}.
disconnect(Sock) ->
_pipe = pgl@internal@socket:shutdown(Sock),
gleam@result:map_error(_pipe, fun from_internal_error/1).
-file("src/pgl.gleam", 461).
-spec connect(db()) -> {ok, pgl@internal@socket:socket()} | {error, pgl_error()}.
connect(Db) ->
_pipe = authenticated_connection(
erlang:element(6, Db),
erlang:element(3, Db)
),
gleam@result:map_error(_pipe, fun from_internal_error/1).
-file("src/pgl.gleam", 433).
?DOC(
" Starts the connection pool, type cache, query cache, and socket\n"
" factory under a supervision tree.\n"
).
-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:on_open(_pipe@1, fun() -> connect(Db) end),
_pipe@3 = db_pool:on_close(_pipe@2, fun disconnect/1),
_pipe@4 = db_pool:on_idle(
_pipe@3,
fun(_capture) ->
pgl@internal@socket:start_ping(
_capture,
erlang:element(13, erlang:element(6, Db))
)
end
),
db_pool:on_active(_pipe@4, fun pgl@internal@socket:stop_ping/1)
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", 451).
?DOC(" Returns a child specification for use in an existing supervision tree.\n").
-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", 502).
?DOC(" Creates a `Connection`.\n").
-spec connection(db()) -> connection().
connection(Db) ->
{pool, Db}.
-file("src/pgl.gleam", 506).
-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;
connection_unavailable ->
connection_unavailable
end.
-file("src/pgl.gleam", 515).
?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", 531).
-spec with_single_connection(
connection(),
fun((pgl@internal@conn:conn(), db()) -> {ok, NUI} | {error, pgl_error()})
) -> {ok, NUI} | {error, pgl_error()}.
with_single_connection(Connection, Next) ->
case Connection of
{pool, Db} ->
Res = begin
_pipe = erlang:element(2, Db),
_pipe@1 = gleam@erlang@process:named_subject(_pipe),
_pipe@3 = db_pool:with_connection(
_pipe@1,
erlang:element(14, erlang:element(6, Db)),
30000,
fun(Socket) ->
_pipe@2 = pgl@internal@conn:new(Socket, erlang:self()),
Next(_pipe@2, Db)
end
),
gleam@result:map_error(_pipe@3, fun pool_error_to_pgl_error/1)
end,
case Res of
{ok, Ok} ->
Ok;
{error, Err} ->
{error, Err}
end;
{connection, Conn, Db@1} ->
Next(Conn, Db@1)
end.
-file("src/pgl.gleam", 555).
-spec checkout(db(), gleam@erlang@process:pid_()) -> {ok,
pgl@internal@conn:conn()} |
{error, pgl_error()}.
checkout(Db, Self) ->
_pipe = erlang:element(2, Db),
_pipe@1 = gleam@erlang@process:named_subject(_pipe),
_pipe@2 = db_pool:checkout(
_pipe@1,
Self,
erlang:element(14, erlang:element(6, Db)),
30000
),
_pipe@3 = gleam@result:map(
_pipe@2,
fun(_capture) -> pgl@internal@conn:new(_capture, Self) end
),
gleam@result:map_error(_pipe@3, fun pool_error_to_pgl_error/1).
-file("src/pgl.gleam", 563).
-spec checkin(db(), pgl@internal@socket:socket(), gleam@erlang@process:pid_()) -> nil.
checkin(Db, Sock, Self) ->
_pipe = erlang:element(2, Db),
_pipe@1 = gleam@erlang@process:named_subject(_pipe),
db_pool:checkin(_pipe@1, Sock, Self).
-file("src/pgl.gleam", 584).
?DOC(" Returns a `Query` with the provided SQL string.\n").
-spec sql(binary()) -> 'query'().
sql(Sql) ->
{'query', Sql, []}.
-file("src/pgl.gleam", 589).
?DOC(" Sets a list of query parameters for the provided `Query`.\n").
-spec values('query'(), list(pg_value:value())) -> 'query'().
values(Q, Values) ->
{'query', erlang:element(2, Q), Values}.
-file("src/pgl.gleam", 653).
-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", 639).
-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", 718).
-spec on_param_description(
binary(),
list(pg_value:value()),
list(integer()),
db()
) -> {ok, bitstring()} | {error, nil}.
on_param_description(Sql, Params, Oids, Db) ->
gleam@result:'try'(
pgl@internal@query_cache:insert(erlang:element(5, Db), Sql, Oids),
fun(_) ->
gleam@result:'try'(
pgl@internal@type_cache:lookup(erlang:element(4, Db), 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", 748).
-spec decode_row_values(
list(gleam@option:option(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) -> case Val_info of
{none, _} ->
{ok, gleam@dynamic:nil()};
{{some, 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)
end
).
-file("src/pgl.gleam", 733).
-spec decode_row(list(gleam@option:option(bitstring())), list(integer()), db()) -> {ok,
list(gleam@dynamic:dynamic_())} |
{error, pgl@internal:internal_error()}.
decode_row(Values, Oids, Db) ->
_pipe = pgl@internal@type_cache:lookup(erlang:element(4, Db), 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", 692).
-spec extended(db()) -> pgl@internal@protocol:extended(pg_value:value()).
extended(Db) ->
_pipe = pgl@internal@protocol:extended(),
_pipe@1 = pgl@internal@protocol:on_decode_row(
_pipe,
fun(Vals, Oids) -> decode_row(Vals, Oids, Db) end
),
pgl@internal@protocol:on_param_description(
_pipe@1,
fun(Sql, Params, Oids@1) ->
_pipe@2 = on_param_description(Sql, Params, Oids@1, Db),
gleam@result:map_error(
_pipe@2,
fun(_) ->
{protocol_error,
processing_error,
<<"Failed to describe statement parameters"/utf8>>}
end
)
end
).
-file("src/pgl.gleam", 706).
-spec encode_from_cache(binary(), list(pg_value:value()), db()) -> {ok,
pgl@internal@encode:'query'(pg_value:value(), pg_value@type_info:type_info())} |
{error, nil}.
encode_from_cache(Sql, Params, Db) ->
gleam@result:'try'(
pgl@internal@query_cache:lookup(erlang:element(5, Db), Sql),
fun(Oids) ->
gleam@result:map(
pgl@internal@type_cache:lookup(erlang:element(4, Db), 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", 678).
-spec extended_query(
binary(),
list(pg_value:value()),
pgl@internal@conn:conn(),
db()
) -> {ok, pgl@internal@protocol:extended(pg_value:value())} |
{error, pgl@internal:internal_error()}.
extended_query(Sql, Params, Conn, Db) ->
Message = begin
_pipe = encode_from_cache(Sql, Params, Db),
gleam@result:lazy_unwrap(
_pipe,
fun() -> pgl@internal@encode:uncached(Sql, Params) end
)
end,
_pipe@1 = extended(Db),
pgl@internal@protocol:process(_pipe@1, Message, erlang:element(2, Conn)).
-file("src/pgl.gleam", 594).
?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, Connection) ->
with_single_connection(
Connection,
fun(Conn, Db) ->
_pipe = extended_query(
erlang:element(2, Q),
erlang:element(3, Q),
Conn,
Db
),
_pipe@1 = gleam@result:map_error(_pipe, fun from_internal_error/1),
gleam@result:'try'(
_pipe@1,
fun(_capture) ->
to_queried(
_capture,
erlang:element(10, erlang:element(6, Db))
)
end
)
end
).
-file("src/pgl.gleam", 607).
?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, Connection) ->
with_single_connection(
Connection,
fun(Conn, Db) ->
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, Db),
Sql
),
fun(Oids) ->
gleam@result:map(
pgl@internal@type_cache:lookup(
erlang:element(4, Db),
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(Db),
_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(10, erlang:element(6, Db))
)
end
)
end
)
end
).
-file("src/pgl.gleam", 670).
?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, Connection) ->
with_single_connection(
Connection,
fun(Conn, Db) -> _pipe = extended_query(Sql, [], Conn, Db),
_pipe@1 = gleam@result:map(
_pipe,
fun(Rows) -> erlang:element(8, Rows) end
),
gleam@result:map_error(_pipe@1, fun from_internal_error/1) end
).
-file("src/pgl.gleam", 969).
-spec transaction_query(binary(), pgl@internal@conn:conn()) -> {ok,
pgl@internal@conn:conn()} |
{error, transaction_error(any())}.
transaction_query(Query, Conn) ->
Packet = pgl@internal@encode:'query'(Query),
_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", 787).
-spec do_transaction(
pgl@internal@conn:conn(),
fun((pgl@internal@conn:conn()) -> {ok, NWO} | {error, NWP})
) -> {ok, NWO} | {error, transaction_error(NWP)}.
do_transaction(Conn, Next) ->
gleam@result:'try'(
transaction_query(<<"BEGIN"/utf8>>, Conn),
fun(Conn@1) ->
_pipe = pgl@internal:assert_on_crash(
fun() -> transaction_query(<<"ROLLBACK"/utf8>>, Conn@1) end,
<<"ROLLBACK"/utf8>>,
fun() -> Next(Conn@1) end
),
_pipe@1 = gleam@result:map_error(
_pipe,
fun(Err) ->
case transaction_query(<<"ROLLBACK"/utf8>>, Conn@1) of
{ok, _} ->
{rollback_error, Err};
{error, Err@1} ->
Err@1
end
end
),
gleam@result:'try'(
_pipe@1,
fun(Res) ->
_pipe@2 = transaction_query(<<"COMMIT"/utf8>>, Conn@1),
gleam@result:replace(_pipe@2, Res)
end
)
end
).
-file("src/pgl.gleam", 826).
-spec with_transaction(
connection(),
fun((pgl@internal@conn:conn(), db()) -> {ok, NWZ} |
{error, transaction_error(NXA)})
) -> {ok, NWZ} | {error, transaction_error(NXA)}.
with_transaction(Connection, Next) ->
case Connection of
{pool, Db} ->
Self = erlang:self(),
_pipe = checkout(Db, Self),
_pipe@3 = gleam@result:map_error(
_pipe,
fun(Pgl_error) -> _pipe@1 = Pgl_error,
_pipe@2 = error_to_string(_pipe@1),
{transaction_error, _pipe@2} end
),
gleam@result:'try'(_pipe@3, fun(Conn) -> case Next(Conn, Db) of
{ok, Val} ->
{ok, Val};
{error, Err} ->
checkin(
Db,
erlang:element(2, Conn),
erlang:element(4, Conn)
),
{error, Err}
end end);
{connection, Conn@1, Db@1} ->
Next(Conn@1, Db@1)
end.
-file("src/pgl.gleam", 774).
?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, NWH} | {error, NWI})) -> {ok,
NWH} |
{error, transaction_error(NWI)}.
transaction(Connection, Next) ->
with_transaction(
Connection,
fun(Conn, Db) ->
Res = do_transaction(
Conn,
fun(Conn@1) -> Next({connection, Conn@1, Db}) end
),
checkin(Db, erlang:element(2, Conn), erlang:element(4, Conn)),
Res
end
).
-file("src/pgl.gleam", 814).
?DOC(
" Begins a transaction.\n"
"\n"
" You should typically use `pgl.transaction` to take care of starting and\n"
" ending transactions.\n"
).
-spec 'begin'(connection()) -> {ok, connection()} |
{error, transaction_error(any())}.
'begin'(Connection) ->
with_transaction(
Connection,
fun(Conn, Db) -> _pipe = transaction_query(<<"BEGIN"/utf8>>, Conn),
gleam@result:map(
_pipe,
fun(_capture) -> {connection, _capture, Db} end
) end
).
-file("src/pgl.gleam", 858).
?DOC(
" Commits a transaction.\n"
"\n"
" You should typically use `pgl.transaction` to take care of starting and\n"
" ending transactions.\n"
).
-spec commit(connection()) -> {ok, connection()} |
{error, transaction_error(any())}.
commit(Connection) ->
case Connection of
{pool, _} ->
{error, not_in_transaction};
{connection, Conn, Db} ->
_pipe = transaction_query(<<"COMMIT"/utf8>>, Conn),
gleam@result:map(
_pipe,
fun(_) ->
checkin(
Db,
erlang:element(2, Conn),
erlang:element(4, Conn)
),
{pool, Db}
end
)
end.
-file("src/pgl.gleam", 890).
-spec do_rollback(pgl@internal@conn:conn(), db()) -> {ok,
pgl@internal@conn:conn()} |
{error, transaction_error(any())}.
do_rollback(Conn, Db) ->
case pgl@internal@conn:rollback_savepoint_statement(Conn) of
{ok, Stmt} ->
_pipe = transaction_query(Stmt, Conn),
gleam@result:replace(_pipe, Conn);
_ ->
_pipe@1 = transaction_query(<<"ROLLBACK"/utf8>>, Conn),
gleam@result:map(
_pipe@1,
fun(_) ->
checkin(
Db,
erlang:element(2, Conn),
erlang:element(4, Conn)
),
Conn
end
)
end.
-file("src/pgl.gleam", 878).
?DOC(
" Rolls back to a savepoint if one exists, otherwise rolls back the transaction.\n"
"\n"
" You should typically use `pgl.transaction` to take care of starting and\n"
" ending transactions.\n"
).
-spec rollback(connection()) -> {ok, connection()} |
{error, transaction_error(any())}.
rollback(Connection) ->
case Connection of
{pool, _} ->
{error, not_in_transaction};
{connection, Conn, Db} ->
_pipe = do_rollback(Conn, Db),
gleam@result:map(_pipe, fun(_) -> {pool, Db} end)
end.
-file("src/pgl.gleam", 958).
-spec do_release_savepoint(pgl@internal@conn:conn()) -> {ok,
pgl@internal@conn:conn()} |
{error, transaction_error(any())}.
do_release_savepoint(Conn) ->
_pipe = pgl@internal@conn:release_savepoint_statement(Conn),
_pipe@1 = gleam@result:replace_error(_pipe, not_in_transaction),
gleam@result:'try'(
_pipe@1,
fun(Stmt) -> _pipe@2 = transaction_query(Stmt, Conn),
gleam@result:map(_pipe@2, fun pgl@internal@conn:prev_savepoint/1) end
).
-file("src/pgl.gleam", 925).
-spec do_savepoint(
pgl@internal@conn:conn(),
db(),
fun((pgl@internal@conn:conn()) -> {ok, NYA} | {error, NYB})
) -> {ok, NYA} | {error, transaction_error(NYB)}.
do_savepoint(Conn, Db, Next) ->
Conn@1 = pgl@internal@conn:next_savepoint(Conn),
Rollback_and_release = fun(Conn@2) -> _pipe = do_rollback(Conn@2, Db),
gleam@result:'try'(_pipe, fun do_release_savepoint/1) end,
_pipe@1 = pgl@internal@conn:savepoint_statement(Conn@1),
_pipe@2 = transaction_query(_pipe@1, Conn@1),
_pipe@4 = gleam@result:'try'(
_pipe@2,
fun(Conn@3) ->
_pipe@3 = pgl@internal:assert_on_crash(
fun() -> Rollback_and_release(Conn@3) end,
<<"rollback and release savepoint"/utf8>>,
fun() -> Next(Conn@3) end
),
gleam@result:map_error(
_pipe@3,
fun(Err) -> case Rollback_and_release(Conn@3) of
{ok, _} ->
{rollback_error, Err};
{error, Err@1} ->
Err@1
end end
)
end
),
gleam@result:'try'(
_pipe@4,
fun(Res) -> _pipe@5 = do_release_savepoint(Conn@1),
gleam@result:replace(_pipe@5, Res) end
).
-file("src/pgl.gleam", 911).
?DOC(" Creates a new savepoint.\n").
-spec savepoint(connection(), fun((connection()) -> {ok, NXT} | {error, NXU})) -> {ok,
NXT} |
{error, transaction_error(NXU)}.
savepoint(Connection, Next) ->
case Connection of
{pool, _} ->
{error, not_in_transaction};
{connection, Conn, Db} ->
do_savepoint(
Conn,
Db,
fun(Conn@1) -> _pipe = {connection, Conn@1, Db},
Next(_pipe) end
)
end.