Files
dh-inspeccion-v2/api-v3/src/database/migrations/1787767200000-phase-d5-3-7-2-relational-territory-plan.ts
T

93 lines
5.4 KiB
TypeScript

import { MigrationInterface, QueryRunner } from 'typeorm';
function quoteIdentifier(identifier: string): string {
return `"${identifier.replaceAll('"', '""')}"`;
}
export class PhaseD5372RelationalTerritoryPlan1787767200000 implements MigrationInterface {
name = 'PhaseD5372RelationalTerritoryPlan1787767200000';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
ALTER TABLE asset_import_plan_items DROP CONSTRAINT chk_asset_import_plan_item_kind
`);
await queryRunner.query(`
ALTER TABLE asset_import_plan_items ADD CONSTRAINT chk_asset_import_plan_item_kind CHECK (
entity_kind IN (
'DEPARTMENT','ORGANIZATION','AREA','AREA_DEPARTMENT_RELATION','FIELD','OPERATOR_RELATION',
'LEGAL_RIGHT','LEGAL_RIGHT_ORGANIZATION','INSTALLATION','TECHNICAL_ASSET'
)
)
`);
await queryRunner.query(`
CREATE TABLE administrative_departments (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
province_code varchar(40) NOT NULL DEFAULT 'MENDOZA',
code varchar(80) NOT NULL,
name varchar(160) NOT NULL,
normalized_name varchar(180) NOT NULL,
is_active boolean NOT NULL DEFAULT true,
source_document_id uuid,
created_by uuid,
updated_by uuid,
created_at timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT chk_administrative_department_code CHECK (code ~ '^[A-Z0-9][A-Z0-9._/-]{1,79}$'),
CONSTRAINT chk_administrative_department_name CHECK (length(btrim(name)) >= 2),
CONSTRAINT chk_administrative_department_normalized CHECK (length(btrim(normalized_name)) >= 2),
CONSTRAINT fk_administrative_department_source FOREIGN KEY (source_document_id) REFERENCES source_documents(id) ON DELETE SET NULL,
CONSTRAINT fk_administrative_department_created_by FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL,
CONSTRAINT fk_administrative_department_updated_by FOREIGN KEY (updated_by) REFERENCES users(id) ON DELETE SET NULL,
CONSTRAINT uq_administrative_department_code UNIQUE (province_code, code),
CONSTRAINT uq_administrative_department_name UNIQUE (province_code, normalized_name)
)
`);
await queryRunner.query(`CREATE INDEX idx_administrative_departments_active_name ON administrative_departments (is_active, normalized_name)`);
await queryRunner.query(`
CREATE TABLE area_department_relations (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
area_id uuid NOT NULL,
department_id uuid NOT NULL,
valid_from date NOT NULL DEFAULT CURRENT_DATE,
valid_until date,
source_document_id uuid,
notes text,
created_by uuid,
ended_by uuid,
created_at timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT chk_area_department_relation_dates CHECK (valid_until IS NULL OR valid_until >= valid_from),
CONSTRAINT fk_area_department_relation_area FOREIGN KEY (area_id) REFERENCES assets(id) ON DELETE RESTRICT,
CONSTRAINT fk_area_department_relation_department FOREIGN KEY (department_id) REFERENCES administrative_departments(id) ON DELETE RESTRICT,
CONSTRAINT fk_area_department_relation_source FOREIGN KEY (source_document_id) REFERENCES source_documents(id) ON DELETE SET NULL,
CONSTRAINT fk_area_department_relation_created_by FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL,
CONSTRAINT fk_area_department_relation_ended_by FOREIGN KEY (ended_by) REFERENCES users(id) ON DELETE SET NULL
)
`);
await queryRunner.query(`CREATE UNIQUE INDEX uq_area_department_relation_active_pair ON area_department_relations (area_id, department_id) WHERE valid_until IS NULL`);
await queryRunner.query(`CREATE INDEX idx_area_department_relations_area ON area_department_relations (area_id) WHERE valid_until IS NULL`);
await queryRunner.query(`CREATE INDEX idx_area_department_relations_department ON area_department_relations (department_id) WHERE valid_until IS NULL`);
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, UPDATE ON TABLE administrative_departments, area_department_relations TO ${applicationRole}`);
await queryRunner.query(`REVOKE DELETE ON TABLE administrative_departments, area_department_relations FROM ${applicationRole}`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`DROP TABLE area_department_relations`);
await queryRunner.query(`DROP TABLE administrative_departments`);
await queryRunner.query(`ALTER TABLE asset_import_plan_items DROP CONSTRAINT chk_asset_import_plan_item_kind`);
await queryRunner.query(`
ALTER TABLE asset_import_plan_items ADD CONSTRAINT chk_asset_import_plan_item_kind CHECK (
entity_kind IN ('ORGANIZATION','AREA','FIELD','OPERATOR_RELATION','INSTALLATION','TECHNICAL_ASSET')
)
`);
}
}