2026-10-04 19:04:14 +00:00
|
|
|
import type { InferAttributes, InferCreationAttributes, Sequelize } from "sequelize";
|
|
|
|
|
import { DataTypes, Model, QueryTypes } from "sequelize";
|
2026-10-10 10:01:58 +00:00
|
|
|
|
2026-10-04 19:04:14 +00:00
|
|
|
export class WorkstationModel extends Model<
|
|
|
|
|
InferAttributes<WorkstationModel>,
|
|
|
|
|
InferCreationAttributes<WorkstationModel>
|
|
|
|
|
> {
|
|
|
|
|
declare id: string;
|
|
|
|
|
declare companyId: string;
|
|
|
|
|
declare siteId: string | null;
|
|
|
|
|
declare personId: string | null;
|
|
|
|
|
declare values: unknown;
|
|
|
|
|
}
|
2026-10-10 10:01:58 +00:00
|
|
|
|
2026-10-04 19:04:14 +00:00
|
|
|
export class WorkstationRevisionModel extends Model<
|
|
|
|
|
InferAttributes<WorkstationRevisionModel>,
|
|
|
|
|
InferCreationAttributes<WorkstationRevisionModel>
|
|
|
|
|
> {
|
|
|
|
|
declare id: string;
|
|
|
|
|
declare workstationId: string;
|
|
|
|
|
declare actorId: string;
|
|
|
|
|
declare recordedAt: string;
|
|
|
|
|
declare values: unknown;
|
|
|
|
|
declare position: number;
|
|
|
|
|
declare siteId: string | null;
|
|
|
|
|
declare personId: string | null;
|
|
|
|
|
}
|
2026-10-10 10:01:58 +00:00
|
|
|
|
2026-10-04 19:04:14 +00:00
|
|
|
/** Proyección técnica de referencias históricas y reserva vigente; no representa otra entidad de negocio. */
|
|
|
|
|
export class WorkstationAssetModel extends Model<
|
|
|
|
|
InferAttributes<WorkstationAssetModel>,
|
|
|
|
|
InferCreationAttributes<WorkstationAssetModel>
|
|
|
|
|
> {
|
|
|
|
|
declare workstationId: string;
|
|
|
|
|
declare companyId: string;
|
|
|
|
|
declare assetId: string;
|
|
|
|
|
declare activeKey: string | null;
|
|
|
|
|
}
|
2026-10-10 10:01:58 +00:00
|
|
|
|
2026-10-04 19:04:14 +00:00
|
|
|
export async function migrateWorkstations(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 }
|
|
|
|
|
);
|
2026-10-10 10:01:58 +00:00
|
|
|
|
2026-10-04 19:04:14 +00:00
|
|
|
const fk = (model: string, nullable = false) => ({
|
|
|
|
|
type: DataTypes.UUID,
|
|
|
|
|
allowNull: nullable,
|
|
|
|
|
references: { model, key: "id" },
|
|
|
|
|
onDelete: "RESTRICT",
|
|
|
|
|
});
|
2026-10-10 10:01:58 +00:00
|
|
|
|
2026-10-04 19:04:14 +00:00
|
|
|
const root = {
|
|
|
|
|
id: { type: DataTypes.UUID, primaryKey: true },
|
|
|
|
|
companyId: fk("companies"),
|
|
|
|
|
siteId: fk("company_sites", true),
|
|
|
|
|
personId: fk("company_contacts", true),
|
|
|
|
|
values: { type: DataTypes.JSON, allowNull: false },
|
|
|
|
|
};
|
|
|
|
|
const revision = {
|
|
|
|
|
id: { type: DataTypes.UUID, primaryKey: true },
|
|
|
|
|
workstationId: fk("workstations"),
|
|
|
|
|
actorId: fk("users"),
|
|
|
|
|
siteId: fk("company_sites", true),
|
|
|
|
|
personId: fk("company_contacts", true),
|
|
|
|
|
values: { type: DataTypes.JSON, allowNull: false },
|
|
|
|
|
recordedAt: { type: DataTypes.STRING(30), allowNull: false },
|
|
|
|
|
position: { type: DataTypes.INTEGER, allowNull: false },
|
|
|
|
|
};
|
|
|
|
|
const reference = {
|
|
|
|
|
workstationId: { ...fk("workstations"), primaryKey: true },
|
|
|
|
|
companyId: fk("companies"),
|
|
|
|
|
assetId: { ...fk("assets"), primaryKey: true },
|
|
|
|
|
activeKey: { type: DataTypes.STRING(80), unique: true, allowNull: true },
|
|
|
|
|
};
|
2026-10-10 10:01:58 +00:00
|
|
|
|
2026-10-04 19:04:14 +00:00
|
|
|
for (const [table, columns] of [
|
|
|
|
|
["workstations", root],
|
|
|
|
|
["workstation_revisions", revision],
|
|
|
|
|
["workstation_assets", reference],
|
|
|
|
|
] as const) {
|
|
|
|
|
if (!tables.some((item) => item.name === table)) {
|
|
|
|
|
await query.createTable(table, columns);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
const indexes = await database.query<{ name: string }>(
|
|
|
|
|
"SELECT DISTINCT INDEX_NAME AS name FROM information_schema.STATISTICS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='workstations'",
|
|
|
|
|
{ type: QueryTypes.SELECT }
|
|
|
|
|
);
|
2026-10-10 10:01:58 +00:00
|
|
|
|
2026-10-04 19:04:14 +00:00
|
|
|
if (!indexes.some((item) => item.name === "workstations_company_identity")) {
|
|
|
|
|
await query.addIndex("workstations", ["companyId", "id"], {
|
|
|
|
|
name: "workstations_company_identity",
|
|
|
|
|
unique: true,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
const constraints = await database.query<{ name: string }>(
|
|
|
|
|
"SELECT CONSTRAINT_NAME AS name FROM information_schema.TABLE_CONSTRAINTS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='workstation_assets'",
|
|
|
|
|
{ type: QueryTypes.SELECT }
|
|
|
|
|
);
|
2026-10-10 10:01:58 +00:00
|
|
|
|
2026-10-04 19:04:14 +00:00
|
|
|
if (!constraints.some((item) => item.name === "workstation_asset_company")) {
|
|
|
|
|
await database.query(
|
|
|
|
|
"ALTER TABLE workstation_assets ADD CONSTRAINT workstation_asset_company FOREIGN KEY (companyId, assetId) REFERENCES assets(companyId,id)"
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
if (!constraints.some((item) => item.name === "workstation_owner_company")) {
|
|
|
|
|
await database.query(
|
|
|
|
|
"ALTER TABLE workstation_assets ADD CONSTRAINT workstation_owner_company FOREIGN KEY (companyId, workstationId) REFERENCES workstations(companyId,id)"
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
WorkstationModel.init(root, {
|
|
|
|
|
sequelize: database,
|
|
|
|
|
tableName: "workstations",
|
|
|
|
|
timestamps: false,
|
|
|
|
|
});
|
|
|
|
|
WorkstationRevisionModel.init(revision, {
|
|
|
|
|
sequelize: database,
|
|
|
|
|
tableName: "workstation_revisions",
|
|
|
|
|
timestamps: false,
|
|
|
|
|
});
|
|
|
|
|
WorkstationAssetModel.init(reference, {
|
|
|
|
|
sequelize: database,
|
|
|
|
|
tableName: "workstation_assets",
|
|
|
|
|
timestamps: false,
|
|
|
|
|
});
|
|
|
|
|
}
|