AshCommanded.Commanded.Transaction (AshCommanded v0.1.0)

View Source

Transaction support for command execution in AshCommanded.

This module provides functionality for wrapping command execution inside database transactions, ensuring atomicity of operations across multiple resources and commands.

Transactions can be used in two ways:

  1. Automatically based on command configuration in the DSL
  2. Manually by wrapping command execution in a transaction block

Features

  • Supports single command transactions
  • Supports multi-command transactions
  • Integrates with Ash Repository transactions
  • Handles rollback on error
  • Provides transaction options (timeout, isolation level)

Summary

Types

Function that will be executed within a transaction

Options for transaction execution

Functions

Executes multiple commands in a single transaction.

Executes a function within a transaction.

Checks whether a repository supports transactions.

Types

transaction_function()

@type transaction_function() :: (-> any())

Function that will be executed within a transaction

transaction_options()

@type transaction_options() :: [
  timeout: pos_integer(),
  isolation_level: :read_committed | :repeatable_read | :serializable
]

Options for transaction execution

Functions

execute_commands(repo, commands, opts \\ [])

@spec execute_commands(module(), [map()], transaction_options()) ::
  {:ok, map()} | {:error, any(), any(), %{required(atom()) => any()}}

Executes multiple commands in a single transaction.

Parameters

  • repo - The repository to use for the transaction
  • commands - List of commands to execute, each with resource and action
  • opts - Transaction options

Command Structure

Each command in the list should be a map with these keys:

  • :command - The command struct to execute
  • :resource - The resource module
  • :action - The action name (atom)
  • :opts - (Optional) Command-specific options

Returns

  • {:ok, result_map} - Map of results from all commands
  • {:error, failed_operation, failed_value, changes_so_far} - Error information

Examples

iex> AshCommanded.Commanded.Transaction.execute_commands(MyApp.Repo, [
...>   %{command: create_user_cmd, resource: MyApp.User, action: :create},
...>   %{command: create_profile_cmd, resource: MyApp.Profile, action: :create}
...> ])
{:ok, %{create_user: %MyApp.User{...}, create_profile: %MyApp.Profile{...}}}

run(repo, fun, opts \\ [])

@spec run(module(), transaction_function(), transaction_options()) ::
  {:ok, any()} | {:error, any()}

Executes a function within a transaction.

Parameters

  • repo - The repository to use for the transaction
  • fun - The function to execute inside the transaction
  • opts - Transaction options

Options

  • :timeout - Transaction timeout in milliseconds
  • :isolation_level - Transaction isolation level (:read_committed, :repeatable_read, or :serializable)

Returns

  • {:ok, result} - The result of the function, if the transaction succeeded
  • {:error, reason} - The error that caused the transaction to roll back

Examples

iex> AshCommanded.Commanded.Transaction.run(MyApp.Repo, fn ->
...>   # Execute commands or actions
...>   AshCommanded.Commanded.CommandActionMapper.map_to_action(command, resource, action)
...> end)
{:ok, %MyApp.User{id: "123", name: "John"}}

supports_transactions?(repo)

@spec supports_transactions?(module()) :: boolean()

Checks whether a repository supports transactions.

Parameters

  • repo - The repository to check

Returns

  • true - If the repository supports transactions
  • false - If the repository does not support transactions

Examples

iex> AshCommanded.Commanded.Transaction.supports_transactions?(MyApp.Repo)
true

iex> AshCommanded.Commanded.Transaction.supports_transactions?(MyApp.InMemoryRepo)
false