import { UniqueID } from "@repo/rdx-ddd"; import { z } from "zod/v4"; import { Asset } from "../../domain/asset.aggregate"; import { AssetRevision } from "../../domain/asset-revision.entity"; import { AssetInputSchema, AssetSpecificationSchema } from "../../domain/asset-values"; import { AssetSpecification, AssetValues } from "../../domain/value-objects/asset-values"; import type { AssetModel, AssetRevisionModel } from "./asset.model"; export function inventoryIdentity(value: string) { const parsed = UniqueID.create(value); if (!parsed.isSuccess) { throw new Error("Identidad de inventario persistida inconsistente."); } return parsed.data; } export class AssetPersistenceMapper { toDomain(row: AssetModel, revisions: readonly AssetRevisionModel[]) { const specification = AssetSpecification.create( AssetSpecificationSchema.parse(row.specification) ); if (!specification.isSuccess) { throw new Error("Especificación de activo persistida inconsistente."); } const values = AssetValues.create(AssetInputSchema.parse(row.values), specification.data); if (!values.isSuccess) { throw new Error("Valores de activo persistidos inconsistentes."); } const current = values.data.toPrimitive(); if ( row.templateId !== current.templateId || row.siteId !== current.siteId || row.personId !== current.personId ) { throw new Error("Referencias de activo persistidas inconsistentes."); } const history = [...revisions] .sort((a, b) => a.position - b.position) .map((revision, position) => { const previous = AssetValues.create( AssetInputSchema.parse(revision.values), specification.data ); if ( !previous.isSuccess || revision.position !== position || !z.iso.datetime().safeParse(revision.recordedAt).success ) { throw new Error("Historial de activo persistido inconsistente."); } if ( revision.siteId !== previous.data.toPrimitive().siteId || revision.personId !== previous.data.toPrimitive().personId ) { throw new Error("Referencias de revisión persistidas inconsistentes."); } return AssetRevision.rehydrate( { values: previous.data, actorId: inventoryIdentity(revision.actorId), recordedAt: revision.recordedAt, }, inventoryIdentity(revision.id) ); }); if (!(history.length && history.at(-1)?.values.equals(values.data))) { throw new Error("Última revisión de activo inconsistente."); } return Asset.rehydrate( { companyId: inventoryIdentity(row.companyId), specification: specification.data, values: values.data, history, }, inventoryIdentity(row.id) ); } toPersistence(asset: Asset) { const values = asset.values.toPrimitive(); return { asset: { id: asset.id.toPrimitive(), companyId: asset.companyId.toPrimitive(), templateId: values.templateId, siteId: values.siteId, personId: values.personId, specification: asset.specification.toPrimitive(), values, }, revisions: asset.history.map((revision, position) => ({ id: revision.id.toPrimitive(), assetId: asset.id.toPrimitive(), actorId: revision.actorId.toPrimitive(), siteId: revision.values.toPrimitive().siteId, personId: revision.values.toPrimitive().personId, recordedAt: revision.recordedAt, values: revision.values.toPrimitive(), position, })), }; } }