90 lines
3.6 KiB
TypeScript
90 lines
3.6 KiB
TypeScript
|
|
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 }
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|