Skip to content

Commit

Permalink
Merge branch 'Sikora00-bugfix/787'
Browse files Browse the repository at this point in the history
  • Loading branch information
kamilmysliwiec committed Dec 8, 2021
2 parents 041ad7f + 8981557 commit a8ebe2b
Show file tree
Hide file tree
Showing 9 changed files with 87 additions and 37 deletions.
3 changes: 1 addition & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
"prerelease": "npm run build",
"release": "release-it"
},
"dependencies": {
"uuid": "8.3.2"
},
"devDependencies": {
"@commitlint/cli": "15.0.0",
"@commitlint/config-angular": "15.0.0",
Expand Down
45 changes: 31 additions & 14 deletions src/command-bus.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import { Injectable, Type } from '@nestjs/common';
import { ModuleRef } from '@nestjs/core';
import 'reflect-metadata';
import { COMMAND_HANDLER_METADATA } from './decorators/constants';
import { COMMAND_HANDLER_METADATA, COMMAND_METADATA } from './decorators/constants';
import { CommandHandlerNotFoundException } from './exceptions/command-not-found.exception';
import { DefaultCommandPubSub } from './helpers/default-command-pubsub';
import { InvalidCommandHandlerException } from './index';
import { CommandMetadata } from './interfaces/commands/command-metadata.interface';
import {
ICommand,
ICommandBus,
ICommandHandler,
ICommandPublisher,
ICommandPublisher
} from './interfaces/index';
import { ObservableBus } from './utils/observable-bus';

Expand All @@ -36,17 +37,17 @@ export class CommandBus<CommandBase extends ICommand = ICommand>
}

execute<T extends CommandBase, R = any>(command: T): Promise<R> {
const commandName = this.getCommandName(command as any);
const handler = this.handlers.get(commandName);
const commandId = this.getCommandId(command);
const handler = this.handlers.get(commandId);
if (!handler) {
throw new CommandHandlerNotFoundException(commandName);
throw new CommandHandlerNotFoundException(commandId);
}
this.subject$.next(command);
return handler.execute(command);
}

bind<T extends CommandBase>(handler: ICommandHandler<T>, name: string) {
this.handlers.set(name, handler);
bind<T extends CommandBase>(handler: ICommandHandler<T>, id: string) {
this.handlers.set(id, handler);
}

register(handlers: CommandHandlerType[] = []) {
Expand All @@ -58,20 +59,36 @@ export class CommandBus<CommandBase extends ICommand = ICommand>
if (!instance) {
return;
}
const target = this.reflectCommandName(handler);
const target = this.reflectCommandId(handler);
if (!target) {
throw new InvalidCommandHandlerException();
}
this.bind(instance as ICommandHandler<CommandBase>, target.name);
this.bind(instance as ICommandHandler<CommandBase>, target);
}

private getCommandName(command: Type<CommandBase>): string {
const { constructor } = Object.getPrototypeOf(command);
return constructor.name as string;
private getCommandId(command: CommandBase): string {
const { constructor: commandType } = Object.getPrototypeOf(command);
const commandMetadata: CommandMetadata = Reflect.getMetadata(
COMMAND_METADATA,
commandType,
);
if (!commandMetadata) {
throw new CommandHandlerNotFoundException(commandType.name);
}

return commandMetadata.id;
}

private reflectCommandName(handler: CommandHandlerType): FunctionConstructor {
return Reflect.getMetadata(COMMAND_HANDLER_METADATA, handler);
private reflectCommandId(handler: CommandHandlerType): string | undefined {
const command: Type<ICommand> = Reflect.getMetadata(
COMMAND_HANDLER_METADATA,
handler,
);
const commandMetadata: CommandMetadata = Reflect.getMetadata(
COMMAND_METADATA,
command,
);
return commandMetadata.id;
}

private useDefaultPublisher() {
Expand Down
6 changes: 5 additions & 1 deletion src/decorators/command-handler.decorator.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'reflect-metadata';
import { ICommand } from '../index';
import { COMMAND_HANDLER_METADATA } from './constants';
import { COMMAND_HANDLER_METADATA, COMMAND_METADATA } from './constants';
import { v4 } from 'uuid';

/**
* Decorator that marks a class as a Nest command handler. A command handler
Expand All @@ -14,6 +15,9 @@ import { COMMAND_HANDLER_METADATA } from './constants';
*/
export const CommandHandler = (command: ICommand): ClassDecorator => {
return (target: object) => {
if (!Reflect.hasMetadata(COMMAND_METADATA, command)) {
Reflect.defineMetadata(COMMAND_METADATA, { id: v4() }, command);
}
Reflect.defineMetadata(COMMAND_HANDLER_METADATA, command, target);
};
};
2 changes: 2 additions & 0 deletions src/decorators/constants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
export const COMMAND_METADATA = '__command__';
export const COMMAND_HANDLER_METADATA = '__commandHandler__';
export const QUERY_METADATA = '__query__';
export const QUERY_HANDLER_METADATA = '__queryHandler__';
export const EVENTS_HANDLER_METADATA = '__eventsHandler__';
export const SAGA_METADATA = '__saga__';
6 changes: 5 additions & 1 deletion src/decorators/query-handler.decorator.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'reflect-metadata';
import { IQuery } from '../interfaces';
import { QUERY_HANDLER_METADATA } from './constants';
import { QUERY_HANDLER_METADATA, QUERY_METADATA } from './constants';
import { v4 } from 'uuid';

/**
* Decorator that marks a class as a Nest query handler. A query handler
Expand All @@ -14,6 +15,9 @@ import { QUERY_HANDLER_METADATA } from './constants';
*/
export const QueryHandler = (query: IQuery): ClassDecorator => {
return (target: object) => {
if (!Reflect.hasMetadata(QUERY_METADATA, query)) {
Reflect.defineMetadata(QUERY_METADATA, { id: v4() }, query);
}
Reflect.defineMetadata(QUERY_HANDLER_METADATA, query, target);
};
};
3 changes: 3 additions & 0 deletions src/interfaces/commands/command-metadata.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export interface CommandMetadata {
id: string;
}
3 changes: 3 additions & 0 deletions src/interfaces/queries/query-metadata.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export interface QueryMetadata {
id: string;
}
53 changes: 34 additions & 19 deletions src/query-bus.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Injectable, Type } from '@nestjs/common';
import { ModuleRef } from '@nestjs/core';
import 'reflect-metadata';
import { QUERY_HANDLER_METADATA } from './decorators/constants';
import { QUERY_HANDLER_METADATA, QUERY_METADATA } from './decorators/constants';
import { QueryHandlerNotFoundException } from './exceptions';
import { InvalidQueryHandlerException } from './exceptions/invalid-query-handler.exception';
import { DefaultQueryPubSub } from './helpers/default-query-pubsub';
Expand All @@ -10,14 +10,13 @@ import {
IQueryBus,
IQueryHandler,
IQueryPublisher,
IQueryResult,
IQueryResult
} from './interfaces';
import { QueryMetadata } from './interfaces/queries/query-metadata.interface';
import { ObservableBus } from './utils/observable-bus';

export type QueryHandlerType<
QueryBase extends IQuery = IQuery,
QueryResultBase extends IQueryResult = IQueryResult
> = Type<IQueryHandler<QueryBase, QueryResultBase>>;
export type QueryHandlerType<QueryBase extends IQuery = IQuery,
QueryResultBase extends IQueryResult = IQueryResult> = Type<IQueryHandler<QueryBase, QueryResultBase>>;

@Injectable()
export class QueryBus<QueryBase extends IQuery = IQuery>
Expand All @@ -42,10 +41,10 @@ export class QueryBus<QueryBase extends IQuery = IQuery>
async execute<T extends QueryBase, TResult = any>(
query: T,
): Promise<TResult> {
const queryName = this.getQueryName((query as any) as Type<QueryBase>);
const handler = this.handlers.get(queryName);
const queryId = this.getQueryId(query);
const handler = this.handlers.get(queryId);
if (!handler) {
throw new QueryHandlerNotFoundException(queryName);
throw new QueryHandlerNotFoundException(queryId);
}

this.subject$.next(query);
Expand All @@ -55,9 +54,9 @@ export class QueryBus<QueryBase extends IQuery = IQuery>

bind<T extends QueryBase, TResult = any>(
handler: IQueryHandler<T, TResult>,
name: string,
queryId: string,
) {
this.handlers.set(name, handler);
this.handlers.set(queryId, handler);
}

register(handlers: QueryHandlerType<QueryBase>[] = []) {
Expand All @@ -69,22 +68,38 @@ export class QueryBus<QueryBase extends IQuery = IQuery>
if (!instance) {
return;
}
const target = this.reflectQueryName(handler);
const target = this.reflectQueryId(handler);
if (!target) {
throw new InvalidQueryHandlerException();
}
this.bind(instance as IQueryHandler<QueryBase, IQueryResult>, target.name);
this.bind(instance as IQueryHandler<QueryBase, IQueryResult>, target);
}

private getQueryName(query: Type<QueryBase>): string {
const { constructor } = Object.getPrototypeOf(query);
return constructor.name as string;
private getQueryId(query: QueryBase): string {
const { constructor: queryType } = Object.getPrototypeOf(query);
const queryMetadata: QueryMetadata = Reflect.getMetadata(
QUERY_METADATA,
queryType,
);
if (!queryMetadata) {
throw new QueryHandlerNotFoundException(queryType.name);
}

return queryMetadata.id;
}

private reflectQueryName(
private reflectQueryId(
handler: QueryHandlerType<QueryBase>,
): FunctionConstructor {
return Reflect.getMetadata(QUERY_HANDLER_METADATA, handler);
): string | undefined {
const query: Type<QueryBase> = Reflect.getMetadata(
QUERY_HANDLER_METADATA,
handler,
);
const queryMetadata: QueryMetadata = Reflect.getMetadata(
QUERY_METADATA,
query,
);
return queryMetadata.id;
}

private useDefaultPublisher() {
Expand Down

0 comments on commit a8ebe2b

Please sign in to comment.