90 lines
3.3 KiB
TypeScript
90 lines
3.3 KiB
TypeScript
import { MigrationInterface, QueryRunner } from 'typeorm';
|
|
|
|
function quoteIdentifier(identifier: string): string {
|
|
return `"${identifier.replaceAll('"', '""')}"`;
|
|
}
|
|
|
|
export class PhaseD52FindingCatalogAdministration1787335200000 implements MigrationInterface {
|
|
name = 'PhaseD52FindingCatalogAdministration1787335200000';
|
|
|
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
await queryRunner.query(`
|
|
CREATE TABLE finding_catalog_item_versions (
|
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
item_id uuid NOT NULL,
|
|
revision integer NOT NULL,
|
|
snapshot jsonb NOT NULL,
|
|
actor_user_id uuid,
|
|
actor_username varchar(80),
|
|
created_at timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
CONSTRAINT uq_finding_catalog_item_versions_revision
|
|
UNIQUE (item_id, revision),
|
|
CONSTRAINT chk_finding_catalog_item_versions_revision
|
|
CHECK (revision > 0),
|
|
CONSTRAINT chk_finding_catalog_item_versions_snapshot
|
|
CHECK (jsonb_typeof(snapshot) = 'object'),
|
|
CONSTRAINT fk_finding_catalog_item_versions_item FOREIGN KEY (item_id)
|
|
REFERENCES finding_catalog_items(id) ON DELETE RESTRICT,
|
|
CONSTRAINT fk_finding_catalog_item_versions_actor FOREIGN KEY (actor_user_id)
|
|
REFERENCES users(id) ON DELETE SET NULL
|
|
)
|
|
`);
|
|
await queryRunner.query(`
|
|
CREATE INDEX idx_finding_catalog_item_versions_item_revision
|
|
ON finding_catalog_item_versions (item_id, revision DESC)
|
|
`);
|
|
await queryRunner.query(`
|
|
CREATE INDEX idx_finding_catalog_item_versions_created_at
|
|
ON finding_catalog_item_versions (created_at DESC)
|
|
`);
|
|
|
|
await queryRunner.query(`
|
|
INSERT INTO finding_catalog_item_versions (
|
|
item_id, revision, snapshot, actor_username, created_at
|
|
)
|
|
SELECT
|
|
item.id,
|
|
item.revision,
|
|
JSONB_BUILD_OBJECT(
|
|
'id', item.id,
|
|
'categoryId', category.id,
|
|
'categoryCode', category.code,
|
|
'categoryName', category.name,
|
|
'code', item.code,
|
|
'sourceNumber', item.source_number,
|
|
'title', item.title,
|
|
'legalBasis', item.legal_basis,
|
|
'glossary', item.glossary,
|
|
'importNote', item.import_note,
|
|
'revision', item.revision,
|
|
'isActive', item.is_active
|
|
),
|
|
'migration:D5.2',
|
|
item.updated_at
|
|
FROM finding_catalog_items item
|
|
INNER JOIN finding_categories category ON category.id = item.category_id
|
|
`);
|
|
|
|
const appRole = process.env.DB_APP_USER;
|
|
if (!appRole) throw new Error('Missing required environment variable: DB_APP_USER');
|
|
const roleRows = (await queryRunner.query(
|
|
'SELECT 1 FROM pg_roles WHERE rolname = $1',
|
|
[appRole],
|
|
)) as unknown[];
|
|
if (roleRows.length !== 1) throw new Error('Configured DB_APP_USER does not exist');
|
|
const applicationRole = quoteIdentifier(appRole);
|
|
await queryRunner.query(`
|
|
GRANT SELECT, INSERT ON TABLE finding_catalog_item_versions
|
|
TO ${applicationRole}
|
|
`);
|
|
await queryRunner.query(`
|
|
REVOKE UPDATE, DELETE ON TABLE finding_catalog_item_versions
|
|
FROM ${applicationRole}
|
|
`);
|
|
}
|
|
|
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
await queryRunner.query('DROP TABLE finding_catalog_item_versions');
|
|
}
|
|
}
|