metis-desk/modules/assets/src/api/application/asset-relationship.use-cases.ts

89 lines
3.4 KiB
TypeScript
Raw Normal View History

2026-10-04 19:04:14 +00:00
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";
2026-10-09 08:38:19 +00:00
import { AssetRelationshipValues } from "../domain/value-objects/asset-relationship-values.vo";
2026-10-04 19:04:14 +00:00
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);
}
2026-10-04 19:04:14 +00:00
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,
});
}