PhoenixKit.Migrations.Postgres.V176 (phoenix_kit v2.13.12)

Copy Markdown View Source

V176: validate existing NOT VALID foreign keys. Never deletes a row.

Where this comes from

Andi's A002 checked its own premise before writing code: the cascade UUIDFKColumns.@fk_constraints declares for phoenix_kit_users_tokens.user_uuid and phoenix_kit_user_role_assignments.user_uuid already exists and already works — deleting a user with raw SQL, bypassing every application code path, cascades correctly on any schema at V164+ (verified in a rolled-back transaction on a live install). The orphans a prior cleanup removed were rows created BEFORE the constraint existed (17-24 July; the FK repair landed 10 August) — exactly what NOT VALID records: pre-existing rows were never checked, new violations have been impossible since. What never happened is validating it, because nothing in core ever does.

convalidated appears exactly once anywhere in this codebase before this file — inside V164, about constraints IT just created, and V164's own moduledoc says plainly: "re-running it does not retry them … VALIDATE each by hand." Nobody's hand ever did, and mix phoenix_kit.doctor's Orphaned FK check does not report this state at all — it looks for orphan ROWS, which a NOT VALID constraint with zero current violations has none of.

Filed as V175 originally; renumbered to V176 when upstream took V175 for an unrelated Buckets change (phoenix_kit_buckets.integration_uuid) while this branch was still in review. No content changed in the move beyond the version number itself and the COMMENT ON TABLE stamps.

What this does

For every {table, uuid_fk, ref_table, ref_col, _on_delete} in UUIDFKColumns.fk_constraints/0 (the exact list, not a copy — same reason V164 shares it rather than re-declaring): if a foreign key of that exact shape exists — matched by shape (referencing column -> referenced column), not by name, so a constraint V164 adopted under a different name is still found — and is NOT VALID:

  • zero orphaned rows right nowVALIDATE CONSTRAINT. The count is checked FIRST specifically so this never attempts a VALIDATE already known to fail — that is a full table scan under SHARE UPDATE EXCLUSIVE for nothing.
  • one or more orphaned rows → left exactly as it is. Nothing here ever deletes a row or nulls out a reference to force a constraint through — the same policy V164 states for itself, for the same reason: this runs against other people's already-deployed data, not data this call created moments earlier. A warning names the table/column and the real orphan count (PhoenixKit.Migrations.Repair.Probe.orphan_count/6, reused, never a guess), then a one-line end-of-run summary — the per-constraint warnings are easy to lose in a deploy log (same reasoning as V164's report_not_valid_fks/1).

Already-valid constraints, and declarations whose table/column (or the referenced table/column) is absent — an uninstalled feature module, same case V164 skips — are silently left alone: nothing to report, this version has no business with either.

Idempotent: a constraint this pass validates reads convalidated = true on every later run and is skipped instantly (one shape probe, no table scan). A constraint left NOT VALID because of orphans is re-checked fresh on every run — the count is a live read, not cached — so once an operator resolves the rows a re-run validates it with no further action.

down/1

A repair, not a feature — same precedent as V164/V174: rolling back does not un-validate a constraint that is now genuinely clean. Comment restamp only, back to V175 (the Buckets version immediately below this one in the renumbered chain).

Summary

Functions

down(opts)

up(opts)