fix(schema): correct ON DELETE behavior for 5 drifted FKs (#1126)#1411
Merged
Conversation
Schema constraint shape reportdata-shape report errored (exit 0): node:internal/modules/runmain:107 triggerUncaughtException( ^ Error ERRMODULENOTFOUND: Cannot find package 'postgres' imported from /home/runner/work/Backend-Service/Backend-Service/scripts/schema-shape-report.mjs Did you mean to import "postgres/cjs/src/index.js"? at Object.getPackageJ; manual check required |
5 tasks
jakebromberg
added a commit
that referenced
this pull request
Jun 14, 2026
…complete integration coverage Apply five review findings on the #1126 FK ON DELETE drift fix: 1. Migration 0094 now uses ADD CONSTRAINT ... NOT VALID instead of a bare ADD CONSTRAINT. The bare form would have taken AccessExclusiveLock on flowsheet (~857k rows) for the full validation-scan duration, blocking on-air DJ writes during deploy. NOT VALID makes the ADD metadata-only and instant. Drizzle's migrator wraps the whole migration in one transaction (drizzle-orm/pg-core/dialect.js:60), so an in-migration VALIDATE would defeat the lock benefit — VALIDATE is documented as an out-of-band operator step in the header instead. For these five constraints the validation is effectively a no-op anyway: the existing NO ACTION FK already kept the reference relation consistent, and only the ON DELETE action is changing (forward-looking). 2. Integration spec now exercises all three ON DELETE actions in the fix (flowsheet SET NULL, rotation CASCADE, reviews CASCADE) instead of only the flowsheet SET NULL path. The previous spec ran two tests: a static pg_constraint.confdeltype assertion plus a single behavioural test. The behavioural test silently never ran because its library INSERT omitted four NOT NULL columns (artist_id, genre_id, format_id, code_number) and its flowsheet INSERT omitted play_order — so the spec was a false green for the actual cascade/SET-NULL behaviour. 3. Spec now uses the shared getTestDb() pool + withRollback helper from tests/utils/db.js instead of opening its own postgres() connection and rolling back via a hand-written intentional-error idiom. Matches the convention used by neighbouring specs (album-metadata-upsert, enrichment-worker-claim, library-identity-backfill). 4. Inserts now use the seed_db.sql baseline rows (artist 1, genre 11, format 1) to satisfy library's NOT NULL FK columns rather than threading FK resolution through the test. Sequence-assigned ids land at 7200+ (shape fixture sets library_id_seq to 7199), safely above the explicit-id fixture range. Local CI: lint, format:check, typecheck, test:unit all pass. Migration dry-run not available locally (Docker daemon not running); will be covered by CI's migrate-dryrun job since the change touches db-init paths.
Five FK constraints on `wxyc_schema.flowsheet`, `wxyc_schema.rotation`, and `wxyc_schema.reviews` were created with `ON DELETE NO ACTION` in `0000_rare_prima.sql` and recreated unchanged by `0016_nervous_hydra.sql`, but the Drizzle schema source declares them as `SET NULL` (flowsheet) and `CASCADE` (rotation, reviews). Because `meta/0093_snapshot.json` already records the schema-source values, `drizzle-kit generate` produced no fix migration — the drift was invisible to the normal authoring loop. Migration 0094 drops + recreates the five FKs with the intended ON DELETE behaviour, following the pattern in `0048_fix-fk-on-delete-set-null.sql` (the predecessor that patched the analogous drift for `schedule`, `shift_covers`, `shows.primary_dj_id` per #433). The schema source already encodes the desired state, so no `schema.ts` change is needed; the new snapshot is byte-identical to 0093 except for `id` / `prevId`. A new integration spec (`tests/integration/fk-on-delete-flowsheet-rotation-reviews.spec.js`) asserts `pg_constraint.confdeltype` for all five FKs and exercises the SET NULL behaviour via a parent-row DELETE inside a rolled-back transaction. Complements the existing `tests/unit/database/schema.fk-cascades.test.ts` schema-side guard. Closes #1126.
…complete integration coverage Apply five review findings on the #1126 FK ON DELETE drift fix: 1. Migration 0094 now uses ADD CONSTRAINT ... NOT VALID instead of a bare ADD CONSTRAINT. The bare form would have taken AccessExclusiveLock on flowsheet (~857k rows) for the full validation-scan duration, blocking on-air DJ writes during deploy. NOT VALID makes the ADD metadata-only and instant. Drizzle's migrator wraps the whole migration in one transaction (drizzle-orm/pg-core/dialect.js:60), so an in-migration VALIDATE would defeat the lock benefit — VALIDATE is documented as an out-of-band operator step in the header instead. For these five constraints the validation is effectively a no-op anyway: the existing NO ACTION FK already kept the reference relation consistent, and only the ON DELETE action is changing (forward-looking). 2. Integration spec now exercises all three ON DELETE actions in the fix (flowsheet SET NULL, rotation CASCADE, reviews CASCADE) instead of only the flowsheet SET NULL path. The previous spec ran two tests: a static pg_constraint.confdeltype assertion plus a single behavioural test. The behavioural test silently never ran because its library INSERT omitted four NOT NULL columns (artist_id, genre_id, format_id, code_number) and its flowsheet INSERT omitted play_order — so the spec was a false green for the actual cascade/SET-NULL behaviour. 3. Spec now uses the shared getTestDb() pool + withRollback helper from tests/utils/db.js instead of opening its own postgres() connection and rolling back via a hand-written intentional-error idiom. Matches the convention used by neighbouring specs (album-metadata-upsert, enrichment-worker-claim, library-identity-backfill). 4. Inserts now use the seed_db.sql baseline rows (artist 1, genre 11, format 1) to satisfy library's NOT NULL FK columns rather than threading FK resolution through the test. Sequence-assigned ids land at 7200+ (shape fixture sets library_id_seq to 7199), safely above the explicit-id fixture range. Local CI: lint, format:check, typecheck, test:unit all pass. Migration dry-run not available locally (Docker daemon not running); will be covered by CI's migrate-dryrun job since the change touches db-init paths.
The static-assertion test in fk-on-delete-flowsheet-rotation-reviews.spec.js
was failing CI with `op ANY/ALL (array) requires array on right side`
because `sql.array(arr)` (without a type argument) does not bind the value
as a Postgres text[] in postgres-js. The canonical idiom in this codebase
(flowsheet-etl-setwhere.spec.js:61, album-metadata-upsert.spec.js:159,
enrichment-worker-sweep.spec.js:63) is `ANY(${arr})` with a bare JS array —
postgres-js infers the array type from the values. This test was failing
on the previous CI run too (pre-review-fix); this commit clears the
inherited bug.
813d1c2 to
b55f2fc
Compare
jakebromberg
added a commit
that referenced
this pull request
Jun 14, 2026
…complete integration coverage Apply five review findings on the #1126 FK ON DELETE drift fix: 1. Migration 0094 now uses ADD CONSTRAINT ... NOT VALID instead of a bare ADD CONSTRAINT. The bare form would have taken AccessExclusiveLock on flowsheet (~857k rows) for the full validation-scan duration, blocking on-air DJ writes during deploy. NOT VALID makes the ADD metadata-only and instant. Drizzle's migrator wraps the whole migration in one transaction (drizzle-orm/pg-core/dialect.js:60), so an in-migration VALIDATE would defeat the lock benefit — VALIDATE is documented as an out-of-band operator step in the header instead. For these five constraints the validation is effectively a no-op anyway: the existing NO ACTION FK already kept the reference relation consistent, and only the ON DELETE action is changing (forward-looking). 2. Integration spec now exercises all three ON DELETE actions in the fix (flowsheet SET NULL, rotation CASCADE, reviews CASCADE) instead of only the flowsheet SET NULL path. The previous spec ran two tests: a static pg_constraint.confdeltype assertion plus a single behavioural test. The behavioural test silently never ran because its library INSERT omitted four NOT NULL columns (artist_id, genre_id, format_id, code_number) and its flowsheet INSERT omitted play_order — so the spec was a false green for the actual cascade/SET-NULL behaviour. 3. Spec now uses the shared getTestDb() pool + withRollback helper from tests/utils/db.js instead of opening its own postgres() connection and rolling back via a hand-written intentional-error idiom. Matches the convention used by neighbouring specs (album-metadata-upsert, enrichment-worker-claim, library-identity-backfill). 4. Inserts now use the seed_db.sql baseline rows (artist 1, genre 11, format 1) to satisfy library's NOT NULL FK columns rather than threading FK resolution through the test. Sequence-assigned ids land at 7200+ (shape fixture sets library_id_seq to 7199), safely above the explicit-id fixture range. Local CI: lint, format:check, typecheck, test:unit all pass. Migration dry-run not available locally (Docker daemon not running); will be covered by CI's migrate-dryrun job since the change touches db-init paths.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #1126.
Summary
Five FK constraints on
wxyc_schema.flowsheet,wxyc_schema.rotation, andwxyc_schema.reviewswere created withON DELETE NO ACTIONin0000_rare_prima.sqland recreated unchanged by0016_nervous_hydra.sql, but the Drizzle schema source declares them as:Because
meta/0093_snapshot.jsonalready records the schema-source values,drizzle-kit generateproduced no fix migration — the drift was invisible to the normal authoring loop. New environments diverge from prod and deleting a parent row inshowsorlibraryraises23503 foreign_key_violationthe application code is written to expect would be auto-handled.Changes
shared/database/src/migrations/0094_fix-fk-on-delete-flowsheet-rotation-reviews.sql— DROP + ADD each of the five FKs with the intended ON DELETE behaviour. Follows the same shape as0048_fix-fk-on-delete-set-null.sql(the predecessor that patched the analogous drift forschedule/shift_covers/shows.primary_dj_idper FK constraints on schedule, shift_covers, and shows use NO ACTION instead of SET NULL #433; this migration is the missed remainder).shared/database/src/migrations/meta/_journal.json— append idx 94,when = previous + 1ms.shared/database/src/migrations/meta/0094_snapshot.json— byte-identical to 0093 except forid/prevId(no schema change; only DB-side action is patched).shared/database/src/migrations/meta/applied-hashes.json—npm run drizzle:freeze-hashes.tests/integration/fk-on-delete-flowsheet-rotation-reviews.spec.js— assertspg_constraint.confdeltypefor all five FKs against the live DB and exercises the SET NULL behaviour via a parent-row DELETE inside a rolled-back transaction. Complements the existingtests/unit/database/schema.fk-cascades.test.tsschema-side guard.schema.tsis unchanged because the source already declares the intendedonDeleteactions — the drift is purely between migration history and schema.Verification
Test plan
npm run lint:migrations— passes (93 entries→ now 94; only the historical idx-47 duplicate warning).npm run format:check— passes.npm run lint— 0 errors (525 pre-existing warnings unchanged).npm run typecheck— passes.npm run test:unit— 3151 passed (228 suites), including the predecessorschema.fk-cascades.test.tswhich asserts the schema-side declaration.migrate-dryrunjob — will fire automatically (paths-filterdb-initmatchesshared/database/src/migrations/**). The dry-run restores the latest prod RDS snapshot and runsscripts/dryrun-migrate.mjs, exercising the new migration against prod-shaped data.integration-tests— will run the new spec against the per-worker schema in Docker.Related
schedule/shift_covers/shows.primary_dj_idvia0048_fix-fk-on-delete-set-null.sql. This PR is the missed remainder.