Generates a single Ecto migration file for every entity in a
Caravela.Schema.Domain.
Returns {path, source} — the caller writes the file. The migration
file name is timestamped so subsequent runs produce a distinct file.
Deterministic output
By default the migration's filename prefix is now() in UTC. For
snapshot tests, demos, or any scenario where you want byte-stable
output across runs, pass :timestamp:
Caravela.Gen.Migration.render(domain, timestamp: "00000000000000")Without this pin, every render produces a new path and snapshot diffs always appear as "add + remove".
Summary
Functions
@spec existing_migration_basename(Caravela.Schema.Domain.t(), Path.t()) :: String.t() | nil
Locate an existing migration file for the domain's create-tables
step, relative to root.
Returns the file's basename (e.g.
"20260417094708_create_library_tables.exs") when a prior
migration with the same stem exists, or nil when none does.
Reuse its 14-digit timestamp prefix to overwrite the same file on
regeneration instead of appending a duplicate (see
reconcile_timestamp/2).
When more than one matching migration is present (a symptom of prior regenerations that didn't reconcile), the oldest one is returned — regenerating against it lets the caller consolidate state while still surfacing the duplicates for manual cleanup.
@spec reconcile_timestamp(Caravela.Schema.Domain.t(), Path.t()) :: {String.t(), [String.t()]}
Decide which timestamp render/2 should use given the current
filesystem state:
- No matching migration on disk →
default_timestamp/0. - Exactly one matching migration → reuse its timestamp, so
render/2produces the same path (idempotent regeneration). - More than one matching migration → reuse the oldest timestamp and return the extras so the caller can warn about the drift.
Returns {timestamp, duplicates} where duplicates is a list of
basenames callers should flag or clean up.
Render the migration for the domain.
Options:
:timestamp— override the numeric prefix (defaults tonow())