feat(person): V76 migration — birth/death year to date + precision columns
Pre-check aborts on corrupt year data, backfills YYYY-01-01/YEAR, adds five named CHECK constraints, drops birth_year/death_year. Staged-Flyway Testcontainers test covers pre-check aborts, backfill shapes, and post-migration schema. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
-- V76: persons.birth_year/death_year (integer) → birth_date/death_date (date)
|
||||
-- plus NOT NULL precision columns mirroring documents.meta_date_precision.
|
||||
-- Existing years are backfilled as YYYY-01-01 at YEAR precision (ADR-039).
|
||||
-- One-way migration: rollback is a targeted pg_restore -t persons from the
|
||||
-- pre-deploy backup (see docs/DEPLOYMENT.md).
|
||||
|
||||
-- Pre-check (data quality gate — not a race guard): abort on corrupt year data
|
||||
-- before any DDL runs. Single-writer family archive, so no race window matters.
|
||||
DO $$ BEGIN
|
||||
IF EXISTS (SELECT 1 FROM persons WHERE birth_year IS NOT NULL AND death_year IS NOT NULL AND birth_year > death_year)
|
||||
THEN RAISE EXCEPTION 'V76 aborted: % persons have birth_year > death_year — fix data before migrating',
|
||||
(SELECT COUNT(*) FROM persons WHERE birth_year IS NOT NULL AND death_year IS NOT NULL AND birth_year > death_year);
|
||||
END IF;
|
||||
IF EXISTS (SELECT 1 FROM persons WHERE birth_year = 0 OR death_year = 0)
|
||||
THEN RAISE EXCEPTION 'V76 aborted: persons table contains birth_year=0 or death_year=0 rows — clean data before migrating';
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
ALTER TABLE persons ADD COLUMN birth_date date;
|
||||
ALTER TABLE persons ADD COLUMN birth_date_precision varchar(16) NOT NULL DEFAULT 'UNKNOWN';
|
||||
ALTER TABLE persons ADD COLUMN death_date date;
|
||||
ALTER TABLE persons ADD COLUMN death_date_precision varchar(16) NOT NULL DEFAULT 'UNKNOWN';
|
||||
|
||||
UPDATE persons SET birth_date = make_date(birth_year, 1, 1), birth_date_precision = 'YEAR'
|
||||
WHERE birth_year IS NOT NULL;
|
||||
UPDATE persons SET death_date = make_date(death_year, 1, 1), death_date_precision = 'YEAR'
|
||||
WHERE death_year IS NOT NULL;
|
||||
|
||||
-- Named constraints: readable Postgres error messages when violated.
|
||||
ALTER TABLE persons ADD CONSTRAINT chk_person_birth_before_death
|
||||
CHECK (death_date IS NULL OR birth_date IS NULL OR birth_date <= death_date);
|
||||
ALTER TABLE persons ADD CONSTRAINT chk_person_birth_date_precision_coherence
|
||||
CHECK ((birth_date IS NULL) = (birth_date_precision = 'UNKNOWN'));
|
||||
ALTER TABLE persons ADD CONSTRAINT chk_person_birth_date_precision_values
|
||||
CHECK (birth_date_precision IN ('DAY', 'MONTH', 'SEASON', 'YEAR', 'RANGE', 'APPROX', 'UNKNOWN'));
|
||||
ALTER TABLE persons ADD CONSTRAINT chk_person_death_date_precision_coherence
|
||||
CHECK ((death_date IS NULL) = (death_date_precision = 'UNKNOWN'));
|
||||
ALTER TABLE persons ADD CONSTRAINT chk_person_death_date_precision_values
|
||||
CHECK (death_date_precision IN ('DAY', 'MONTH', 'SEASON', 'YEAR', 'RANGE', 'APPROX', 'UNKNOWN'));
|
||||
|
||||
ALTER TABLE persons DROP COLUMN birth_year;
|
||||
ALTER TABLE persons DROP COLUMN death_year;
|
||||
Reference in New Issue
Block a user