metis-desk/modules/companies/src/api/infrastructure/persistence/work-profile-persistence.mapper.ts
2026-10-10 13:32:40 +02:00

120 lines
3.6 KiB
TypeScript

import { UniqueID } from "@repo/rdx-ddd";
import { z } from "zod/v4";
import { WorkProfileValues } from "../../domain/value-objects/work-profile-values.vo";
import { WorkProfile } from "../../domain/work-profile.aggregate";
import { WorkProfileRevision } from "../../domain/work-profile-revision.entity";
import { WorkProfileInputSchema } from "../../domain/work-profile-values";
import { profileSnapshot } from "./configuration-snapshots";
import { snapshotValues } from "./scalar-snapshot-normalization";
export function profileIdentity(value: string) {
const id = UniqueID.create(value);
if (!id.isSuccess) {
throw new Error("Identidad de perfil persistida inconsistente.");
}
return id.data;
}
export function persistedJson(value: unknown): unknown {
return typeof value === "string" ? JSON.parse(value) : value;
}
export type ProfileRow = {
id: string;
companyId: string;
personId: string;
accountId: string | null;
assetId: string;
values?: unknown;
currentKey: string | null;
};
export type ProfileRevisionRow = {
id: string;
profileId: string;
accountId: string | null;
position: number;
actorId: string;
recordedAt: string;
values?: unknown;
};
function valuesOf(raw: unknown) {
const values = WorkProfileValues.create(WorkProfileInputSchema.parse(persistedJson(raw)));
if (!values.isSuccess) {
throw new Error("Valores de perfil persistidos inconsistentes.");
}
return values.data;
}
export class WorkProfilePersistenceMapper {
toDomain(row: ProfileRow, revisions: readonly ProfileRevisionRow[]) {
const values = valuesOf(snapshotValues(profileSnapshot, row));
const ordered = [...revisions].sort((a, b) => a.position - b.position);
const history = ordered.map((revision, position) => {
const revisionValues = valuesOf(snapshotValues(profileSnapshot, revision));
if (
revision.position !== position ||
!z.iso.datetime().safeParse(revision.recordedAt).success ||
revision.recordedAt < (ordered[position - 1]?.recordedAt ?? "") ||
!values.sameTarget(revisionValues) ||
revision.accountId !== revisionValues.toPrimitive().accountId
) {
throw new Error("Historial de perfil persistido inconsistente.");
}
return WorkProfileRevision.rehydrate(
{
values: revisionValues,
actorId: profileIdentity(revision.actorId),
recordedAt: revision.recordedAt,
},
profileIdentity(revision.id)
);
});
if (
!history.at(-1)?.values.equals(values) ||
row.personId !== values.personId.toPrimitive() ||
row.accountId !== values.toPrimitive().accountId ||
row.assetId !== values.assetId.toPrimitive() ||
row.currentKey !== (values.active ? [row.personId, row.assetId].join(":") : null)
) {
throw new Error("Referencias de perfil persistidas inconsistentes.");
}
return WorkProfile.rehydrate(
{ companyId: profileIdentity(row.companyId), values, history },
profileIdentity(row.id)
);
}
toPersistence(item: WorkProfile) {
const values = item.values.toPrimitive();
return {
root: {
id: item.id.toPrimitive(),
companyId: item.companyId.toPrimitive(),
...values,
currentKey: item.values.active ? [values.personId, values.assetId].join(":") : null,
},
revisions: item.history.map((revision, position) => ({
id: revision.id.toPrimitive(),
profileId: item.id.toPrimitive(),
position,
actorId: revision.actorId.toPrimitive(),
recordedAt: revision.recordedAt,
...revision.values.toPrimitive(),
})),
};
}
}