import type { InferAttributes, InferCreationAttributes, Sequelize } from "sequelize"; import { DataTypes, Model, QueryTypes } from "sequelize"; export class AssetModel extends Model< InferAttributes, InferCreationAttributes > { declare id: string; declare companyId: string; declare templateId: string; declare siteId: string | null; declare personId: string | null; declare specification: unknown; declare values: unknown; } export class AssetRevisionModel extends Model< InferAttributes, InferCreationAttributes > { declare id: string; declare assetId: string; declare actorId: string; declare recordedAt: string; declare values: unknown; declare position: number; declare siteId: string | null; declare personId: string | null; } const id = { type: DataTypes.UUID, primaryKey: true }; const fk = (model: string, nullable = false) => ({ type: DataTypes.UUID, allowNull: nullable, references: { model, key: "id" }, onDelete: "RESTRICT", }); export async function migrateInventory(database: Sequelize) { const query = database.getQueryInterface(); const tables = await database.query<{ name: string }>( "SELECT TABLE_NAME AS name FROM information_schema.TABLES WHERE TABLE_SCHEMA=DATABASE()", { type: QueryTypes.SELECT } ); const asset = { id, companyId: fk("companies"), templateId: fk("asset_definitions"), siteId: fk("company_sites", true), personId: fk("company_contacts", true), specification: { type: DataTypes.JSON, allowNull: false }, values: { type: DataTypes.JSON, allowNull: false }, }; const revision = { id, assetId: fk("assets"), actorId: fk("users"), siteId: fk("company_sites", true), personId: fk("company_contacts", true), recordedAt: { type: DataTypes.STRING(30), allowNull: false }, values: { type: DataTypes.JSON, allowNull: false }, position: { type: DataTypes.INTEGER, allowNull: false }, }; if (!tables.some((table) => table.name === "assets")) { await query.createTable("assets", asset); } if (!tables.some((table) => table.name === "asset_revisions")) { await query.createTable("asset_revisions", revision); } const revisionColumns = await query.describeTable("asset_revisions"); for (const [column, reference] of [ ["siteId", "company_sites"], ["personId", "company_contacts"], ] as const) { if (!(column in revisionColumns)) { await query.addColumn("asset_revisions", column, fk(reference, true)); } // Reconstruye las referencias de instalaciones que ya hubieran registrado revisiones. const source = column === "siteId" ? "UPDATE asset_revisions SET siteId = NULLIF(JSON_UNQUOTE(JSON_EXTRACT(`values`, '$.siteId')), 'null')" : "UPDATE asset_revisions SET personId = NULLIF(JSON_UNQUOTE(JSON_EXTRACT(`values`, '$.personId')), 'null')"; await database.query( source + (column === "siteId" ? " WHERE siteId IS NULL" : " WHERE personId IS NULL") ); } AssetModel.init(asset, { sequelize: database, tableName: "assets", timestamps: false }); AssetRevisionModel.init(revision, { sequelize: database, tableName: "asset_revisions", timestamps: false, }); }