Current section

Files

Jump to
common_sql_postgresql src common_sql_postgresql.erl
Raw

src/common_sql_postgresql.erl

-module(common_sql_postgresql).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/common_sql_postgresql.gleam").
-export([driver/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.
-file("src/common_sql_postgresql.gleam", 9).
-spec param_to_value(common_sql:param()) -> pog:value().
param_to_value(Param) ->
case Param of
{p_int, N} ->
pog_ffi:coerce(N);
{p_string, S} ->
pog_ffi:coerce(S);
{p_float, F} ->
pog_ffi:coerce(F);
{p_bool, B} ->
pog_ffi:coerce(B);
p_null ->
pog_ffi:null()
end.
-file("src/common_sql_postgresql.gleam", 19).
-spec pog_error_to_db_error(pog:query_error()) -> common_sql:db_error().
pog_error_to_db_error(Err) ->
case Err of
connection_unavailable ->
{connection_error, <<"Connection unavailable"/utf8>>};
{constraint_violated, Message, _, _} ->
{query_error, <<"Constraint violated: "/utf8, Message/binary>>};
{postgresql_error, _, _, Message@1} ->
{query_error, <<"PostgreSQL error: "/utf8, Message@1/binary>>};
{unexpected_argument_count, Expected, Got} ->
{query_error,
<<<<<<"Wrong argument count: expected "/utf8,
(erlang:integer_to_binary(Expected))/binary>>/binary,
", got "/utf8>>/binary,
(erlang:integer_to_binary(Got))/binary>>};
{unexpected_argument_type, Expected@1, Got@1} ->
{query_error,
<<<<<<"Wrong argument type: expected "/utf8, Expected@1/binary>>/binary,
", got "/utf8>>/binary,
Got@1/binary>>};
{unexpected_result_type, Errors} ->
{query_error,
<<"Unexpected result type: "/utf8,
(gleam@string:inspect(Errors))/binary>>};
query_timeout ->
{query_error, <<"Query timed out"/utf8>>}
end.
-file("src/common_sql_postgresql.gleam", 55).
?DOC(
" Returns a `common_sql.Driver` backed by PostgreSQL via the `pog` library.\n"
"\n"
" Call `driver()` once at application startup and pass it down. Each call\n"
" creates one Erlang atom for the pool name — do not call it in a loop.\n"
"\n"
" Closing a pog connection pool has no explicit stop API; the pool runs as\n"
" an OTP actor for the lifetime of the application. `common_sql.close/2` is\n"
" a no-op for this driver. Use `pog.supervised/1` to manage the pool in an\n"
" OTP supervision tree.\n"
).
-spec driver() -> common_sql:driver(pog:connection()).
driver() ->
Pool_name = gleam_erlang_ffi:new_name(<<"common_sql_pg"/utf8>>),
{driver,
<<"postgresql"/utf8>>,
fun(Url) -> case pog:url_config(Pool_name, Url) of
{error, nil} ->
{error,
{connection_error,
<<"Invalid PostgreSQL URL: "/utf8, Url/binary>>}};
{ok, Config} ->
case pog:start(Config) of
{ok, Started} ->
{ok, erlang:element(3, Started)};
{error, _} ->
case gleam_erlang_ffi:process_named(Pool_name) of
{ok, _} ->
{ok, pog:named_connection(Pool_name)};
{error, nil} ->
{error,
{connection_error,
<<"Failed to start connection pool for: "/utf8,
Url/binary>>}}
end
end
end end,
fun(Conn, Query, Params) ->
Sql = case Query of
{sql, S} ->
S;
{portable, S} ->
S
end,
Q@1 = gleam@list:fold(
Params,
pog:'query'(Sql),
fun(Q, Param) -> pog:parameter(Q, param_to_value(Param)) end
),
Q@2 = pog:returning(
Q@1,
{decoder, fun gleam@dynamic@decode:decode_dynamic/1}
),
case pog:execute(Q@2, Conn) of
{ok, {returned, _, Rows}} ->
{ok, Rows};
{error, Err} ->
{error, pog_error_to_db_error(Err)}
end
end,
fun(_) -> nil end}.