metis-desk/modules/companies/src/api/infrastructure/persistence/mailbox-migration.ts
David 6375fa1b32 feat(mailbox): implement mailbox and mailbox use management features
- Add mailbox persistence mapper for domain object mapping.
- Create Sequelize repository for mailbox data access.
- Define common mailbox schemas and types for validation.
- Implement mailbox API for frontend communication.
- Develop mailbox form component for creating and editing mailboxes.
- Add internationalization support for mailbox labels and messages.
- Create mailbox use form for managing mailbox usage periods.
- Build mailboxes page to display and manage mailboxes and their usage.
2026-10-05 10:45:02 +02:00

69 lines
2.3 KiB
TypeScript

import { DataTypes, QueryTypes, type Sequelize } from "sequelize";
export async function migrateMailboxes(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 = (table: string, nullable = false) => ({
type: DataTypes.UUID,
allowNull: nullable,
references: { model: table, key: "id" },
onDelete: "RESTRICT",
});
const root = {
id: { type: DataTypes.UUID, primaryKey: true },
companyId: fk("companies"),
values: { type: DataTypes.JSON, allowNull: false },
};
for (const [table, columns] of [
[
"mailboxes",
{
...root,
accountId: fk("access_items", true),
addressKey: { type: DataTypes.STRING(300), allowNull: false, unique: true },
},
],
["mailbox_uses", { ...root, mailboxId: fk("mailboxes"), personId: fk("company_contacts") }],
[
"mailbox_revisions",
{
id: root.id,
itemId: fk("mailboxes"),
position: { type: DataTypes.INTEGER, allowNull: false },
values: root.values,
actorId: fk("users"),
recordedAt: { type: DataTypes.STRING(24), allowNull: false },
},
],
[
"mailbox_use_revisions",
{
id: root.id,
itemId: fk("mailbox_uses"),
position: { type: DataTypes.INTEGER, allowNull: false },
values: root.values,
actorId: fk("users"),
recordedAt: { type: DataTypes.STRING(24), allowNull: false },
},
],
] as const) {
if (!tables.some((row) => row.name === table)) {
await query.createTable(table, columns);
}
}
for (const table of ["mailbox_revisions", "mailbox_use_revisions"]) {
const indexes = await database.query<{ name: string }>(
"SELECT DISTINCT INDEX_NAME AS name FROM information_schema.STATISTICS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=:table",
{ replacements: { table }, type: QueryTypes.SELECT }
);
if (!indexes.some((item) => item.name === `${table}_position`)) {
await query.addIndex(table, ["itemId", "position"], {
unique: true,
name: `${table}_position`,
});
}
}
}