# `Arangox.Transaction`
[🔗](https://github.com/ArangoDB-Community/arangox/blob/v0.8.0/lib/arangox/transaction.ex#L1)

A handle to an ArangoDB stream transaction, carried as a value.

`Arangox.begin_transaction/2` returns one. The handle form's functions
(`Arangox.commit_transaction/3`, `Arangox.abort_transaction/3`,
`Arangox.transaction_status/3`) and the `:transaction` per-request option
accept only this struct, never a bare identifier binary.

## Identity travels in the request, never in the connection

Where `Arangox.transaction/3` binds a transaction to one checked-out
connection for the span of a closure, a handle carries the transaction's
identity as a value. A request made with `transaction: handle` sends the
identifier in its own `x-arango-trx-id` header, for that request only —
connection state is never written, so a checked-in connection cannot carry
one caller's transaction to the next.

Any pooled connection to the same deployment can therefore serve any request
of the transaction. Verified against an ArangoDB 3.12 cluster (3.12.4, three
coordinators): a transaction begun through one coordinator accepted writes,
served isolated reads, reported status, and committed or aborted through the
other coordinators — the identifier encodes the issuing coordinator and
foreign coordinators forward to it. That is the measured scope: any
connection, any coordinator, one deployment. A handle means nothing to a
different deployment, and this states measured behaviour rather than an
unconditional promise about future server versions.

## The identifier is a bearer capability

Any code that can reach the deployment with the pool's credentials and holds
the identifier can read and write inside the transaction, commit it, or
abort it. Server-assigned identifiers are sequential, so an identifier is
also a hint about its neighbours. Treat the handle like authentication
material: do not let it cross a trust boundary, and keep it out of URLs,
logs and telemetry.

The driver treats it that way itself: the identifier is redacted from
`inspect/1` of this struct, from the headers of the request struct that
`Arangox.request/6` echoes back, and from every error message the driver
constructs. (The *server's* error messages may name the identifier — they
are returned verbatim in `Arangox.Error`'s `:message`, as documented there.)

## Identifier shape

A stream-transaction identifier on the wire is a nonempty string of decimal
digits (`"3298558923352"`). The driver validates that shape before an
identifier reaches a header or a request path, so a malformed value —
anything empty, non-digit, or carrying control characters — is rejected
locally and never goes near the wire. Wrap an identifier obtained outside
this driver with `new/1`, which applies the same validation.

A transaction lives in the database it was begun in: pass the same
`:database` option to the requests, commit, abort and status calls that you
passed to `Arangox.begin_transaction/2`.

# `id`

```elixir
@type id() :: binary()
```

The server-assigned transaction identifier: a nonempty string of decimal digits.

# `t`

```elixir
@type t() :: %Arangox.Transaction{id: id()}
```

A stream-transaction handle. Treat it as authentication material.

# `new`

```elixir
@spec new(id()) :: t()
```

Wraps a transaction identifier obtained outside this driver in a handle.

`Arangox.begin_transaction/2` is the normal way to obtain a handle; this
exists for identifiers that arrive from elsewhere (another process, another
driver, an HTTP header). The identifier must be a nonempty string of decimal
digits — the only shape the server issues — or an `ArgumentError` is raised.
The error never echoes the value, which may be a live transaction identifier.

    iex> Arangox.Transaction.new("3298558923352")
    #Arangox.Transaction<id: "[redacted]">

# `valid_id?`

```elixir
@spec valid_id?(term()) :: boolean()
```

Whether `id` has the shape of a stream-transaction identifier: a nonempty
binary of decimal digits.

    iex> Arangox.Transaction.valid_id?("3298558923352")
    true

    iex> Arangox.Transaction.valid_id?("3298\n5589")
    false

---

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