-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, start/1, supervised/1, connection/1, shutdown/1, sql/1, values/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"). -opaque 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 | connection_unavailable | {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(NSX) :: {rollback_error, NSX} | 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", 98). ?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", 103). ?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", 108). ?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", 113). ?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", 118). ?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", 123). ?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", 128). ?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", 140). ?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", 146). ?DOC( " Configures rows to be returned as `Dict` rather than n-tuples.\n" " The keys of the `Dict` are the queried column names.\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", 151). ?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", 156). ?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", 161). ?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", 166). ?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", 193). -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", 210). -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", 217). -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", 224). -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", 231). -spec apply_ssl_mode(config(), gleam@uri:uri()) -> {ok, config()} | {error, nil}. apply_ssl_mode(Conf, Uri) -> Ssl_mode = case erlang:element(7, Uri) of none -> {ok, ssl_verified}; {some, Query} -> case gleam_stdlib:parse_query(Query) of {ok, Params} -> case gleam@list:key_find(Params, <<"sslmode"/utf8>>) of {ok, <<"require"/utf8>>} -> {ok, ssl_unverified}; {ok, <<"verify-ca"/utf8>>} -> {ok, ssl_verified}; {ok, <<"verify-full"/utf8>>} -> {ok, ssl_verified}; {ok, <<"disable"/utf8>>} -> {ok, ssl_disabled}; {ok, _} -> {error, nil}; {error, _} -> {ok, ssl_disabled} end; {error, _} -> {error, nil} end end, _pipe = Ssl_mode, gleam@result:map(_pipe, fun(_capture) -> ssl(Conf, _capture) end). -file("src/pgl.gleam", 279). ?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>>); connection_unavailable -> pgl@internal:format_error( <<"ConnectionUnavailable"/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", 358). -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", 324). -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, Kind@1, Message@3} -> Message@4 = <<<<<<"["/utf8, (pgl@internal:socket_error_to_string(Kind@1))/binary>>/binary, "] "/utf8>>/binary, Message@3/binary>>, {socket_error, Message@4}; {protocol_error, Kind@2, Message@5} -> Message@6 = <<<<<<"["/utf8, (pgl@internal:protocol_error_to_string(Kind@2))/binary>>/binary, "] "/utf8>>/binary, Message@5/binary>>, {protocol_error, Message@6} end. -file("src/pgl.gleam", 466). -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", 471). -spec authenticated_connection(config(), pgl@internal@socket:factory()) -> {ok, pgl@internal@socket:socket()} | {error, pgl@internal:internal_error()}. authenticated_connection(Config, Sockets) -> Ssl = case erlang:element(9, Config) of ssl_disabled -> ssl_disabled; ssl_verified -> ssl_verified; ssl_unverified -> ssl_unverified end, Conf = begin _pipe = {config, <<""/utf8>>, <<""/utf8>>, none, <<""/utf8>>, [], ssl_verified}, _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) ), _pipe@5 = pgl@internal@protocol:database( _pipe@4, erlang:element(7, Config) ), pgl@internal@protocol:ssl(_pipe@5, Ssl) end, _pipe@6 = Sockets, _pipe@7 = pgl@internal@socket:connect(_pipe@6), _pipe@8 = gleam@result:map_error( _pipe@7, fun(_) -> {socket_error, {connect_error, <<"Failed to start socket connection"/utf8>>}, <<"Failed to start socket connection"/utf8>>} end ), gleam@result:'try'( _pipe@8, fun(Sock) -> pgl@internal@protocol:auth(Sock, Conf) end ). -file("src/pgl.gleam", 405). ?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() -> _pipe@5 = authenticated_connection(Config, Sockets), gleam@result:map_error(_pipe@5, fun(_) -> nil end) end ) end, {db, Pool, Sockets, Type_cache, Query_cache, Config}. -file("src/pgl.gleam", 461). -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 from_internal_error/1). -file("src/pgl.gleam", 433). ?DOC( " Starts the connection pool, type cache, query cache, and socket\n" " factory under a supervision tree.\n" ). -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:on_open(_pipe@1, fun() -> connect(Db) end), _pipe@3 = db_pool:on_close(_pipe@2, fun disconnect/1), _pipe@4 = db_pool:on_idle( _pipe@3, fun(_capture) -> pgl@internal@socket:start_ping( _capture, erlang:element(13, erlang:element(6, Db)) ) end ), db_pool:on_active(_pipe@4, fun pgl@internal@socket:stop_ping/1) 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", 451). ?DOC(" Returns a child specification for use in an existing supervision tree.\n"). -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", 502). ?DOC(" Creates a `Connection`.\n"). -spec connection(db()) -> connection(). connection(Db) -> {pool, Db}. -file("src/pgl.gleam", 506). -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; connection_unavailable -> connection_unavailable end. -file("src/pgl.gleam", 515). ?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", 531). -spec with_single_connection( connection(), fun((pgl@internal@conn:conn(), db()) -> {ok, NTX} | {error, pgl_error()}) ) -> {ok, NTX} | {error, pgl_error()}. with_single_connection(Connection, Next) -> case Connection of {pool, Db} -> Res = begin _pipe = erlang:element(2, Db), _pipe@1 = gleam@erlang@process:named_subject(_pipe), _pipe@3 = db_pool:with_connection( _pipe@1, erlang:element(14, erlang:element(6, Db)), 30000, fun(Socket) -> _pipe@2 = pgl@internal@conn:new(Socket, erlang:self()), Next(_pipe@2, Db) end ), gleam@result:map_error(_pipe@3, fun pool_error_to_pgl_error/1) end, case Res of {ok, Ok} -> Ok; {error, Err} -> {error, Err} end; {connection, Conn, Db@1} -> Next(Conn, Db@1) end. -file("src/pgl.gleam", 555). -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)), 30000 ), _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", 563). -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", 584). ?DOC(" Returns a `Query` with the provided SQL string.\n"). -spec sql(binary()) -> 'query'(). sql(Sql) -> {'query', Sql, []}. -file("src/pgl.gleam", 589). ?DOC(" Sets a list of query parameters for the provided `Query`.\n"). -spec values('query'(), list(pg_value:value())) -> 'query'(). values(Q, Values) -> {'query', erlang:element(2, Q), Values}. -file("src/pgl.gleam", 653). -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", 639). -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", 706). -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", 718). -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", 748). -spec decode_row_values( list(gleam@option:option(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) -> case Val_info of {none, _} -> {ok, gleam@dynamic:nil()}; {{some, 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) end ). -file("src/pgl.gleam", 733). -spec decode_row(list(gleam@option:option(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", 692). -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", 607). ?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", 678). -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", 594). ?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", 670). ?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", 826). -spec with_transaction( connection(), fun((pgl@internal@conn:conn(), db()) -> {ok, NWO} | {error, transaction_error(NWP)}) ) -> {ok, NWO} | {error, transaction_error(NWP)}. 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(Conn) -> case Next(Conn, Db) of {ok, Val} -> {ok, Val}; {error, Err} -> checkin( Db, erlang:element(2, Conn), erlang:element(4, Conn) ), {error, Err} end end); {connection, Conn@1, Db@1} -> Next(Conn@1, Db@1) end. -file("src/pgl.gleam", 969). -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", 787). -spec do_transaction( pgl@internal@conn:conn(), fun((pgl@internal@conn:conn()) -> {ok, NWD} | {error, NWE}) ) -> {ok, NWD} | {error, transaction_error(NWE)}. 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", 774). ?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, NVW} | {error, NVX})) -> {ok, NVW} | {error, transaction_error(NVX)}. 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", 814). ?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", 858). ?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", 890). -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", 878). ?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", 958). -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", 925). -spec do_savepoint( pgl@internal@conn:conn(), db(), fun((pgl@internal@conn:conn()) -> {ok, NXP} | {error, NXQ}) ) -> {ok, NXP} | {error, transaction_error(NXQ)}. 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", 911). ?DOC(" Creates a new savepoint.\n"). -spec savepoint(connection(), fun((connection()) -> {ok, NXI} | {error, NXJ})) -> {ok, NXI} | {error, transaction_error(NXJ)}. 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", 182). -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_verified, false, ipv4, 5, 1000, 50}}; <<"postgresql"/utf8>> -> {ok, {config, <<""/utf8>>, <<"127.0.0.1"/utf8>>, 5432, <<""/utf8>>, <<""/utf8>>, <<""/utf8>>, [], ssl_verified, false, ipv4, 5, 1000, 50}}; _ -> {error, nil} end end), gleam@option:lazy_unwrap(_pipe@1, fun() -> {error, nil} end). -file("src/pgl.gleam", 171). ?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 ).