# `MishkaInstaller.Helper.MnesiaAssistant.Transaction`
[🔗](https://github.com/mishka-group/mishka_installer/blob/v0.1.16/lib/helper/mnesia_assistant/transaction.ex#L1)

Runs Mnesia activities and maps aborted results to the installer's error shape.

# `dirty`

```elixir
@spec dirty((-&gt; any())) :: {:atomic, any()} | {:aborted, term()}
```

Runs `fun`, a function of dirty reads (`MishkaInstaller.Helper.MnesiaAssistant.Query`'s `dirty_*`
functions), and answers like `transaction/1`: `{:atomic, result}`, or `{:aborted, reason}` when
Mnesia aborts a read because it is not running or the table does not exist.

A dirty read looks the record up in the node's own ETS copy of the table. It takes no lock and
sends nothing to Mnesia's transaction or lock manager, so concurrent readers never queue behind
one process, and a read never waits for a write that holds the record. It sees every record as
last committed; the writes stay in `durable_transaction/1`, which re-reads under a write lock.

The `catch` is the boundary where Mnesia's abort exit becomes `{:aborted, reason}`: a read that
succeeds runs no exception code.

# `durable_transaction`

```elixir
@spec durable_transaction((-&gt; any())) :: {:atomic, any()} | {:aborted, term()}
```

Runs `fun` inside a **durable** transaction: `:mnesia.sync_transaction/1` to commit on every node
holding a copy of the table, then `:mnesia.sync_log/0` to flush the transaction log to disk before
returning.

Use it for writes that must survive an unclean node exit. `transaction/1` alone buffers the commit
and only reaches the disk on the periodic dump (`dump_log_time_threshold`, three minutes by
default), so a node that dies in between comes back with the old record — and a plugin's
`:stopped`/`:started` status is an operator's setting, not a cache.

Returns `{:atomic, result}` or `{:aborted, reason}`.

# `ets`

```elixir
@spec ets((-&gt; any())) :: any()
```

Runs `fun` as a fast, dirty `ets` activity. Delegates to `:mnesia.ets/1`.

> Only safe for `ram_copies` tables or read-only access on `disc_copies`.

# `transaction`

```elixir
@spec transaction((-&gt; any())) :: {:atomic, any()} | {:aborted, term()}
```

Runs `fun` inside a Mnesia transaction. Delegates to `:mnesia.transaction/1`.

Returns `{:atomic, result}` or `{:aborted, reason}`.

# `transaction_error`

```elixir
@spec transaction_error(term(), module(), String.t(), atom(), atom()) ::
  {:error, [map()]}
```

Builds a standard `{:error, [map]}` from an aborted transaction `reason`.

The returned map carries `:message`, `:field`, `:action` and the raw `:source` error, so callers
can surface a consistent error across the codebase.

## Example

```elixir
transaction_error(reason, MyTable, "reading", :global, :database)
```

---

*Consult [api-reference.md](api-reference.md) for complete listing*
