import { UniqueID } from "@repo/rdx-ddd"; import { Maybe, Result } from "@repo/rdx-utils"; import type { RelationshipInputDTO } from "../../common/relationships"; import { AssetCatalogError } from "../domain/asset-definition"; import { AssetRelationship } from "../domain/asset-relationship.aggregate"; import { AssetRelationshipValues } from "../domain/value-objects/asset-relationship-values.vo"; import type { IAssetRepository, InventoryContext } from "./asset.repository"; export class AssetRelationshipUseCases { constructor(private readonly repository: IAssetRepository) {} save(companyId: string, input: RelationshipInputDTO, actorId: string) { const company = UniqueID.create(companyId); const actor = UniqueID.create(actorId); if (!(company.isSuccess && actor.isSuccess)) { return Promise.resolve(Result.fail(new AssetCatalogError("INVALID_REQUEST"))); } return this.repository.saveRelationship(company.data, (context) => { const mapped = mapRelationshipInput(input, company.data, context); if (!mapped.isSuccess) { return Result.fail(mapped.error); } const previous = context.relationships.find( (item) => item.active && item.values.key() === mapped.data.key() ); if (previous) { return previous.values.notes === mapped.data.notes ? Result.ok(previous) : Result.fail(new AssetCatalogError("RELATIONSHIP_EXISTS")); } return AssetRelationship.create( company.data, mapped.data, actor.data, new Date().toISOString() ); }); } remove(companyId: string, id: string) { const company = UniqueID.create(companyId); const identity = UniqueID.create(id); if (!(company.isSuccess && identity.isSuccess)) { return Promise.resolve(Result.fail(new AssetCatalogError("INVALID_REQUEST"))); } return this.repository.removeRelationship(company.data, identity.data); } end(companyId: string, id: string, actorId: string) { const company = UniqueID.create(companyId); const identity = UniqueID.create(id); const actor = UniqueID.create(actorId); if (!(company.isSuccess && identity.isSuccess && actor.isSuccess)) { return Promise.resolve(Result.fail(new AssetCatalogError("INVALID_REQUEST"))); } return this.repository.saveRelationship(company.data, (context) => { const item = context.relationships.find((entry) => entry.id.equals(identity.data)); return item ? item.end(actor.data, new Date().toISOString()) : Result.fail(new AssetCatalogError("RELATIONSHIP_NOT_FOUND")); }); } } export function mapRelationshipInput( input: RelationshipInputDTO, company: UniqueID, context: InventoryContext ) { if ( ![input.sourceId, input.targetId].every((id) => context.assets.some((asset) => asset.id.toPrimitive() === id) ) ) { return Result.fail(new AssetCatalogError("ASSET_NOT_FOUND")); } const scope = Maybe.some(company); const type = context.catalog .visible(scope) .find((item) => item.id.toPrimitive() === input.typeId); if (!(type && type.values.data.kind === "relation" && context.catalog.active(type, scope))) { return Result.fail(new AssetCatalogError("RELATION_TYPE_UNAVAILABLE")); } return AssetRelationshipValues.create({ ...input, name: type.values.data.name, inverseName: type.values.data.inverseName, symmetric: type.values.data.symmetric, }); }