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

104 lines
3.7 KiB
TypeScript
Raw Normal View History

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";
2026-10-09 08:38:19 +00:00
import { AssetSpecification, AssetValues } from "../../domain/value-objects/asset-values.vo";
2026-10-10 09:41:42 +00:00
import type { InventoryRow, RevisionRow } from "./asset-inventory-relational";
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 {
2026-10-10 09:41:42 +00:00
toDomain(row: InventoryRow, revisions: readonly RevisionRow[]) {
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 ||
2026-10-07 16:08:48 +00:00
row.brandId !== (current.brandId ?? null)
) {
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 ||
2026-10-07 16:08:48 +00:00
revision.brandId !== (previous.data.toPrimitive().brandId ?? null)
) {
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,
2026-10-07 16:08:48 +00:00
brandId: values.brandId ?? null,
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,
2026-10-07 16:08:48 +00:00
brandId: revision.values.toPrimitive().brandId ?? null,
recordedAt: revision.recordedAt,
values: revision.values.toPrimitive(),
position,
})),
};
}
}