-module(postgleam). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/postgleam.gleam"). -export([connect/1, 'query'/3, simple_query/2, prepare/3, execute/3, close/2, disconnect/1, transaction/2, query_error/1, int/1, float/1, text/1, bool/1, null/0, bytea/1, uuid/1, uuid_string/1, json/1, jsonb/1, numeric/1, date/1, timestamp/1, timestamptz/1, nullable/2, query_with/4, query_one/4]). -export_type([response/1, connection/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. -type response(IRB) :: {response, list(IRB), integer(), binary()}. -opaque connection() :: {connection, gleam@erlang@process:subject(postgleam@internal@connection_actor:message()), postgleam@config:config()}. -file("src/postgleam.gleam", 49). ?DOC( " Connect to PostgreSQL and return a connection handle.\n" " The connection is managed by an OTP actor process.\n" ). -spec connect(postgleam@config:config()) -> {ok, connection()} | {error, postgleam@error:error()}. connect(Config) -> case postgleam@internal@connection_actor:start(Config) of {ok, Started} -> {ok, {connection, erlang:element(3, Started), Config}}; {error, init_timeout} -> {error, {connection_error, <<"Connection initialization timed out"/utf8>>}}; {error, {init_failed, Reason}} -> {error, {connection_error, Reason}}; {error, {init_exited, _}} -> {error, {connection_error, <<"Connection process exited during init"/utf8>>}} end. -file("src/postgleam.gleam", 65). ?DOC( " Execute a parameterized query using the extended protocol (binary format).\n" " Returns typed values decoded through the codec registry.\n" "\n" " Panics if the actor does not respond within the configured timeout.\n" ). -spec 'query'( connection(), binary(), list(gleam@option:option(postgleam@value:value())) ) -> {ok, postgleam@connection:extended_query_result()} | {error, postgleam@error:error()}. 'query'(Conn, Sql, Params) -> gleam@erlang@process:call( erlang:element(2, Conn), erlang:element(7, erlang:element(3, Conn)), fun(Reply) -> {'query', Sql, Params, Reply} end ). -file("src/postgleam.gleam", 116). ?DOC( " Execute a simple text query (no parameters).\n" " Returns text-formatted results.\n" ). -spec simple_query(connection(), binary()) -> {ok, list(postgleam@connection:simple_query_result())} | {error, postgleam@error:error()}. simple_query(Conn, Sql) -> gleam@erlang@process:call( erlang:element(2, Conn), erlang:element(7, erlang:element(3, Conn)), fun(Reply) -> {simple_query, Sql, Reply} end ). -file("src/postgleam.gleam", 126). ?DOC(" Prepare a named statement for later execution.\n"). -spec prepare(connection(), binary(), binary()) -> {ok, postgleam@connection:prepared_statement()} | {error, postgleam@error:error()}. prepare(Conn, Name, Sql) -> gleam@erlang@process:call( erlang:element(2, Conn), erlang:element(7, erlang:element(3, Conn)), fun(Reply) -> {prepare, Name, Sql, Reply} end ). -file("src/postgleam.gleam", 137). ?DOC(" Execute a previously prepared statement.\n"). -spec execute( connection(), postgleam@connection:prepared_statement(), list(gleam@option:option(postgleam@value:value())) ) -> {ok, postgleam@connection:extended_query_result()} | {error, postgleam@error:error()}. execute(Conn, Prepared, Params) -> gleam@erlang@process:call( erlang:element(2, Conn), erlang:element(7, erlang:element(3, Conn)), fun(Reply) -> {execute_prepared, Prepared, Params, Reply} end ). -file("src/postgleam.gleam", 148). ?DOC(" Close a prepared statement.\n"). -spec close(connection(), binary()) -> {ok, nil} | {error, postgleam@error:error()}. close(Conn, Name) -> gleam@erlang@process:call( erlang:element(2, Conn), erlang:element(7, erlang:element(3, Conn)), fun(Reply) -> {close_statement, Name, Reply} end ). -file("src/postgleam.gleam", 155). ?DOC(" Disconnect from PostgreSQL and stop the actor.\n"). -spec disconnect(connection()) -> nil. disconnect(Conn) -> gleam@erlang@process:call( erlang:element(2, Conn), erlang:element(7, erlang:element(3, Conn)), fun(Reply) -> {disconnect, Reply} end ). -file("src/postgleam.gleam", 163). ?DOC( " Execute a function within a transaction.\n" " Automatically BEGINs, and COMMITs on Ok or ROLLBACKs on Error.\n" ). -spec transaction( connection(), fun((connection()) -> {ok, ISD} | {error, postgleam@error:error()}) ) -> {ok, ISD} | {error, postgleam@error:error()}. transaction(Conn, F) -> case simple_query(Conn, <<"BEGIN"/utf8>>) of {error, E} -> {error, E}; {ok, _} -> case F(Conn) of {ok, Val} -> case simple_query(Conn, <<"COMMIT"/utf8>>) of {ok, _} -> {ok, Val}; {error, E@1} -> {error, E@1} end; {error, E@2} -> _ = simple_query(Conn, <<"ROLLBACK"/utf8>>), {error, E@2} end end. -file("src/postgleam.gleam", 187). ?DOC(" Create an error value for use in transactions or other contexts.\n"). -spec query_error(binary()) -> postgleam@error:error(). query_error(Message) -> {connection_error, Message}. -file("src/postgleam.gleam", 196). ?DOC(" Create an integer parameter (int2, int4, int8).\n"). -spec int(integer()) -> gleam@option:option(postgleam@value:value()). int(Val) -> {some, {integer, Val}}. -file("src/postgleam.gleam", 201). ?DOC(" Create a float parameter (float4, float8).\n"). -spec float(float()) -> gleam@option:option(postgleam@value:value()). float(Val) -> {some, {float, Val}}. -file("src/postgleam.gleam", 206). ?DOC(" Create a text/string parameter.\n"). -spec text(binary()) -> gleam@option:option(postgleam@value:value()). text(Val) -> {some, {text, Val}}. -file("src/postgleam.gleam", 211). ?DOC(" Create a boolean parameter.\n"). -spec bool(boolean()) -> gleam@option:option(postgleam@value:value()). bool(Val) -> {some, {boolean, Val}}. -file("src/postgleam.gleam", 216). ?DOC(" Create a NULL parameter.\n"). -spec null() -> gleam@option:option(postgleam@value:value()). null() -> none. -file("src/postgleam.gleam", 221). ?DOC(" Create a bytea (binary data) parameter.\n"). -spec bytea(bitstring()) -> gleam@option:option(postgleam@value:value()). bytea(Val) -> {some, {bytea, Val}}. -file("src/postgleam.gleam", 226). ?DOC(" Create a UUID parameter (16-byte binary).\n"). -spec uuid(bitstring()) -> gleam@option:option(postgleam@value:value()). uuid(Val) -> {some, {uuid, Val}}. -file("src/postgleam.gleam", 232). ?DOC( " Create a UUID parameter from a string like \"550e8400-e29b-41d4-a716-446655440000\".\n" " Returns None (NULL) if the string is not a valid UUID.\n" ). -spec uuid_string(binary()) -> gleam@option:option(postgleam@value:value()). uuid_string(Val) -> case postgleam@value:uuid_from_string(Val) of {ok, V} -> {some, V}; {error, _} -> none end. -file("src/postgleam.gleam", 240). ?DOC(" Create a JSON parameter.\n"). -spec json(binary()) -> gleam@option:option(postgleam@value:value()). json(Val) -> {some, {json, Val}}. -file("src/postgleam.gleam", 245). ?DOC(" Create a JSONB parameter.\n"). -spec jsonb(binary()) -> gleam@option:option(postgleam@value:value()). jsonb(Val) -> {some, {jsonb, Val}}. -file("src/postgleam.gleam", 250). ?DOC(" Create a numeric/decimal parameter (string representation).\n"). -spec numeric(binary()) -> gleam@option:option(postgleam@value:value()). numeric(Val) -> {some, {numeric, Val}}. -file("src/postgleam.gleam", 255). ?DOC(" Create a date parameter (days since 2000-01-01).\n"). -spec date(integer()) -> gleam@option:option(postgleam@value:value()). date(Val) -> {some, {date, Val}}. -file("src/postgleam.gleam", 260). ?DOC(" Create a timestamp parameter (microseconds since 2000-01-01 00:00:00).\n"). -spec timestamp(integer()) -> gleam@option:option(postgleam@value:value()). timestamp(Val) -> {some, {timestamp, Val}}. -file("src/postgleam.gleam", 265). ?DOC(" Create a timestamptz parameter (microseconds since 2000-01-01 00:00:00 UTC).\n"). -spec timestamptz(integer()) -> gleam@option:option(postgleam@value:value()). timestamptz(Val) -> {some, {timestamptz, Val}}. -file("src/postgleam.gleam", 278). ?DOC( " Create a nullable parameter from an Option value.\n" "\n" " ```gleam\n" " postgleam.nullable(Some(\"hello\"), postgleam.text)\n" " // => Some(value.Text(\"hello\"))\n" "\n" " postgleam.nullable(None, postgleam.text)\n" " // => None\n" " ```\n" ). -spec nullable( gleam@option:option(ISI), fun((ISI) -> gleam@option:option(postgleam@value:value())) ) -> gleam@option:option(postgleam@value:value()). nullable(Val, To_param) -> case Val of {some, V} -> To_param(V); none -> none end. -file("src/postgleam.gleam", 289). -spec decode_rows( list(list(gleam@option:option(postgleam@value:value()))), postgleam@decode:row_decoder(ISN), list(ISN) ) -> {ok, list(ISN)} | {error, postgleam@error:error()}. decode_rows(Rows, Decoder, Acc) -> case Rows of [] -> {ok, lists:reverse(Acc)}; [Row | Rest] -> case postgleam@decode:run(Decoder, Row) of {ok, Val} -> decode_rows(Rest, Decoder, [Val | Acc]); {error, E} -> {error, E} end end. -file("src/postgleam.gleam", 76). ?DOC(" Execute a parameterized query and decode each row using the provided decoder.\n"). -spec query_with( connection(), binary(), list(gleam@option:option(postgleam@value:value())), postgleam@decode:row_decoder(IRJ) ) -> {ok, response(IRJ)} | {error, postgleam@error:error()}. query_with(Conn, Sql, Params, Decoder) -> case 'query'(Conn, Sql, Params) of {ok, Result} -> case decode_rows(erlang:element(4, Result), Decoder, []) of {ok, Decoded} -> {ok, {response, Decoded, erlang:length(Decoded), erlang:element(2, Result)}}; {error, E} -> {error, E} end; {error, E@1} -> {error, E@1} end. -file("src/postgleam.gleam", 98). ?DOC(" Execute a query and return the first decoded row, or error if no rows.\n"). -spec query_one( connection(), binary(), list(gleam@option:option(postgleam@value:value())), postgleam@decode:row_decoder(IRP) ) -> {ok, IRP} | {error, postgleam@error:error()}. query_one(Conn, Sql, Params, Decoder) -> case query_with(Conn, Sql, Params, Decoder) of {ok, Response} -> case erlang:element(2, Response) of [First | _] -> {ok, First}; [] -> {error, {decode_error, <<"Expected at least one row, got none"/utf8>>}} end; {error, E} -> {error, E} end.