-module(pgl). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/pgl.gleam"). -export([application/2, host/2, port/2, username/2, password/2, database/2, connection_parameter/3, ssl/2, rows_as_dict/2, ip_version/2, pool_size/2, idle_interval/2, queue_target/2, error_to_string/1, new/1, connection/1, shutdown/1, start/1, supervised/1, sql/1, params/2, batch/2, 'query'/2, execute/2, transaction/2, 'begin'/1, commit/1, rollback/1, savepoint/2, from_url/1]). -export_type([config/0, ip_version/0, ssl/0, pgl_error/0, field/0, transaction_error/1, db/0, connection/0, queried/0, 'query'/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. ?MODULEDOC(" PostgreSQL database client\n"). -type config() :: {config, binary(), binary(), integer(), binary(), binary(), binary(), list({binary(), binary()}), ssl(), boolean(), ip_version(), integer(), integer(), integer()}. -type ip_version() :: ipv4 | ipv6. -type ssl() :: ssl_disabled | ssl_verified | ssl_unverified. -type pgl_error() :: {query_error, binary()} | {connection_error, binary()} | connection_timeout | {authentication_error, binary()} | {protocol_error, binary()} | {socket_error, binary()} | {postgres_error, binary(), binary(), binary(), gleam@dict:dict(field(), binary())}. -type field() :: severity | code | message | detail | hint | position | internal_position | internal_query | where | schema | table | column | data_type | constraint | file | line | routine | {other, bitstring()}. -type transaction_error(MMK) :: {rollback_error, MMK} | not_in_transaction | {transaction_error, binary()}. -opaque db() :: {db, gleam@erlang@process:name(db_pool:message(pgl@internal@socket:socket(), pgl_error())), pgl@internal@socket:factory(), pgl@internal@type_cache:type_cache(), pgl@internal@query_cache:query_cache(), config()}. -opaque connection() :: {pool, db()} | {connection, pgl@internal@conn:conn(), db()}. -type queried() :: {queried, integer(), list(binary()), list(gleam@dynamic:dynamic_())}. -type 'query'() :: {'query', binary(), list(pg_value:value())}. -file("src/pgl.gleam", 94). ?DOC(" Name of the application connecting to the database.\n"). -spec application(config(), binary()) -> config(). application(Conf, Application) -> {config, Application, erlang:element(3, Conf), erlang:element(4, Conf), erlang:element(5, Conf), erlang:element(6, Conf), erlang:element(7, Conf), erlang:element(8, Conf), erlang:element(9, Conf), erlang:element(10, Conf), erlang:element(11, Conf), erlang:element(12, Conf), erlang:element(13, Conf), erlang:element(14, Conf)}. -file("src/pgl.gleam", 99). ?DOC(" The database server hostname.\n"). -spec host(config(), binary()) -> config(). host(Conf, Host) -> {config, erlang:element(2, Conf), Host, erlang:element(4, Conf), erlang:element(5, Conf), erlang:element(6, Conf), erlang:element(7, Conf), erlang:element(8, Conf), erlang:element(9, Conf), erlang:element(10, Conf), erlang:element(11, Conf), erlang:element(12, Conf), erlang:element(13, Conf), erlang:element(14, Conf)}. -file("src/pgl.gleam", 104). ?DOC(" The port on which the database server is listening.\n"). -spec port(config(), integer()) -> config(). port(Conf, Port) -> {config, erlang:element(2, Conf), erlang:element(3, Conf), Port, erlang:element(5, Conf), erlang:element(6, Conf), erlang:element(7, Conf), erlang:element(8, Conf), erlang:element(9, Conf), erlang:element(10, Conf), erlang:element(11, Conf), erlang:element(12, Conf), erlang:element(13, Conf), erlang:element(14, Conf)}. -file("src/pgl.gleam", 109). ?DOC(" The username to connect to the database as.\n"). -spec username(config(), binary()) -> config(). username(Conf, Username) -> {config, erlang:element(2, Conf), erlang:element(3, Conf), erlang:element(4, Conf), Username, erlang:element(6, Conf), erlang:element(7, Conf), erlang:element(8, Conf), erlang:element(9, Conf), erlang:element(10, Conf), erlang:element(11, Conf), erlang:element(12, Conf), erlang:element(13, Conf), erlang:element(14, Conf)}. -file("src/pgl.gleam", 114). ?DOC(" The password of the user.\n"). -spec password(config(), binary()) -> config(). password(Conf, Password) -> {config, erlang:element(2, Conf), erlang:element(3, Conf), erlang:element(4, Conf), erlang:element(5, Conf), Password, erlang:element(7, Conf), erlang:element(8, Conf), erlang:element(9, Conf), erlang:element(10, Conf), erlang:element(11, Conf), erlang:element(12, Conf), erlang:element(13, Conf), erlang:element(14, Conf)}. -file("src/pgl.gleam", 119). ?DOC(" The name of the database to use.\n"). -spec database(config(), binary()) -> config(). database(Conf, Database) -> {config, erlang:element(2, Conf), erlang:element(3, Conf), erlang:element(4, Conf), erlang:element(5, Conf), erlang:element(6, Conf), Database, erlang:element(8, Conf), erlang:element(9, Conf), erlang:element(10, Conf), erlang:element(11, Conf), erlang:element(12, Conf), erlang:element(13, Conf), erlang:element(14, Conf)}. -file("src/pgl.gleam", 124). ?DOC(" Sets other postgres connection parameters.\n"). -spec connection_parameter(config(), binary(), binary()) -> config(). connection_parameter(Conf, Name, Value) -> Connection_parameters = gleam@list:prepend( erlang:element(8, Conf), {Name, Value} ), {config, erlang:element(2, Conf), erlang:element(3, Conf), erlang:element(4, Conf), erlang:element(5, Conf), erlang:element(6, Conf), erlang:element(7, Conf), Connection_parameters, erlang:element(9, Conf), erlang:element(10, Conf), erlang:element(11, Conf), erlang:element(12, Conf), erlang:element(13, Conf), erlang:element(14, Conf)}. -file("src/pgl.gleam", 136). ?DOC(" Whether SSL should be used.\n"). -spec ssl(config(), ssl()) -> config(). ssl(Conf, Ssl) -> {config, erlang:element(2, Conf), erlang:element(3, Conf), erlang:element(4, Conf), erlang:element(5, Conf), erlang:element(6, Conf), erlang:element(7, Conf), erlang:element(8, Conf), Ssl, erlang:element(10, Conf), erlang:element(11, Conf), erlang:element(12, Conf), erlang:element(13, Conf), erlang:element(14, Conf)}. -file("src/pgl.gleam", 141). ?DOC(" Configures rows to be returns as `Dict` rather than n-tuples.\n"). -spec rows_as_dict(config(), boolean()) -> config(). rows_as_dict(Conf, Rows_as_dict) -> {config, erlang:element(2, Conf), erlang:element(3, Conf), erlang:element(4, Conf), erlang:element(5, Conf), erlang:element(6, Conf), erlang:element(7, Conf), erlang:element(8, Conf), erlang:element(9, Conf), Rows_as_dict, erlang:element(11, Conf), erlang:element(12, Conf), erlang:element(13, Conf), erlang:element(14, Conf)}. -file("src/pgl.gleam", 146). ?DOC(" Which IP version to use\n"). -spec ip_version(config(), ip_version()) -> config(). ip_version(Conf, Ip_version) -> {config, erlang:element(2, Conf), erlang:element(3, Conf), erlang:element(4, Conf), erlang:element(5, Conf), erlang:element(6, Conf), erlang:element(7, Conf), erlang:element(8, Conf), erlang:element(9, Conf), erlang:element(10, Conf), Ip_version, erlang:element(12, Conf), erlang:element(13, Conf), erlang:element(14, Conf)}. -file("src/pgl.gleam", 151). ?DOC(" Sets the size of the connection pool.\n"). -spec pool_size(config(), integer()) -> config(). pool_size(Conf, Pool_size) -> {config, erlang:element(2, Conf), erlang:element(3, Conf), erlang:element(4, Conf), erlang:element(5, Conf), erlang:element(6, Conf), erlang:element(7, Conf), erlang:element(8, Conf), erlang:element(9, Conf), erlang:element(10, Conf), erlang:element(11, Conf), Pool_size, erlang:element(13, Conf), erlang:element(14, Conf)}. -file("src/pgl.gleam", 156). ?DOC(" How often idle connections should ping the database server.\n"). -spec idle_interval(config(), integer()) -> config(). idle_interval(Conf, Idle_interval) -> {config, erlang:element(2, Conf), erlang:element(3, Conf), erlang:element(4, Conf), erlang:element(5, Conf), erlang:element(6, Conf), erlang:element(7, Conf), erlang:element(8, Conf), erlang:element(9, Conf), erlang:element(10, Conf), erlang:element(11, Conf), erlang:element(12, Conf), Idle_interval, erlang:element(14, Conf)}. -file("src/pgl.gleam", 161). ?DOC(" How long it should take to check out a connection from the connection pool.\n"). -spec queue_target(config(), integer()) -> config(). queue_target(Conf, Queue_target) -> {config, erlang:element(2, Conf), erlang:element(3, Conf), erlang:element(4, Conf), erlang:element(5, Conf), erlang:element(6, Conf), erlang:element(7, Conf), erlang:element(8, Conf), erlang:element(9, Conf), erlang:element(10, Conf), erlang:element(11, Conf), erlang:element(12, Conf), erlang:element(13, Conf), Queue_target}. -file("src/pgl.gleam", 188). -spec apply_user_info(config(), gleam@uri:uri()) -> {ok, config()} | {error, nil}. apply_user_info(Conf, Uri) -> _pipe = erlang:element(3, Uri), _pipe@4 = gleam@option:map( _pipe, fun(User_info) -> case gleam@string:split(User_info, <<":"/utf8>>) of [User] -> {ok, username(Conf, User)}; [User@1, Pass] -> _pipe@1 = Conf, _pipe@2 = username(_pipe@1, User@1), _pipe@3 = password(_pipe@2, Pass), {ok, _pipe@3}; _ -> {error, nil} end end ), gleam@option:unwrap(_pipe@4, {error, nil}). -file("src/pgl.gleam", 205). -spec apply_host(config(), gleam@uri:uri()) -> {ok, config()} | {error, nil}. apply_host(Conf, Uri) -> case erlang:element(4, Uri) of {some, Val} -> {ok, host(Conf, Val)}; none -> {error, nil} end. -file("src/pgl.gleam", 212). -spec apply_port(config(), gleam@uri:uri()) -> {ok, config()} | {error, nil}. apply_port(Conf, Uri) -> _pipe = erlang:element(5, Uri), _pipe@1 = gleam@option:map(_pipe, fun(_capture) -> port(Conf, _capture) end), _pipe@2 = gleam@option:unwrap(_pipe@1, Conf), {ok, _pipe@2}. -file("src/pgl.gleam", 219). -spec apply_database(config(), gleam@uri:uri()) -> {ok, config()} | {error, nil}. apply_database(Conf, Uri) -> case gleam@string:split(erlang:element(6, Uri), <<"/"/utf8>>) of [<<""/utf8>>, Db] -> {ok, database(Conf, Db)}; _ -> {error, nil} end. -file("src/pgl.gleam", 226). -spec apply_ssl_mode(config(), gleam@uri:uri()) -> {ok, config()} | {error, nil}. apply_ssl_mode(Conf, Uri) -> _pipe = case erlang:element(7, Uri) of none -> {ok, ssl_disabled}; {some, Query} -> gleam@result:'try'( gleam_stdlib:parse_query(Query), fun(Query@1) -> gleam@result:'try'( gleam@list:key_find(Query@1, <<"sslmode"/utf8>>), fun(Sslmode) -> case Sslmode of <<"require"/utf8>> -> {ok, ssl_unverified}; <<"verify-ca"/utf8>> -> {ok, ssl_verified}; <<"verify-full"/utf8>> -> {ok, ssl_verified}; <<"disable"/utf8>> -> {ok, ssl_disabled}; _ -> {error, nil} end end ) end ) end, gleam@result:map(_pipe, fun(_capture) -> ssl(Conf, _capture) end). -file("src/pgl.gleam", 260). ?DOC(" Returns a formatted string representation of the provided error.\n"). -spec error_to_string(pgl_error()) -> binary(). error_to_string(Err) -> case Err of {query_error, Message} -> pgl@internal:format_error(<<"QueryError"/utf8>>, Message); {connection_error, Message@1} -> pgl@internal:format_error(<<"ConnectionError"/utf8>>, Message@1); connection_timeout -> pgl@internal:format_error(<<"ConnectionTimeout"/utf8>>, <<""/utf8>>); {authentication_error, Message@2} -> pgl@internal:format_error(<<"AuthenticationError"/utf8>>, Message@2); {protocol_error, Message@3} -> pgl@internal:format_error(<<"ProtocolError"/utf8>>, Message@3); {socket_error, Message@4} -> pgl@internal:format_error(<<"SocketError"/utf8>>, Message@4); {postgres_error, Code, Name, Message@5, _} -> pgl@internal:format_error_with_values( <<"PostgresError"/utf8>>, <<""/utf8>>, [{<<"code"/utf8>>, Code}, {<<"name"/utf8>>, Name}, {<<"message"/utf8>>, Message@5}], fun gleam@function:identity/1 ) end. -file("src/pgl.gleam", 338). -spec field_from_bit_array(bitstring()) -> field(). field_from_bit_array(Field_type) -> case Field_type of <<"S"/utf8>> -> severity; <<"C"/utf8>> -> code; <<"M"/utf8>> -> message; <<"D"/utf8>> -> detail; <<"H"/utf8>> -> hint; <<"P"/utf8>> -> position; <<"p"/utf8>> -> internal_position; <<"q"/utf8>> -> internal_query; <<"W"/utf8>> -> where; <<"s"/utf8>> -> schema; <<"t"/utf8>> -> table; <<"c"/utf8>> -> column; <<"d"/utf8>> -> data_type; <<"n"/utf8>> -> constraint; <<"F"/utf8>> -> file; <<"L"/utf8>> -> line; <<"R"/utf8>> -> routine; Bits -> {other, Bits} end. -file("src/pgl.gleam", 304). -spec from_internal_error(pgl@internal:internal_error()) -> pgl_error(). from_internal_error(Err) -> case Err of {postgres_error, Code, Name, Message, Fields} -> Fields@1 = begin _pipe = begin gleam@list:map( maps:to_list(Fields), fun(_use0) -> {Field, Val} = _use0, Field1 = field_from_bit_array(Field), {Field1, Val} end ) end, maps:from_list(_pipe) end, {postgres_error, Code, Name, Message, Fields@1}; {authentication_error, Kind, Message@1} -> Message@2 = <<<<<<"["/utf8, (pgl@internal:auth_error_to_string(Kind))/binary>>/binary, "] "/utf8>>/binary, Message@1/binary>>, {authentication_error, Message@2}; {socket_error, Code@1, Message@3} -> Message@4 = <<<<<<"["/utf8, (pgl@internal:posix_error_to_string(Code@1))/binary>>/binary, "] "/utf8>>/binary, Message@3/binary>>, {socket_error, Message@4}; {protocol_error, Kind@1, Message@5} -> Message@6 = <<<<<<"["/utf8, (pgl@internal:protocol_error_to_string(Kind@1))/binary>>/binary, "] "/utf8>>/binary, Message@5/binary>>, {protocol_error, Message@6} end. -file("src/pgl.gleam", 440). -spec disconnect(pgl@internal@socket:socket()) -> {ok, nil} | {error, pgl_error()}. disconnect(Sock) -> _pipe = pgl@internal@socket:shutdown(Sock), gleam@result:map_error(_pipe, fun from_internal_error/1). -file("src/pgl.gleam", 445). -spec authenticated_connection(config(), pgl@internal@socket:factory()) -> {ok, pgl@internal@socket:socket()} | {error, nil}. authenticated_connection(Config, Sockets) -> Conf = begin _pipe = {config, <<""/utf8>>, <<""/utf8>>, <<""/utf8>>, <<""/utf8>>, [], none}, _pipe@1 = pgl@internal@protocol:application( _pipe, erlang:element(2, Config) ), _pipe@2 = pgl@internal@protocol:connection_parameters( _pipe@1, erlang:element(8, Config) ), _pipe@3 = pgl@internal@protocol:username( _pipe@2, erlang:element(5, Config) ), _pipe@4 = pgl@internal@protocol:password( _pipe@3, erlang:element(6, Config) ), pgl@internal@protocol:database(_pipe@4, erlang:element(7, Config)) end, _pipe@5 = Sockets, _pipe@6 = pgl@internal@socket:connect(_pipe@5), _pipe@7 = gleam@result:map_error(_pipe@6, fun(_) -> nil end), gleam@result:'try'( _pipe@7, fun(Sock) -> _pipe@8 = pgl@internal@protocol:auth(Sock, Conf), gleam@result:map_error(_pipe@8, fun(_) -> nil end) end ). -file("src/pgl.gleam", 381). ?DOC( " Creates a new `Db` record. This must be passed to `pgl.start` or\n" " `pgl.supervised` before it can be used.\n" ). -spec new(config()) -> db(). new(Config) -> Sockets = begin _pipe = pgl@internal@socket:new(), _pipe@1 = pgl@internal@socket:host(_pipe, erlang:element(3, Config)), _pipe@2 = pgl@internal@socket:port(_pipe@1, erlang:element(4, Config)), _pipe@3 = pgl@internal@socket:ipv6( _pipe@2, (case erlang:element(11, Config) of ipv4 -> false; ipv6 -> true end) ), pgl@internal@socket:factory(_pipe@3) end, Pool = gleam_erlang_ffi:new_name(<<"pgl_pool"/utf8>>), Query_cache = pgl@internal@query_cache:new(), Type_cache = begin _pipe@4 = pgl@internal@type_cache:new(), pgl@internal@type_cache:on_connect( _pipe@4, fun() -> authenticated_connection(Config, Sockets) end ) end, {db, Pool, Sockets, Type_cache, Query_cache, Config}. -file("src/pgl.gleam", 435). -spec connect(db()) -> {ok, pgl@internal@socket:socket()} | {error, pgl_error()}. connect(Db) -> _pipe = authenticated_connection( erlang:element(6, Db), erlang:element(3, Db) ), gleam@result:map_error( _pipe, fun(_) -> {connection_error, <<"Failed to open connection"/utf8>>} end ). -file("src/pgl.gleam", 467). ?DOC(" Creates a `Connection`.\n"). -spec connection(db()) -> connection(). connection(Db) -> {pool, Db}. -file("src/pgl.gleam", 471). -spec pool_error_to_pgl_error(db_pool:pool_error(pgl_error())) -> pgl_error(). pool_error_to_pgl_error(Err) -> case Err of {connection_error, Err@1} -> Err@1; connection_timeout -> connection_timeout end. -file("src/pgl.gleam", 479). ?DOC(" Shuts down the `Db`\n"). -spec shutdown(db()) -> {ok, nil} | {error, pgl_error()}. shutdown(Db) -> _pipe = erlang:element(2, Db), _pipe@1 = gleam@erlang@process:named_subject(_pipe), _pipe@2 = db_pool:shutdown(_pipe@1, 1000), gleam@result:map_error(_pipe@2, fun pool_error_to_pgl_error/1). -file("src/pgl.gleam", 486). -spec ping(pgl@internal@socket:socket()) -> {ok, pgl@internal@socket:socket()} | {error, pgl_error()}. ping(Sock) -> _pipe = pgl@internal@protocol:ping(Sock), gleam@result:map_error(_pipe, fun from_internal_error/1). -file("src/pgl.gleam", 404). -spec start(db()) -> {ok, gleam@otp@actor:started(gleam@otp@static_supervisor:supervisor())} | {error, gleam@otp@actor:start_error()}. start(Db) -> Pool = begin _pipe = db_pool:new(), _pipe@1 = db_pool:size(_pipe, erlang:element(12, erlang:element(6, Db))), _pipe@2 = db_pool:interval( _pipe@1, erlang:element(13, erlang:element(6, Db)) ), _pipe@3 = db_pool:on_open(_pipe@2, fun() -> connect(Db) end), _pipe@4 = db_pool:on_close(_pipe@3, fun disconnect/1), db_pool:on_interval( _pipe@4, fun(Conn) -> _ = ping(Conn), nil end ) end, _pipe@5 = gleam@otp@static_supervisor:new(one_for_one), _pipe@6 = gleam@otp@static_supervisor:add( _pipe@5, pgl@internal@type_cache:supervised(erlang:element(4, Db)) ), _pipe@7 = gleam@otp@static_supervisor:add( _pipe@6, pgl@internal@query_cache:supervised(erlang:element(5, Db)) ), _pipe@8 = gleam@otp@static_supervisor:add( _pipe@7, pgl@internal@socket:supervised(erlang:element(3, Db)) ), _pipe@9 = gleam@otp@static_supervisor:add( _pipe@8, db_pool:supervised(Pool, erlang:element(2, Db), 1000) ), gleam@otp@static_supervisor:start(_pipe@9). -file("src/pgl.gleam", 425). -spec supervised(db()) -> gleam@otp@supervision:child_specification(gleam@otp@static_supervisor:supervisor()). supervised(Db) -> Pool_supervisor = begin _pipe = gleam@otp@supervision:supervisor(fun() -> start(Db) end), gleam@otp@supervision:restart(_pipe, transient) end, _pipe@1 = gleam@otp@static_supervisor:new(one_for_one), _pipe@2 = gleam@otp@static_supervisor:add(_pipe@1, Pool_supervisor), gleam@otp@static_supervisor:supervised(_pipe@2). -file("src/pgl.gleam", 520). -spec checkout(db(), gleam@erlang@process:pid_()) -> {ok, pgl@internal@conn:conn()} | {error, pgl_error()}. checkout(Db, Self) -> _pipe = erlang:element(2, Db), _pipe@1 = gleam@erlang@process:named_subject(_pipe), _pipe@2 = db_pool:checkout( _pipe@1, Self, erlang:element(14, erlang:element(6, Db)) ), _pipe@3 = gleam@result:map( _pipe@2, fun(_capture) -> pgl@internal@conn:new(_capture, Self) end ), gleam@result:map_error(_pipe@3, fun pool_error_to_pgl_error/1). -file("src/pgl.gleam", 528). -spec checkin(db(), pgl@internal@socket:socket(), gleam@erlang@process:pid_()) -> nil. checkin(Db, Sock, Self) -> _pipe = erlang:element(2, Db), _pipe@1 = gleam@erlang@process:named_subject(_pipe), db_pool:checkin(_pipe@1, Sock, Self). -file("src/pgl.gleam", 500). -spec with_single_connection( connection(), fun((pgl@internal@conn:conn(), db()) -> {ok, MNM} | {error, pgl_error()}) ) -> {ok, MNM} | {error, pgl_error()}. with_single_connection(Connection, Next) -> case Connection of {pool, Db} -> Self = erlang:self(), gleam@result:'try'( checkout(Db, Self), fun(Conn) -> Res = Next(Conn, Db), checkin(Db, erlang:element(2, Conn), Self), Res end ); {connection, Conn@1, Db@1} -> Next(Conn@1, Db@1) end. -file("src/pgl.gleam", 549). ?DOC(" Returns a `Query` with the provided SQL string.\n"). -spec sql(binary()) -> 'query'(). sql(Sql) -> {'query', Sql, []}. -file("src/pgl.gleam", 554). ?DOC(" Sets a list of query parameters for the provided `Query`.\n"). -spec params('query'(), list(pg_value:value())) -> 'query'(). params(Q, Params) -> {'query', erlang:element(2, Q), Params}. -file("src/pgl.gleam", 619). -spec rows_to_dicts(list(binary()), list(list(gleam@dynamic:dynamic_()))) -> {ok, list(gleam@dynamic:dynamic_())} | {error, nil}. rows_to_dicts(Fields, Values) -> gleam@result:map( gleam@list:try_map( Values, fun(_capture) -> gleam@list:strict_zip(Fields, _capture) end ), fun(Rows) -> _pipe = begin gleam@list:map( Rows, fun(Row) -> gleam@list:map( Row, fun(_use0) -> {Col, Val} = _use0, {gleam_stdlib:identity(Col), Val} end ) end ) end, gleam@list:map(_pipe, fun gleam@dynamic:properties/1) end ). -file("src/pgl.gleam", 605). -spec to_queried(pgl@internal@protocol:extended(pg_value:value()), boolean()) -> {ok, queried()} | {error, pgl_error()}. to_queried(Ext, Rows_as_dict) -> Values = lists:reverse(erlang:element(7, Ext)), _pipe = case Rows_as_dict of true -> rows_to_dicts(erlang:element(6, Ext), Values); false -> {ok, gleam@list:map(Values, fun erlang:list_to_tuple/1)} end, _pipe@1 = gleam@result:map( _pipe, fun(_capture) -> {queried, erlang:element(8, Ext), erlang:element(6, Ext), _capture} end ), gleam@result:map_error( _pipe@1, fun(_) -> {query_error, <<"Failed to process queried rows"/utf8>>} end ). -file("src/pgl.gleam", 672). -spec encode_from_cache(binary(), list(pg_value:value()), db()) -> {ok, pgl@internal@encode:'query'(pg_value:value(), pg_value@type_info:type_info())} | {error, nil}. encode_from_cache(Sql, Params, Db) -> gleam@result:'try'( pgl@internal@query_cache:lookup(erlang:element(5, Db), Sql), fun(Oids) -> gleam@result:map( pgl@internal@type_cache:lookup(erlang:element(4, Db), Oids), fun(Info) -> _pipe = pgl@internal@encode:cached( Sql, Params, Info, fun pg_value:encode/2 ), pgl@internal@encode:with_sync(_pipe) end ) end ). -file("src/pgl.gleam", 684). -spec on_param_description( binary(), list(pg_value:value()), list(integer()), db() ) -> {ok, bitstring()} | {error, nil}. on_param_description(Sql, Params, Oids, Db) -> gleam@result:'try'( pgl@internal@query_cache:insert(erlang:element(5, Db), Sql, Oids), fun(_) -> gleam@result:'try'( pgl@internal@type_cache:lookup(erlang:element(4, Db), Oids), fun(Info) -> _pipe = pgl@internal@encode:cached( Sql, Params, Info, fun pg_value:encode/2 ), _pipe@1 = pgl@internal@encode:with_sync(_pipe), _pipe@2 = pgl@internal@encode:to_bit_array(_pipe@1), gleam@result:map_error(_pipe@2, fun(_) -> nil end) end ) end ). -file("src/pgl.gleam", 714). -spec decode_row_values(list(bitstring()), list(pg_value@type_info:type_info())) -> {ok, list(gleam@dynamic:dynamic_())} | {error, pgl@internal:internal_error()}. decode_row_values(Values, Infos) -> _pipe = gleam@list:strict_zip(Values, Infos), _pipe@2 = gleam@result:map_error(_pipe, fun(_) -> _pipe@1 = decoding_error, {protocol_error, _pipe@1, <<"Mismatched values and infos"/utf8>>} end), gleam@result:'try'( _pipe@2, fun(Vals_infos) -> gleam@list:try_map( Vals_infos, fun(Val_info) -> {Val, Info} = Val_info, _pipe@3 = pg_value:decode(Val, Info), gleam@result:map_error( _pipe@3, fun(_capture) -> {protocol_error, decoding_error, _capture} end ) end ) end ). -file("src/pgl.gleam", 699). -spec decode_row(list(bitstring()), list(integer()), db()) -> {ok, list(gleam@dynamic:dynamic_())} | {error, pgl@internal:internal_error()}. decode_row(Values, Oids, Db) -> _pipe = pgl@internal@type_cache:lookup(erlang:element(4, Db), Oids), _pipe@1 = gleam@result:map_error( _pipe, fun(_) -> {protocol_error, decoding_error, <<"Failed to decode row"/utf8>>} end ), gleam@result:'try'( _pipe@1, fun(_capture) -> decode_row_values(Values, _capture) end ). -file("src/pgl.gleam", 658). -spec extended(db()) -> pgl@internal@protocol:extended(pg_value:value()). extended(Db) -> _pipe = pgl@internal@protocol:extended(), _pipe@1 = pgl@internal@protocol:on_decode_row( _pipe, fun(Vals, Oids) -> decode_row(Vals, Oids, Db) end ), pgl@internal@protocol:on_param_description( _pipe@1, fun(Sql, Params, Oids@1) -> _pipe@2 = on_param_description(Sql, Params, Oids@1, Db), gleam@result:map_error( _pipe@2, fun(_) -> {protocol_error, processing_error, <<"Failed to describe statement parameters"/utf8>>} end ) end ). -file("src/pgl.gleam", 573). ?DOC( " Uses [pipelining][1] to send multiple queries to the database server without\n" " waiting for previous queries to complete. Reduces the number of network\n" " roundtrips needed for multiple queries.\n" "\n" " [1]: https://www.postgresql.org/docs/current/protocol-flow.html#PROTOCOL-FLOW-PIPELINING\n" ). -spec batch(list('query'()), connection()) -> {ok, list(queried())} | {error, pgl_error()}. batch(Queries, Connection) -> with_single_connection( Connection, fun(Conn, Db) -> Messages = begin _pipe = Queries, _pipe@1 = gleam@list:try_map( _pipe, fun(Query) -> {'query', Sql, Params} = Query, gleam@result:'try'( pgl@internal@query_cache:lookup( erlang:element(5, Db), Sql ), fun(Oids) -> gleam@result:map( pgl@internal@type_cache:lookup( erlang:element(4, Db), Oids ), fun(Info) -> pgl@internal@encode:cached( Sql, Params, Info, fun pg_value:encode/2 ) end ) end ) end ), gleam@result:lazy_unwrap( _pipe@1, fun() -> gleam@list:map( Queries, fun(Q) -> pgl@internal@encode:uncached( erlang:element(2, Q), erlang:element(3, Q) ) end ) end ) end, Ext = extended(Db), _pipe@2 = pgl@internal@protocol:pipeline(), _pipe@3 = pgl@internal@protocol:batch_process( _pipe@2, Ext, Messages, erlang:element(2, Conn) ), _pipe@4 = gleam@result:map_error(_pipe@3, fun from_internal_error/1), gleam@result:'try'( _pipe@4, fun(Exts) -> gleam@list:try_map( Exts, fun(Ext@1) -> to_queried( Ext@1, erlang:element(10, erlang:element(6, Db)) ) end ) end ) end ). -file("src/pgl.gleam", 644). -spec extended_query( binary(), list(pg_value:value()), pgl@internal@conn:conn(), db() ) -> {ok, pgl@internal@protocol:extended(pg_value:value())} | {error, pgl@internal:internal_error()}. extended_query(Sql, Params, Conn, Db) -> Message = begin _pipe = encode_from_cache(Sql, Params, Db), gleam@result:lazy_unwrap( _pipe, fun() -> pgl@internal@encode:uncached(Sql, Params) end ) end, _pipe@1 = extended(Db), pgl@internal@protocol:process(_pipe@1, Message, erlang:element(2, Conn)). -file("src/pgl.gleam", 559). ?DOC(" Perform a query with the given SQL string and list of parameters.\n"). -spec 'query'('query'(), connection()) -> {ok, queried()} | {error, pgl_error()}. 'query'(Q, Connection) -> with_single_connection( Connection, fun(Conn, Db) -> _pipe = extended_query( erlang:element(2, Q), erlang:element(3, Q), Conn, Db ), _pipe@1 = gleam@result:map_error(_pipe, fun from_internal_error/1), gleam@result:'try'( _pipe@1, fun(_capture) -> to_queried( _capture, erlang:element(10, erlang:element(6, Db)) ) end ) end ). -file("src/pgl.gleam", 636). ?DOC( " Perform a query with the given SQL string. This function will send the\n" " SQL string as is to the postgres database server.\n" ). -spec execute(binary(), connection()) -> {ok, integer()} | {error, pgl_error()}. execute(Sql, Connection) -> with_single_connection( Connection, fun(Conn, Db) -> _pipe = extended_query(Sql, [], Conn, Db), _pipe@1 = gleam@result:map( _pipe, fun(Rows) -> erlang:element(8, Rows) end ), gleam@result:map_error(_pipe@1, fun from_internal_error/1) end ). -file("src/pgl.gleam", 789). -spec with_transaction( connection(), fun((pgl@internal@conn:conn(), db()) -> {ok, MQB} | {error, transaction_error(MQC)}) ) -> {ok, MQB} | {error, transaction_error(MQC)}. with_transaction(Connection, Next) -> case Connection of {pool, Db} -> Self = erlang:self(), _pipe = checkout(Db, Self), _pipe@3 = gleam@result:map_error( _pipe, fun(Pgl_error) -> _pipe@1 = Pgl_error, _pipe@2 = error_to_string(_pipe@1), {transaction_error, _pipe@2} end ), gleam@result:'try'(_pipe@3, fun(_capture) -> Next(_capture, Db) end); {connection, Conn, Db@1} -> Next(Conn, Db@1) end. -file("src/pgl.gleam", 924). -spec transaction_query(binary(), pgl@internal@conn:conn()) -> {ok, pgl@internal@conn:conn()} | {error, transaction_error(any())}. transaction_query(Query, Conn) -> Packet = pgl@internal@encode:'query'(Query), _pipe = pgl@internal@protocol:simple(Packet, erlang:element(2, Conn)), _pipe@1 = gleam@result:replace(_pipe, Conn), gleam@result:map_error(_pipe@1, fun(Err) -> _pipe@2 = Err, _pipe@3 = pgl@internal:error_to_string(_pipe@2), {transaction_error, _pipe@3} end). -file("src/pgl.gleam", 751). -spec do_transaction( pgl@internal@conn:conn(), fun((pgl@internal@conn:conn()) -> {ok, MPQ} | {error, MPR}) ) -> {ok, MPQ} | {error, transaction_error(MPR)}. do_transaction(Conn, Next) -> gleam@result:'try'( transaction_query(<<"BEGIN"/utf8>>, Conn), fun(Conn@1) -> _pipe = pgl@internal:assert_on_crash( fun() -> transaction_query(<<"ROLLBACK"/utf8>>, Conn@1) end, <<"ROLLBACK"/utf8>>, fun() -> Next(Conn@1) end ), _pipe@1 = gleam@result:map_error( _pipe, fun(Err) -> case transaction_query(<<"ROLLBACK"/utf8>>, Conn@1) of {ok, _} -> {rollback_error, Err}; {error, Err@1} -> Err@1 end end ), gleam@result:'try'( _pipe@1, fun(Res) -> _pipe@2 = transaction_query(<<"COMMIT"/utf8>>, Conn@1), gleam@result:replace(_pipe@2, Res) end ) end ). -file("src/pgl.gleam", 738). ?DOC( " Starts a transaction and then calls the provided function, passing it the\n" " transaction connection. If the given function throws an exception, the\n" " transaction will be rolled back the exception propagated up.\n" " If the given function returns an error result, the transaction will also\n" " be rolled back and an error result returned.\n" ). -spec transaction(connection(), fun((connection()) -> {ok, MPJ} | {error, MPK})) -> {ok, MPJ} | {error, transaction_error(MPK)}. transaction(Connection, Next) -> with_transaction( Connection, fun(Conn, Db) -> Res = do_transaction( Conn, fun(Conn@1) -> Next({connection, Conn@1, Db}) end ), checkin(Db, erlang:element(2, Conn), erlang:element(4, Conn)), Res end ). -file("src/pgl.gleam", 778). ?DOC( " Begins a transaction.\n" "\n" " You should typically use `pgl.transaction` to take care of starting and\n" " ending transactions.\n" ). -spec 'begin'(connection()) -> {ok, connection()} | {error, transaction_error(any())}. 'begin'(Connection) -> with_transaction( Connection, fun(Conn, Db) -> _pipe = transaction_query(<<"BEGIN"/utf8>>, Conn), gleam@result:map( _pipe, fun(_capture) -> {connection, _capture, Db} end ) end ). -file("src/pgl.gleam", 813). ?DOC( " Commits a transaction.\n" "\n" " You should typically use `pgl.transaction` to take care of starting and\n" " ending transactions.\n" ). -spec commit(connection()) -> {ok, connection()} | {error, transaction_error(any())}. commit(Connection) -> case Connection of {pool, _} -> {error, not_in_transaction}; {connection, Conn, Db} -> _pipe = transaction_query(<<"COMMIT"/utf8>>, Conn), gleam@result:map( _pipe, fun(_) -> checkin( Db, erlang:element(2, Conn), erlang:element(4, Conn) ), {pool, Db} end ) end. -file("src/pgl.gleam", 845). -spec do_rollback(pgl@internal@conn:conn(), db()) -> {ok, pgl@internal@conn:conn()} | {error, transaction_error(any())}. do_rollback(Conn, Db) -> case pgl@internal@conn:rollback_savepoint_statement(Conn) of {ok, Stmt} -> _pipe = transaction_query(Stmt, Conn), gleam@result:replace(_pipe, Conn); _ -> _pipe@1 = transaction_query(<<"ROLLBACK"/utf8>>, Conn), gleam@result:map( _pipe@1, fun(_) -> checkin( Db, erlang:element(2, Conn), erlang:element(4, Conn) ), Conn end ) end. -file("src/pgl.gleam", 833). ?DOC( " Rolls back to a savepoint if one exists, otherwise rolls back the transaction.\n" "\n" " You should typically use `pgl.transaction` to take care of starting and\n" " ending transactions.\n" ). -spec rollback(connection()) -> {ok, connection()} | {error, transaction_error(any())}. rollback(Connection) -> case Connection of {pool, _} -> {error, not_in_transaction}; {connection, Conn, Db} -> _pipe = do_rollback(Conn, Db), gleam@result:map(_pipe, fun(_) -> {pool, Db} end) end. -file("src/pgl.gleam", 913). -spec do_release_savepoint(pgl@internal@conn:conn()) -> {ok, pgl@internal@conn:conn()} | {error, transaction_error(any())}. do_release_savepoint(Conn) -> _pipe = pgl@internal@conn:release_savepoint_statement(Conn), _pipe@1 = gleam@result:replace_error(_pipe, not_in_transaction), gleam@result:'try'( _pipe@1, fun(Stmt) -> _pipe@2 = transaction_query(Stmt, Conn), gleam@result:map(_pipe@2, fun pgl@internal@conn:prev_savepoint/1) end ). -file("src/pgl.gleam", 880). -spec do_savepoint( pgl@internal@conn:conn(), db(), fun((pgl@internal@conn:conn()) -> {ok, MRC} | {error, MRD}) ) -> {ok, MRC} | {error, transaction_error(MRD)}. do_savepoint(Conn, Db, Next) -> Conn@1 = pgl@internal@conn:next_savepoint(Conn), Rollback_and_release = fun(Conn@2) -> _pipe = do_rollback(Conn@2, Db), gleam@result:'try'(_pipe, fun do_release_savepoint/1) end, _pipe@1 = pgl@internal@conn:savepoint_statement(Conn@1), _pipe@2 = transaction_query(_pipe@1, Conn@1), _pipe@4 = gleam@result:'try'( _pipe@2, fun(Conn@3) -> _pipe@3 = pgl@internal:assert_on_crash( fun() -> Rollback_and_release(Conn@3) end, <<"rollback and release savepoint"/utf8>>, fun() -> Next(Conn@3) end ), gleam@result:map_error( _pipe@3, fun(Err) -> case Rollback_and_release(Conn@3) of {ok, _} -> {rollback_error, Err}; {error, Err@1} -> Err@1 end end ) end ), gleam@result:'try'( _pipe@4, fun(Res) -> _pipe@5 = do_release_savepoint(Conn@1), gleam@result:replace(_pipe@5, Res) end ). -file("src/pgl.gleam", 866). ?DOC(" Creates a new savepoint.\n"). -spec savepoint(connection(), fun((connection()) -> {ok, MQV} | {error, MQW})) -> {ok, MQV} | {error, transaction_error(MQW)}. savepoint(Connection, Next) -> case Connection of {pool, _} -> {error, not_in_transaction}; {connection, Conn, Db} -> do_savepoint( Conn, Db, fun(Conn@1) -> _pipe = {connection, Conn@1, Db}, Next(_pipe) end ) end. -file("src/pgl.gleam", 177). -spec options_from_uri(gleam@uri:uri()) -> {ok, config()} | {error, nil}. options_from_uri(Uri) -> _pipe = erlang:element(2, Uri), _pipe@1 = gleam@option:map(_pipe, fun(Scheme) -> case Scheme of <<"postgres"/utf8>> -> {ok, {config, <<""/utf8>>, <<"127.0.0.1"/utf8>>, 5432, <<""/utf8>>, <<""/utf8>>, <<""/utf8>>, [], ssl_disabled, false, ipv4, 5, 1000, 50}}; <<"postgresql"/utf8>> -> {ok, {config, <<""/utf8>>, <<"127.0.0.1"/utf8>>, 5432, <<""/utf8>>, <<""/utf8>>, <<""/utf8>>, [], ssl_disabled, false, ipv4, 5, 1000, 50}}; _ -> {error, nil} end end), gleam@option:lazy_unwrap(_pipe@1, fun() -> {error, nil} end). -file("src/pgl.gleam", 166). ?DOC(" Build a `Config` from a connection url\n"). -spec from_url(binary()) -> {ok, config()} | {error, nil}. from_url(Url) -> gleam@result:'try'( gleam_stdlib:uri_parse(Url), fun(Uri) -> gleam@result:'try'( options_from_uri(Uri), fun(Conf) -> gleam@result:'try'( apply_user_info(Conf, Uri), fun(Conf@1) -> gleam@result:'try'( apply_host(Conf@1, Uri), fun(Conf@2) -> gleam@result:'try'( apply_port(Conf@2, Uri), fun(Conf@3) -> gleam@result:'try'( apply_database(Conf@3, Uri), fun(Conf@4) -> apply_ssl_mode(Conf@4, Uri) end ) end ) end ) end ) end ) end ).