The library-owned DDL, callable from a host migration — the dirty-frontier
table ReactiveDag.Frontier reads and writes (coalesced by (cell_id, key);
claim is a DELETE … RETURNING):
defmodule MyApp.Repo.Migrations.AddReactiveDag do
use Ecto.Migration
def up, do: ReactiveDag.Migration.up()
def down, do: ReactiveDag.Migration.down()
endThe table name resolves exactly as Frontier's reads do — an explicit
:dirty_table option, else config :reactive_dag, dirty_table:, else
"reactive_dag_dirty" — so a host that sets the config gets a migration
matching the table the runtime queries, with no second place to keep in sync.
Options (both directions):
:dirty_table— override the resolved table name for this migration only (rare; the config is the normal home).
This is the ONLY table the library owns. Every node's results live in that node's own resource, with its own migration — there is no second table shadowing them.
Summary
Functions
Add the tenant column to a frontier table created before it existed.
Drop the dirty-frontier table.
Reverse add_tenant/1.
Create the dirty-frontier table + its coalescing unique index.
Functions
Add the tenant column to a frontier table created before it existed.
For hosts already running the library: up/1 is create_if_not_exists, so
re-running it will NOT add a column to an existing table.
def up, do: ReactiveDag.Migration.add_tenant()
def down, do: ReactiveDag.Migration.remove_tenant()Existing rows become "*" — untenanted, which is what they were. The old
(cell_id, key) index is dropped only after the new one exists, so
mark_dirty's ON CONFLICT is backed by an index at every point.
Drop the dirty-frontier table.
Reverse add_tenant/1.
Create the dirty-frontier table + its coalescing unique index.