-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 => <>, 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).