Current section

Files

Jump to
postgleam src postgleam.erl
Raw

src/postgleam.erl

-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, query_batch/3, simple_query/2, prepare/3, execute/3, close/2, copy_in/3, copy_out/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, time/1, timetz/2, interval/3, xml/1, jsonpath/1, money/1, point/2, circle/3, macaddr/1, macaddr8/1, array/1, line/3, lseg/4, box/4, path/2, polygon/1, inet/3, bit_string/2, 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(KNA) :: {response, list(KNA), 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", 101).
?DOC(
" Execute the same query with multiple param sets in a single pipeline.\n"
" All Bind+Execute messages are sent together with a single Sync,\n"
" eliminating N-1 round-trips compared to calling query() N times.\n"
" Returns one result per param set.\n"
).
-spec query_batch(
connection(),
binary(),
list(list(gleam@option:option(postgleam@value:value())))
) -> {ok, list(postgleam@connection:extended_query_result())} |
{error, postgleam@error:error()}.
query_batch(Conn, Sql, Param_sets) ->
gleam@erlang@process:call(
erlang:element(2, Conn),
erlang:element(7, erlang:element(3, Conn)),
fun(Reply) -> {batch_query, Sql, Param_sets, Reply} end
).
-file("src/postgleam.gleam", 130).
?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", 140).
?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", 151).
?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", 162).
?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", 172).
?DOC(
" Bulk insert data using the COPY protocol.\n"
" `sql` should be a COPY ... FROM STDIN statement.\n"
" `data` is a list of text-format row chunks (each ending with \\n).\n"
" Returns the command tag (e.g., \"COPY 1000\").\n"
).
-spec copy_in(connection(), binary(), list(bitstring())) -> {ok, binary()} |
{error, postgleam@error:error()}.
copy_in(Conn, Sql, Data) ->
gleam@erlang@process:call(
erlang:element(2, Conn),
erlang:element(7, erlang:element(3, Conn)),
fun(Reply) -> {copy_in, Sql, Data, Reply} end
).
-file("src/postgleam.gleam", 185).
?DOC(
" Export data using the COPY protocol.\n"
" `sql` should be a COPY ... TO STDOUT statement.\n"
" Returns the raw data chunks from PostgreSQL.\n"
).
-spec copy_out(connection(), binary()) -> {ok, list(bitstring())} |
{error, postgleam@error:error()}.
copy_out(Conn, Sql) ->
gleam@erlang@process:call(
erlang:element(2, Conn),
erlang:element(7, erlang:element(3, Conn)),
fun(Reply) -> {copy_out, Sql, Reply} end
).
-file("src/postgleam.gleam", 195).
?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", 203).
?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, KON} | {error, postgleam@error:error()})
) -> {ok, KON} | {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", 227).
?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", 236).
?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", 241).
?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", 246).
?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", 251).
?DOC(" Create a boolean parameter.\n").
-spec bool(boolean()) -> gleam@option:option(postgleam@value:value()).
bool(Val) ->
{some, {boolean, Val}}.
-file("src/postgleam.gleam", 256).
?DOC(" Create a NULL parameter.\n").
-spec null() -> gleam@option:option(postgleam@value:value()).
null() ->
none.
-file("src/postgleam.gleam", 261).
?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", 266).
?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", 272).
?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", 280).
?DOC(" Create a JSON parameter.\n").
-spec json(binary()) -> gleam@option:option(postgleam@value:value()).
json(Val) ->
{some, {json, Val}}.
-file("src/postgleam.gleam", 285).
?DOC(" Create a JSONB parameter.\n").
-spec jsonb(binary()) -> gleam@option:option(postgleam@value:value()).
jsonb(Val) ->
{some, {jsonb, Val}}.
-file("src/postgleam.gleam", 290).
?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", 295).
?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", 300).
?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", 305).
?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", 310).
?DOC(" Create a time parameter (microseconds since midnight).\n").
-spec time(integer()) -> gleam@option:option(postgleam@value:value()).
time(Val) ->
{some, {time, Val}}.
-file("src/postgleam.gleam", 315).
?DOC(" Create a timetz parameter (microseconds since midnight, tz offset in seconds).\n").
-spec timetz(integer(), integer()) -> gleam@option:option(postgleam@value:value()).
timetz(Microseconds, Tz_offset) ->
{some, {time_tz, Microseconds, Tz_offset}}.
-file("src/postgleam.gleam", 320).
?DOC(" Create an interval parameter (microseconds, days, months).\n").
-spec interval(integer(), integer(), integer()) -> gleam@option:option(postgleam@value:value()).
interval(Microseconds, Days, Months) ->
{some, {interval, Microseconds, Days, Months}}.
-file("src/postgleam.gleam", 325).
?DOC(" Create an XML parameter.\n").
-spec xml(binary()) -> gleam@option:option(postgleam@value:value()).
xml(Val) ->
{some, {xml, Val}}.
-file("src/postgleam.gleam", 330).
?DOC(" Create a JSONPath parameter.\n").
-spec jsonpath(binary()) -> gleam@option:option(postgleam@value:value()).
jsonpath(Val) ->
{some, {jsonpath, Val}}.
-file("src/postgleam.gleam", 335).
?DOC(" Create a money parameter (int64 cents).\n").
-spec money(integer()) -> gleam@option:option(postgleam@value:value()).
money(Val) ->
{some, {money, Val}}.
-file("src/postgleam.gleam", 340).
?DOC(" Create a point parameter (x, y).\n").
-spec point(float(), float()) -> gleam@option:option(postgleam@value:value()).
point(X, Y) ->
{some, {point, X, Y}}.
-file("src/postgleam.gleam", 345).
?DOC(" Create a circle parameter (center x, center y, radius).\n").
-spec circle(float(), float(), float()) -> gleam@option:option(postgleam@value:value()).
circle(X, Y, Radius) ->
{some, {circle, X, Y, Radius}}.
-file("src/postgleam.gleam", 350).
?DOC(" Create a macaddr parameter (6-byte binary).\n").
-spec macaddr(bitstring()) -> gleam@option:option(postgleam@value:value()).
macaddr(Val) ->
{some, {macaddr, Val}}.
-file("src/postgleam.gleam", 355).
?DOC(" Create a macaddr8 parameter (8-byte binary).\n").
-spec macaddr8(bitstring()) -> gleam@option:option(postgleam@value:value()).
macaddr8(Val) ->
{some, {macaddr8, Val}}.
-file("src/postgleam.gleam", 364).
?DOC(
" Create an array parameter from a list of optional values.\n"
"\n"
" ```gleam\n"
" postgleam.array([Some(value.Integer(1)), Some(value.Integer(2)), None])\n"
" ```\n"
).
-spec array(list(gleam@option:option(postgleam@value:value()))) -> gleam@option:option(postgleam@value:value()).
array(Val) ->
{some, {array, Val}}.
-file("src/postgleam.gleam", 369).
?DOC(" Create a line parameter (Ax + By + C = 0).\n").
-spec line(float(), float(), float()) -> gleam@option:option(postgleam@value:value()).
line(A, B, C) ->
{some, {line, A, B, C}}.
-file("src/postgleam.gleam", 374).
?DOC(" Create a line segment parameter (two endpoints).\n").
-spec lseg(float(), float(), float(), float()) -> gleam@option:option(postgleam@value:value()).
lseg(X1, Y1, X2, Y2) ->
{some, {lseg, X1, Y1, X2, Y2}}.
-file("src/postgleam.gleam", 379).
?DOC(" Create a box parameter (upper-right and lower-left corners).\n").
-spec box(float(), float(), float(), float()) -> gleam@option:option(postgleam@value:value()).
box(X1, Y1, X2, Y2) ->
{some, {box, X1, Y1, X2, Y2}}.
-file("src/postgleam.gleam", 384).
?DOC(" Create a path parameter (closed/open flag + list of points).\n").
-spec path(boolean(), list({float(), float()})) -> gleam@option:option(postgleam@value:value()).
path(Closed, Points) ->
{some, {path, Closed, Points}}.
-file("src/postgleam.gleam", 389).
?DOC(" Create a polygon parameter (list of vertices).\n").
-spec polygon(list({float(), float()})) -> gleam@option:option(postgleam@value:value()).
polygon(Vertices) ->
{some, {polygon, Vertices}}.
-file("src/postgleam.gleam", 395).
?DOC(
" Create an inet/cidr parameter (family, address bytes, netmask).\n"
" Family: 2 for IPv4, 3 for IPv6.\n"
).
-spec inet(integer(), bitstring(), integer()) -> gleam@option:option(postgleam@value:value()).
inet(Family, Address, Netmask) ->
{some, {inet, Family, Address, Netmask}}.
-file("src/postgleam.gleam", 400).
?DOC(" Create a bit string parameter (bit count + data bytes).\n").
-spec bit_string(integer(), bitstring()) -> gleam@option:option(postgleam@value:value()).
bit_string(Bit_count, Data) ->
{some, {bit_string, Bit_count, Data}}.
-file("src/postgleam.gleam", 413).
?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(KOW),
fun((KOW) -> 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", 424).
-spec decode_rows(
list(list(gleam@option:option(postgleam@value:value()))),
postgleam@decode:row_decoder(KPB),
list(KPB)
) -> {ok, list(KPB)} | {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(KNI)
) -> {ok, response(KNI)} | {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", 112).
?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(KNT)
) -> {ok, KNT} | {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.