import { v4 as uuidv4 } from "uuid"; import Joi from "joi"; import { NullOr, UndefinedOr } from "../../../../utilities"; import { RuleValidator } from "../RuleValidator"; import { DomainError, handleDomainError } from "../errors"; import { INullableValueObjectOptions, NullableValueObject, } from "./NullableValueObject"; import { Result } from "./Result"; export interface IUniqueIDOptions extends INullableValueObjectOptions { generateOnEmpty?: boolean; } export class UniqueID extends NullableValueObject { protected static validate( value: UndefinedOr, options: IUniqueIDOptions, ) { const ruleIsEmpty = RuleValidator.RULE_ALLOW_EMPTY.default(""); const ruleIsGuid = Joi.string() .guid({ version: ["uuidv4"], }) .label(options.label ? options.label : "id"); const rules = Joi.alternatives(ruleIsEmpty, ruleIsGuid); return RuleValidator.validate(rules, value); } private static sanitize(id: string): string { return id.trim(); } public static create(value: NullOr, options: IUniqueIDOptions = {}) { const _options: IUniqueIDOptions = { label: "id", generateOnEmpty: false, ...options, }; if (!value && !_options.generateOnEmpty) { return Result.fail( handleDomainError( DomainError.INVALID_INPUT_DATA, "ID is null or empty", ), ); } if (value) { const validationResult = UniqueID.validate(value, _options); if (validationResult.isFailure) { return Result.fail( handleDomainError( DomainError.INVALID_INPUT_DATA, validationResult.error.message, _options, ), ); } return Result.ok( new UniqueID(UniqueID.sanitize(validationResult.object)), ); } if (_options.generateOnEmpty) { return UniqueID.generateNewID(); } return Result.ok(new UniqueID(null)); } public static generateNewID(): Result { return Result.ok(new UniqueID(uuidv4())); } get value(): string { return String(this.props); } public toString(): string { return String(this.props); } public toPrimitive(): string { return this.toString(); } } export class InvalidUniqueIDError extends Error {}