# `PhoenixMountable.Backfill`
[🔗](https://github.com/hattoriai/phoenix_mountable/blob/v0.2.1/lib/phoenix_mountable/backfill.ex#L2)

Data migrations, kept apart from schema changes and run in batches.

Filling a new column on a table with millions of rows inside a migration
holds locks for minutes and blocks the deploy. A backfill runs in batches
instead: inline in the migration for small tables, or deferred to a process
in the running app after the deploy, recording its progress after every
batch so it resumes where it stopped after a crash or a restart.

    defmodule MyLib.Backfills.Slugs do
      use PhoenixMountable.Backfill,
        table: "my_lib_items",
        where: "slug IS NULL",
        set: "slug = LOWER(title)",
        batch_size: 1_000
    end

    # in a migration version
    def up(ctx) do
      alter table(:my_lib_items, prefix: ctx.prefix), do: add(:slug, :string)
      backfill(ctx, MyLib.Backfills.Slugs)
    end

A later contract version that relies on the data declares
`requires_backfills: [MyLib.Backfills.Slugs]`, and refuses to run until the
backfill has finished.

## Options

  * `:mode` — `:inline` (the default) runs every batch inside the migration;
    `:deferred` records the backfill as pending, to be run by
    `PhoenixMountable.Backfill.Runner` (or `mix phoenix_mountable.backfill`).
    The host overrides it for a migration with
    `up(version: n, backfills: :deferred)`.
  * `:batch_size` — rows per batch. Defaults to `1_000`.
  * `:throttle` — milliseconds to wait between batches (deferred mode).
    Defaults to `0`.

For the common case, an `UPDATE` keyed by an ordered column:

  * `:table` — the table.
  * `:key` — the column to paginate by. Defaults to `"id"`.
  * `:where` — an SQL condition selecting the rows still to fill.
  * `:set` — the SQL assignments.

For anything else, implement `c:batch/3` instead.

# `batch`

```elixir
@callback batch(
  PhoenixMountable.Migrations.Context.t(),
  cursor :: term(),
  batch_size :: pos_integer()
) ::
  {:cont, term(), non_neg_integer()} | :done
```

Processes one batch after `cursor` (`nil` for the first), returning the
cursor to continue from and the number of rows processed, or `:done`.

Runs in a transaction together with the recording of the new cursor, so a
batch is either fully done and recorded, or not at all.

---

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