import { EventEmitter } from "events"; import { AnyEntity } from "../entity/any-entity.type"; import { EntityType } from "../entity/entity-type.interface"; import { META } from "../symbols"; import { BerryOrm } from "./berry-orm.class"; const events = ["resolve", "update"] as const; type EntityEvent = typeof events[number]; type Listener = (entity: Entity) => void; export class EntityEventManager { private emitter = new EventEmitter(); constructor(private orm: BerryOrm) {} on( target: EventTarget, event: EntityEvent, listener: Listener, ): this { this.emitter.on(this.identify(target, event), listener); return this; } once( target: EventTarget, event: EntityEvent, listener: Listener, ): this { this.emitter.once(this.identify(target, event), listener); return this; } off( target: EventTarget, event: EntityEvent, listener: Listener, ): this; off( target: EventTarget, event: EntityEvent, ): this; off(target: EventTarget): this; off(): void; off( target?: EventTarget, event?: EntityEvent, listener?: Listener, ): this { if (target && event && listener) { this.emitter.off(this.identify(target, event), listener); } else if (target && event) { const id = this.identify(target, event); const listeners = this.emitter.listeners(id) as Listener[]; listeners.forEach((listener) => this.off(target, event, listener)); } else if (target) { events.forEach((event) => this.off(target, event)); } else { this.emitter.removeAllListeners(); } return this; } emit(entity: AnyEntity, event: EntityEvent): this { const type = entity.constructor as EntityType; this.emitter.emit(this.identify(entity, event), entity); this.emitter.emit(this.identify(type, event), entity); this.emitter.emit(this.identify("any", event), entity); return this; } private identify( target: EventTarget, event: EntityEvent, ) { if (typeof target == "string") { return `${target}:${event}`; } else if (target instanceof Function) { const name = target.name; return `${name}:${event}`; } else { const name = target.constructor.name; const pk = target[target[META].primary]; return `${name}:${pk}:${event}` as const; } } } type EventTarget = | Entity | EntityType | "any";