-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", 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", 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, <<<>/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, <<<>/binary, Error_description/binary>>. -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 ).