add event handlers
This commit is contained in:
parent
6fafbbd109
commit
6fb473fa60
|
@ -1,6 +1,5 @@
|
||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
import { ConfigModule, ConfigService } from '@nestjs/config';
|
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||||
// import { HealthModule } from './modules/health/health.module';
|
|
||||||
import { AdModule } from './modules/ad/ad.module';
|
import { AdModule } from './modules/ad/ad.module';
|
||||||
import {
|
import {
|
||||||
MessageBrokerModule,
|
MessageBrokerModule,
|
||||||
|
|
|
@ -41,6 +41,7 @@ export abstract class PrismaRepositoryBase<
|
||||||
await this.prisma.create({
|
await this.prisma.create({
|
||||||
data: this.mapper.toPersistence(entity),
|
data: this.mapper.toPersistence(entity),
|
||||||
});
|
});
|
||||||
|
entity.publishEvents(this.logger, this.eventEmitter);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof Prisma.PrismaClientKnownRequestError) {
|
if (e instanceof Prisma.PrismaClientKnownRequestError) {
|
||||||
if (e.message.includes('Already exists')) {
|
if (e.message.includes('Already exists')) {
|
||||||
|
|
|
@ -22,6 +22,8 @@ import { PrismaService } from '@libs/db/prisma.service';
|
||||||
import { TimeConverter } from './infrastructure/time-converter';
|
import { TimeConverter } from './infrastructure/time-converter';
|
||||||
import { FindAdByIdGrpcController } from './interface/grpc-controllers/find-ad-by-id.grpc.controller';
|
import { FindAdByIdGrpcController } from './interface/grpc-controllers/find-ad-by-id.grpc.controller';
|
||||||
import { FindAdByIdQueryHandler } from './core/queries/find-ad-by-id/find-ad-by-id.query-handler';
|
import { FindAdByIdQueryHandler } from './core/queries/find-ad-by-id/find-ad-by-id.query-handler';
|
||||||
|
import { PublishMessageWhenAdIsCreatedDomainEventHandler } from './core/event-handlers/publish-message-when-ad-is-created.domain-event-handler';
|
||||||
|
import { PublishLogMessageWhenAdIsCreatedDomainEventHandler } from './core/event-handlers/publish-log-message-when-ad-is-created.domain-event-handler';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [CqrsModule],
|
imports: [CqrsModule],
|
||||||
|
@ -29,6 +31,8 @@ import { FindAdByIdQueryHandler } from './core/queries/find-ad-by-id/find-ad-by-
|
||||||
providers: [
|
providers: [
|
||||||
CreateAdService,
|
CreateAdService,
|
||||||
FindAdByIdQueryHandler,
|
FindAdByIdQueryHandler,
|
||||||
|
PublishMessageWhenAdIsCreatedDomainEventHandler,
|
||||||
|
PublishLogMessageWhenAdIsCreatedDomainEventHandler,
|
||||||
PrismaService,
|
PrismaService,
|
||||||
AdMapper,
|
AdMapper,
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
import { MessagePublisherPort } from '@libs/ports/message-publisher.port';
|
||||||
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
|
import { OnEvent } from '@nestjs/event-emitter';
|
||||||
|
import { MESSAGE_PUBLISHER } from '@src/app.constants';
|
||||||
|
import { AdCreatedDomainEvent } from '../events/ad-created.domain-events';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class PublishLogMessageWhenAdIsCreatedDomainEventHandler {
|
||||||
|
constructor(
|
||||||
|
@Inject(MESSAGE_PUBLISHER)
|
||||||
|
private readonly messagePublisher: MessagePublisherPort,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
@OnEvent(AdCreatedDomainEvent.name, { async: true, promisify: true })
|
||||||
|
async handle(event: AdCreatedDomainEvent): Promise<any> {
|
||||||
|
this.messagePublisher.publish(
|
||||||
|
'logging.ad.created.info',
|
||||||
|
JSON.stringify(event),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
import { MessagePublisherPort } from '@libs/ports/message-publisher.port';
|
||||||
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
|
import { OnEvent } from '@nestjs/event-emitter';
|
||||||
|
import { MESSAGE_PUBLISHER } from '@src/app.constants';
|
||||||
|
import { AdCreatedDomainEvent } from '../events/ad-created.domain-events';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class PublishMessageWhenAdIsCreatedDomainEventHandler {
|
||||||
|
constructor(
|
||||||
|
@Inject(MESSAGE_PUBLISHER)
|
||||||
|
private readonly messagePublisher: MessagePublisherPort,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
@OnEvent(AdCreatedDomainEvent.name, { async: true, promisify: true })
|
||||||
|
async handle(event: AdCreatedDomainEvent): Promise<any> {
|
||||||
|
this.messagePublisher.publish('ad.created', JSON.stringify(event));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,94 @@
|
||||||
|
import { Frequency } from '@modules/ad/core/ad.types';
|
||||||
|
import { PublishLogMessageWhenAdIsCreatedDomainEventHandler } from '@modules/ad/core/event-handlers/publish-log-message-when-ad-is-created.domain-event-handler';
|
||||||
|
import { AdCreatedDomainEvent } from '@modules/ad/core/events/ad-created.domain-events';
|
||||||
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import { MESSAGE_PUBLISHER } from '@src/app.constants';
|
||||||
|
|
||||||
|
const mockMessagePublisher = {
|
||||||
|
publish: jest.fn().mockImplementation(),
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('Publish log message when ad is created domain event handler', () => {
|
||||||
|
let publishLogMessageWhenAdIsCreatedDomainEventHandler: PublishLogMessageWhenAdIsCreatedDomainEventHandler;
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: MESSAGE_PUBLISHER,
|
||||||
|
useValue: mockMessagePublisher,
|
||||||
|
},
|
||||||
|
PublishLogMessageWhenAdIsCreatedDomainEventHandler,
|
||||||
|
],
|
||||||
|
}).compile();
|
||||||
|
|
||||||
|
publishLogMessageWhenAdIsCreatedDomainEventHandler =
|
||||||
|
module.get<PublishLogMessageWhenAdIsCreatedDomainEventHandler>(
|
||||||
|
PublishLogMessageWhenAdIsCreatedDomainEventHandler,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should publish a log message', () => {
|
||||||
|
jest.spyOn(mockMessagePublisher, 'publish');
|
||||||
|
const adCreatedDomainEvent: AdCreatedDomainEvent = {
|
||||||
|
id: 'some-domain-event-id',
|
||||||
|
aggregateId: 'some-aggregate-id',
|
||||||
|
userId: 'some-user-id',
|
||||||
|
driver: false,
|
||||||
|
passenger: true,
|
||||||
|
frequency: Frequency.PUNCTUAL,
|
||||||
|
fromDate: '2023-06-28',
|
||||||
|
toDate: '2023-06-28',
|
||||||
|
monTime: undefined,
|
||||||
|
tueTime: undefined,
|
||||||
|
wedTime: '07:15',
|
||||||
|
thuTime: undefined,
|
||||||
|
friTime: undefined,
|
||||||
|
satTime: undefined,
|
||||||
|
sunTime: undefined,
|
||||||
|
monMarginDuration: 900,
|
||||||
|
tueMarginDuration: 900,
|
||||||
|
wedMarginDuration: 900,
|
||||||
|
thuMarginDuration: 900,
|
||||||
|
friMarginDuration: 900,
|
||||||
|
satMarginDuration: 900,
|
||||||
|
sunMarginDuration: 900,
|
||||||
|
seatsProposed: 3,
|
||||||
|
seatsRequested: 1,
|
||||||
|
strict: false,
|
||||||
|
waypoints: [
|
||||||
|
{
|
||||||
|
position: 0,
|
||||||
|
houseNumber: '5',
|
||||||
|
street: 'Avenue Foch',
|
||||||
|
locality: 'Nancy',
|
||||||
|
postalCode: '54000',
|
||||||
|
country: 'France',
|
||||||
|
lat: 48.689445,
|
||||||
|
lon: 6.1765102,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
position: 1,
|
||||||
|
locality: 'Paris',
|
||||||
|
postalCode: '75000',
|
||||||
|
country: 'France',
|
||||||
|
lat: 48.8566,
|
||||||
|
lon: 2.3522,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
metadata: {
|
||||||
|
timestamp: new Date('2023-06-28T05:00:00Z').getTime(),
|
||||||
|
correlationId: 'some-correlation-id',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
publishLogMessageWhenAdIsCreatedDomainEventHandler.handle(
|
||||||
|
adCreatedDomainEvent,
|
||||||
|
);
|
||||||
|
expect(publishLogMessageWhenAdIsCreatedDomainEventHandler).toBeDefined();
|
||||||
|
expect(mockMessagePublisher.publish).toHaveBeenCalledTimes(1);
|
||||||
|
expect(mockMessagePublisher.publish).toHaveBeenCalledWith(
|
||||||
|
'logging.ad.created.info',
|
||||||
|
'{"id":"some-domain-event-id","aggregateId":"some-aggregate-id","userId":"some-user-id","driver":false,"passenger":true,"frequency":"PUNCTUAL","fromDate":"2023-06-28","toDate":"2023-06-28","wedTime":"07:15","monMarginDuration":900,"tueMarginDuration":900,"wedMarginDuration":900,"thuMarginDuration":900,"friMarginDuration":900,"satMarginDuration":900,"sunMarginDuration":900,"seatsProposed":3,"seatsRequested":1,"strict":false,"waypoints":[{"position":0,"houseNumber":"5","street":"Avenue Foch","locality":"Nancy","postalCode":"54000","country":"France","lat":48.689445,"lon":6.1765102},{"position":1,"locality":"Paris","postalCode":"75000","country":"France","lat":48.8566,"lon":2.3522}],"metadata":{"timestamp":1687928400000,"correlationId":"some-correlation-id"}}',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,94 @@
|
||||||
|
import { Frequency } from '@modules/ad/core/ad.types';
|
||||||
|
import { PublishMessageWhenAdIsCreatedDomainEventHandler } from '@modules/ad/core/event-handlers/publish-message-when-ad-is-created.domain-event-handler';
|
||||||
|
import { AdCreatedDomainEvent } from '@modules/ad/core/events/ad-created.domain-events';
|
||||||
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import { MESSAGE_PUBLISHER } from '@src/app.constants';
|
||||||
|
|
||||||
|
const mockMessagePublisher = {
|
||||||
|
publish: jest.fn().mockImplementation(),
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('Publish message when ad is created domain event handler', () => {
|
||||||
|
let publishMessageWhenAdIsCreatedDomainEventHandler: PublishMessageWhenAdIsCreatedDomainEventHandler;
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: MESSAGE_PUBLISHER,
|
||||||
|
useValue: mockMessagePublisher,
|
||||||
|
},
|
||||||
|
PublishMessageWhenAdIsCreatedDomainEventHandler,
|
||||||
|
],
|
||||||
|
}).compile();
|
||||||
|
|
||||||
|
publishMessageWhenAdIsCreatedDomainEventHandler =
|
||||||
|
module.get<PublishMessageWhenAdIsCreatedDomainEventHandler>(
|
||||||
|
PublishMessageWhenAdIsCreatedDomainEventHandler,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should publish a message', () => {
|
||||||
|
jest.spyOn(mockMessagePublisher, 'publish');
|
||||||
|
const adCreatedDomainEvent: AdCreatedDomainEvent = {
|
||||||
|
id: 'some-domain-event-id',
|
||||||
|
aggregateId: 'some-aggregate-id',
|
||||||
|
userId: 'some-user-id',
|
||||||
|
driver: false,
|
||||||
|
passenger: true,
|
||||||
|
frequency: Frequency.PUNCTUAL,
|
||||||
|
fromDate: '2023-06-28',
|
||||||
|
toDate: '2023-06-28',
|
||||||
|
monTime: undefined,
|
||||||
|
tueTime: undefined,
|
||||||
|
wedTime: '07:15',
|
||||||
|
thuTime: undefined,
|
||||||
|
friTime: undefined,
|
||||||
|
satTime: undefined,
|
||||||
|
sunTime: undefined,
|
||||||
|
monMarginDuration: 900,
|
||||||
|
tueMarginDuration: 900,
|
||||||
|
wedMarginDuration: 900,
|
||||||
|
thuMarginDuration: 900,
|
||||||
|
friMarginDuration: 900,
|
||||||
|
satMarginDuration: 900,
|
||||||
|
sunMarginDuration: 900,
|
||||||
|
seatsProposed: 3,
|
||||||
|
seatsRequested: 1,
|
||||||
|
strict: false,
|
||||||
|
waypoints: [
|
||||||
|
{
|
||||||
|
position: 0,
|
||||||
|
houseNumber: '5',
|
||||||
|
street: 'Avenue Foch',
|
||||||
|
locality: 'Nancy',
|
||||||
|
postalCode: '54000',
|
||||||
|
country: 'France',
|
||||||
|
lat: 48.689445,
|
||||||
|
lon: 6.1765102,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
position: 1,
|
||||||
|
locality: 'Paris',
|
||||||
|
postalCode: '75000',
|
||||||
|
country: 'France',
|
||||||
|
lat: 48.8566,
|
||||||
|
lon: 2.3522,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
metadata: {
|
||||||
|
timestamp: new Date('2023-06-28T05:00:00Z').getTime(),
|
||||||
|
correlationId: 'some-correlation-id',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
publishMessageWhenAdIsCreatedDomainEventHandler.handle(
|
||||||
|
adCreatedDomainEvent,
|
||||||
|
);
|
||||||
|
expect(publishMessageWhenAdIsCreatedDomainEventHandler).toBeDefined();
|
||||||
|
expect(mockMessagePublisher.publish).toHaveBeenCalledTimes(1);
|
||||||
|
expect(mockMessagePublisher.publish).toHaveBeenCalledWith(
|
||||||
|
'ad.created',
|
||||||
|
'{"id":"some-domain-event-id","aggregateId":"some-aggregate-id","userId":"some-user-id","driver":false,"passenger":true,"frequency":"PUNCTUAL","fromDate":"2023-06-28","toDate":"2023-06-28","wedTime":"07:15","monMarginDuration":900,"tueMarginDuration":900,"wedMarginDuration":900,"thuMarginDuration":900,"friMarginDuration":900,"satMarginDuration":900,"sunMarginDuration":900,"seatsProposed":3,"seatsRequested":1,"strict":false,"waypoints":[{"position":0,"houseNumber":"5","street":"Avenue Foch","locality":"Nancy","postalCode":"54000","country":"France","lat":48.689445,"lon":6.1765102},{"position":1,"locality":"Paris","postalCode":"75000","country":"France","lat":48.8566,"lon":2.3522}],"metadata":{"timestamp":1687928400000,"correlationId":"some-correlation-id"}}',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue