metis-desk/modules/assets/src/api/domain/value-objects/asset-relationship-values.vo.ts

102 lines
2.8 KiB
TypeScript
Raw Normal View History

2026-10-04 19:04:14 +00:00
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),
});
2026-10-10 10:01:58 +00:00
2026-10-04 19:04:14 +00:00
export type RelationshipValuesData = z.infer<typeof RelationshipValuesSchema>;
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);
}
2026-10-10 10:01:58 +00:00
2026-10-04 19:04:14 +00:00
static create(input: RelationshipValuesData): Result<AssetRelationshipValues, AssetCatalogError> {
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);
2026-10-10 10:01:58 +00:00
2026-10-04 19:04:14 +00:00
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"));
}
2026-10-10 10:01:58 +00:00
2026-10-04 19:04:14 +00:00
return Result.ok(
new AssetRelationshipValues(
source.data,
target.data,
type.data,
name.data,
inverse.data,
input.symmetric,
input.notes.trim()
)
);
}
2026-10-10 10:01:58 +00:00
2026-10-04 19:04:14 +00:00
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,
};
}
2026-10-10 10:01:58 +00:00
2026-10-04 19:04:14 +00:00
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
);
}
2026-10-10 10:01:58 +00:00
2026-10-04 19:04:14 +00:00
/** Identifica un vínculo; las relaciones simétricas normalizan el orden de sus extremos. */
key(): string {
const ids = [this.sourceId.toPrimitive(), this.targetId.toPrimitive()];
2026-10-10 10:01:58 +00:00
2026-10-04 19:04:14 +00:00
if (this.symmetric) {
ids.sort();
}
2026-10-10 10:01:58 +00:00
2026-10-04 19:04:14 +00:00
return [this.typeId.toPrimitive(), ...ids].join(":");
}
}