EventStoreDB NestJS CQRS module.
- Asynchronous commit/publish
- Event handler decorator
- Single event for read/write
npm install --save nestjs-cqrx
import { CqrxModule } from 'nestjs-cqrx';
@Module({
imports: [
CqrxModule.forRoot({
eventstoreDbConnectionString: 'esdb://localhost:2113?tls=false',
}),
],
})
export class AppModule {}
You can generate connection string on Connection details page
import { ConflictException } from '@nestjs/common';
import { AggregateRoot, EventHandler } from 'nestjs-cqrx';
import { UserRegistered } from '../events';
export class User extends AggregateRoot {
protected static readonly streamName: string = 'user';
isRegistered = false;
email!: string;
password!: string;
@EventHandler(UserRegistered)
createUser(event: UserRegistered): void {
this.isRegistered = true;
this.email = event.data.email;
this.password = event.data.password;
}
register(email: string, password: string) {
if (this.isRegistered) {
throw new ConflictException();
}
this.apply(
new UserRegistered({
email,
password,
}),
);
}
}
const user = new User('123');
user.apply(new UserRegistered({ data }));
await userAggregateRepository.save(user);
// Or you can create aggregate from repository
// In this case you can use commit method
const user = userAggregateRepository.create('123');
user.apply(new UserRegistered({ data }));
await user.commit();
import { Event } from 'nestjs-cqrx';
type UserRegisteredDto = { email: string; password: string };
export class UserRegistered extends Event<UserRegisteredDto> {}
@Module({
imports: [
CqrxModule.forFeature(
[User],
// Subscribe and transform events from eventstore
[['UserRegistered', event => new UserRegistered(event)]],
),
],
})
export class UserModule {}
// Signature of transformers
type Transformer = [
/* Recorded event type */ string,
/* Function which accept stream event (plain object) */ (
event: RecordedEvent,
) => Event,
];
['UserRegistered', event => new UserRegistered(event)]
can be shorthanded to UserRegistered
Note: If you have decorator EventsHandler
(from @nestjs/cqrs
) of some event,
it will be automatically added to transform service.
[+] good option (save event to db, subscribe to event from db)
[–] synchronous (we must wait when event will be saved then reply to client)
[+] official nestjs/cqrs implementation, command handlers (fire new command via saga)
[+] faster, we reply processing to client, and do command on
[–] can emit only 1 event from saga
- docker-compose up
- http://localhost:2113/web/index.html#/dashboard
- https://github.com/bradsheppard/nestjs-async-cqrs
- https://github.com/valueadd-poland/nestjs-packages/tree/master/packages/typed-cqrs
- https://github.com/ArkerLabs/event-sourcing-nestjs
- https://github.com/amehat?tab=repositories&q=cqrs
- https://github.com/orhanveli/nestjs-saga-pattern-example
- https://github.com/tuanitpro/nestjs-sagas-cqrs
- https://github.com/ntxinh/nestjs-cqrs-es
- https://github.com/ArkerLabs/event-sourcing-nestjs-graphql-example
- https://github.com/oskardudycz/EventSourcing.JVM/tree/main/samples/event-sourcing-esdb-simple
- https://github.com/PrestaShopCorp/nestjs-geteventstore
- read from specific position
- find lib for creating errors
- better to split on read/write events
- reducer (similar to evolve of emmet)
MIT License (c) 2024