import { UniqueID } from "@repo/rdx-ddd"; import { z } from "zod/v4"; import { Resource } from "../../domain/resource.aggregate"; import { ResourceRevision } from "../../domain/resource-revision.entity"; import { ResourceInputSchema, ResourceSpecificationSchema } from "../../domain/resource-values"; import { ResourceSpecification, ResourceValues, } from "../../domain/value-objects/resource-values.vo"; import type { InventoryRow, RevisionRow } from "./resource-inventory-relational"; export function inventoryIdentity(value: string) { const parsed = UniqueID.create(value); if (!parsed.isSuccess) { throw new Error("Identidad de recurso persistida inconsistente."); } return parsed.data; } export class ResourcePersistenceMapper { toDomain(row: InventoryRow, revisions: readonly RevisionRow[]) { const specification = ResourceSpecification.create( ResourceSpecificationSchema.parse(row.specification) ); if (!specification.isSuccess) { throw new Error("Especificación de recurso persistida inconsistente."); } const values = ResourceValues.reconstruct( ResourceInputSchema.parse(row.values), specification.data ); if (!values.isSuccess) { throw new Error("Valores de recurso persistidos inconsistentes."); } const current = values.data.toPrimitive(); if (row.templateId !== current.templateId) { throw new Error("Referencia de recurso persistida inconsistente."); } const ordered = [...revisions].sort((a, b) => a.position - b.position); const history = ordered.map((revision, position) => { const revisionSpecification = ResourceSpecification.create( ResourceSpecificationSchema.parse(revision.specification ?? row.specification) ); if (!revisionSpecification.isSuccess) { throw new Error("Especificación histórica inconsistente."); } const previous = ResourceValues.reconstruct( ResourceInputSchema.parse(revision.values), revisionSpecification.data ); if ( !previous.isSuccess || revision.position !== position || (position > 0 && revision.recordedAt < (ordered[position - 1]?.recordedAt ?? "")) || !z.iso.datetime().safeParse(revision.recordedAt).success ) { throw new Error("Historial de recurso persistido inconsistente."); } if (revision.resourceId !== row.id) { throw new Error("Revisión fuera del recurso."); } return ResourceRevision.rehydrate( { values: previous.data, specification: revisionSpecification.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 recurso inconsistente."); } return Resource.rehydrate( { companyId: inventoryIdentity(row.companyId), specification: specification.data, values: values.data, history, }, inventoryIdentity(row.id) ); } toPersistence(resource: Resource) { const values = resource.values.toPrimitive(); return { resource: { id: resource.id.toPrimitive(), companyId: resource.companyId.toPrimitive(), templateId: values.templateId, specification: resource.specification.toPrimitive(), values, }, revisions: resource.history.map((revision, position) => ({ id: revision.id.toPrimitive(), resourceId: resource.id.toPrimitive(), actorId: revision.actorId.toPrimitive(), recordedAt: revision.recordedAt, values: revision.values.toPrimitive(), specification: revision.specification.toPrimitive(), position, })), }; } }