Packages

A lean Elixir wrapper for ArcadeDB's REST API with connection pooling, transactions, and database switching.

Current section

Files

Jump to
arcadex test integration transaction_test.exs
Raw

test/integration/transaction_test.exs

defmodule Arcadex.Integration.TransactionTest do
@moduledoc """
Integration tests for transaction operations against ArcadeDB.
"""
use Arcadex.IntegrationCase, async: true
setup_all %{conn: conn} do
Arcadex.command!(conn, "CREATE DOCUMENT TYPE Account")
Arcadex.command!(conn, "CREATE PROPERTY Account.uid STRING")
Arcadex.command!(conn, "CREATE PROPERTY Account.balance INTEGER")
Arcadex.command!(conn, "CREATE INDEX ON Account (uid) UNIQUE")
:ok
end
describe "transaction commit" do
test "transaction commits on success", %{conn: conn} do
uid = generate_uid()
{:ok, [account]} =
Arcadex.transaction(conn, fn tx ->
Arcadex.command!(
tx,
"INSERT INTO Account SET uid = :uid, balance = 100",
%{uid: uid}
)
end)
assert account["uid"] == uid
assert account["balance"] == 100
# Verify data persisted
[found] =
Arcadex.query!(
conn,
"SELECT FROM Account WHERE uid = :uid",
%{uid: uid}
)
assert found["balance"] == 100
end
test "transaction returns function result", %{conn: conn} do
uid = generate_uid()
{:ok, result} =
Arcadex.transaction(conn, fn tx ->
[account] =
Arcadex.command!(
tx,
"INSERT INTO Account SET uid = :uid, balance = 200",
%{uid: uid}
)
%{rid: account["@rid"], balance: account["balance"]}
end)
assert result.balance == 200
assert result.rid
end
end
describe "transaction rollback" do
test "transaction rolls back on error", %{conn: conn} do
uid = generate_uid()
result =
Arcadex.transaction(conn, fn tx ->
Arcadex.command!(
tx,
"INSERT INTO Account SET uid = :uid, balance = 100",
%{uid: uid}
)
# Force an error with invalid SQL
Arcadex.command!(tx, "INVALID SQL SYNTAX")
end)
assert {:error, _error} = result
# Verify data was NOT persisted
found =
Arcadex.query!(
conn,
"SELECT FROM Account WHERE uid = :uid",
%{uid: uid}
)
assert found == []
end
test "transaction rolls back on raise", %{conn: conn} do
uid = generate_uid()
result =
Arcadex.transaction(conn, fn tx ->
Arcadex.command!(
tx,
"INSERT INTO Account SET uid = :uid, balance = 100",
%{uid: uid}
)
raise "Intentional error"
end)
assert {:error, _error} = result
# Verify data was NOT persisted
found =
Arcadex.query!(
conn,
"SELECT FROM Account WHERE uid = :uid",
%{uid: uid}
)
assert found == []
end
end
describe "multiple operations in transaction" do
test "multiple commands in single transaction", %{conn: conn} do
uid1 = generate_uid()
uid2 = generate_uid()
{:ok, _} =
Arcadex.transaction(conn, fn tx ->
Arcadex.command!(
tx,
"INSERT INTO Account SET uid = :uid, balance = 100",
%{uid: uid1}
)
Arcadex.command!(
tx,
"INSERT INTO Account SET uid = :uid, balance = 200",
%{uid: uid2}
)
end)
# Verify both accounts exist
[account1] =
Arcadex.query!(
conn,
"SELECT FROM Account WHERE uid = :uid",
%{uid: uid1}
)
[account2] =
Arcadex.query!(
conn,
"SELECT FROM Account WHERE uid = :uid",
%{uid: uid2}
)
assert account1["balance"] == 100
assert account2["balance"] == 200
end
test "transfer between accounts in transaction", %{conn: conn} do
uid1 = generate_uid()
uid2 = generate_uid()
# Create initial accounts
Arcadex.command!(
conn,
"INSERT INTO Account SET uid = :uid, balance = 100",
%{uid: uid1}
)
Arcadex.command!(
conn,
"INSERT INTO Account SET uid = :uid, balance = 50",
%{uid: uid2}
)
# Transfer 30 from account1 to account2
{:ok, _} =
Arcadex.transaction(conn, fn tx ->
Arcadex.command!(
tx,
"UPDATE Account SET balance = balance - 30 WHERE uid = :uid",
%{uid: uid1}
)
Arcadex.command!(
tx,
"UPDATE Account SET balance = balance + 30 WHERE uid = :uid",
%{uid: uid2}
)
end)
# Verify balances
[account1] =
Arcadex.query!(
conn,
"SELECT FROM Account WHERE uid = :uid",
%{uid: uid1}
)
[account2] =
Arcadex.query!(
conn,
"SELECT FROM Account WHERE uid = :uid",
%{uid: uid2}
)
assert account1["balance"] == 70
assert account2["balance"] == 80
end
test "all operations rollback on failure", %{conn: conn} do
uid1 = generate_uid()
uid2 = generate_uid()
# Create initial account
Arcadex.command!(
conn,
"INSERT INTO Account SET uid = :uid, balance = 100",
%{uid: uid1}
)
# Attempt transaction that will fail
result =
Arcadex.transaction(conn, fn tx ->
# First operation succeeds
Arcadex.command!(
tx,
"UPDATE Account SET balance = balance - 50 WHERE uid = :uid",
%{uid: uid1}
)
# Second operation succeeds
Arcadex.command!(
tx,
"INSERT INTO Account SET uid = :uid, balance = 50",
%{uid: uid2}
)
# Third operation fails
raise "Transaction aborted"
end)
assert {:error, _} = result
# Verify first account balance unchanged
[account1] =
Arcadex.query!(
conn,
"SELECT FROM Account WHERE uid = :uid",
%{uid: uid1}
)
assert account1["balance"] == 100
# Verify second account was not created
found =
Arcadex.query!(
conn,
"SELECT FROM Account WHERE uid = :uid",
%{uid: uid2}
)
assert found == []
end
end
end