@event-nest/core 0.0.1 → 0.0.3
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.
- package/README.md +234 -6
- package/package.json +6 -5
- package/src/index.d.ts +14 -9
- package/src/index.js +14 -9
- package/src/index.js.map +1 -1
- package/src/lib/aggregate-root-aware-event.d.ts +4 -0
- package/src/lib/aggregate-root-aware-event.js +3 -0
- package/src/lib/aggregate-root-aware-event.js.map +1 -0
- package/src/lib/aggregate-root-name.d.ts +2 -0
- package/src/lib/aggregate-root-name.js +16 -0
- package/src/lib/aggregate-root-name.js.map +1 -0
- package/src/lib/aggregate-root.d.ts +50 -0
- package/src/lib/aggregate-root.js +134 -0
- package/src/lib/aggregate-root.js.map +1 -0
- package/src/lib/core-module-options.d.ts +11 -0
- package/src/lib/core-module-options.js +3 -0
- package/src/lib/core-module-options.js.map +1 -0
- package/src/lib/domain-event-emitter.d.ts +13 -0
- package/src/lib/domain-event-emitter.js +59 -0
- package/src/lib/domain-event-emitter.js.map +1 -0
- package/src/lib/domain-event-subscription.d.ts +5 -0
- package/src/lib/domain-event-subscription.js +33 -0
- package/src/lib/domain-event-subscription.js.map +1 -0
- package/src/lib/event-processor.d.ts +5 -0
- package/src/lib/{decorators/event-processor.js → event-processor.js} +5 -5
- package/src/lib/event-processor.js.map +1 -0
- package/src/lib/{decorators → exceptions}/event-name-conflict-exception.js.map +1 -1
- package/src/lib/exceptions/id-generation-exception.js.map +1 -0
- package/src/lib/exceptions/missing-aggregate-root-name-exception.d.ts +3 -0
- package/src/lib/exceptions/missing-aggregate-root-name-exception.js +10 -0
- package/src/lib/exceptions/missing-aggregate-root-name-exception.js.map +1 -0
- package/src/lib/exceptions/unknown-event-exception.d.ts +3 -0
- package/src/lib/exceptions/unknown-event-exception.js +10 -0
- package/src/lib/exceptions/unknown-event-exception.js.map +1 -0
- package/src/lib/exceptions/unregistered-event-exception.d.ts +3 -0
- package/src/lib/exceptions/unregistered-event-exception.js +10 -0
- package/src/lib/exceptions/unregistered-event-exception.js.map +1 -0
- package/src/lib/metadata-keys.d.ts +4 -0
- package/src/lib/metadata-keys.js +8 -0
- package/src/lib/metadata-keys.js.map +1 -0
- package/src/lib/on-domain-event.d.ts +4 -0
- package/src/lib/{storage/event-payload.js → on-domain-event.js} +1 -1
- package/src/lib/on-domain-event.js.map +1 -0
- package/src/lib/{decorators/registered-event.d.ts → registered-event.d.ts} +2 -2
- package/src/lib/{decorators/registered-event.js → registered-event.js} +7 -3
- package/src/lib/registered-event.js.map +1 -0
- package/src/lib/storage/abstract-event-store.d.ts +6 -4
- package/src/lib/storage/abstract-event-store.js +14 -5
- package/src/lib/storage/abstract-event-store.js.map +1 -1
- package/src/lib/storage/event-store.d.ts +36 -2
- package/src/lib/storage/event-store.js.map +1 -1
- package/src/lib/storage/stored-aggregate-root.d.ts +4 -0
- package/src/lib/storage/stored-aggregate-root.js +4 -0
- package/src/lib/storage/stored-aggregate-root.js.map +1 -1
- package/src/lib/storage/stored-event.d.ts +37 -3
- package/src/lib/storage/stored-event.js +43 -5
- package/src/lib/storage/stored-event.js.map +1 -1
- package/src/lib/decorators/event-processor.d.ts +0 -5
- package/src/lib/decorators/event-processor.js.map +0 -1
- package/src/lib/decorators/registered-event.js.map +0 -1
- package/src/lib/domain/aggregate-root.d.ts +0 -48
- package/src/lib/domain/aggregate-root.js +0 -109
- package/src/lib/domain/aggregate-root.js.map +0 -1
- package/src/lib/domain/missing-event-processor-exception.d.ts +0 -3
- package/src/lib/domain/missing-event-processor-exception.js +0 -10
- package/src/lib/domain/missing-event-processor-exception.js.map +0 -1
- package/src/lib/storage/event-payload.d.ts +0 -3
- package/src/lib/storage/event-payload.js.map +0 -1
- package/src/lib/storage/id-generation-exception.js.map +0 -1
- /package/src/lib/{decorators → exceptions}/event-name-conflict-exception.d.ts +0 -0
- /package/src/lib/{decorators → exceptions}/event-name-conflict-exception.js +0 -0
- /package/src/lib/{storage → exceptions}/id-generation-exception.d.ts +0 -0
- /package/src/lib/{storage → exceptions}/id-generation-exception.js +0 -0
package/README.md
CHANGED
|
@@ -1,11 +1,239 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Event Nest
|
|
2
|
+
A collection of [nest.js](https://nestjs.com/) libraries to help you build applications based on event sourcing architecture.
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
## Description
|
|
5
|
+
Event Nest is a collection of libraries based on nest.js that assists in implementing the core concepts of event sourcing:
|
|
6
|
+
* Saving events in a persistent storage
|
|
7
|
+
* Utilizing the saved events to trigger side effects, such as updating your read model
|
|
8
|
+
* Replaying events to reconstruct the state of your application
|
|
4
9
|
|
|
5
|
-
|
|
10
|
+
Given that event sourcing is commonly used in conjunction with [CQRS](https://martinfowler.com/bliki/CQRS.html) and [Domain Driven Design](https://en.wikipedia.org/wiki/Domain-driven_design), these libraries adopt principles from these architectural patterns.
|
|
6
11
|
|
|
7
|
-
|
|
12
|
+
It would also probably help to make some distinctions about what Event Nest is not :
|
|
13
|
+
* It is not a framework, it is a set of libraries which are designed to be used with nest.js.
|
|
14
|
+
* It is not an ORM, if you want an ORM to define simple models, there are far better solutions out there.
|
|
15
|
+
* It is not a library for establishing event-based communication between services.
|
|
16
|
+
* **Although the code is covered by tests, the library is not widely tested in production. Use it at your own risk.**
|
|
8
17
|
|
|
9
|
-
##
|
|
18
|
+
## Why?
|
|
19
|
+
Implementing event sourcing in an application can be challenging, particularly when combined with CQRS and DDD.
|
|
20
|
+
|
|
21
|
+
Nest.js provides a [fantastic module](https://github.com/nestjs/cqrs) for CQRS but after using it for a while I thought that maybe some things could be improved.
|
|
22
|
+
Furthermore, these improvements can't be added to the official module due to its lightweight and abstract nature.
|
|
23
|
+
For instance, the official module lacks a specific way of persisting the events to a storage.
|
|
24
|
+
|
|
25
|
+
This is where Event Nest comes into play. In fact, a significant portion of the code in Event Nest is influenced by how things are implemented in the official module.
|
|
26
|
+
|
|
27
|
+
This project evolved into a library after I used the official module with my improvements in a few projects and I thought that it could be useful to other people. To make things
|
|
28
|
+
simpler, the library is not depending on the official module, so you can use it without having to worry about conflicts.
|
|
29
|
+
|
|
30
|
+
## Getting Started
|
|
31
|
+
Depending on the storage solution you intend to use, you will need to install the corresponding packages.
|
|
32
|
+
At the moment, only MongoDB is supported, hopefully soon there will be more.
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npm install --save @event-nest/core @event-nest/mongodb
|
|
36
|
+
```
|
|
37
|
+
After installation, import the `EventNestMongoDbModule` to your nest.js application :
|
|
38
|
+
```typescript
|
|
39
|
+
import { Module } from "@nestjs/common";
|
|
40
|
+
import { EventNestMongoDbModule } from "@event-nest/mongodb";
|
|
41
|
+
|
|
42
|
+
@Module({
|
|
43
|
+
imports: [
|
|
44
|
+
EventNestMongoDbModule.register({
|
|
45
|
+
connectionUri: "mongodb://localhost:27017/example",
|
|
46
|
+
aggregatesCollection: "aggregates-collection",
|
|
47
|
+
eventsCollection: "events-collection"
|
|
48
|
+
}),
|
|
49
|
+
],
|
|
50
|
+
})
|
|
51
|
+
export class AppModule {}
|
|
52
|
+
```
|
|
53
|
+
The collection settings define which MongoDB collections will be used to store the aggregates and the events.
|
|
54
|
+
Use any collection you want but be sure to create it before running the application.
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
## Concepts
|
|
59
|
+
### Aggregate Root
|
|
60
|
+
An [aggregate root](https://stackoverflow.com/questions/1958621/whats-an-aggregate-root) is a concept from Domain Driven Design. It is a domain object that is responsible for maintaining the consistency of the aggregate.
|
|
61
|
+
To achieve this, the aggregate root should expose methods which encapsulate its behaviour. Any method that needs to update the state, should also append an event to the aggregate root's event stream.
|
|
62
|
+
|
|
63
|
+
### Event
|
|
64
|
+
An event is a representation of something that has happened in the past. It is identified by a unique name, and it may contain additional data that will be persisted with the event.
|
|
65
|
+
|
|
66
|
+
Each event can be used for three purposes :
|
|
67
|
+
* It will be persisted so that it can be used to reconstruct the state of an aggregate root
|
|
68
|
+
* It will be passed to any internal subscribers that need to react to this event (e.g. updating the read model)
|
|
69
|
+
* When it's time to recreate the aggregate root, the event will be processed by the correct method in the aggregate root
|
|
70
|
+
|
|
71
|
+
Enough with the theory, let's see an example that includes all of the above.
|
|
72
|
+
|
|
73
|
+
#### Example
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
import { RegisteredEvent } from "@event-nest/core";
|
|
77
|
+
|
|
78
|
+
@RegisteredEvent("user-created-event")
|
|
79
|
+
export class UserCreatedEvent {
|
|
80
|
+
constructor(public name: string, public email: string) {}
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
import { RegisteredEvent } from "@event-nest/core";
|
|
86
|
+
|
|
87
|
+
@RegisteredEvent("user-updated-event")
|
|
88
|
+
export class UserUpdatedEvent {
|
|
89
|
+
constructor(public newName: string) {}
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
We start this example by defining two simple events for a user: a creation event and an update event. Each one has its own data, and they are identified by a unique name which is set with the `@RegisteredEvent` decorator.
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
import { AggregateRoot, AggregateRootName, EventProcessor, StoredEvent } from "@event-nest/core";
|
|
97
|
+
|
|
98
|
+
@AggregateRootName("User")
|
|
99
|
+
export class User extends AggregateRoot {
|
|
100
|
+
private _name: string;
|
|
101
|
+
private _email: string;
|
|
102
|
+
|
|
103
|
+
private constructor(id: string) {
|
|
104
|
+
super(id);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
public static createNew(id: string, name: string, email: string): User {
|
|
108
|
+
const user = new User(id);
|
|
109
|
+
const event = new UserCreatedEvent(name, email);
|
|
110
|
+
user.processUserCreatedEvent(event);
|
|
111
|
+
user.append(event);
|
|
112
|
+
return user;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
public static fromEvents(id: string, events: Array<StoredEvent>): User {
|
|
116
|
+
const user = new User(id);
|
|
117
|
+
user.reconstitute(events);
|
|
118
|
+
return user;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
public update(newName: string) {
|
|
122
|
+
const event = new UserUpdatedEvent(newName);
|
|
123
|
+
this.processUserUpdatedEvent(event);
|
|
124
|
+
this.append(event);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
@EventProcessor(UserCreatedEvent)
|
|
128
|
+
private processUserCreatedEvent = (event: UserCreatedEvent) => {
|
|
129
|
+
this._name = event.name;
|
|
130
|
+
this._email = event.email;
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
@EventProcessor(UserUpdatedEvent)
|
|
134
|
+
private processUserUpdatedEvent = (event: UserUpdatedEvent) => {
|
|
135
|
+
this._name = event.newName;
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Next, we define the aggregate root for the user. There's a lot going on here so let's break it down.
|
|
142
|
+
|
|
143
|
+
First of all, the class has to extend the `AggregateRoot` class, and it has to be decorated with the `@AggregateRootName` decorator.
|
|
144
|
+
The name is required to associate persisted events with the correct aggregate root when retrieving them from storage.
|
|
145
|
+
|
|
146
|
+
Now let's talk about the constructor. TypeScript doesn't allow us to define multiple constructors. So if we have two ways of creating an object, we could use static methods as factories.
|
|
147
|
+
In our case, we have the following creation cases :
|
|
148
|
+
* The user is new, and we need to create it from scratch. In that case, we create a new `UserCreatedEvent` event, and we `append` it to the aggregate root's event stream.
|
|
149
|
+
* The user already exists. In that case we need to recreate the aggregate root from the events that have been persisted. We do that by calling the `reconstitute` method.
|
|
150
|
+
|
|
151
|
+
The `reconstitute` method will initiate the event processing based on the events order.
|
|
152
|
+
|
|
153
|
+
To process each event, we have defined two private methods which are decorated with the `@EventProcessor` decorator. Each method will be called when the corresponding event is retrieved, and it's ready to be processed.
|
|
154
|
+
This is the place to update the object's internal state based on the event's data. **Make sure that these methods are defined as arrow functions, otherwise they won't be called.**
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
Finally, we define an `update` method which is the place to run any business logic we need and append the corresponding event (`UserUpdatedEvent`) to the event stream.
|
|
158
|
+
|
|
159
|
+
It's important to note that the append method is not saving the event. All the appended events can be saved by calling the `commit` method on the aggregate root.
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
import { EVENT_STORE, EventStore } from "@event-nest/core";
|
|
163
|
+
|
|
164
|
+
@Injectable()
|
|
165
|
+
export class UserService {
|
|
166
|
+
constructor(@Inject(EVENT_STORE) private eventStore: EventStore) {}
|
|
167
|
+
|
|
168
|
+
async createUser(name: string, email: string) {
|
|
169
|
+
const user = User.createNew(new ObjectId().toHexString(), name, email);
|
|
170
|
+
const userWithPublisher = this.eventStore.addPublisher(user);
|
|
171
|
+
await userWithPublisher.commit();
|
|
172
|
+
return user.id;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
async updateUser(id: string, newName: string) {
|
|
176
|
+
const events = await this.eventStore.findByAggregateRootId(User, id);
|
|
177
|
+
const user = User.fromEvents(id, events);
|
|
178
|
+
const userWithPublisher = this.eventStore.addPublisher(user);
|
|
179
|
+
user.update(newName);
|
|
180
|
+
await userWithPublisher.commit();
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
The final piece of the puzzle is a nest.js service that will manage the process.
|
|
186
|
+
|
|
187
|
+
We start by injecting the `EventStore`, which will be used to retrieve persisted events.
|
|
188
|
+
|
|
189
|
+
Additionally, since the aggregate root classes are not managed by the nest.js dependency injection system, we need to connect them to the event store by calling the `addPublisher` method. This will allow the
|
|
190
|
+
`commit` method to work as expected.
|
|
191
|
+
|
|
192
|
+
### Domain Event Subscription
|
|
193
|
+
When working with event sourcing, you will likely need a way of updating other parts of your system when an event is persisted. For example, you may have a read model for users that needs to be updated when a user is created or updated.
|
|
194
|
+
|
|
195
|
+
To achieve this, you can implement a service decorated with the `@DomainEventSubscription` decorator. This decorator takes a list of events that the service is interested in, and it automatically subscribes to them when the service is initialized.
|
|
196
|
+
|
|
197
|
+
To ensure that the method is implemented correctly, you can use the `OnDomainEvent` interface.
|
|
198
|
+
|
|
199
|
+
#### Example
|
|
200
|
+
```typescript
|
|
201
|
+
import { AggregateRootAwareEvent, DomainEventSubscription, OnDomainEvent } from "@event-nest/core";
|
|
202
|
+
|
|
203
|
+
@Injectable()
|
|
204
|
+
@DomainEventSubscription(UserCreatedEvent, UserUpdatedEvent)
|
|
205
|
+
export class UserEventSubscription implements OnDomainEvent<UserCreatedEvent | UserUpdatedEvent> {
|
|
206
|
+
|
|
207
|
+
onDomainEvent(event: AggregateRootAwareEvent<UserCreatedEvent | UserUpdatedEvent>): Promise<unknown> {
|
|
208
|
+
//Here you can create/update your read model based on the event and your custom logic.
|
|
209
|
+
return Promise.resolve(undefined);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
If there are multiple subscription services for the same event, they will be executed in parallel.
|
|
216
|
+
However, if there are multiple events that the service is subscribed to, they will be executed sequentially based on the order they were emitted.
|
|
217
|
+
|
|
218
|
+
This is the default behaviour because there are cases where the logic may depend on the completion of the previous event. If you want better performance
|
|
219
|
+
and your logic doesn't depend on the order of the events, you can change this setting when you import the module.
|
|
220
|
+
|
|
221
|
+
```typescript
|
|
222
|
+
@Module({
|
|
223
|
+
imports: [
|
|
224
|
+
EventNestMongoDbModule.register({
|
|
225
|
+
connectionUri: "mongodb://localhost:27017/example",
|
|
226
|
+
aggregatesCollection: "aggregates-collection",
|
|
227
|
+
eventsCollection: "events-collection",
|
|
228
|
+
runParallelSubscriptions:true
|
|
229
|
+
})
|
|
230
|
+
]
|
|
231
|
+
})
|
|
232
|
+
export class AppModule {}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
## License
|
|
238
|
+
Event Nest is [MIT licensed](https://github.com/nestjs/nest/blob/master/LICENSE).
|
|
10
239
|
|
|
11
|
-
Run `nx test core` to execute the unit tests via [Jest](https://jestjs.io).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@event-nest/core",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "Nick Tsitlakidis",
|
|
6
6
|
"description": "Event sourcing module for NestJS. It provides a set of decorators and interfaces to help you build your event sourcing application.",
|
|
@@ -12,13 +12,14 @@
|
|
|
12
12
|
],
|
|
13
13
|
"type": "commonjs",
|
|
14
14
|
"peerDependencies": {
|
|
15
|
-
"@nestjs/common": "^
|
|
16
|
-
"@nestjs/core": "^
|
|
15
|
+
"@nestjs/common": "^9.0.0",
|
|
16
|
+
"@nestjs/core": "^9.0.0",
|
|
17
|
+
"reflect-metadata": "0.1.13",
|
|
18
|
+
"rxjs": "^7.2.0",
|
|
17
19
|
"tslib": "2.5.3"
|
|
18
20
|
},
|
|
19
21
|
"dependencies": {
|
|
20
|
-
"class-transformer": "^0.5.1"
|
|
21
|
-
"reflect-metadata": "^0.1.13"
|
|
22
|
+
"class-transformer": "^0.5.1"
|
|
22
23
|
},
|
|
23
24
|
"main": "./src/index.js",
|
|
24
25
|
"types": "./src/index.d.ts"
|
package/src/index.d.ts
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
|
-
export * from "./lib/
|
|
2
|
-
export * from "./lib/
|
|
3
|
-
export * from "./lib/
|
|
4
|
-
export * from "./lib/
|
|
5
|
-
export * from "./lib/
|
|
6
|
-
export * from "./lib/
|
|
7
|
-
export * from "./lib/
|
|
8
|
-
export * from "./lib/
|
|
9
|
-
export * from "./lib/
|
|
1
|
+
export * from "./lib/exceptions/event-name-conflict-exception";
|
|
2
|
+
export * from "./lib/exceptions/unknown-event-exception";
|
|
3
|
+
export * from "./lib/exceptions/missing-aggregate-root-name-exception";
|
|
4
|
+
export * from "./lib/event-processor";
|
|
5
|
+
export * from "./lib/registered-event";
|
|
6
|
+
export * from "./lib/domain-event-subscription";
|
|
7
|
+
export * from "./lib/aggregate-root";
|
|
8
|
+
export * from "./lib/aggregate-root-name";
|
|
9
|
+
export * from "./lib/aggregate-root-aware-event";
|
|
10
|
+
export * from "./lib/on-domain-event";
|
|
11
|
+
export * from "./lib/domain-event-emitter";
|
|
12
|
+
export * from "./lib/core-module-options";
|
|
10
13
|
export * from "./lib/storage/stored-event";
|
|
11
14
|
export * from "./lib/storage/stored-aggregate-root";
|
|
15
|
+
export * from "./lib/storage/abstract-event-store";
|
|
16
|
+
export * from "./lib/storage/event-store";
|
|
12
17
|
export * from "./lib/utils/type-utils";
|
package/src/index.js
CHANGED
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
|
-
tslib_1.__exportStar(require("./lib/
|
|
5
|
-
tslib_1.__exportStar(require("./lib/
|
|
6
|
-
tslib_1.__exportStar(require("./lib/
|
|
7
|
-
tslib_1.__exportStar(require("./lib/
|
|
8
|
-
tslib_1.__exportStar(require("./lib/
|
|
9
|
-
tslib_1.__exportStar(require("./lib/
|
|
10
|
-
tslib_1.__exportStar(require("./lib/
|
|
11
|
-
tslib_1.__exportStar(require("./lib/
|
|
12
|
-
tslib_1.__exportStar(require("./lib/
|
|
4
|
+
tslib_1.__exportStar(require("./lib/exceptions/event-name-conflict-exception"), exports);
|
|
5
|
+
tslib_1.__exportStar(require("./lib/exceptions/unknown-event-exception"), exports);
|
|
6
|
+
tslib_1.__exportStar(require("./lib/exceptions/missing-aggregate-root-name-exception"), exports);
|
|
7
|
+
tslib_1.__exportStar(require("./lib/event-processor"), exports);
|
|
8
|
+
tslib_1.__exportStar(require("./lib/registered-event"), exports);
|
|
9
|
+
tslib_1.__exportStar(require("./lib/domain-event-subscription"), exports);
|
|
10
|
+
tslib_1.__exportStar(require("./lib/aggregate-root"), exports);
|
|
11
|
+
tslib_1.__exportStar(require("./lib/aggregate-root-name"), exports);
|
|
12
|
+
tslib_1.__exportStar(require("./lib/aggregate-root-aware-event"), exports);
|
|
13
|
+
tslib_1.__exportStar(require("./lib/on-domain-event"), exports);
|
|
14
|
+
tslib_1.__exportStar(require("./lib/domain-event-emitter"), exports);
|
|
15
|
+
tslib_1.__exportStar(require("./lib/core-module-options"), exports);
|
|
13
16
|
tslib_1.__exportStar(require("./lib/storage/stored-event"), exports);
|
|
14
17
|
tslib_1.__exportStar(require("./lib/storage/stored-aggregate-root"), exports);
|
|
18
|
+
tslib_1.__exportStar(require("./lib/storage/abstract-event-store"), exports);
|
|
19
|
+
tslib_1.__exportStar(require("./lib/storage/event-store"), exports);
|
|
15
20
|
tslib_1.__exportStar(require("./lib/utils/type-utils"), exports);
|
|
16
21
|
//# sourceMappingURL=index.js.map
|
package/src/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../libs/core/src/index.ts"],"names":[],"mappings":";;;AAAA,yFAA+D;AAC/D,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../libs/core/src/index.ts"],"names":[],"mappings":";;;AAAA,yFAA+D;AAC/D,mFAAyD;AACzD,iGAAuE;AAEvE,gEAAsC;AACtC,iEAAuC;AACvC,0EAAgD;AAChD,+DAAqC;AACrC,oEAA0C;AAC1C,2EAAiD;AACjD,gEAAsC;AACtC,qEAA2C;AAC3C,oEAA0C;AAE1C,qEAA2C;AAC3C,8EAAoD;AACpD,6EAAmD;AACnD,oEAA0C;AAE1C,iEAAuC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aggregate-root-aware-event.js","sourceRoot":"","sources":["../../../../../libs/core/src/lib/aggregate-root-aware-event.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getAggregateRootName = exports.AggregateRootName = void 0;
|
|
4
|
+
const metadata_keys_1 = require("./metadata-keys");
|
|
5
|
+
const AggregateRootName = (name) => {
|
|
6
|
+
return (target) => {
|
|
7
|
+
Reflect.defineMetadata(metadata_keys_1.AGGREGATE_ROOT_NAME_KEY, { aggregateRootName: name }, target);
|
|
8
|
+
};
|
|
9
|
+
};
|
|
10
|
+
exports.AggregateRootName = AggregateRootName;
|
|
11
|
+
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
12
|
+
function getAggregateRootName(targetClass) {
|
|
13
|
+
return Reflect.getMetadata(metadata_keys_1.AGGREGATE_ROOT_NAME_KEY, targetClass)?.aggregateRootName;
|
|
14
|
+
}
|
|
15
|
+
exports.getAggregateRootName = getAggregateRootName;
|
|
16
|
+
//# sourceMappingURL=aggregate-root-name.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aggregate-root-name.js","sourceRoot":"","sources":["../../../../../libs/core/src/lib/aggregate-root-name.ts"],"names":[],"mappings":";;;AAAA,mDAA0D;AAEnD,MAAM,iBAAiB,GAAG,CAAC,IAAY,EAAkB,EAAE;IAC9D,OAAO,CAAC,MAAc,EAAE,EAAE;QACtB,OAAO,CAAC,cAAc,CAAC,uCAAuB,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,EAAE,MAAM,CAAC,CAAC;IACzF,CAAC,CAAC;AACN,CAAC,CAAC;AAJW,QAAA,iBAAiB,qBAI5B;AAEF,wDAAwD;AACxD,SAAgB,oBAAoB,CAAC,WAAqB;IACtD,OAAO,OAAO,CAAC,WAAW,CAAC,uCAAuB,EAAE,WAAW,CAAC,EAAE,iBAAiB,CAAC;AACxF,CAAC;AAFD,oDAEC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Logger } from "@nestjs/common";
|
|
2
|
+
import { StoredEvent } from "./storage/stored-event";
|
|
3
|
+
import { AggregateRootAwareEvent } from "./aggregate-root-aware-event";
|
|
4
|
+
export declare abstract class AggregateRoot {
|
|
5
|
+
private readonly _id;
|
|
6
|
+
private _appendedEvents;
|
|
7
|
+
private _version;
|
|
8
|
+
private readonly _logger;
|
|
9
|
+
protected constructor(_id: string, logger?: Logger);
|
|
10
|
+
get id(): string;
|
|
11
|
+
get version(): number;
|
|
12
|
+
get logger(): Logger;
|
|
13
|
+
/**
|
|
14
|
+
* Publishes all the provided events using a connected event publisher. To connect a publisher, use the
|
|
15
|
+
* {@link EventStore}. Normally this should never be called by application logic. Instead, after you append the
|
|
16
|
+
* events, you should call the commit method which will end up calling this method.
|
|
17
|
+
*
|
|
18
|
+
* If a publisher is not connected, the method will return a rejected promise.
|
|
19
|
+
* @param events The events to be published
|
|
20
|
+
*/
|
|
21
|
+
publish(events: Array<AggregateRootAwareEvent<object>>): Promise<Array<StoredEvent>>;
|
|
22
|
+
/**
|
|
23
|
+
* All the events that have been previously appended will be committed once this method runs. After publishing,
|
|
24
|
+
* the appended events will be deleted so that the next commit publishes newer events.
|
|
25
|
+
* During publishing, the events will be saved and after the successful save, all the application event
|
|
26
|
+
* handlers will be called to take care of async updates.
|
|
27
|
+
* Call this once all the events you want, have been appended.
|
|
28
|
+
*/
|
|
29
|
+
commit(): Promise<AggregateRoot>;
|
|
30
|
+
/**
|
|
31
|
+
* Adds an event to the currently existing events of the entity. This will not publish the event. Use the {@link commit}
|
|
32
|
+
* method once all the events you want are appended.
|
|
33
|
+
* @param event The event to be appended
|
|
34
|
+
*/
|
|
35
|
+
append(event: object): void;
|
|
36
|
+
/**
|
|
37
|
+
* Returns a clone array of all the currently appended events of the entity.
|
|
38
|
+
*/
|
|
39
|
+
get appendedEvents(): Array<AggregateRootAwareEvent<object>>;
|
|
40
|
+
/**
|
|
41
|
+
* Used when a set of events have been retrieved from the database. These events can be passed to the method and the
|
|
42
|
+
* method will trigger all the matching {@link EventProcessor} functions of the entity to populate the object based on
|
|
43
|
+
* application logic.
|
|
44
|
+
* @param events The events that will be sent to EventProcessor functions
|
|
45
|
+
*/
|
|
46
|
+
reconstitute(events: Array<StoredEvent>): void;
|
|
47
|
+
protected resolveVersion(events: Array<StoredEvent>): void;
|
|
48
|
+
protected sortEvents(events: Array<StoredEvent>): Array<StoredEvent>;
|
|
49
|
+
private splitEvents;
|
|
50
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AggregateRoot = void 0;
|
|
4
|
+
const common_1 = require("@nestjs/common");
|
|
5
|
+
const registered_event_1 = require("./registered-event");
|
|
6
|
+
const event_processor_1 = require("./event-processor");
|
|
7
|
+
const unknown_event_exception_1 = require("./exceptions/unknown-event-exception");
|
|
8
|
+
const type_utils_1 = require("./utils/type-utils");
|
|
9
|
+
const unregistered_event_exception_1 = require("./exceptions/unregistered-event-exception");
|
|
10
|
+
class AggregateRoot {
|
|
11
|
+
constructor(_id, logger) {
|
|
12
|
+
this._id = _id;
|
|
13
|
+
this._appendedEvents = [];
|
|
14
|
+
this._version = 0;
|
|
15
|
+
this._logger = (0, type_utils_1.isNil)(logger) ? new common_1.Logger(AggregateRoot.name) : logger;
|
|
16
|
+
}
|
|
17
|
+
get id() {
|
|
18
|
+
return this._id;
|
|
19
|
+
}
|
|
20
|
+
get version() {
|
|
21
|
+
return this._version;
|
|
22
|
+
}
|
|
23
|
+
get logger() {
|
|
24
|
+
return this._logger;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Publishes all the provided events using a connected event publisher. To connect a publisher, use the
|
|
28
|
+
* {@link EventStore}. Normally this should never be called by application logic. Instead, after you append the
|
|
29
|
+
* events, you should call the commit method which will end up calling this method.
|
|
30
|
+
*
|
|
31
|
+
* If a publisher is not connected, the method will return a rejected promise.
|
|
32
|
+
* @param events The events to be published
|
|
33
|
+
*/
|
|
34
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
35
|
+
publish(events) {
|
|
36
|
+
this.logger.error("There is no event publisher assigned");
|
|
37
|
+
return Promise.reject("There is no event publisher assigned");
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* All the events that have been previously appended will be committed once this method runs. After publishing,
|
|
41
|
+
* the appended events will be deleted so that the next commit publishes newer events.
|
|
42
|
+
* During publishing, the events will be saved and after the successful save, all the application event
|
|
43
|
+
* handlers will be called to take care of async updates.
|
|
44
|
+
* Call this once all the events you want, have been appended.
|
|
45
|
+
*/
|
|
46
|
+
commit() {
|
|
47
|
+
const toPublish = this._appendedEvents.slice(0);
|
|
48
|
+
this._appendedEvents = [];
|
|
49
|
+
if (toPublish.length > 0) {
|
|
50
|
+
return this.publish(toPublish).then(() => Promise.resolve(this));
|
|
51
|
+
}
|
|
52
|
+
return Promise.resolve(this);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Adds an event to the currently existing events of the entity. This will not publish the event. Use the {@link commit}
|
|
56
|
+
* method once all the events you want are appended.
|
|
57
|
+
* @param event The event to be appended
|
|
58
|
+
*/
|
|
59
|
+
append(event) {
|
|
60
|
+
if (!(0, registered_event_1.isRegistered)(event)) {
|
|
61
|
+
this.logger.error(`Event ${event.constructor.name} is not registered.`);
|
|
62
|
+
throw new unregistered_event_exception_1.UnregisteredEventException(event.constructor.name);
|
|
63
|
+
}
|
|
64
|
+
this._appendedEvents.push({
|
|
65
|
+
aggregateRootId: this.id,
|
|
66
|
+
payload: event
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Returns a clone array of all the currently appended events of the entity.
|
|
71
|
+
*/
|
|
72
|
+
get appendedEvents() {
|
|
73
|
+
return this._appendedEvents.slice(0);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Used when a set of events have been retrieved from the database. These events can be passed to the method and the
|
|
77
|
+
* method will trigger all the matching {@link EventProcessor} functions of the entity to populate the object based on
|
|
78
|
+
* application logic.
|
|
79
|
+
* @param events The events that will be sent to EventProcessor functions
|
|
80
|
+
*/
|
|
81
|
+
reconstitute(events) {
|
|
82
|
+
if (events.length > 0) {
|
|
83
|
+
const [unregistered, missingProcessor, known] = this.splitEvents(this.sortEvents(events));
|
|
84
|
+
if (unregistered.length > 0 || missingProcessor.length > 0) {
|
|
85
|
+
const e = new unknown_event_exception_1.UnknownEventException(unregistered, missingProcessor, this.id);
|
|
86
|
+
this.logger.error(e.message);
|
|
87
|
+
throw e;
|
|
88
|
+
}
|
|
89
|
+
known.forEach((event) => {
|
|
90
|
+
try {
|
|
91
|
+
this[event.processorKey](event.payload);
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
this.logger.error(`Unable to process domain event due to error in processor function: ${error}`);
|
|
95
|
+
throw error;
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
this.resolveVersion(events);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
resolveVersion(events) {
|
|
102
|
+
const sorted = events.sort((e1, e2) => e1.aggregateRootVersion - e2.aggregateRootVersion);
|
|
103
|
+
this._version = sorted.slice(-1)[0].aggregateRootVersion;
|
|
104
|
+
}
|
|
105
|
+
sortEvents(events) {
|
|
106
|
+
return events.sort((e1, e2) => e1.aggregateRootVersion - e2.aggregateRootVersion);
|
|
107
|
+
}
|
|
108
|
+
splitEvents(events) {
|
|
109
|
+
const known = [];
|
|
110
|
+
const unregistered = [];
|
|
111
|
+
const missingProcessor = [];
|
|
112
|
+
events.forEach((ev) => {
|
|
113
|
+
const eventClass = (0, registered_event_1.getEventClass)(ev.eventName);
|
|
114
|
+
if ((0, type_utils_1.isNil)(eventClass)) {
|
|
115
|
+
unregistered.push(ev.eventName);
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
const processorKey = (0, event_processor_1.getDecoratedPropertyKey)(this, eventClass);
|
|
119
|
+
if ((0, type_utils_1.isNil)(processorKey)) {
|
|
120
|
+
missingProcessor.push(ev.eventName);
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
known.push({
|
|
124
|
+
processorKey,
|
|
125
|
+
payload: ev.getPayloadAs(eventClass)
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
return [unregistered, missingProcessor, known];
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
exports.AggregateRoot = AggregateRoot;
|
|
134
|
+
//# sourceMappingURL=aggregate-root.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aggregate-root.js","sourceRoot":"","sources":["../../../../../libs/core/src/lib/aggregate-root.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface CoreModuleOptions {
|
|
2
|
+
/**
|
|
3
|
+
* Each domain event that is saved in the store will then be passed to any classes you have registered with the
|
|
4
|
+
* {@link DomainEventSubscription} decorator.
|
|
5
|
+
* By default, the events will be processed sequentially to make sure that a subscription can count on the fact that
|
|
6
|
+
* the previous event has been processed. If you don't need this functionality, and you want faster event processing,
|
|
7
|
+
* you can set this to true.
|
|
8
|
+
*
|
|
9
|
+
*/
|
|
10
|
+
runParallelSubscriptions?: boolean;
|
|
11
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core-module-options.js","sourceRoot":"","sources":["../../../../../libs/core/src/lib/core-module-options.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Module } from "@nestjs/core/injector/module";
|
|
2
|
+
import { AggregateRootAwareEvent } from "./aggregate-root-aware-event";
|
|
3
|
+
import { OnModuleDestroy } from "@nestjs/common";
|
|
4
|
+
export declare class DomainEventEmitter implements OnModuleDestroy {
|
|
5
|
+
private _runParallelSubscriptions;
|
|
6
|
+
private _handlers;
|
|
7
|
+
private _logger;
|
|
8
|
+
constructor(_runParallelSubscriptions?: boolean);
|
|
9
|
+
onModuleDestroy(): void;
|
|
10
|
+
bindSubscriptions(injectorModules: Map<string, Module>): void;
|
|
11
|
+
emit(withAggregate: AggregateRootAwareEvent<object>): Promise<unknown>;
|
|
12
|
+
emitMultiple(withAggregate: AggregateRootAwareEvent<object>[]): Promise<unknown>;
|
|
13
|
+
}
|