Current section
Files
Jump to
Current section
Files
src/based.erl
-module(based).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/based.gleam").
-export([database_error_to_string/1, error_to_string/1, transaction/3, new/2, driver/4, 'query'/2, execute/2, batch/2, decode/2, all/3, one/3]).
-export_type([based_error/0, database_error/0, transaction_error/1, queried/0, returning/1, db/2, driver/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.
?MODULEDOC(
" A standardized interface for database operations. This module defines\n"
" types for adapter packages to use in their public interfaces.\n"
).
-type based_error() :: {based_error, binary()} |
not_found |
{decode_error, list(gleam@dynamic@decode:decode_error())} |
{db_error, database_error()}.
-type database_error() :: {database_error, binary(), binary(), binary()} |
{constraint_error, binary(), binary(), binary()} |
{syntax_error, binary(), binary(), binary()} |
{connection_error, binary()} |
connection_unavailable |
connection_timeout.
-type transaction_error(GFD) :: {rollback, GFD} |
not_in_transaction |
{transaction_error, binary()}.
-type queried() :: {queried,
integer(),
list(binary()),
list(gleam@dynamic:dynamic_())}.
-type returning(GFE) :: {returning, integer(), list(GFE)}.
-type db(GFF, GFG) :: {db, driver(GFF, GFG), based@sql:adapter(GFF)}.
-opaque driver(GFH, GFI) :: {driver,
GFI,
fun((based@sql:'query'(GFH), GFI) -> {ok, queried()} |
{error, based_error()}),
fun((binary(), GFI) -> {ok, integer()} | {error, based_error()}),
fun((list(based@sql:'query'(GFH)), GFI) -> {ok, list(queried())} |
{error, based_error()})}.
-file("src/based.gleam", 113).
-spec format_error_parts(list({binary(), binary()})) -> binary().
format_error_parts(Errors) ->
_pipe = Errors,
_pipe@1 = gleam@list:map(
_pipe,
fun(Key_val) ->
{Key, Val} = Key_val,
<<<<Key/binary, ": "/utf8>>/binary, Val/binary>>
end
),
gleam@string:join(_pipe@1, <<", "/utf8>>).
-file("src/based.gleam", 87).
-spec format_db_error(binary(), binary(), binary(), binary()) -> binary().
format_db_error(Kind, Code, Name, Message) ->
Error_description = begin
_pipe = [{<<"code"/utf8>>, Code},
{<<"name"/utf8>>, Name},
{<<"message"/utf8>>, Message}],
format_error_parts(_pipe)
end,
<<<<Kind/binary, " "/utf8>>/binary, Error_description/binary>>.
-file("src/based.gleam", 104).
-spec format_error_kind(list(binary()), binary()) -> binary().
format_error_kind(Path, Kind) ->
Error_kind = begin
_pipe = gleam@string:join(Path, <<"/"/utf8>>),
_pipe@1 = gleam@string:append(_pipe, <<"."/utf8>>),
gleam@string:append(_pipe@1, Kind)
end,
<<<<"["/utf8, Error_kind/binary>>/binary, "]"/utf8>>.
-file("src/based.gleam", 66).
?DOC(" Formats the provided `DatabaseError` as a string.\n").
-spec database_error_to_string(database_error()) -> binary().
database_error_to_string(Err) ->
case Err of
connection_timeout ->
format_error_kind([<<"based"/utf8>>], <<"ConnectionTimeout"/utf8>>);
connection_unavailable ->
format_error_kind(
[<<"based"/utf8>>],
<<"ConnectionUnavailable"/utf8>>
);
{connection_error, Message} ->
_pipe = format_error_kind(
[<<"based"/utf8>>],
<<"ConnectionError"/utf8>>
),
_pipe@1 = gleam@string:append(_pipe, <<" "/utf8>>),
gleam@string:append(_pipe@1, Message);
{database_error, Code, Name, Message@1} ->
_pipe@2 = format_error_kind(
[<<"based"/utf8>>],
<<"DatabaseError"/utf8>>
),
format_db_error(_pipe@2, Code, Name, Message@1);
{constraint_error, Code@1, Name@1, Message@2} ->
_pipe@3 = format_error_kind(
[<<"based"/utf8>>],
<<"ConstraintError"/utf8>>
),
format_db_error(_pipe@3, Code@1, Name@1, Message@2);
{syntax_error, Code@2, Name@2, Message@3} ->
_pipe@4 = format_error_kind(
[<<"based"/utf8>>],
<<"SyntaxError"/utf8>>
),
format_db_error(_pipe@4, Code@2, Name@2, Message@3)
end.
-file("src/based.gleam", 29).
-spec error_to_string(based_error()) -> binary().
error_to_string(Err) ->
case Err of
{based_error, Message} ->
_pipe = format_error_kind([<<"based"/utf8>>], <<"BasedError"/utf8>>),
_pipe@1 = gleam@string:append(_pipe, <<" "/utf8>>),
gleam@string:append(_pipe@1, Message);
not_found ->
format_error_kind([<<"based"/utf8>>], <<"NotFound"/utf8>>);
{decode_error, Errors} ->
Error_string = begin
_pipe@6 = gleam@list:map(
Errors,
fun(Err@1) ->
{decode_error, Expected, Found, Path} = Err@1,
Error_description = begin
_pipe@2 = [{<<"expected"/utf8>>, Expected},
{<<"found"/utf8>>, Found},
{<<"path"/utf8>>,
gleam@string:join(Path, <<", "/utf8>>)}],
format_error_parts(_pipe@2)
end,
_pipe@3 = [<<"gleam"/utf8>>,
<<"dynamic"/utf8>>,
<<"decode"/utf8>>],
_pipe@4 = format_error_kind(
_pipe@3,
<<"DecodeError"/utf8>>
),
_pipe@5 = gleam@string:append(_pipe@4, <<" "/utf8>>),
gleam@string:append(_pipe@5, Error_description)
end
),
gleam@string:join(_pipe@6, <<", "/utf8>>)
end,
_pipe@7 = [<<"based"/utf8>>],
_pipe@8 = format_error_kind(_pipe@7, <<"DecodeError"/utf8>>),
_pipe@9 = gleam@string:append(_pipe@8, <<" errors: "/utf8>>),
gleam@string:append(_pipe@9, Error_string);
{db_error, Error} ->
database_error_to_string(Error)
end.
-file("src/based.gleam", 155).
?DOC(
" Runs `next` inside a database transaction using the provided `handler`.\n"
"\n"
" The handler (supplied by an adapter package) is responsible for beginning\n"
" the transaction, committing on success, and rolling back on failure.\n"
).
-spec transaction(
db(GGI, GGJ),
fun((GGJ, fun((GGJ) -> {ok, GGM} | {error, GGN})) -> {ok, GGM} |
{error, transaction_error(GGN)}),
fun((db(GGI, GGJ)) -> {ok, GGM} | {error, GGN})
) -> {ok, GGM} | {error, transaction_error(GGN)}.
transaction(Db, Handler, Next) ->
Handler(
erlang:element(2, erlang:element(2, Db)),
fun(Conn) ->
Driver = begin
_record = erlang:element(2, Db),
{driver,
Conn,
erlang:element(3, _record),
erlang:element(4, _record),
erlang:element(5, _record)}
end,
_pipe = {db, Driver, erlang:element(3, Db)},
Next(_pipe)
end
).
-file("src/based.gleam", 188).
?DOC(" Creates a new `Db` from a driver and adapter.\n").
-spec new(driver(GGY, GGZ), based@sql:adapter(GGY)) -> db(GGY, GGZ).
new(Driver, Sql) ->
{db, Driver, Sql}.
-file("src/based.gleam", 204).
?DOC(" Returns a configured `Driver` record.\n").
-spec driver(
GHF,
fun((based@sql:'query'(GHG), GHF) -> {ok, queried()} |
{error, based_error()}),
fun((binary(), GHF) -> {ok, integer()} | {error, based_error()}),
fun((list(based@sql:'query'(GHG)), GHF) -> {ok, list(queried())} |
{error, based_error()})
) -> driver(GHG, GHF).
driver(Conn, Handle_query, Handle_execute, Handle_batch) ->
{driver, Conn, Handle_query, Handle_execute, Handle_batch}.
-file("src/based.gleam", 214).
?DOC(" Executes a query using the configured driver.\n").
-spec 'query'(based@sql:'query'(GHO), db(GHO, any())) -> {ok, queried()} |
{error, based_error()}.
'query'(Query, Db) ->
(erlang:element(3, erlang:element(2, Db)))(
Query,
erlang:element(2, erlang:element(2, Db))
).
-file("src/based.gleam", 222).
?DOC(" Executes a raw SQL string using the configured driver.\n").
-spec execute(binary(), db(any(), any())) -> {ok, integer()} |
{error, based_error()}.
execute(Sql, Db) ->
(erlang:element(4, erlang:element(2, Db)))(
Sql,
erlang:element(2, erlang:element(2, Db))
).
-file("src/based.gleam", 227).
?DOC(" Executes a list of queries as a batch.\n").
-spec batch(list(based@sql:'query'(GIB)), db(GIB, any())) -> {ok,
list(queried())} |
{error, based_error()}.
batch(Queries, Db) ->
(erlang:element(5, erlang:element(2, Db)))(
Queries,
erlang:element(2, erlang:element(2, Db))
).
-file("src/based.gleam", 266).
?DOC(
" Accepts a `Queried` record and applies a decoder to its rows. Returns a\n"
" `Returning` record with the decoded rows.\n"
).
-spec decode(queried(), gleam@dynamic@decode:decoder(GJD)) -> {ok,
returning(GJD)} |
{error, based_error()}.
decode(Queried, Decoder) ->
_pipe = erlang:element(4, Queried),
_pipe@1 = gleam@list:try_map(
_pipe,
fun(_capture) -> gleam@dynamic@decode:run(_capture, Decoder) end
),
_pipe@2 = gleam@result:map_error(
_pipe@1,
fun(Field@0) -> {decode_error, Field@0} end
),
gleam@result:map(
_pipe@2,
fun(_capture@1) ->
{returning, erlang:element(2, Queried), _capture@1}
end
).
-file("src/based.gleam", 236).
?DOC(
" A convenience function for callers performing a query that will return\n"
" a list of rows, but don't need the full `Returning` record.\n"
).
-spec all(
based@sql:'query'(GIK),
db(GIK, any()),
gleam@dynamic@decode:decoder(GIP)
) -> {ok, list(GIP)} | {error, based_error()}.
all(Query, Db, Decoder) ->
gleam@result:'try'(
(erlang:element(3, erlang:element(2, Db)))(
Query,
erlang:element(2, erlang:element(2, Db))
),
fun(Queried) ->
gleam@result:map(
decode(Queried, Decoder),
fun(Returning) -> erlang:element(3, Returning) end
)
end
).
-file("src/based.gleam", 251).
?DOC(
" A convenience function for callers performing a query that will return\n"
" only one row. It's up to callers to ensure they're providing the correct\n"
" SQL query to avoid decoding `n` rows and then losing all but the first.\n"
" Returns `Error(NotFound)` if the query returns zero rows.\n"
).
-spec one(
based@sql:'query'(GIU),
db(GIU, any()),
gleam@dynamic@decode:decoder(GIZ)
) -> {ok, GIZ} | {error, based_error()}.
one(Query, Db, Decoder) ->
gleam@result:'try'(
(erlang:element(3, erlang:element(2, Db)))(
Query,
erlang:element(2, erlang:element(2, Db))
),
fun(Queried) ->
gleam@result:'try'(
decode(Queried, Decoder),
fun(Returning) -> _pipe = erlang:element(3, Returning),
_pipe@1 = gleam@list:first(_pipe),
gleam@result:map_error(_pipe@1, fun(_) -> not_found end) end
)
end
).