Current section

Files

Jump to
db_pool src db_pool.erl
Raw

src/db_pool.erl

-module(db_pool).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/db_pool.gleam").
-export([new/0, size/2, interval/2, on_open/2, on_close/2, on_interval/2, checkout/3, checkin/3, shutdown/2, start/3, supervised/3]).
-export_type([pool_error/1, pool/2, message/2]).
-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 pool_error(GWK) :: {connection_error, GWK} | connection_timeout.
-opaque pool(GWL, GWM) :: {pool,
integer(),
integer(),
fun(() -> {ok, GWL} | {error, pool_error(GWM)}),
fun((GWL) -> {ok, nil} | {error, pool_error(GWM)}),
fun((GWL) -> nil)}.
-opaque message(GWN, GWO) :: interval |
{check_in, GWN, gleam@erlang@process:pid_()} |
{check_out,
gleam@erlang@process:subject({ok, GWN} | {error, pool_error(GWO)}),
gleam@erlang@process:pid_(),
integer()} |
{timeout, integer(), integer()} |
{pool_exit, gleam@erlang@process:exit_message()} |
{caller_down, gleam@erlang@process:down()} |
{shutdown,
gleam@erlang@process:subject({ok, nil} | {error, pool_error(GWO)})}.
-file("src/db_pool.gleam", 39).
?DOC(" Returns a `Pool` that needs to be configured.\n").
-spec new() -> pool(any(), any()).
new() ->
Handle_open = fun() -> {error, connection_timeout} end,
Handle_close = fun(_) -> {ok, nil} end,
Handle_interval = fun(_) -> nil end,
{pool, 5, 1000, Handle_open, Handle_close, Handle_interval}.
-file("src/db_pool.gleam", 49).
?DOC(
" Sets the size of the pool. At startup the pool will create `size`\n"
" number of connections.\n"
).
-spec size(pool(GWT, GWU), integer()) -> pool(GWT, GWU).
size(Pool, Size) ->
{pool,
Size,
erlang:element(3, Pool),
erlang:element(4, Pool),
erlang:element(5, Pool),
erlang:element(6, Pool)}.
-file("src/db_pool.gleam", 55).
?DOC(
" Sets the `Pool`'s `interval` value. The pool will call the\n"
" configured `on_interval` function every `interval` milliseconds.\n"
).
-spec interval(pool(GWZ, GXA), integer()) -> pool(GWZ, GXA).
interval(Pool, Interval) ->
{pool,
erlang:element(2, Pool),
Interval,
erlang:element(4, Pool),
erlang:element(5, Pool),
erlang:element(6, Pool)}.
-file("src/db_pool.gleam", 61).
?DOC(
" Sets the `Pool`'s `on_open` function. The provided function will be\n"
" called at startup to create connections.\n"
).
-spec on_open(pool(GXF, GXG), fun(() -> {ok, GXF} | {error, GXG})) -> pool(GXF, GXG).
on_open(Pool, Handle_open) ->
Handle_open@1 = fun() -> _pipe = Handle_open(),
gleam@result:map_error(
_pipe,
fun(Field@0) -> {connection_error, Field@0} end
) end,
{pool,
erlang:element(2, Pool),
erlang:element(3, Pool),
Handle_open@1,
erlang:element(5, Pool),
erlang:element(6, Pool)}.
-file("src/db_pool.gleam", 72).
?DOC(
" Sets the `Pool`'s `on_close` function. The provided function will be\n"
" called on each idle connection when the pool is shut down or exits.\n"
).
-spec on_close(pool(GXN, GXO), fun((GXN) -> {ok, nil} | {error, GXO})) -> pool(GXN, GXO).
on_close(Pool, Handle_close) ->
Handle_close@1 = fun(Conn) -> _pipe = Handle_close(Conn),
gleam@result:map_error(
_pipe,
fun(Field@0) -> {connection_error, Field@0} end
) end,
{pool,
erlang:element(2, Pool),
erlang:element(3, Pool),
erlang:element(4, Pool),
Handle_close@1,
erlang:element(6, Pool)}.
-file("src/db_pool.gleam", 85).
?DOC(
" Sets the `Pool`'s `on_interval` function. The provided function\n"
" will be called every `interval` milliseconds.\n"
).
-spec on_interval(pool(GXV, GXW), fun((GXV) -> nil)) -> pool(GXV, GXW).
on_interval(Pool, Handle_interval) ->
{pool,
erlang:element(2, Pool),
erlang:element(3, Pool),
erlang:element(4, Pool),
erlang:element(5, Pool),
Handle_interval}.
-file("src/db_pool.gleam", 121).
-spec initialise_pool(
gleam@erlang@process:subject(message(GYX, GYY)),
pool(GYX, GYY)
) -> {ok,
gleam@otp@actor:initialised(db_pool@internal@state:state(GYX, message(GYX, GYY), pool_error(GYY)), message(GYX, GYY), gleam@erlang@process:subject(message(GYX, GYY)))} |
{error, binary()}.
initialise_pool(Self, Pool) ->
gleam_erlang_ffi:trap_exits(true),
Selector = begin
_pipe = gleam_erlang_ffi:new_selector(),
_pipe@1 = gleam@erlang@process:select(_pipe, Self),
gleam@erlang@process:select_trapped_exits(
_pipe@1,
fun(Field@0) -> {pool_exit, Field@0} end
)
end,
_pipe@2 = db_pool@internal@state:new(),
_pipe@3 = db_pool@internal@state:max_size(_pipe@2, erlang:element(2, Pool)),
_pipe@4 = db_pool@internal@state:on_open(_pipe@3, erlang:element(4, Pool)),
_pipe@5 = db_pool@internal@state:on_close(_pipe@4, erlang:element(5, Pool)),
_pipe@6 = db_pool@internal@state:on_interval(
_pipe@5,
erlang:element(6, Pool)
),
_pipe@7 = db_pool@internal@state:interval(_pipe@6, erlang:element(3, Pool)),
_pipe@8 = db_pool@internal@state:build(_pipe@7, Selector),
gleam@result:map(
_pipe@8,
fun(State) -> _pipe@9 = gleam@otp@actor:initialised(State),
_pipe@10 = gleam@otp@actor:selecting(_pipe@9, Selector),
gleam@otp@actor:returning(_pipe@10, Self) end
).
-file("src/db_pool.gleam", 168).
?DOC(" Attempts to check out a connection from the pool.\n").
-spec checkout(
gleam@erlang@process:subject(message(GZU, GZV)),
gleam@erlang@process:pid_(),
integer()
) -> {ok, GZU} | {error, pool_error(GZV)}.
checkout(Pool, Caller, Timeout) ->
Checkout_timeout = Timeout - 50,
{Process_timeout, Timeout@1} = case Checkout_timeout < 0 of
true ->
{Timeout, Timeout};
false ->
{Timeout + 50, Checkout_timeout}
end,
gleam@erlang@process:call(
Pool,
Process_timeout,
fun(_capture) -> {check_out, _capture, Caller, Timeout@1} end
).
-file("src/db_pool.gleam", 184).
?DOC(" Returns a connection back to the pool.\n").
-spec checkin(
gleam@erlang@process:subject(message(HAC, any())),
HAC,
gleam@erlang@process:pid_()
) -> nil.
checkin(Pool, Conn, Caller) ->
gleam@erlang@process:send(Pool, {check_in, Conn, Caller}).
-file("src/db_pool.gleam", 193).
?DOC(" Shuts down the pool and any idle connections.\n").
-spec shutdown(gleam@erlang@process:subject(message(any(), HAI)), integer()) -> {ok,
nil} |
{error, pool_error(HAI)}.
shutdown(Pool, Timeout) ->
gleam@erlang@process:call(
Pool,
Timeout,
fun(Field@0) -> {shutdown, Field@0} end
).
-file("src/db_pool.gleam", 200).
-spec handle_message(
db_pool@internal@state:state(HAP, message(HAP, HAQ), pool_error(HAQ)),
message(HAP, HAQ)
) -> gleam@otp@actor:next(db_pool@internal@state:state(HAP, message(HAP, HAQ), pool_error(HAQ)), message(HAP, HAQ)).
handle_message(State, Msg) ->
case Msg of
interval ->
State@1 = db_pool@internal@state:ping(State, interval),
db_pool@internal@state:with_selector(
State@1,
fun(Selector) -> _pipe = gleam@otp@actor:continue(State@1),
gleam@otp@actor:with_selector(_pipe, Selector) end
);
{check_in, Conn, Caller} ->
Handler = fun(Client, Conn@1) ->
gleam@otp@actor:send(Client, {ok, Conn@1})
end,
State@2 = db_pool@internal@state:dequeue(
State,
{some, Conn},
Caller,
fun(Field@0) -> {caller_down, Field@0} end,
Handler
),
db_pool@internal@state:with_selector(
State@2,
fun(Selector@1) -> _pipe@1 = gleam@otp@actor:continue(State@2),
gleam@otp@actor:with_selector(_pipe@1, Selector@1) end
);
{check_out, Client@1, Caller@1, Timeout} ->
State@3 = begin
_pipe@2 = db_pool@internal@state:checkout(
State,
Caller@1,
fun(Field@0) -> {caller_down, Field@0} end,
fun(Conn@2) ->
gleam@otp@actor:send(Client@1, {ok, Conn@2})
end
),
gleam@result:lazy_unwrap(
_pipe@2,
fun() ->
db_pool@internal@state:enqueue(
State,
Caller@1,
Client@1,
Timeout,
fun(Field@0, Field@1) -> {timeout, Field@0, Field@1} end,
fun(Field@0) -> {caller_down, Field@0} end
)
end
)
end,
db_pool@internal@state:with_selector(
State@3,
fun(Selector@2) -> _pipe@3 = gleam@otp@actor:continue(State@3),
gleam@otp@actor:with_selector(_pipe@3, Selector@2) end
);
{timeout, Time_sent, Timeout@1} ->
State@4 = begin
On_expiry = fun(_capture) ->
gleam@otp@actor:send(_capture, {error, connection_timeout})
end,
db_pool@internal@state:expire(
State,
Time_sent,
Timeout@1,
On_expiry,
fun(Field@0, Field@1) -> {timeout, Field@0, Field@1} end
)
end,
db_pool@internal@state:with_selector(
State@4,
fun(Selector@3) -> _pipe@4 = gleam@otp@actor:continue(State@4),
gleam@otp@actor:with_selector(_pipe@4, Selector@3) end
);
{caller_down, Down} ->
Pid@1 = case Down of
{process_down, _, Pid, _} -> Pid;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"db_pool"/utf8>>,
function => <<"handle_message"/utf8>>,
line => 260,
value => _assert_fail,
start => 7076,
'end' => 7123,
pattern_start => 7087,
pattern_end => 7116})
end,
Handler@1 = fun(Client@2, Conn@3) ->
gleam@otp@actor:send(Client@2, {ok, Conn@3})
end,
State@5 = db_pool@internal@state:dequeue(
State,
none,
Pid@1,
fun(Field@0) -> {caller_down, Field@0} end,
Handler@1
),
db_pool@internal@state:with_selector(
State@5,
fun(Selector@4) -> _pipe@5 = gleam@otp@actor:continue(State@5),
gleam@otp@actor:with_selector(_pipe@5, Selector@4) end
);
{pool_exit, Exit} ->
db_pool@internal@state:close(State),
case erlang:element(3, Exit) of
normal ->
gleam@otp@actor:stop();
killed ->
gleam@otp@actor:stop_abnormal(<<"pool killed"/utf8>>);
{abnormal, _} ->
gleam@otp@actor:stop_abnormal(
<<"pool stopped abnormally"/utf8>>
)
end;
{shutdown, Client@3} ->
db_pool@internal@state:shutdown(State),
gleam@otp@actor:send(Client@3, {ok, nil}),
gleam@otp@actor:stop()
end.
-file("src/db_pool.gleam", 93).
?DOC(" Starts a connection pool.\n").
-spec start(
pool(GYB, GYC),
gleam@erlang@process:name(message(GYB, GYC)),
integer()
) -> {ok,
gleam@otp@actor:started(gleam@erlang@process:subject(message(GYB, GYC)))} |
{error, gleam@otp@actor:start_error()}.
start(Pool, Name, Timeout) ->
_pipe = gleam@otp@actor:new_with_initialiser(
Timeout,
fun(_capture) -> initialise_pool(_capture, Pool) end
),
_pipe@1 = gleam@otp@actor:on_message(_pipe, fun handle_message/2),
_pipe@2 = gleam@otp@actor:named(_pipe@1, Name),
_pipe@3 = gleam@otp@actor:start(_pipe@2),
gleam@result:map(
_pipe@3,
fun(Started) ->
_ = gleam@erlang@process:send_after(
erlang:element(3, Started),
erlang:element(3, Pool),
interval
),
Started
end
).
-file("src/db_pool.gleam", 111).
?DOC(
" Creates a `supervision.ChildSpecification` so the pool can be\n"
" added to an application's supervision tree.\n"
).
-spec supervised(
pool(GYM, GYN),
gleam@erlang@process:name(message(GYM, GYN)),
integer()
) -> gleam@otp@supervision:child_specification(gleam@erlang@process:subject(message(GYM, GYN))).
supervised(Pool, Name, Timeout) ->
_pipe = gleam@otp@supervision:worker(
fun() -> start(Pool, Name, Timeout) end
),
_pipe@1 = gleam@otp@supervision:timeout(_pipe, Timeout),
gleam@otp@supervision:restart(_pipe@1, transient).