diff --git a/src/command-bus.ts b/src/command-bus.ts index 1f5f95bd..f3239b45 100644 --- a/src/command-bus.ts +++ b/src/command-bus.ts @@ -1,4 +1,4 @@ -import { Injectable, Type } from '@nestjs/common'; +import { Injectable, Logger, Type } from '@nestjs/common'; import { ModuleRef } from '@nestjs/core'; import 'reflect-metadata'; import { @@ -26,6 +26,7 @@ export class CommandBus { private handlers = new Map>(); private _publisher: ICommandPublisher; + private readonly _logger = new Logger(CommandBus.name); constructor(private readonly moduleRef: ModuleRef) { super(); @@ -64,7 +65,17 @@ export class CommandBus return handler.execute(command); } - bind(handler: ICommandHandler, id: string) { + bind( + handler: ICommandHandler, + { id, name }: CommandMetadata, + ) { + if (this.handlers.has(id)) { + const previousHandlerName = this.handlers.get(id).constructor.name; + const handlerName = handler.constructor.name; + this._logger.warn( + `Multiple handlers for command ${name}. Repleacing ${previousHandlerName} with ${handlerName}.`, + ); + } this.handlers.set(id, handler); } @@ -77,11 +88,11 @@ export class CommandBus if (!instance) { return; } - const target = this.reflectCommandId(handler); - if (!target) { + const commandMetadata = this.reflectCommandMetadata(handler); + if (!commandMetadata) { throw new InvalidCommandHandlerException(); } - this.bind(instance as ICommandHandler, target); + this.bind(instance as ICommandHandler, commandMetadata); } private getCommandId(command: CommandBase): string { @@ -97,16 +108,12 @@ export class CommandBus return commandMetadata.id; } - private reflectCommandId(handler: CommandHandlerType): string | undefined { + private reflectCommandMetadata(handler: CommandHandlerType): CommandMetadata { const command: Type = Reflect.getMetadata( COMMAND_HANDLER_METADATA, handler, ); - const commandMetadata: CommandMetadata = Reflect.getMetadata( - COMMAND_METADATA, - command, - ); - return commandMetadata.id; + return Reflect.getMetadata(COMMAND_METADATA, command); } private useDefaultPublisher() { diff --git a/src/decorators/command-handler.decorator.ts b/src/decorators/command-handler.decorator.ts index 8490830f..8a89a3f7 100644 --- a/src/decorators/command-handler.decorator.ts +++ b/src/decorators/command-handler.decorator.ts @@ -2,6 +2,7 @@ import 'reflect-metadata'; import { ICommand } from '../index'; import { COMMAND_HANDLER_METADATA, COMMAND_METADATA } from './constants'; import { v4 } from 'uuid'; +import { Type } from '@nestjs/common'; /** * Decorator that marks a class as a Nest command handler. A command handler @@ -13,10 +14,14 @@ import { v4 } from 'uuid'; * * @see https://docs.nestjs.com/recipes/cqrs#commands */ -export const CommandHandler = (command: ICommand | (new (...args: any[]) => ICommand)): ClassDecorator => { +export const CommandHandler = (command: Type): ClassDecorator => { return (target: object) => { if (!Reflect.hasOwnMetadata(COMMAND_METADATA, command)) { - Reflect.defineMetadata(COMMAND_METADATA, { id: v4() }, command); + Reflect.defineMetadata( + COMMAND_METADATA, + { id: v4(), name: command.name }, + command, + ); } Reflect.defineMetadata(COMMAND_HANDLER_METADATA, command, target); }; diff --git a/src/decorators/query-handler.decorator.ts b/src/decorators/query-handler.decorator.ts index e52e3a83..2c1f077c 100644 --- a/src/decorators/query-handler.decorator.ts +++ b/src/decorators/query-handler.decorator.ts @@ -2,6 +2,7 @@ import 'reflect-metadata'; import { IQuery } from '../interfaces'; import { QUERY_HANDLER_METADATA, QUERY_METADATA } from './constants'; import { v4 } from 'uuid'; +import { Type } from '@nestjs/common'; /** * Decorator that marks a class as a Nest query handler. A query handler @@ -13,10 +14,14 @@ import { v4 } from 'uuid'; * * @see https://docs.nestjs.com/recipes/cqrs#queries */ -export const QueryHandler = (query: IQuery): ClassDecorator => { +export const QueryHandler = (query: Type): ClassDecorator => { return (target: object) => { if (!Reflect.hasOwnMetadata(QUERY_METADATA, query)) { - Reflect.defineMetadata(QUERY_METADATA, { id: v4() }, query); + Reflect.defineMetadata( + QUERY_METADATA, + { id: v4(), name: query.name }, + query, + ); } Reflect.defineMetadata(QUERY_HANDLER_METADATA, query, target); }; diff --git a/src/interfaces/commands/command-metadata.interface.ts b/src/interfaces/commands/command-metadata.interface.ts index 80f4b377..7379b0d3 100644 --- a/src/interfaces/commands/command-metadata.interface.ts +++ b/src/interfaces/commands/command-metadata.interface.ts @@ -1,3 +1,4 @@ export interface CommandMetadata { id: string; -} \ No newline at end of file + name: string; +} diff --git a/src/interfaces/queries/query-metadata.interface.ts b/src/interfaces/queries/query-metadata.interface.ts index b60e436c..039f7735 100644 --- a/src/interfaces/queries/query-metadata.interface.ts +++ b/src/interfaces/queries/query-metadata.interface.ts @@ -1,3 +1,4 @@ export interface QueryMetadata { id: string; -} \ No newline at end of file + name: string; +} diff --git a/src/query-bus.ts b/src/query-bus.ts index 39666bb3..76ac1738 100644 --- a/src/query-bus.ts +++ b/src/query-bus.ts @@ -1,4 +1,4 @@ -import { Injectable, Type } from '@nestjs/common'; +import { Injectable, Logger, Type } from '@nestjs/common'; import { ModuleRef } from '@nestjs/core'; import 'reflect-metadata'; import { QUERY_HANDLER_METADATA, QUERY_METADATA } from './decorators/constants'; @@ -27,6 +27,7 @@ export class QueryBus { private handlers = new Map>(); private _publisher: IQueryPublisher; + private readonly _logger = new Logger(QueryBus.name); constructor(private readonly moduleRef: ModuleRef) { super(); @@ -69,9 +70,16 @@ export class QueryBus bind( handler: IQueryHandler, - queryId: string, + { id, name }: QueryMetadata, ) { - this.handlers.set(queryId, handler); + if (this.handlers.has(id)) { + const previousHandlerName = this.handlers.get(id).constructor.name; + const handlerName = handler.constructor.name; + this._logger.warn( + `Multiple handlers for query ${name}. Repleacing ${previousHandlerName} with ${handlerName}.`, + ); + } + this.handlers.set(id, handler); } register(handlers: QueryHandlerType[] = []) { @@ -83,11 +91,14 @@ export class QueryBus if (!instance) { return; } - const target = this.reflectQueryId(handler); - if (!target) { + const queryMetadata = this.reflectQueryMetadata(handler); + if (!queryMetadata) { throw new InvalidQueryHandlerException(); } - this.bind(instance as IQueryHandler, target); + this.bind( + instance as IQueryHandler, + queryMetadata, + ); } private getQueryId(query: QueryBase): string { @@ -103,18 +114,14 @@ export class QueryBus return queryMetadata.id; } - private reflectQueryId( + private reflectQueryMetadata( handler: QueryHandlerType, - ): string | undefined { + ): QueryMetadata { const query: Type = Reflect.getMetadata( QUERY_HANDLER_METADATA, handler, ); - const queryMetadata: QueryMetadata = Reflect.getMetadata( - QUERY_METADATA, - query, - ); - return queryMetadata.id; + return Reflect.getMetadata(QUERY_METADATA, query); } private useDefaultPublisher() {