diff --git a/src/app.constants.ts b/src/app.constants.ts index d64baf7..c13df6c 100644 --- a/src/app.constants.ts +++ b/src/app.constants.ts @@ -15,6 +15,9 @@ export const MATCHER_AD_CREATION_FAILED_ROUTING_KEY = export const AD_CREATED_MESSAGE_HANDLER = 'adCreated'; export const AD_CREATED_ROUTING_KEY = 'ad.created'; export const AD_CREATED_QUEUE = 'matcher.ad.created'; +export const AD_DELETED_MESSAGE_HANDLER = 'adDeleted'; +export const AD_DELETED_ROUTING_KEY = 'ad.deleted'; +export const AD_DELETED_QUEUE = 'matcher.ad.deleted'; // health export const GRPC_HEALTH_PACKAGE_NAME = 'health'; diff --git a/src/modules/ad/ad.module.ts b/src/modules/ad/ad.module.ts index e1e765b..9040de9 100644 --- a/src/modules/ad/ad.module.ts +++ b/src/modules/ad/ad.module.ts @@ -43,6 +43,7 @@ import { TimeConverter } from './infrastructure/time-converter'; import { TimezoneFinder } from './infrastructure/timezone-finder'; import { MatchGrpcController } from './interface/grpc-controllers/match.grpc-controller'; import { AdCreatedMessageHandler } from './interface/message-handlers/ad-created.message-handler'; +import { AdDeletedMessageHandler } from './interface/message-handlers/ad-deleted.message-handler'; import { MatchMapper } from './match.mapper'; import { MatchingMapper } from './matching.mapper'; @@ -97,7 +98,7 @@ const imports = [ const grpcControllers = [MatchGrpcController]; -const messageHandlers = [AdCreatedMessageHandler]; +const messageHandlers = [AdCreatedMessageHandler, AdDeletedMessageHandler]; const eventHandlers: Provider[] = [ PublishMessageWhenMatcherAdIsCreatedDomainEventHandler, diff --git a/src/modules/ad/interface/message-handlers/ad-deleted.message-handler.ts b/src/modules/ad/interface/message-handlers/ad-deleted.message-handler.ts new file mode 100644 index 0000000..841eb90 --- /dev/null +++ b/src/modules/ad/interface/message-handlers/ad-deleted.message-handler.ts @@ -0,0 +1,32 @@ +import { RabbitSubscribe } from '@mobicoop/message-broker-module'; +import { DeleteAdCommand } from '@modules/ad/core/application/commands/delete-ad/delete-ad.command'; +import { Injectable } from '@nestjs/common'; +import { CommandBus } from '@nestjs/cqrs'; +import { + AD_DELETED_MESSAGE_HANDLER, + AD_DELETED_ROUTING_KEY, +} from '@src/app.constants'; +import { AdReference } from './ad.types'; + +@Injectable() +export class AdDeletedMessageHandler { + constructor(private readonly commandBus: CommandBus) {} + + @RabbitSubscribe({ + name: AD_DELETED_MESSAGE_HANDLER, + routingKey: AD_DELETED_ROUTING_KEY, + }) + public async adDeleted(message: string): Promise { + try { + const deletedAd: AdReference = JSON.parse(message); + await this.commandBus.execute( + new DeleteAdCommand({ + id: deletedAd.aggregateId, + }), + ); + } catch (error: any) { + // do not throw error to acknowledge incoming message + // error handling should be done in the command handler, if relevant + } + } +} diff --git a/src/modules/ad/interface/message-handlers/ad.types.ts b/src/modules/ad/interface/message-handlers/ad.types.ts index 45eb53b..e1fac43 100644 --- a/src/modules/ad/interface/message-handlers/ad.types.ts +++ b/src/modules/ad/interface/message-handlers/ad.types.ts @@ -1,7 +1,10 @@ import { Frequency } from '@modules/ad/core/domain/ad.types'; -export type Ad = { +export type AdReference = { aggregateId: string; +}; + +export type Ad = AdReference & { driver: boolean; passenger: boolean; frequency: Frequency; diff --git a/src/modules/ad/tests/unit/interface/ad-deleted.message-handler.spec.ts b/src/modules/ad/tests/unit/interface/ad-deleted.message-handler.spec.ts new file mode 100644 index 0000000..6a4df2d --- /dev/null +++ b/src/modules/ad/tests/unit/interface/ad-deleted.message-handler.spec.ts @@ -0,0 +1,44 @@ +import { AdDeletedMessageHandler } from '@modules/ad/interface/message-handlers/ad-deleted.message-handler'; +import { CommandBus } from '@nestjs/cqrs'; +import { Test, TestingModule } from '@nestjs/testing'; + +const adDeletedMessage = + '{"aggregateId":"4eb6a6af-ecfd-41c3-9118-473a507014d4"}'; + +const mockCommandBus = { + execute: jest.fn(), +}; + +describe('Ad Deleted Message Handler', () => { + let adDeletedMessageHandler: AdDeletedMessageHandler; + + beforeAll(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ + { + provide: CommandBus, + useValue: mockCommandBus, + }, + AdDeletedMessageHandler, + ], + }).compile(); + + adDeletedMessageHandler = module.get( + AdDeletedMessageHandler, + ); + }); + + afterEach(async () => { + jest.clearAllMocks(); + }); + + it('should be defined', () => { + expect(adDeletedMessageHandler).toBeDefined(); + }); + + it('should call the delete command', async () => { + jest.spyOn(mockCommandBus, 'execute'); + await adDeletedMessageHandler.adDeleted(adDeletedMessage); + expect(mockCommandBus.execute).toHaveBeenCalledTimes(1); + }); +}); diff --git a/src/modules/messager/messager.module.ts b/src/modules/messager/messager.module.ts index 8f58080..73086db 100644 --- a/src/modules/messager/messager.module.ts +++ b/src/modules/messager/messager.module.ts @@ -1,17 +1,20 @@ -import { Module, Provider } from '@nestjs/common'; -import { MESSAGE_PUBLISHER } from './messager.di-tokens'; import { MessageBrokerModule, MessageBrokerModuleOptions, MessageBrokerPublisher, } from '@mobicoop/message-broker-module'; +import { Module, Provider } from '@nestjs/common'; import { ConfigModule, ConfigService } from '@nestjs/config'; import { AD_CREATED_MESSAGE_HANDLER, AD_CREATED_QUEUE, AD_CREATED_ROUTING_KEY, + AD_DELETED_MESSAGE_HANDLER, + AD_DELETED_QUEUE, + AD_DELETED_ROUTING_KEY, SERVICE_NAME, } from '@src/app.constants'; +import { MESSAGE_PUBLISHER } from './messager.di-tokens'; const imports = [ MessageBrokerModule.forRootAsync({ @@ -33,6 +36,10 @@ const imports = [ routingKey: AD_CREATED_ROUTING_KEY, queue: AD_CREATED_QUEUE, }, + [AD_DELETED_MESSAGE_HANDLER]: { + routingKey: AD_DELETED_ROUTING_KEY, + queue: AD_DELETED_QUEUE, + }, }, }), }),