Files
edr-platform/apps/edr-freight-api/src/migrations/2030000000000-AddTrainScheduleReference.ts

59 lines
2.0 KiB
TypeScript

import { MigrationInterface, QueryRunner } from 'typeorm';
/**
* Adds train_schedules.reference: a human-facing unique schedule number
* S-YYYY-NNNNN (per-year sequence, like bookings' BK-YYYY-NNNNNN).
*
* - Adds the nullable column.
* - Backfills existing rows: within each created-at year, numbers rows by
* created_at ascending (oldest → S-<year>-00001). Deterministic order.
* - Adds a partial unique index (NULLs allowed so a future insert can stage
* the row before the app stamps its reference).
*/
export class AddTrainScheduleReference2030000000000
implements MigrationInterface
{
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
ALTER TABLE freight.train_schedules
ADD COLUMN IF NOT EXISTS reference VARCHAR(20);
`);
// Backfill per-year, ordered by created_at (oldest = 00001). Uses the row's
// own created-at year as the reference year so historical rows keep a
// sensible number.
await queryRunner.query(`
WITH numbered AS (
SELECT
id,
EXTRACT(YEAR FROM created_at)::int AS yr,
ROW_NUMBER() OVER (
PARTITION BY EXTRACT(YEAR FROM created_at)
ORDER BY created_at ASC, id ASC
) AS seq
FROM freight.train_schedules
WHERE reference IS NULL
)
UPDATE freight.train_schedules ts
SET reference = 'S-' || numbered.yr || '-' || LPAD(numbered.seq::text, 5, '0')
FROM numbered
WHERE ts.id = numbered.id;
`);
await queryRunner.query(`
CREATE UNIQUE INDEX IF NOT EXISTS ux_train_schedules_reference
ON freight.train_schedules (reference)
WHERE reference IS NOT NULL;
`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
DROP INDEX IF EXISTS freight.ux_train_schedules_reference;
`);
await queryRunner.query(`
ALTER TABLE freight.train_schedules DROP COLUMN IF EXISTS reference;
`);
}
}