Prisma Event Dispatcher is Prisma compatible middleware, which dispatches several types of events while working with Prisma models. It's EventEmitter agnostic and allows you to choose for what kind of models, actions and moment of lifecycle to emit the events.
You attach it to Prisma Middleware:
const eventEmitter = new EventEmitter();
const options: PrismaEventDispatcherOptions = {
models: ['User', 'Post'],
actions: ['create', 'update'],
when: ['before', 'after'],
};
const prisma = new PrismaClient()
prisma.$use(async (params, next) => {
const prismaEventDisptacher = new PrismaEventDispatcher.(options, eventEmitter);
return await prismaEventDisptacher.dispatch(params, next);
})
You can use static method setup
as well:
const eventEmitter = new EventEmitter();
const options: PrismaEventDispatcherOptions = {
models: ['User', 'Post'],
actions: ['create', 'update'],
when: ['before', 'after'],
};
const prisma = new PrismaClient()
prisma.$use(async (params, next) => {
return await PrismaEventDispatcher.setup(options, this.eventEmitter).dispatch(params, next);
})
Dispatch method requires params
and next
values from middleware and returns Prisma Client query response.
Passing options object allows to define for what kind of models, actions and when the event will be dispatched. When you don't pass any of the options fields, the dispatcher will treat it as 'all'.
export declare type PrismaEventDispatcherOptions = {
models?: string[];
actions?: PrismaAction[];
when?: When[];
};
Available prisma actions:
- findUnique
- findMany
- findFirst
- create
- createMany
- update
- updateMany
- upsert
- delete
- deleteMany
- executeRaw
- queryRaw
- aggregate
- count
Available when parameters:
- before
- after
Emitted events has string name in convention Model.when.action
, for example – when you create new User, dispatcher will emit User.before.create
and User.after.create
event.
Each event comes with whole params object from Prisma Middleware. Additionally, after
events have response from Prisma Client query.
Prisma Middleware Params Object example:
{
args: { where: { id: 170 }, data: { name: 'Karol' } },
dataPath: [],
runInTransaction: false,
action: 'update',
model: 'User'
}
Example response from Prisma Client after updating User model:
{
id: 170,
name: 'Karol',
createdAt: 2021-10-22T13:34:52.000Z
}
Prisma Event Emitter works smoothly with NestJS framework events module.
You need to inject EventEmitter2 to PrismaService, and pass it into PrismaEventDispatcher.
import { INestApplication, Injectable, OnModuleInit } from '@nestjs/common';
import { PrismaClient, Prisma } from '@prisma/client';
import { EventEmitter2 } from 'eventemitter2';
import { PrismaEventDispatcher } from 'prisma-event-dispatcher';
@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit {
constructor(private eventEmmiter: EventEmitter2) {
super();
const options = {
models: ['User']
}
this.$use(async (params, next) => {
return await PrismaEventDispatcher.setup(options, this.eventEmmiter).dispatch(params, next);
});
}
async onModuleInit(): Promise<void> {
await this.$connect();
}
async enableShutdownHooks(app: INestApplication): Promise<void> {
this.$on('beforeExit', async () => {
await app.close();
});
}
}
Then you can create event listeners as usual:
@OnEvent('User.before.update')
async testCreate(payload: any) {
console.log('before');
}
@OnEvent('User.after.update')
async testUpdated(payload: any, response: any) {
console.log('after');
}
Prisma Event Dispatcher is EventEmitter agnostic. It means you can use any NodeJS EventEmitter which implements emit
method:
export interface EventEmitter {
emit(event: symbol | string, ...values: any[]): boolean;
}
So it's compatible with NodeJS core API EventEmitter
and e.g. EventEmitter2
npm package.
Contributions more than welcome!