import { Name, UniqueID } from "@repo/rdx-ddd"; import { Result } from "@repo/rdx-utils"; import { z } from "zod/v4"; import { AssetCatalogError } from "../asset-definition"; export const RelationshipValuesSchema = z.strictObject({ sourceId: z.uuid(), targetId: z.uuid(), typeId: z.uuid(), name: z.string().min(1).max(100), inverseName: z.string().min(1).max(100), symmetric: z.boolean(), notes: z.string().max(10000), }); export type RelationshipValuesData = z.infer; export class AssetRelationshipValues { private constructor( public readonly sourceId: UniqueID, public readonly targetId: UniqueID, public readonly typeId: UniqueID, public readonly name: Name, public readonly inverseName: Name, public readonly symmetric: boolean, public readonly notes: string ) { Object.freeze(this); } static create(input: RelationshipValuesData): Result { const parsed = RelationshipValuesSchema.safeParse(input); const source = UniqueID.create(input.sourceId); const target = UniqueID.create(input.targetId); const type = UniqueID.create(input.typeId); const name = Name.create(input.name, 100); const inverse = Name.create(input.symmetric ? input.name : input.inverseName, 100); if ( !( parsed.success && source.isSuccess && target.isSuccess && type.isSuccess && name.isSuccess && inverse.isSuccess ) ) { return Result.fail(new AssetCatalogError("INVALID_REQUEST")); } if (source.data.equals(target.data)) { return Result.fail(new AssetCatalogError("SELF_RELATIONSHIP")); } return Result.ok( new AssetRelationshipValues( source.data, target.data, type.data, name.data, inverse.data, input.symmetric, input.notes.trim() ) ); } toPrimitive(): RelationshipValuesData { return { sourceId: this.sourceId.toPrimitive(), targetId: this.targetId.toPrimitive(), typeId: this.typeId.toPrimitive(), name: this.name.toPrimitive(), inverseName: this.inverseName.toPrimitive(), symmetric: this.symmetric, notes: this.notes, }; } equals(other: AssetRelationshipValues): boolean { return ( this.key() === other.key() && this.name.equals(other.name) && this.inverseName.equals(other.inverseName) && this.symmetric === other.symmetric && this.notes === other.notes ); } /** Identifica un vínculo; las relaciones simétricas normalizan el orden de sus extremos. */ key(): string { const ids = [this.sourceId.toPrimitive(), this.targetId.toPrimitive()]; if (this.symmetric) { ids.sort(); } return [this.typeId.toPrimitive(), ...ids].join(":"); } }