import { DataTypes, QueryTypes, type Sequelize } from "sequelize"; import { interventionTemplateSeeds } from "../../domain/intervention-template-seed"; import { InterventionTemplatePersistenceMapper } from "./intervention-template-persistence.mapper"; export async function migrateInterventionTemplates(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 fk = (model: string) => ({ type: DataTypes.UUID, allowNull: true, references: { model, key: "id" }, onDelete: "RESTRICT", }); const definitions = [ ["intervention_template_lock", { id: { type: DataTypes.INTEGER, primaryKey: true } }], [ "intervention_templates", { id: { type: DataTypes.UUID, primaryKey: true }, companyId: fk("companies"), requestKey: { type: DataTypes.UUID, allowNull: false, unique: true }, values: { type: DataTypes.JSON, allowNull: false }, }, ], [ "intervention_template_revisions", { id: { type: DataTypes.UUID, primaryKey: true }, templateId: { type: DataTypes.UUID, allowNull: false, references: { model: "intervention_templates", key: "id" }, onDelete: "RESTRICT", }, actorId: fk("users"), values: { type: DataTypes.JSON, allowNull: false }, recordedAt: { type: DataTypes.STRING(30), allowNull: false }, position: { type: DataTypes.INTEGER, allowNull: false }, }, ], ] as const; for (const [table, columns] of definitions) { if (!tables.some((item) => item.name === table)) { await query.createTable(table, columns); } } await database.query("INSERT IGNORE INTO intervention_template_lock (id) VALUES (1)"); const indexes = await database.query<{ name: string }>( "SELECT DISTINCT INDEX_NAME AS name FROM information_schema.STATISTICS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='intervention_template_revisions'", { type: QueryTypes.SELECT } ); if (!indexes.some((item) => item.name === "intervention_template_revision_position")) { await query.addIndex("intervention_template_revisions", ["templateId", "position"], { name: "intervention_template_revision_position", unique: true, }); } await database.transaction(async (transaction) => { await database.query("SELECT id FROM intervention_template_lock WHERE id=1 FOR UPDATE", { type: QueryTypes.SELECT, transaction, }); const existing = await database.query<{ requestKey: string }>( "SELECT requestKey FROM intervention_templates", { type: QueryTypes.SELECT, transaction } ); const mapper = new InterventionTemplatePersistenceMapper(); for (const seed of interventionTemplateSeeds()) { if (existing.some((item) => item.requestKey === seed.requestKey.toPrimitive())) { continue; } const persisted = mapper.toPersistence(seed); await database.query( "INSERT INTO intervention_templates (id,companyId,requestKey,`values`) VALUES (:id,:companyId,:requestKey,:values)", { replacements: persisted.root, transaction } ); for (const revision of persisted.revisions) { await database.query( "INSERT INTO intervention_template_revisions (id,templateId,`values`,actorId,recordedAt,position) VALUES (:id,:templateId,:values,:actorId,:recordedAt,:position)", { replacements: revision, transaction } ); } } }); }