metis-desk/modules/assets/src/api/infrastructure/persistence/workstation-persistence.mapper.ts

118 lines
3.9 KiB
TypeScript
Raw Normal View History

2026-10-04 19:04:14 +00:00
import { z } from "zod/v4";
2026-10-09 08:38:19 +00:00
import { WorkstationValues } from "../../domain/value-objects/workstation-values.vo";
2026-10-04 19:04:14 +00:00
import { Workstation } from "../../domain/workstation.aggregate";
import { WorkstationRevision } from "../../domain/workstation-revision.entity";
import { WorkstationInputSchema } from "../../domain/workstation-values";
import { inventoryIdentity } from "./asset-persistence.mapper";
2026-10-10 11:32:40 +00:00
import type { WorkstationAssetModel } from "./workstation.model";
import type { WorkstationRevisionRow, WorkstationRow } from "./workstation-relational";
2026-10-04 19:04:14 +00:00
function valuesOf(raw: unknown, siteId: string | null, personId: string | null) {
2026-10-10 15:57:05 +00:00
const values = WorkstationValues.create(WorkstationInputSchema.parse(raw));
2026-10-10 10:01:58 +00:00
2026-10-04 19:04:14 +00:00
if (
!values.isSuccess ||
values.data.toPrimitive().siteId !== siteId ||
values.data.toPrimitive().personId !== personId
) {
throw new Error("Valores de puesto persistidos inconsistentes.");
}
2026-10-10 10:01:58 +00:00
2026-10-04 19:04:14 +00:00
return values.data;
}
2026-10-10 10:01:58 +00:00
2026-10-04 19:04:14 +00:00
export class WorkstationPersistenceMapper {
toDomain(
2026-10-10 11:32:40 +00:00
row: WorkstationRow,
revisions: readonly WorkstationRevisionRow[],
2026-10-04 19:04:14 +00:00
references: readonly WorkstationAssetModel[]
) {
const values = valuesOf(row.values, row.siteId, row.personId);
const ordered = [...revisions].sort((a, b) => a.position - b.position);
const history = ordered.map((revision, position) => {
if (
revision.position !== position ||
!z.iso.datetime().safeParse(revision.recordedAt).success ||
revision.recordedAt < (ordered[position - 1]?.recordedAt ?? "")
) {
throw new Error("Historial de puesto inconsistente.");
}
2026-10-10 10:01:58 +00:00
2026-10-04 19:04:14 +00:00
return WorkstationRevision.rehydrate(
{
values: valuesOf(revision.values, revision.siteId, revision.personId),
actorId: inventoryIdentity(revision.actorId),
recordedAt: revision.recordedAt,
},
inventoryIdentity(revision.id)
);
});
2026-10-10 10:01:58 +00:00
2026-10-04 19:04:14 +00:00
if (!(history.length && history.at(-1)?.values.equals(values))) {
throw new Error("Última revisión de puesto inconsistente.");
}
2026-10-05 07:53:29 +00:00
const expected = new Set(
history.flatMap((item) => [
...item.values.toPrimitive().assetIds,
...item.values.toPrimitive().sharedAssetIds,
])
);
2026-10-10 10:01:58 +00:00
2026-10-04 19:04:14 +00:00
if (
references.length !== expected.size ||
references.some(
(item) =>
item.companyId !== row.companyId ||
!expected.has(item.assetId) ||
item.activeKey !==
(values.active && values.assetIds.some((id) => id.toPrimitive() === item.assetId)
? `${row.companyId}:${item.assetId}`
: null)
)
) {
throw new Error("Referencias de puesto inconsistentes.");
}
2026-10-10 10:01:58 +00:00
2026-10-04 19:04:14 +00:00
return Workstation.rehydrate(
{ companyId: inventoryIdentity(row.companyId), values, history },
inventoryIdentity(row.id)
);
}
2026-10-10 10:01:58 +00:00
2026-10-04 19:04:14 +00:00
toPersistence(item: Workstation) {
const values = item.values.toPrimitive();
const companyId = item.companyId.toPrimitive();
const id = item.id.toPrimitive();
2026-10-10 10:01:58 +00:00
2026-10-04 19:04:14 +00:00
return {
workstation: { id, companyId, values, siteId: values.siteId, personId: values.personId },
revisions: item.history.map((revision, position) => ({
id: revision.id.toPrimitive(),
workstationId: id,
actorId: revision.actorId.toPrimitive(),
recordedAt: revision.recordedAt,
values: revision.values.toPrimitive(),
position,
siteId: revision.values.toPrimitive().siteId,
personId: revision.values.toPrimitive().personId,
})),
references: [
2026-10-05 07:53:29 +00:00
...new Set(
item.history.flatMap((revision) => [
...revision.values.toPrimitive().assetIds,
...revision.values.toPrimitive().sharedAssetIds,
])
),
2026-10-04 19:04:14 +00:00
].map((assetId) => ({
workstationId: id,
companyId,
assetId,
activeKey:
values.active && values.assetIds.includes(assetId) ? `${companyId}:${assetId}` : null,
})),
};
}
}