Current section
Files
Jump to
Current section
Files
src/ducky@connection.erl
-module(ducky@connection).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/ducky/connection.gleam").
-export([connect/1, close/1, path/1, native/1, with_connection/2, transaction/2]).
-export_type([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.
?MODULEDOC(" Database connection management.\n").
-opaque connection() :: {connection,
ducky@internal@ffi:native_connection(),
binary()}.
-file("src/ducky/connection.gleam", 25).
?DOC(
" Opens a connection to a DuckDB database.\n"
"\n"
" Must call `close()` when done. Use `with_connection()` instead\n"
" for automatic cleanup.\n"
"\n"
" ```gleam\n"
" connect(\":memory:\")\n"
" // => Ok(Connection(...))\n"
"\n"
" connect(\"data.duckdb\")\n"
" // => Ok(Connection(...))\n"
" ```\n"
).
-spec connect(binary()) -> {ok, connection()} | {error, ducky@error:error()}.
connect(Path) ->
case Path of
<<""/utf8>> ->
{error, {connection_failed, <<"path cannot be empty"/utf8>>}};
_ ->
_pipe = ducky_nif:connect(Path),
_pipe@1 = gleam@result:map(
_pipe,
fun(Native) -> {connection, Native, Path} end
),
gleam@result:map_error(
_pipe@1,
fun ducky@internal@error_decoder:decode_nif_error/1
)
end.
-file("src/ducky/connection.gleam", 48).
?DOC(
" Closes a database connection.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" let assert Ok(conn) = connect(\":memory:\")\n"
" let assert Ok(_) = close(conn)\n"
" ```\n"
"\n"
" ## Errors\n"
"\n"
" Returns an error if the connection cannot be closed.\n"
).
-spec close(connection()) -> {ok, nil} | {error, ducky@error:error()}.
close(Connection) ->
_pipe = ducky_nif:close(erlang:element(2, Connection)),
_pipe@1 = gleam@result:map(_pipe, fun(_) -> nil end),
gleam@result:map_error(
_pipe@1,
fun ducky@internal@error_decoder:decode_nif_error/1
).
-file("src/ducky/connection.gleam", 55).
?DOC(" Returns the database path for a connection.\n").
-spec path(connection()) -> binary().
path(Connection) ->
erlang:element(3, Connection).
-file("src/ducky/connection.gleam", 62).
?DOC(
" Returns the native connection handle for FFI calls.\n"
"\n"
" This is an internal function for use by other modules in the ducky package.\n"
).
-spec native(connection()) -> ducky@internal@ffi:native_connection().
native(Connection) ->
erlang:element(2, Connection).
-file("src/ducky/connection.gleam", 74).
?DOC(
" Executes operations with automatic connection cleanup.\n"
"\n"
" Connection closes automatically on success or error.\n"
"\n"
" ```gleam\n"
" use conn <- with_connection(\":memory:\")\n"
" query.query(conn, \"SELECT 42\")\n"
" ```\n"
).
-spec with_connection(
binary(),
fun((connection()) -> {ok, DRK} | {error, ducky@error:error()})
) -> {ok, DRK} | {error, ducky@error:error()}.
with_connection(Path, Callback) ->
gleam@result:'try'(
connect(Path),
fun(Conn) ->
Result = Callback(Conn),
_ = close(Conn),
Result
end
).
-file("src/ducky/connection.gleam", 94).
?DOC(
" Executes operations within a transaction.\n"
"\n"
" Commits on success, rolls back on error.\n"
"\n"
" ```gleam\n"
" transaction(conn, fn(conn) {\n"
" use _ <- result.try(query.query(conn, \"UPDATE accounts ...\"))\n"
" query.query(conn, \"SELECT * FROM accounts\")\n"
" })\n"
" ```\n"
).
-spec transaction(
connection(),
fun((connection()) -> {ok, DRP} | {error, ducky@error:error()})
) -> {ok, DRP} | {error, ducky@error:error()}.
transaction(Conn, Callback) ->
gleam@result:'try'(
begin
_pipe = ducky_nif:execute_query(
erlang:element(2, Conn),
<<"BEGIN TRANSACTION"/utf8>>,
[]
),
_pipe@1 = gleam@result:map(_pipe, fun(_) -> nil end),
gleam@result:map_error(
_pipe@1,
fun ducky@internal@error_decoder:decode_nif_error/1
)
end,
fun(_) -> case Callback(Conn) of
{ok, Value} ->
gleam@result:'try'(
begin
_pipe@2 = ducky_nif:execute_query(
erlang:element(2, Conn),
<<"COMMIT"/utf8>>,
[]
),
_pipe@3 = gleam@result:map(
_pipe@2,
fun(_) -> nil end
),
gleam@result:map_error(
_pipe@3,
fun ducky@internal@error_decoder:decode_nif_error/1
)
end,
fun(_) -> {ok, Value} end
);
{error, Err} ->
_ = begin
_pipe@4 = ducky_nif:execute_query(
erlang:element(2, Conn),
<<"ROLLBACK"/utf8>>,
[]
),
gleam@result:map(_pipe@4, fun(_) -> nil end)
end,
{error, Err}
end end
).