-
Notifications
You must be signed in to change notification settings - Fork 23
Expand file tree
/
Copy pathIAggregate.ts
More file actions
106 lines (89 loc) · 3.5 KB
/
IAggregate.ts
File metadata and controls
106 lines (89 loc) · 3.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
import type { ICommand } from './ICommand.ts';
import type { Identifier } from './Identifier.ts';
import type { IEvent } from './IEvent.ts';
import type { IEventSet } from './IEventSet.ts';
import type { IMutableState } from './IMutableState.ts';
/**
* Core interface representing an Aggregate in a CQRS architecture.
* An aggregate encapsulates business logic and state, handling commands
* and applying events to transition between states.
*/
export interface IAggregate {
/**
* Applies a single event to update the aggregate's internal state.
*
* This method is used primarily when rehydrating the aggregate
* from the persisted sequence of events
*
* @param event - The event to be applied
*/
mutate(event: IEvent): void;
/**
* Processes a command by executing the aggregate's business logic,
* resulting in new events that capture the state changes.
* It serves as the primary entry point for invoking aggregate behavior
*
* @param command - The command to be processed
* @returns A set of events produced by the command
*/
handle(command: ICommand): IEventSet | Promise<IEventSet>;
}
export type IAggregateConstructorParams<TState extends IMutableState | object | void> = {
/** Unique aggregate identifier */
id: Identifier,
/**
* @deprecated The aggregate no longer receives all events in the constructor.
* Instead, events are loaded and passed to the `mutate` method after instantiation.
*/
events?: IEventSet,
/** Aggregate state instance */
state?: TState
};
export type RetryOnConcurrencyErrorDecision = boolean | 'ignore';
export type RetryOnConcurrencyErrorResolver =
(err: unknown, events: IEventSet | undefined, attempt: number) => RetryOnConcurrencyErrorDecision;
export type RetryOnConcurrencyErrorConfig = {
maxRetries?: number;
ignoreAfterMaxRetries?: boolean;
};
export type RetryOnConcurrencyErrorOptions =
RetryOnConcurrencyErrorDecision |
RetryOnConcurrencyErrorConfig |
RetryOnConcurrencyErrorResolver |
number;
export interface IAggregateConstructor<
TAggregate extends IAggregate,
TState extends IMutableState | object | void
> {
/**
* List of command types handled by the aggregate.
*
* Used to subscribe AggregateCommandHandler to the command bus.
*/
readonly handles: string[];
/**
* Optional list of event types that are required to restore the aggregate state.
*
* If provided, AggregateCommandHandler can request only these events from storage
* (typically together with a `tail: 'last'` marker to restore the version).
*/
readonly restoresFrom?: Readonly<string[]>;
/**
* Defines retry behavior when a ConcurrencyError is thrown during event dispatch.
*
* - `undefined` (default): retry up to 5 times on ConcurrencyError
* - `false`: no retry
* - `true`: retry up to 5 times on ConcurrencyError
* - `'ignore'`: on ConcurrencyError, force-dispatch immediately with `ignoreConcurrencyError: true`
* - `number`: retry up to the specified number of times on ConcurrencyError
* - `{ maxRetries?: number, ignoreAfterMaxRetries?: boolean }`: configure retries
* - `(err, events, attempt) => RetryOnConcurrencyErrorDecision`:
* custom function to decide whether to retry (`true`), stop (`false`) or ignore (`'ignore'`)
*/
readonly retryOnConcurrencyError?: RetryOnConcurrencyErrorOptions;
new(options: IAggregateConstructorParams<TState>): TAggregate;
}
export type IAggregateFactory<
TAggregate extends IAggregate,
TState extends IMutableState | object | void
> = (options: IAggregateConstructorParams<TState>) => TAggregate;