@nestjs/cqrs 10.2.8 → 11.0.0-next.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/.circleci/config.yml +29 -1
  2. package/.husky/commit-msg +0 -3
  3. package/.husky/pre-commit +0 -3
  4. package/dist/classes/command.d.ts +9 -0
  5. package/dist/classes/command.js +7 -0
  6. package/dist/classes/constants.d.ts +1 -0
  7. package/dist/classes/constants.js +4 -0
  8. package/dist/classes/index.d.ts +2 -0
  9. package/dist/classes/index.js +18 -0
  10. package/dist/classes/query.d.ts +9 -0
  11. package/dist/classes/query.js +7 -0
  12. package/dist/command-bus.d.ts +26 -7
  13. package/dist/command-bus.js +57 -21
  14. package/dist/constants.d.ts +1 -1
  15. package/dist/constants.js +1 -0
  16. package/dist/cqrs.module.d.ts +5 -4
  17. package/dist/cqrs.module.js +21 -11
  18. package/dist/decorators/command-handler.decorator.d.ts +3 -1
  19. package/dist/decorators/command-handler.decorator.js +8 -3
  20. package/dist/decorators/events-handler.decorator.d.ts +3 -1
  21. package/dist/decorators/events-handler.decorator.js +9 -2
  22. package/dist/decorators/index.d.ts +1 -0
  23. package/dist/decorators/index.js +6 -1
  24. package/dist/decorators/publishable.decorator.d.ts +5 -0
  25. package/dist/decorators/publishable.decorator.js +13 -0
  26. package/dist/decorators/query-handler.decorator.d.ts +3 -1
  27. package/dist/decorators/query-handler.decorator.js +8 -3
  28. package/dist/event-bus.d.ts +51 -10
  29. package/dist/event-bus.js +108 -31
  30. package/dist/event-publisher.d.ts +5 -2
  31. package/dist/event-publisher.js +10 -8
  32. package/dist/exceptions/command-not-found.exception.js +1 -1
  33. package/dist/exceptions/index.d.ts +1 -0
  34. package/dist/exceptions/index.js +6 -1
  35. package/dist/exceptions/invalid-command-handler.exception.js +1 -1
  36. package/dist/exceptions/invalid-events-handler.exception.js +1 -1
  37. package/dist/exceptions/invalid-query-handler.exception.js +1 -1
  38. package/dist/exceptions/invalid-saga.exception.js +1 -1
  39. package/dist/exceptions/query-not-found.exception.js +1 -1
  40. package/dist/exceptions/unsupported-saga-scope.exception.d.ts +3 -0
  41. package/dist/exceptions/unsupported-saga-scope.exception.js +9 -0
  42. package/dist/helpers/default-event-id-provider.d.ts +7 -0
  43. package/dist/helpers/default-event-id-provider.js +10 -0
  44. package/dist/index.d.ts +2 -0
  45. package/dist/index.js +7 -1
  46. package/dist/interfaces/commands/command-bus.interface.d.ts +18 -1
  47. package/dist/interfaces/commands/command-handler.interface.d.ts +9 -2
  48. package/dist/interfaces/cqrs-module-options.interface.d.ts +38 -8
  49. package/dist/interfaces/events/event-bus.interface.d.ts +41 -4
  50. package/dist/interfaces/events/event-id-provider.interface.d.ts +12 -0
  51. package/dist/interfaces/events/event-id-provider.interface.js +2 -0
  52. package/dist/interfaces/events/event-publisher.interface.d.ts +7 -4
  53. package/dist/interfaces/index.d.ts +2 -0
  54. package/dist/interfaces/index.js +7 -1
  55. package/dist/interfaces/providers-introspection-result.interface.d.ts +10 -0
  56. package/dist/interfaces/providers-introspection-result.interface.js +2 -0
  57. package/dist/interfaces/queries/query-bus.interface.d.ts +18 -1
  58. package/dist/interfaces/queries/query-handler.interface.d.ts +9 -2
  59. package/dist/interfaces/saga.type.d.ts +1 -1
  60. package/dist/operators/index.js +5 -1
  61. package/dist/operators/of-type.d.ts +1 -1
  62. package/dist/operators/of-type.js +1 -2
  63. package/dist/query-bus.d.ts +26 -6
  64. package/dist/query-bus.js +49 -20
  65. package/dist/scopes/async.context.d.ts +30 -0
  66. package/dist/scopes/async.context.js +58 -0
  67. package/dist/scopes/index.d.ts +1 -0
  68. package/dist/scopes/index.js +17 -0
  69. package/dist/services/explorer.service.d.ts +4 -6
  70. package/dist/services/explorer.service.js +14 -14
  71. package/dist/storages/aggregate-root.storage.d.ts +8 -0
  72. package/dist/storages/aggregate-root.storage.js +21 -0
  73. package/dist/unhandled-exception-bus.d.ts +4 -3
  74. package/dist/unhandled-exception-bus.js +18 -5
  75. package/dist/utils/index.js +5 -1
  76. package/jest.config.js +5 -0
  77. package/package.json +29 -17
  78. package/renovate.json +8 -7
  79. package/test/e2e/basic-flows.spec.ts +106 -0
  80. package/test/e2e/generics.spec.ts +198 -0
  81. package/test/e2e/request-scope.spec.ts +141 -0
  82. package/test/e2e/unhandled-exceptions.spec.ts +73 -0
  83. package/test/jest-e2e.json +9 -0
  84. package/test/utils/wait-immediate.ts +2 -0
  85. package/tsconfig.build.json +10 -0
@@ -1,3 +1,4 @@
1
+ import { AsyncContext } from '../../scopes/async.context';
1
2
  import { IEvent } from './event.interface';
2
3
  /**
3
4
  * Represents an event bus.
@@ -6,13 +7,49 @@ export interface IEventBus<EventBase extends IEvent = IEvent> {
6
7
  /**
7
8
  * Publishes an event.
8
9
  * @param event The event to publish.
9
- * @param context The context.
10
10
  */
11
- publish<TEvent extends EventBase, TContext = unknown>(event: TEvent, context?: TContext): any;
11
+ publish<TEvent extends EventBase>(event: TEvent): any;
12
+ /**
13
+ * Publishes an event.
14
+ * @param event The event to publish.
15
+ * @param asyncContext Async context
16
+ */
17
+ publish<TEvent extends EventBase>(event: TEvent, asyncContext: AsyncContext): any;
18
+ /**
19
+ * Publishes an event.
20
+ * @param event The event to publish.
21
+ * @param dispatcherContext Dispatcher context
22
+ */
23
+ publish<TEvent extends EventBase, TContext = unknown>(event: TEvent, dispatcherContext: TContext): any;
24
+ /**
25
+ * Publishes an event.
26
+ * @param event The event to publish.
27
+ * @param dispatcherContext Dispatcher context
28
+ * @param asyncContext Async context
29
+ */
30
+ publish<TEvent extends EventBase, TContext = unknown>(event: TEvent, dispatcherContext: TContext, asyncContext: AsyncContext): any;
31
+ /**
32
+ * Publishes multiple events.
33
+ * @param events The events to publish.
34
+ */
35
+ publishAll<TEvent extends EventBase>(events: TEvent[]): any;
36
+ /**
37
+ * Publishes multiple events.
38
+ * @param events The events to publish.
39
+ * @param asyncContext Async context
40
+ */
41
+ publishAll<TEvent extends EventBase>(events: TEvent[], asyncContext: AsyncContext): any;
42
+ /**
43
+ * Publishes multiple events.
44
+ * @param events The events to publish.
45
+ * @param dispatcherContext Dispatcher context
46
+ */
47
+ publishAll<TEvent extends EventBase, TContext = unknown>(events: TEvent[], dispatcherContext: TContext): any;
12
48
  /**
13
49
  * Publishes multiple events.
14
50
  * @param events The events to publish.
15
- * @param context The context.
51
+ * @param dispatcherContext Dispatcher context
52
+ * @param asyncContext Async context
16
53
  */
17
- publishAll<TEvent extends EventBase, TContext = unknown>(events: TEvent[], context?: TContext): any;
54
+ publishAll<TEvent extends EventBase, TContext = unknown>(events: TEvent[], dispatcherContext: TContext, asyncContext: AsyncContext): any;
18
55
  }
@@ -0,0 +1,12 @@
1
+ import { Type } from '@nestjs/common';
2
+ import { IEvent } from './event.interface';
3
+ export interface EventIdProvider<EventBase extends IEvent = IEvent> {
4
+ /**
5
+ * Retrieves the unique identifier for the given event instance.
6
+ * Returns null if the event is not associated with any handler.
7
+ *
8
+ * @param event - The event type for which to retrieve the ID.
9
+ * @returns The unique identifier for the event, or null if not connected to any handler.
10
+ */
11
+ getEventId(event: Type<EventBase>): string | null;
12
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,15 +1,18 @@
1
+ import { AsyncContext } from '../../scopes';
1
2
  import { IEvent } from './event.interface';
2
3
  export interface IEventPublisher<EventBase extends IEvent = IEvent> {
3
4
  /**
4
5
  * Publishes an event.
5
6
  * @param event The event to publish.
6
- * @param context The context.
7
+ * @param dispatcherContext Dispatcher context or undefined.
8
+ * @param asyncContext The async context (if scoped).
7
9
  */
8
- publish<TEvent extends EventBase>(event: TEvent, context?: unknown): any;
10
+ publish<TEvent extends EventBase>(event: TEvent, dispatcherContext?: unknown, asyncContext?: AsyncContext): any;
9
11
  /**
10
12
  * Publishes multiple events.
11
13
  * @param events The events to publish.
12
- * @param context The context.
14
+ * @param dispatcherContext Dispatcher context or undefined.
15
+ * @param asyncContext The async context (if scoped).
13
16
  */
14
- publishAll?<TEvent extends EventBase>(events: TEvent[], context?: unknown): any;
17
+ publishAll?<TEvent extends EventBase>(events: TEvent[], dispatcherContext?: unknown, asyncContext?: AsyncContext): any;
15
18
  }
@@ -2,11 +2,13 @@ export * from './commands/command-bus.interface';
2
2
  export * from './commands/command-handler.interface';
3
3
  export * from './commands/command-publisher.interface';
4
4
  export * from './commands/command.interface';
5
+ export * from './cqrs-module-options.interface';
5
6
  export * from './events/event-bus.interface';
6
7
  export * from './events/event-handler.interface';
7
8
  export * from './events/event-publisher.interface';
8
9
  export * from './events/event.interface';
9
10
  export * from './events/message-source.interface';
11
+ export * from './events/event-id-provider.interface';
10
12
  export * from './exceptions/unhandled-exception-info.interface';
11
13
  export * from './exceptions/unhandled-exception-publisher.interface';
12
14
  export * from './queries/query-bus.interface';
@@ -1,7 +1,11 @@
1
1
  "use strict";
2
2
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
3
  if (k2 === undefined) k2 = k;
4
- Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
5
9
  }) : (function(o, m, k, k2) {
6
10
  if (k2 === undefined) k2 = k;
7
11
  o[k2] = m[k];
@@ -14,11 +18,13 @@ __exportStar(require("./commands/command-bus.interface"), exports);
14
18
  __exportStar(require("./commands/command-handler.interface"), exports);
15
19
  __exportStar(require("./commands/command-publisher.interface"), exports);
16
20
  __exportStar(require("./commands/command.interface"), exports);
21
+ __exportStar(require("./cqrs-module-options.interface"), exports);
17
22
  __exportStar(require("./events/event-bus.interface"), exports);
18
23
  __exportStar(require("./events/event-handler.interface"), exports);
19
24
  __exportStar(require("./events/event-publisher.interface"), exports);
20
25
  __exportStar(require("./events/event.interface"), exports);
21
26
  __exportStar(require("./events/message-source.interface"), exports);
27
+ __exportStar(require("./events/event-id-provider.interface"), exports);
22
28
  __exportStar(require("./exceptions/unhandled-exception-info.interface"), exports);
23
29
  __exportStar(require("./exceptions/unhandled-exception-publisher.interface"), exports);
24
30
  __exportStar(require("./queries/query-bus.interface"), exports);
@@ -0,0 +1,10 @@
1
+ import { InstanceWrapper } from '@nestjs/core/injector/instance-wrapper';
2
+ import { ICommandHandler } from './commands/command-handler.interface';
3
+ import { IEventHandler } from './events/event-handler.interface';
4
+ import { IQueryHandler } from './queries/query-handler.interface';
5
+ export interface ProvidersIntrospectionResult {
6
+ events?: InstanceWrapper<IEventHandler>[];
7
+ queries?: InstanceWrapper<IQueryHandler>[];
8
+ commands?: InstanceWrapper<ICommandHandler>[];
9
+ sagas?: InstanceWrapper<object>[];
10
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,3 +1,5 @@
1
+ import { Query } from '../../classes/query';
2
+ import { AsyncContext } from '../../scopes/async.context';
1
3
  import { IQuery } from './query.interface';
2
4
  /**
3
5
  * Represents a query bus.
@@ -7,5 +9,20 @@ export interface IQueryBus<QueryBase extends IQuery = IQuery> {
7
9
  * Executes a query.
8
10
  * @param query The query to execute.
9
11
  */
10
- execute<T extends QueryBase = QueryBase, TRes = any>(query: T): Promise<TRes>;
12
+ execute<TResult>(query: Query<TResult>): Promise<TResult>;
13
+ /**
14
+ * Executes a query.
15
+ * @param query The query to execute.
16
+ */
17
+ execute<T extends QueryBase, TResult = any>(query: T): Promise<TResult>;
18
+ /**
19
+ * Executes a query.
20
+ * @param query The query to execute.
21
+ */
22
+ execute<TResult>(query: Query<TResult>, asyncContext: AsyncContext): Promise<TResult>;
23
+ /**
24
+ * Executes a query.
25
+ * @param query The query to execute.
26
+ */
27
+ execute<T extends QueryBase, TResult = any>(query: T, asyncContext: AsyncContext): Promise<TResult>;
11
28
  }
@@ -1,11 +1,18 @@
1
+ import { Query } from '../../classes';
1
2
  import { IQuery } from './query.interface';
2
3
  /**
3
4
  * Represents a query handler.
4
5
  */
5
- export interface IQueryHandler<T extends IQuery = any, TRes = any> {
6
+ export type IQueryHandler<T extends IQuery = any, TRes = any> = T extends Query<infer InferredQueryResult> ? {
7
+ /**
8
+ * Executes a query.
9
+ * @param query The query to execute.
10
+ */
11
+ execute(query: T): Promise<InferredQueryResult>;
12
+ } : {
6
13
  /**
7
14
  * Executes a query.
8
15
  * @param query The query to execute.
9
16
  */
10
17
  execute(query: T): Promise<TRes>;
11
- }
18
+ };
@@ -1,4 +1,4 @@
1
1
  import { Observable } from 'rxjs';
2
2
  import { ICommand } from './commands/command.interface';
3
3
  import { IEvent } from './events/event.interface';
4
- export declare type ISaga<EventBase extends IEvent = IEvent, CommandBase extends ICommand = ICommand> = (events$: Observable<EventBase>) => Observable<CommandBase>;
4
+ export type ISaga<EventBase extends IEvent = IEvent, CommandBase extends ICommand = ICommand> = (events$: Observable<EventBase>) => Observable<CommandBase>;
@@ -1,7 +1,11 @@
1
1
  "use strict";
2
2
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
3
  if (k2 === undefined) k2 = k;
4
- Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
5
9
  }) : (function(o, m, k, k2) {
6
10
  if (k2 === undefined) k2 = k;
7
11
  o[k2] = m[k];
@@ -9,4 +9,4 @@ import { IEvent } from '../interfaces';
9
9
  *
10
10
  * @return A stream only emitting the filtered instances.
11
11
  */
12
- export declare function ofType<TInput extends IEvent, TOutput extends IEvent>(...types: Type<TOutput>[]): (source: Observable<TInput>) => Observable<TOutput>;
12
+ export declare function ofType<TInput extends IEvent, T extends Type<IEvent>[]>(...types: T): (source: Observable<TInput>) => Observable<T[number] extends infer T_1 ? T_1 extends T[number] ? T_1 extends Type<infer I> ? I : never : never : never>;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ofType = void 0;
3
+ exports.ofType = ofType;
4
4
  const operators_1 = require("rxjs/operators");
5
5
  /**
6
6
  * Filter values depending on their instance type (comparison is made
@@ -14,4 +14,3 @@ function ofType(...types) {
14
14
  const isInstanceOf = (event) => !!types.find((classType) => event instanceof classType);
15
15
  return (source) => source.pipe((0, operators_1.filter)(isInstanceOf));
16
16
  }
17
- exports.ofType = ofType;
@@ -1,14 +1,19 @@
1
1
  import { Type } from '@nestjs/common';
2
2
  import { ModuleRef } from '@nestjs/core';
3
+ import { InstanceWrapper } from '@nestjs/core/injector/instance-wrapper';
3
4
  import 'reflect-metadata';
4
- import { IQuery, IQueryBus, IQueryHandler, IQueryPublisher, IQueryResult } from './interfaces';
5
+ import { Query } from './classes/query';
6
+ import { CqrsModuleOptions, IQuery, IQueryBus, IQueryHandler, IQueryPublisher, IQueryResult } from './interfaces';
7
+ import { AsyncContext } from './scopes';
5
8
  import { ObservableBus } from './utils/observable-bus';
6
- export declare type QueryHandlerType<QueryBase extends IQuery = IQuery, QueryResultBase extends IQueryResult = IQueryResult> = Type<IQueryHandler<QueryBase, QueryResultBase>>;
9
+ export type QueryHandlerType<QueryBase extends IQuery = IQuery, QueryResultBase extends IQueryResult = IQueryResult> = Type<IQueryHandler<QueryBase, QueryResultBase>>;
7
10
  export declare class QueryBus<QueryBase extends IQuery = IQuery> extends ObservableBus<QueryBase> implements IQueryBus<QueryBase> {
8
11
  private readonly moduleRef;
12
+ private readonly options?;
13
+ private readonly logger;
9
14
  private handlers;
10
15
  private _publisher;
11
- constructor(moduleRef: ModuleRef);
16
+ constructor(moduleRef: ModuleRef, options?: CqrsModuleOptions | undefined);
12
17
  /**
13
18
  * Returns the publisher.
14
19
  */
@@ -19,14 +24,29 @@ export declare class QueryBus<QueryBase extends IQuery = IQuery> extends Observa
19
24
  * @param _publisher The publisher to set.
20
25
  */
21
26
  set publisher(_publisher: IQueryPublisher<QueryBase>);
27
+ /**
28
+ * Executes a query.
29
+ * @param query The query to execute.
30
+ */
31
+ execute<TResult>(query: Query<TResult>): Promise<TResult>;
22
32
  /**
23
33
  * Executes a query.
24
34
  * @param query The query to execute.
25
35
  */
26
36
  execute<T extends QueryBase, TResult = any>(query: T): Promise<TResult>;
27
- bind<T extends QueryBase, TResult = any>(handler: IQueryHandler<T, TResult>, queryId: string): void;
28
- register(handlers?: QueryHandlerType<QueryBase>[]): void;
29
- protected registerHandler(handler: QueryHandlerType<QueryBase>): void;
37
+ /**
38
+ * Executes a query.
39
+ * @param query The query to execute.
40
+ */
41
+ execute<TResult>(query: Query<TResult>, asyncContext: AsyncContext): Promise<TResult>;
42
+ /**
43
+ * Executes a query.
44
+ * @param query The query to execute.
45
+ */
46
+ execute<T extends QueryBase, TResult = any>(query: T, asyncContext: AsyncContext): Promise<TResult>;
47
+ bind<T extends QueryBase, TResult extends IQueryResult = any>(handler: InstanceWrapper<IQueryHandler<T, TResult>>, queryId: string): void;
48
+ register(handlers?: InstanceWrapper<IQueryHandler<QueryBase>>[]): void;
49
+ protected registerHandler(handler: InstanceWrapper<IQueryHandler<QueryBase>>): void;
30
50
  private getQueryId;
31
51
  private reflectQueryId;
32
52
  private useDefaultPublisher;
package/dist/query-bus.js CHANGED
@@ -8,22 +8,35 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
8
8
  var __metadata = (this && this.__metadata) || function (k, v) {
9
9
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
10
  };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ var QueryBus_1;
11
15
  Object.defineProperty(exports, "__esModule", { value: true });
12
16
  exports.QueryBus = void 0;
13
17
  const common_1 = require("@nestjs/common");
14
18
  const core_1 = require("@nestjs/core");
15
19
  require("reflect-metadata");
16
- const constants_1 = require("./decorators/constants");
20
+ const constants_1 = require("./constants");
21
+ const constants_2 = require("./decorators/constants");
17
22
  const exceptions_1 = require("./exceptions");
18
23
  const invalid_query_handler_exception_1 = require("./exceptions/invalid-query-handler.exception");
19
24
  const default_query_pubsub_1 = require("./helpers/default-query-pubsub");
25
+ const scopes_1 = require("./scopes");
20
26
  const observable_bus_1 = require("./utils/observable-bus");
21
- let QueryBus = class QueryBus extends observable_bus_1.ObservableBus {
22
- constructor(moduleRef) {
27
+ let QueryBus = QueryBus_1 = class QueryBus extends observable_bus_1.ObservableBus {
28
+ constructor(moduleRef, options) {
23
29
  super();
24
30
  this.moduleRef = moduleRef;
31
+ this.options = options;
32
+ this.logger = new common_1.Logger(QueryBus_1.name);
25
33
  this.handlers = new Map();
26
- this.useDefaultPublisher();
34
+ if (this.options?.queryPublisher) {
35
+ this._publisher = this.options.queryPublisher;
36
+ }
37
+ else {
38
+ this.useDefaultPublisher();
39
+ }
27
40
  }
28
41
  /**
29
42
  * Returns the publisher.
@@ -43,7 +56,7 @@ let QueryBus = class QueryBus extends observable_bus_1.ObservableBus {
43
56
  * Executes a query.
44
57
  * @param query The query to execute.
45
58
  */
46
- async execute(query) {
59
+ async execute(query, asyncContext) {
47
60
  const queryId = this.getQueryId(query);
48
61
  const handler = this.handlers.get(queryId);
49
62
  if (!handler) {
@@ -51,37 +64,51 @@ let QueryBus = class QueryBus extends observable_bus_1.ObservableBus {
51
64
  throw new exceptions_1.QueryHandlerNotFoundException(queryName);
52
65
  }
53
66
  this._publisher.publish(query);
54
- const result = await handler.execute(query);
55
- return result;
67
+ return (await handler(query, asyncContext));
56
68
  }
57
69
  bind(handler, queryId) {
58
- this.handlers.set(queryId, handler);
70
+ if (handler.isDependencyTreeStatic()) {
71
+ const instance = handler.instance;
72
+ if (!instance.execute) {
73
+ throw new invalid_query_handler_exception_1.InvalidQueryHandlerException();
74
+ }
75
+ this.handlers.set(queryId, (query) => instance.execute(query));
76
+ return;
77
+ }
78
+ this.handlers.set(queryId, async (query, context) => {
79
+ context ??= scopes_1.AsyncContext.of(query) ?? new scopes_1.AsyncContext();
80
+ this.moduleRef.registerRequestByContextId(context, context.id);
81
+ const instance = await this.moduleRef.resolve(handler.metatype, context.id, {
82
+ strict: false,
83
+ });
84
+ return instance.execute(query);
85
+ });
59
86
  }
60
87
  register(handlers = []) {
61
88
  handlers.forEach((handler) => this.registerHandler(handler));
62
89
  }
63
90
  registerHandler(handler) {
64
- const instance = this.moduleRef.get(handler, { strict: false });
65
- if (!instance) {
66
- return;
67
- }
68
- const target = this.reflectQueryId(handler);
91
+ const typeRef = handler.metatype;
92
+ const target = this.reflectQueryId(typeRef);
69
93
  if (!target) {
70
94
  throw new invalid_query_handler_exception_1.InvalidQueryHandlerException();
71
95
  }
72
- this.bind(instance, target);
96
+ if (this.handlers.has(target)) {
97
+ this.logger.warn(`Query handler [${typeRef.name}] is already registered. Overriding previously registered handler.`);
98
+ }
99
+ this.bind(handler, target);
73
100
  }
74
101
  getQueryId(query) {
75
102
  const { constructor: queryType } = Object.getPrototypeOf(query);
76
- const queryMetadata = Reflect.getMetadata(constants_1.QUERY_METADATA, queryType);
103
+ const queryMetadata = Reflect.getMetadata(constants_2.QUERY_METADATA, queryType);
77
104
  if (!queryMetadata) {
78
105
  throw new exceptions_1.QueryHandlerNotFoundException(queryType.name);
79
106
  }
80
107
  return queryMetadata.id;
81
108
  }
82
109
  reflectQueryId(handler) {
83
- const query = Reflect.getMetadata(constants_1.QUERY_HANDLER_METADATA, handler);
84
- const queryMetadata = Reflect.getMetadata(constants_1.QUERY_METADATA, query);
110
+ const query = Reflect.getMetadata(constants_2.QUERY_HANDLER_METADATA, handler);
111
+ const queryMetadata = Reflect.getMetadata(constants_2.QUERY_METADATA, query);
85
112
  return queryMetadata.id;
86
113
  }
87
114
  useDefaultPublisher() {
@@ -92,8 +119,10 @@ let QueryBus = class QueryBus extends observable_bus_1.ObservableBus {
92
119
  return constructor.name;
93
120
  }
94
121
  };
95
- QueryBus = __decorate([
122
+ exports.QueryBus = QueryBus;
123
+ exports.QueryBus = QueryBus = QueryBus_1 = __decorate([
96
124
  (0, common_1.Injectable)(),
97
- __metadata("design:paramtypes", [core_1.ModuleRef])
125
+ __param(1, (0, common_1.Optional)()),
126
+ __param(1, (0, common_1.Inject)(constants_1.CQRS_MODULE_OPTIONS)),
127
+ __metadata("design:paramtypes", [core_1.ModuleRef, Object])
98
128
  ], QueryBus);
99
- exports.QueryBus = QueryBus;
@@ -0,0 +1,30 @@
1
+ export declare const ASYNC_CONTEXT_ATTRIBUTE: unique symbol;
2
+ /**
3
+ * Represents the context of an asynchronous operation.
4
+ */
5
+ export declare class AsyncContext {
6
+ readonly id: import("@nestjs/core").ContextId;
7
+ /**
8
+ * Attaches the context to an object.
9
+ * @param target The object to attach the context to.
10
+ */
11
+ attachTo(target: object): void;
12
+ /**
13
+ * Checks if target is already attached to any async context.
14
+ * @param target The object to check.
15
+ * @returns "true" if the target is attached to an async context, "false" otherwise.
16
+ */
17
+ static isAttached(target: object): boolean;
18
+ /**
19
+ * Merges the context of an asynchronous operation from a given command, query, or event to another object.
20
+ * @param from A command, query, or event.
21
+ * @param to A command, query, or event to merge the context to.
22
+ */
23
+ static merge(from: object, to: object): void;
24
+ /**
25
+ * Gets the context of an asynchronous operation from a given object.
26
+ * @param target A command, query, or event.
27
+ * @returns An "AsyncContext" instance or "undefined" if the context is not found.
28
+ */
29
+ static of(target: object): AsyncContext | undefined;
30
+ }
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AsyncContext = exports.ASYNC_CONTEXT_ATTRIBUTE = void 0;
4
+ const core_1 = require("@nestjs/core");
5
+ exports.ASYNC_CONTEXT_ATTRIBUTE = Symbol('ASYNC_CONTEXT_ATTRIBUTE');
6
+ /**
7
+ * Represents the context of an asynchronous operation.
8
+ */
9
+ class AsyncContext {
10
+ constructor() {
11
+ this.id = core_1.ContextIdFactory.create();
12
+ }
13
+ /**
14
+ * Attaches the context to an object.
15
+ * @param target The object to attach the context to.
16
+ */
17
+ attachTo(target) {
18
+ Object.defineProperty(target, exports.ASYNC_CONTEXT_ATTRIBUTE, {
19
+ value: this,
20
+ enumerable: false,
21
+ });
22
+ }
23
+ /**
24
+ * Checks if target is already attached to any async context.
25
+ * @param target The object to check.
26
+ * @returns "true" if the target is attached to an async context, "false" otherwise.
27
+ */
28
+ static isAttached(target) {
29
+ return !!target[exports.ASYNC_CONTEXT_ATTRIBUTE];
30
+ }
31
+ /**
32
+ * Merges the context of an asynchronous operation from a given command, query, or event to another object.
33
+ * @param from A command, query, or event.
34
+ * @param to A command, query, or event to merge the context to.
35
+ */
36
+ static merge(from, to) {
37
+ if (!from || !to) {
38
+ return;
39
+ }
40
+ const fromContext = from[exports.ASYNC_CONTEXT_ATTRIBUTE];
41
+ if (!fromContext) {
42
+ return;
43
+ }
44
+ Object.defineProperty(to, exports.ASYNC_CONTEXT_ATTRIBUTE, {
45
+ value: fromContext,
46
+ enumerable: false,
47
+ });
48
+ }
49
+ /**
50
+ * Gets the context of an asynchronous operation from a given object.
51
+ * @param target A command, query, or event.
52
+ * @returns An "AsyncContext" instance or "undefined" if the context is not found.
53
+ */
54
+ static of(target) {
55
+ return target[exports.ASYNC_CONTEXT_ATTRIBUTE];
56
+ }
57
+ }
58
+ exports.AsyncContext = AsyncContext;
@@ -0,0 +1 @@
1
+ export * from './async.context';
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./async.context"), exports);
@@ -1,14 +1,12 @@
1
- import { Type } from '@nestjs/common';
2
1
  import { InstanceWrapper } from '@nestjs/core/injector/instance-wrapper';
3
2
  import { Module } from '@nestjs/core/injector/module';
4
3
  import { ModulesContainer } from '@nestjs/core/injector/modules-container';
5
4
  import { IEvent } from '../interfaces';
6
- import { CqrsOptions } from '../interfaces/cqrs-options.interface';
5
+ import { ProvidersIntrospectionResult } from '../interfaces/providers-introspection-result.interface';
7
6
  export declare class ExplorerService<EventBase extends IEvent = IEvent> {
8
7
  private readonly modulesContainer;
9
8
  constructor(modulesContainer: ModulesContainer);
10
- explore(): CqrsOptions;
11
- flatMap<T>(modules: Module[], callback: (instance: InstanceWrapper) => Type<any> | undefined): Type<T>[];
12
- filterProvider(wrapper: InstanceWrapper, metadataKey: string): Type<any> | undefined;
13
- extractMetadata(instance: Record<string, any>, metadataKey: string): Type<any>;
9
+ explore(): ProvidersIntrospectionResult;
10
+ flatMap<T extends object>(modules: Module[], callback: (instance: InstanceWrapper) => InstanceWrapper<any> | undefined): InstanceWrapper<T>[];
11
+ filterByMetadataKey(wrapper: InstanceWrapper, metadataKey: string): InstanceWrapper<any> | undefined;
14
12
  }
@@ -19,35 +19,35 @@ let ExplorerService = class ExplorerService {
19
19
  }
20
20
  explore() {
21
21
  const modules = [...this.modulesContainer.values()];
22
- const commands = this.flatMap(modules, (instance) => this.filterProvider(instance, constants_1.COMMAND_HANDLER_METADATA));
23
- const queries = this.flatMap(modules, (instance) => this.filterProvider(instance, constants_1.QUERY_HANDLER_METADATA));
24
- const events = this.flatMap(modules, (instance) => this.filterProvider(instance, constants_1.EVENTS_HANDLER_METADATA));
25
- const sagas = this.flatMap(modules, (instance) => this.filterProvider(instance, constants_1.SAGA_METADATA));
22
+ const commands = this.flatMap(modules, (instance) => this.filterByMetadataKey(instance, constants_1.COMMAND_HANDLER_METADATA));
23
+ const queries = this.flatMap(modules, (instance) => this.filterByMetadataKey(instance, constants_1.QUERY_HANDLER_METADATA));
24
+ const events = this.flatMap(modules, (instance) => this.filterByMetadataKey(instance, constants_1.EVENTS_HANDLER_METADATA));
25
+ const sagas = this.flatMap(modules, (instance) => this.filterByMetadataKey(instance, constants_1.SAGA_METADATA));
26
26
  return { commands, queries, events, sagas };
27
27
  }
28
28
  flatMap(modules, callback) {
29
29
  const items = modules
30
- .map((module) => [...module.providers.values()].map(callback))
30
+ .map((moduleRef) => [...moduleRef.providers.values()].map(callback))
31
31
  .reduce((a, b) => a.concat(b), []);
32
- return items.filter((element) => !!element);
32
+ return items.filter((item) => !!item);
33
33
  }
34
- filterProvider(wrapper, metadataKey) {
34
+ filterByMetadataKey(wrapper, metadataKey) {
35
35
  const { instance } = wrapper;
36
36
  if (!instance) {
37
- return undefined;
37
+ return;
38
38
  }
39
- return this.extractMetadata(instance, metadataKey);
40
- }
41
- extractMetadata(instance, metadataKey) {
42
39
  if (!instance.constructor) {
43
40
  return;
44
41
  }
45
42
  const metadata = Reflect.getMetadata(metadataKey, instance.constructor);
46
- return metadata ? instance.constructor : undefined;
43
+ if (!metadata) {
44
+ return;
45
+ }
46
+ return wrapper;
47
47
  }
48
48
  };
49
- ExplorerService = __decorate([
49
+ exports.ExplorerService = ExplorerService;
50
+ exports.ExplorerService = ExplorerService = __decorate([
50
51
  (0, common_1.Injectable)(),
51
52
  __metadata("design:paramtypes", [modules_container_1.ModulesContainer])
52
53
  ], ExplorerService);
53
- exports.ExplorerService = ExplorerService;
@@ -0,0 +1,8 @@
1
+ import { Type } from '@nestjs/common';
2
+ import { AggregateRoot } from '../aggregate-root';
3
+ import { EventBus } from '../event-bus';
4
+ export declare class AggregateRootStorage {
5
+ private static storage;
6
+ static add(type: Type<AggregateRoot>): void;
7
+ static mergeContext(eventBus: EventBus): void;
8
+ }
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AggregateRootStorage = void 0;
4
+ class AggregateRootStorage {
5
+ static add(type) {
6
+ this.storage.push(type);
7
+ }
8
+ static mergeContext(eventBus) {
9
+ for (const item of this.storage) {
10
+ item.prototype.publish = function (event) {
11
+ eventBus.publish(event);
12
+ };
13
+ item.prototype.publishAll = function (events) {
14
+ eventBus.publishAll(events);
15
+ };
16
+ }
17
+ this.storage = [];
18
+ }
19
+ }
20
+ exports.AggregateRootStorage = AggregateRootStorage;
21
+ AggregateRootStorage.storage = [];