Search documentation of Ragex

# Ragex.Editor.Transaction (Ragex v0.4.0)

View Source

Multi-file atomic edit transactions.

Provides transaction-like semantics for editing multiple files:

- All-or-nothing atomicity
- Coordinated backups across files
- Validation of all files before committing
- Automatic rollback on any failure

## Summary

### Types

file_edit()

A single file edit within a transaction.

t()

A transaction containing multiple file edits.

transaction_result()

Result of a transaction commit.

### Functions

add(transaction, path, changes, opts \\ [])

Adds a file edit to the transaction.

commit(transaction)

Commits the transaction, applying all edits atomically.

new(opts \\ [])

Creates a new empty transaction.

validate(transaction)

Validates all edits in the transaction without applying them.

## Types

# file_edit()

    @type file_edit() :: %{
      path: String.t(),
      changes: [Ragex.Editor.Types.change()],
      opts: keyword()
    }

A single file edit within a transaction.

# t()

    @type t() :: %Ragex.Editor.Transaction{edits: [file_edit()], opts: keyword()}

A transaction containing multiple file edits.

# transaction_result()

    @type transaction_result() :: %{
      status: :success | :failure,
      files_edited: non_neg_integer(),
      results: [Ragex.Editor.Types.edit_result()],
      errors: [term()],
      rolled_back: boolean()
    }

Result of a transaction commit.

## Functions

# add(transaction, path, changes, opts \\ [])

    @spec add(t(), String.t(), [Ragex.Editor.Types.change()], keyword()) :: t()

Adds a file edit to the transaction.

## Parameters

- `transaction`: The transaction to add to
- `path`: Path to the file
- `changes`: List of changes to apply
- `opts`: Per-file options (override transaction defaults)

## Examples

    iex> txn = Transaction.new()
    iex> txn = Transaction.add(txn, "lib/file1.ex", [Types.replace(1, 1, "new")])
    iex> txn = Transaction.add(txn, "lib/file2.ex", [Types.replace(2, 2, "new")])

# commit(transaction)

    @spec commit(t()) :: {:ok, transaction_result()} | {:error, transaction_result()}

Commits the transaction, applying all edits atomically.

If any edit fails (including validation), all changes are rolled back and the transaction returns an error.

## Process

1. Validate all edits
2. Create backups for all files
3. Apply all edits
4. If any step fails, rollback all changes

## Returns

- `{:ok, result}` if all edits succeeded
- `{:error, result}` if any edit failed (includes rollback status)

## Examples

    iex> txn = Transaction.new()
    iex>   |> Transaction.add("lib/file1.ex", changes1)
    iex>   |> Transaction.add("lib/file2.ex", changes2)
    iex> Transaction.commit(txn)
    {:ok, %{status: :success, files_edited: 2, ...}}

# new(opts \\ [])

    @spec new(keyword()) :: t()

Creates a new empty transaction.

## Examples

    iex> Transaction.new()
    %Transaction{edits: [], opts: []}

    iex> Transaction.new(validate: false)
    %Transaction{edits: [], opts: [validate: false]}

# validate(transaction)

    @spec validate(t()) :: {:ok, :valid} | {:error, [{String.t(), term()}]}

Validates all edits in the transaction without applying them.

Returns {:ok, :valid} if all edits are valid, or {:error, errors} with details about which files failed validation.

## Examples

    iex> txn = Transaction.new() |> Transaction.add("lib/file.ex", changes)
    iex> Transaction.validate(txn)
    {:ok, :valid}