-module(based). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([register/2, new_query/1, with_values/2, execute/2, string/1, decode/2, all/3, one/3, int/1, float/1, bool/1, null/0]). -export_type([value/0, based_error/0, 'query'/0, based_adapter/3, returned/1, db/0, message/0]). -type value() :: {string, binary()} | {int, integer()} | {float, float()} | {bool, boolean()} | null. -type based_error() :: {based_error, binary(), binary(), binary()}. -type 'query'() :: {'query', binary(), list(value())}. -type based_adapter(HFB, HFC, HFD) :: {based_adapter, fun((HFB, fun((HFC) -> HFD)) -> HFD), HFB, fun(('query'(), HFC) -> {ok, list(gleam@dynamic:dynamic_())} | {error, based_error()})}. -type returned(HFE) :: {returned, integer(), list(HFE)}. -opaque db() :: {db, gleam@erlang@process:subject(message())}. -type message() :: {execute, gleam@erlang@process:subject({ok, list(gleam@dynamic:dynamic_())} | {error, based_error()}), 'query'()} | shutdown. -spec shutdown(gleam@erlang@process:subject(message())) -> nil. shutdown(Actor) -> gleam@erlang@process:send(Actor, shutdown). -spec handle_message( message(), {HFY, fun(('query'(), HFY) -> {ok, list(gleam@dynamic:dynamic_())} | {error, based_error()})} ) -> gleam@otp@actor:next(message(), {HFY, fun(('query'(), HFY) -> {ok, list(gleam@dynamic:dynamic_())} | {error, based_error()})}). handle_message(Message, Backend) -> case Message of shutdown -> {stop, normal}; {execute, Client, Query} -> {Conn, Service} = Backend, gleam@erlang@process:send(Client, Service(Query, Conn)), gleam@otp@actor:continue(Backend) end. -spec start( HFS, fun(('query'(), HFS) -> {ok, list(gleam@dynamic:dynamic_())} | {error, based_error()}) ) -> {ok, gleam@erlang@process:subject(message())} | {error, gleam@otp@actor:start_error()}. start(Conn, Service) -> gleam@otp@actor:start({Conn, Service}, fun handle_message/2). -spec register(based_adapter(any(), any(), HFO), fun((db()) -> HFO)) -> HFO. register(Based_adapter, Callback) -> {based_adapter, With_connection, Conf, Service} = Based_adapter, With_connection( Conf, fun(Connection) -> _assert_subject = start(Connection, Service), {ok, Actor} = case _assert_subject of {ok, _} -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Assertion pattern match failed"/utf8>>, value => _assert_fail, module => <<"based"/utf8>>, function => <<"register"/utf8>>, line => 68}) end, Result = Callback({db, Actor}), shutdown(Actor), Result end ). -spec new_query(binary()) -> 'query'(). new_query(Sql) -> {'query', Sql, []}. -spec with_values('query'(), list(value())) -> 'query'(). with_values(Query, Values) -> {'query', erlang:element(2, Query), lists:append(erlang:element(3, Query), Values)}. -spec execute('query'(), db()) -> {ok, list(gleam@dynamic:dynamic_())} | {error, based_error()}. execute(Query, Db) -> {db, Subject} = Db, gleam@erlang@process:call( Subject, fun(_capture) -> {execute, _capture, Query} end, 100 ). -spec string(binary()) -> value(). string(Value) -> {string, Value}. -spec decode_error(list(gleam@dynamic:decode_error())) -> based_error(). decode_error(Errors) -> [{decode_error, Expected, Actual, Path} | _] = case Errors of [{decode_error, _, _, _} | _] -> Errors; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Assertion pattern match failed"/utf8>>, value => _assert_fail, module => <<"based"/utf8>>, function => <<"decode_error"/utf8>>, line => 171}) end, Path@1 = gleam@string:join(Path, <<"."/utf8>>), Message = <<<<<<<<<<"Decoder failed, expected "/utf8, Expected/binary>>/binary, ", got "/utf8>>/binary, Actual/binary>>/binary, " in "/utf8>>/binary, Path@1/binary>>, {based_error, <<""/utf8>>, <<"decode_error"/utf8>>, Message}. -spec decode( list(gleam@dynamic:dynamic_()), fun((gleam@dynamic:dynamic_()) -> {ok, HGR} | {error, list(gleam@dynamic:decode_error())}) ) -> {ok, returned(HGR)} | {error, based_error()}. decode(Rows, Decoder) -> gleam@result:'try'( begin _pipe = gleam@list:try_map(Rows, Decoder), gleam@result:map_error(_pipe, fun decode_error/1) end, fun(Rows@1) -> _pipe@1 = erlang:length(Rows@1), _pipe@2 = {returned, _pipe@1, Rows@1}, {ok, _pipe@2} end ). -spec all( 'query'(), db(), fun((gleam@dynamic:dynamic_()) -> {ok, HGE} | {error, list(gleam@dynamic:decode_error())}) ) -> {ok, returned(HGE)} | {error, based_error()}. all(Query, Db, Decoder) -> gleam@result:'try'( execute(Query, Db), fun(Rows) -> decode(Rows, Decoder) end ). -spec one( 'query'(), db(), fun((gleam@dynamic:dynamic_()) -> {ok, HGJ} | {error, list(gleam@dynamic:decode_error())}) ) -> {ok, HGJ} | {error, based_error()}. one(Query, Db, Decoder) -> gleam@result:'try'( execute(Query, Db), fun(Rows) -> Returned = decode(Rows, Decoder), gleam@result:'try'( Returned, fun(Returned@1) -> {returned, _, Rows@1} = Returned@1, gleam@result:'try'( begin _pipe = Rows@1, _pipe@1 = gleam@list:first(_pipe), gleam@result:replace_error( _pipe@1, {based_error, <<""/utf8>>, <<"not_found"/utf8>>, <<"Expected one row but found none"/utf8>>} ) end, fun(Row) -> {ok, Row} end ) end ) end ). -spec int(integer()) -> value(). int(Value) -> {int, Value}. -spec float(float()) -> value(). float(Value) -> {float, Value}. -spec bool(boolean()) -> value(). bool(Value) -> {bool, Value}. -spec null() -> value(). null() -> null.