metis-desk/modules/resources/src/api/infrastructure/persistence/resource-compatibility.ts

148 lines
5.0 KiB
TypeScript
Raw Normal View History

2026-10-05 15:01:32 +00:00
import { UniqueID } from "@repo/rdx-ddd";
import type { Sequelize, Transaction } from "sequelize";
import { QueryTypes } from "sequelize";
import type { Resource } from "../../domain/resource.aggregate";
import type { ResourceInput } from "../../domain/resource-values";
/** Proyecciones para los contratos de accesos y perfiles: la ficha editable pertenece a resources. */
export async function projectResource(
database: Sequelize,
resource: Resource,
transaction: Transaction
) {
const current = resource.values.toPrimitive();
const integration = current.integration;
2026-10-10 10:01:58 +00:00
2026-10-05 15:01:32 +00:00
if (!integration) {
return;
}
const companyId = resource.companyId.toPrimitive();
const id = resource.id.toPrimitive();
2026-10-10 10:01:58 +00:00
2026-10-05 15:01:32 +00:00
if (integration.kind === "mailbox") {
const values = mailboxProjection(current);
2026-10-10 10:01:58 +00:00
2026-10-05 15:01:32 +00:00
await database.query(
"INSERT INTO mailboxes (id,companyId,accountId,addressKey,`values`) VALUES (:id,:companyId,:accountId,:addressKey,:values) ON DUPLICATE KEY UPDATE accountId=VALUES(accountId),addressKey=VALUES(addressKey),`values`=VALUES(`values`)",
{
replacements: {
id,
companyId,
accountId: values.accountId,
addressKey: `${companyId}:${values.address}`,
values: JSON.stringify(values),
},
transaction,
}
);
for (const [position, revision] of resource.history.entries()) {
await database.query(
"INSERT INTO mailbox_revisions (id,itemId,position,actorId,recordedAt,`values`) VALUES (:id,:itemId,:position,:actorId,:recordedAt,:values) ON DUPLICATE KEY UPDATE id=id",
{
replacements: {
id: revision.id.toPrimitive(),
itemId: id,
position,
actorId: revision.actorId.toPrimitive(),
recordedAt: revision.recordedAt,
values: JSON.stringify(mailboxProjection(revision.values.toPrimitive())),
},
transaction,
}
);
}
2026-10-10 10:01:58 +00:00
2026-10-05 15:01:32 +00:00
return;
}
const roots = await database.query<{ id: string }>(
"SELECT id FROM access_workspaces WHERE companyId=:companyId",
{ replacements: { companyId }, transaction, type: QueryTypes.SELECT }
);
let workspaceId = roots[0]?.id;
2026-10-10 10:01:58 +00:00
2026-10-05 15:01:32 +00:00
if (!workspaceId) {
workspaceId = UniqueID.generateNewID().toPrimitive();
await database.query(
"INSERT INTO access_workspaces (id,companyId,scopeKey) VALUES (:id,:companyId,:companyId)",
{ replacements: { id: workspaceId, companyId }, transaction }
);
}
const values = accessProjection(current);
2026-10-10 10:01:58 +00:00
2026-10-05 15:01:32 +00:00
await database.query(
"INSERT INTO access_items (id,workspaceId,kind,`values`) VALUES (:id,:workspaceId,'resource',:values) ON DUPLICATE KEY UPDATE `values`=VALUES(`values`)",
{ replacements: { id, workspaceId, values: JSON.stringify(values) }, transaction }
);
for (const [sequence, revision] of resource.history.entries()) {
await database.query(
"INSERT INTO access_revisions (id,itemId,sequence,actorId,recordedAt,`values`) VALUES (:id,:itemId,:sequence,:actorId,:recordedAt,:values) ON DUPLICATE KEY UPDATE id=id",
{
replacements: {
id: revision.id.toPrimitive(),
itemId: id,
sequence,
actorId: revision.actorId.toPrimitive(),
recordedAt: revision.recordedAt,
values: JSON.stringify(accessProjection(revision.values.toPrimitive())),
},
transaction,
}
);
}
// El contexto es fijo; estas referencias preservan las FK utilizadas por permisos y necesidades.
for (const targetId of [
integration.resourceTypeId,
integration.systemId,
integration.environmentId,
].filter(Boolean)) {
const existing = await database.query<{ itemId: string }>(
"SELECT itemId FROM access_references WHERE itemId=:id AND targetId=:targetId",
{ replacements: { id, targetId }, transaction, type: QueryTypes.SELECT }
);
2026-10-10 10:01:58 +00:00
2026-10-05 15:01:32 +00:00
if (!existing.length) {
await database.query(
"INSERT INTO access_references (itemId,targetId) VALUES (:id,:targetId)",
{ replacements: { id, targetId }, transaction }
);
}
}
}
2026-10-10 10:01:58 +00:00
2026-10-05 15:01:32 +00:00
function mailboxProjection(input: ResourceInput) {
const integration = input.integration;
2026-10-10 10:01:58 +00:00
2026-10-05 15:01:32 +00:00
if (integration?.kind !== "mailbox") {
throw new Error("Recurso sin contexto de buzón.");
}
2026-10-10 10:01:58 +00:00
2026-10-05 15:01:32 +00:00
return {
address: input.characteristics[integration.addressFieldId],
kind: integration.mailboxKind,
context: input.characteristics[integration.contextFieldId] || null,
accountId: integration.accountId,
active: input.active,
notes: input.notes || null,
};
}
2026-10-10 10:01:58 +00:00
2026-10-05 15:01:32 +00:00
function accessProjection(input: ResourceInput) {
const integration = input.integration;
2026-10-10 10:01:58 +00:00
2026-10-05 15:01:32 +00:00
if (integration?.kind !== "access") {
throw new Error("Recurso sin contexto de acceso.");
}
2026-10-10 10:01:58 +00:00
2026-10-05 15:01:32 +00:00
return {
kind: "resource",
name: input.name,
active: input.active,
resourceTypeId: integration.resourceTypeId,
systemId: integration.systemId,
environmentId: integration.environmentId,
reference: input.characteristics[integration.referenceFieldId] || null,
notes: input.notes || null,
};
}