# `Ramal.Capture`
[🔗](https://github.com/agustinrojas1/ramal/blob/v0.2.0/lib/ramal/capture.ex#L1)

The change `Ramal.Resource` installs on every create, update and destroy action.

Inside `Ramal.run/2` it replaces "write this row to the data layer" with "put this row in the branch's overlay".
Everything else about the action still happens: argument casting, validations, policies, defaults, timestamps and
the action's own `before_action` and `after_action` hooks. Outside a branch it does nothing.

What the action returns is what the action would have returned: a created or updated record, or the destroyed one.
The write is also appended to the branch log so that `Ramal.merge/2` can replay the action later.

How it works, confirmed against Ash 3.37 (`lib/ash/changeset/changeset.ex` and `lib/ash/actions/*`):

  * `Ash.Changeset.around_action/3` wraps the before-action hooks, the data-layer call and the after-action hooks.
    The around hook adds one more `before_action`, so that it is the last of them and sees the changeset as every
    other hook left it.
  * That hook builds the record with `Ash.Changeset.apply_attributes/2`, which also applies defaults, and calls
    `Ash.Changeset.set_result/2`. The create, update and destroy actions skip the data layer when a result is set
    and carry on with relationship management and the after-action hooks.
  * An update runs `fully_atomic_changeset` first and, when it succeeds, updates the row in the database without
    calling any hook. `atomic/3` therefore reports `{:not_atomic, reason}` while a branch is current, and
    the resource transformer sets `require_atomic? false` so Ash falls back to the path above.
  * Bulk actions call the data layer directly and never look at the result, so they are refused. Upserts too:
    the branch cannot know whether the row exists in the base.

A failed action leaves the branch as it found it: the writes of the action and of the actions its hooks ran are
taken back. A write made by a hook of another captured action is logged with `nested?: true`, because replaying the
outer action runs the hook again.

## Example

    {:ok, branch} = Ramal.branch(MyApp.Farm)

    Ramal.run!(branch, fn ->
      herd = Ash.create!(MyApp.Farm.Herd, %{name: "R7", head: 40})
      Ash.destroy!(herd)
    end)
    # The database was not written; the branch log holds the create and the destroy.

---

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