Skip to content

feat: add after_tables to custom_statements so raw SQL can depend on another table#799

Merged
zachdaniel merged 2 commits into
ash-project:mainfrom
jechol:migration-ordering-and-after-tables
Jul 23, 2026
Merged

feat: add after_tables to custom_statements so raw SQL can depend on another table#799
zachdaniel merged 2 commits into
ash-project:mainfrom
jechol:migration-ordering-and-after-tables

Conversation

@jechol

@jechol jechol commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Motivation

custom_statements had no way to declare "this depends on another table's structure being finalized first." The only rule was "adds always run last, removes always run first." That breaks for a raw-SQL statement that needs to run after some other table is fully set up — e.g. a composite foreign key referencing a unique index that isn't guaranteed to exist yet.

What changed

AshPostgres.Statement gets a new after_tables option (a list of table name strings) so a statement can declare that dependency explicitly:

custom_statements do
  statement :children_parent_composite_fk do
    after_tables ["parents"]
    up "ALTER TABLE children ADD CONSTRAINT children_parent_fk FOREIGN KEY (region_id, parent_id) REFERENCES parents (region_id, id);"
    down "ALTER TABLE children DROP CONSTRAINT children_parent_fk;"
  end
end

Internally, #798 has a single per-table "doneness" fact, :table_structure_ready — provided by every structural operation (columns, indexes, constraints, etc.) on the table. This PR adds a second, broader fact on top of it:

  • :table_structure_ready (existing) — this table's structural operations are done.
  • :table_finalized (new) — the table is truly done, including any custom_statements declared on it. Provided by everything that provides :table_structure_ready, plus each AddCustomStatement on the table — so a table with no custom statements is finalized as soon as its structure is ready.

A statement's own implicit "wait for my own table" requirement uses the narrower :table_structure_ready, so two statements on the same table never end up requiring each other's completion (a guaranteed cycle if both used the broader fact). A declared after_tables entry uses the broader :table_finalized, so it also waits for the referenced table's own custom statements — not just its structure.

Statements with no after_tables keep the previous default behavior exactly (no declared dependency → best-effort last), so this is fully backwards compatible.

Testing

Builds on the dependency-graph rewrite in #798. New tests in test/migration_generator/operation_deps_test.exs cover: a statement's own-table requirement being satisfied by structural ops, an after_tables requirement being satisfied by another table's custom statement (the actual new capability), and two same-table statements not creating a cycle. Full mix test: 858 passed.

Contributor checklist

Leave anything that you believe does not apply unchecked.

  • I accept the AI Policy, or AI was not used in the creation of this PR.
  • Bug fixes include regression tests
  • Chores
  • Documentation changes
  • Features include unit/acceptance tests
  • Refactoring
  • Update dependencies

@jechol
jechol force-pushed the migration-ordering-and-after-tables branch from bbd0d0a to 5a883ea Compare July 18, 2026 16:54
@jechol
jechol marked this pull request as draft July 18, 2026 17:20
@jechol
jechol force-pushed the migration-ordering-and-after-tables branch 6 times, most recently from 28ccc51 to bd9b300 Compare July 19, 2026 10:05
@jechol
jechol marked this pull request as ready for review July 19, 2026 10:35
@jechol
jechol marked this pull request as draft July 20, 2026 08:26
@zachdaniel

Copy link
Copy Markdown
Contributor

Ready for this to be backmerged

@jechol
jechol force-pushed the migration-ordering-and-after-tables branch from bd9b300 to 2d27e29 Compare July 22, 2026 22:46
@jechol
jechol force-pushed the migration-ordering-and-after-tables branch from 2d27e29 to 251aaec Compare July 22, 2026 22:58
@jechol

jechol commented Jul 22, 2026

Copy link
Copy Markdown
Contributor Author

Done — rebased onto main, full suite passes (879 tests). @zachdaniel ready for another look.

@jechol
jechol marked this pull request as ready for review July 22, 2026 23:29
@zachdaniel
zachdaniel merged commit 314e019 into ash-project:main Jul 23, 2026
99 of 120 checks passed
@zachdaniel

Copy link
Copy Markdown
Contributor

🚀 Thank you for your contribution! 🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants