import createUUID from 'uuid-by-string' import { createId } from '@paralleldrive/cuid2' import Hashids from 'hashids'; import {HashError} from "./error/HashError"; export class EntityId { protected _recordId: T|null = null; protected _uuid: string|null = null; constructor(recordId?: T|string, isHash:boolean = false, uuid?: string) { this._recordId = recordId ? recordId as T : null; if (isHash) { this.fromHash(recordId as string); } if (!uuid) { this.createUUID(); } } private createUUID():void { this._uuid = createUUID(this._recordId ? this._recordId.toString() : createId(), createUUID(this.constructor.name)); } get hashOptions() : [string, number] { return [this.constructor.name, 5]; } toHash(): string { if (!this._recordId) { throw new Error('Cannot hash an empty recordId'); } const hashids = new Hashids(...this.hashOptions); return hashids.encode(this._recordId.toString()); } protected fromHash(hash: string) : EntityId { if (!hash) { return this; } const hashids = new Hashids(...this.hashOptions); const num = hashids.decode(hash)[0]; if (!num) { throw new HashError(`Invalid hash ${hash}`); } this._recordId = (typeof this._recordId === 'string' ? num.toString() : num); this.createUUID(); return this; } toPrimitive(): T { return this._recordId!; } toString(): string|null { return this._uuid; } toJSON(): string|null { return this._recordId ? this.toHash() : null; } equals(id: EntityId): boolean { return this._uuid === id._uuid; } }