Listen to user.deleted events to delete the corresponding user ads
This commit is contained in:
parent
492bb3ca44
commit
9fb7ef2eac
|
@ -20,6 +20,10 @@ export const MATCHER_AD_CREATION_FAILED_ROUTING_KEY =
|
|||
'matcher-ad.creation-failed';
|
||||
export const MATCHER_AD_CREATION_FAILED_QUEUE = 'ad.matcher-ad.creation-failed';
|
||||
|
||||
export const USER_DELETED_MESSAGE_HANDLER = 'userDeleted';
|
||||
export const USER_DELETED_ROUTING_KEY = 'user.deleted';
|
||||
export const USER_DELETED_QUEUE = 'ad.user.deleted';
|
||||
|
||||
// configuration
|
||||
export const SERVICE_CONFIGURATION_SET_QUEUE = 'ad-configuration-set';
|
||||
export const SERVICE_CONFIGURATION_DELETE_QUEUE = 'ad-configuration-delete';
|
||||
|
|
|
@ -12,6 +12,7 @@ import {
|
|||
import { AdMapper } from './ad.mapper';
|
||||
import { CreateAdService } from './core/application/commands/create-ad/create-ad.service';
|
||||
import { DeleteAdService } from './core/application/commands/delete-ad/delete-ad.service';
|
||||
import { DeleteUserAdsService } from './core/application/commands/delete-user-ads/delete-user-ads.service';
|
||||
import { InvalidateAdService } from './core/application/commands/invalidate-ad/invalidate-ad.service';
|
||||
import { ValidateAdService } from './core/application/commands/validate-ad/validate-ad.service';
|
||||
import { PublishMessageWhenAdIsDeletedDomainEventHandler } from './core/application/event-handlers/publish-message-when-ad-deleted.domain-event-handler';
|
||||
|
@ -32,6 +33,7 @@ import { FindAdsByIdsGrpcController } from './interface/grpc-controllers/find-ad
|
|||
import { FindAdsByUserIdGrpcController } from './interface/grpc-controllers/find-ads-by-user-id.grpc.controller';
|
||||
import { MatcherAdCreatedMessageHandler } from './interface/message-handlers/matcher-ad-created.message-handler';
|
||||
import { MatcherAdCreationFailedMessageHandler } from './interface/message-handlers/matcher-ad-creation-failed.message-handler';
|
||||
import { UserDeletedMessageHandler } from './interface/message-handlers/user-deleted.message-handler';
|
||||
|
||||
const grpcControllers = [
|
||||
CreateAdGrpcController,
|
||||
|
@ -44,6 +46,7 @@ const grpcControllers = [
|
|||
const messageHandlers = [
|
||||
MatcherAdCreatedMessageHandler,
|
||||
MatcherAdCreationFailedMessageHandler,
|
||||
UserDeletedMessageHandler,
|
||||
];
|
||||
|
||||
const eventHandlers: Provider[] = [
|
||||
|
@ -54,6 +57,7 @@ const eventHandlers: Provider[] = [
|
|||
const commandHandlers: Provider[] = [
|
||||
CreateAdService,
|
||||
DeleteAdService,
|
||||
DeleteUserAdsService,
|
||||
ValidateAdService,
|
||||
InvalidateAdService,
|
||||
];
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
import { Command, CommandProps } from '@mobicoop/ddd-library';
|
||||
|
||||
export class DeleteUserAdsCommand extends Command {
|
||||
constructor(props: CommandProps<DeleteUserAdsCommand>) {
|
||||
super(props);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
import { AdEntity } from '@modules/ad/core/domain/ad.entity';
|
||||
import {
|
||||
CommandBus,
|
||||
CommandHandler,
|
||||
ICommandHandler,
|
||||
QueryBus,
|
||||
} from '@nestjs/cqrs';
|
||||
import { FindAdsByUserIdQuery } from '../../queries/find-ads-by-user-id/find-ads-by-user-id.query';
|
||||
import { DeleteAdCommand } from '../delete-ad/delete-ad.command';
|
||||
import { DeleteUserAdsCommand } from './delete-user-ads.command';
|
||||
|
||||
@CommandHandler(DeleteUserAdsCommand)
|
||||
export class DeleteUserAdsService implements ICommandHandler {
|
||||
constructor(
|
||||
private readonly queryBus: QueryBus,
|
||||
private readonly commandBus: CommandBus,
|
||||
) {}
|
||||
|
||||
async execute(command: DeleteUserAdsCommand): Promise<void> {
|
||||
const ads: AdEntity[] = await this.queryBus.execute(
|
||||
new FindAdsByUserIdQuery(command.id),
|
||||
);
|
||||
await Promise.all(
|
||||
ads.map((ad) =>
|
||||
this.commandBus.execute(new DeleteAdCommand({ id: ad.id })),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
import { IntegrationEvent } from '@mobicoop/ddd-library';
|
||||
import { RabbitSubscribe } from '@mobicoop/message-broker-module';
|
||||
import { DeleteUserAdsCommand } from '@modules/ad/core/application/commands/delete-user-ads/delete-user-ads.command';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { CommandBus } from '@nestjs/cqrs';
|
||||
import { USER_DELETED_MESSAGE_HANDLER } from '@src/app.constants';
|
||||
|
||||
type UserDeletedEvent = IntegrationEvent;
|
||||
|
||||
@Injectable()
|
||||
export class UserDeletedMessageHandler {
|
||||
constructor(private readonly commandBus: CommandBus) {}
|
||||
|
||||
@RabbitSubscribe({
|
||||
name: USER_DELETED_MESSAGE_HANDLER,
|
||||
})
|
||||
public async userDeleted(message: string) {
|
||||
const deletedUser: UserDeletedEvent = JSON.parse(message);
|
||||
await this.commandBus.execute(
|
||||
new DeleteUserAdsCommand({ id: deletedUser.id }),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,6 +1,11 @@
|
|||
import { Module, Provider } from '@nestjs/common';
|
||||
import { MESSAGE_PUBLISHER } from './messager.di-tokens';
|
||||
|
||||
import {
|
||||
MessageBrokerModule,
|
||||
MessageBrokerModuleOptions,
|
||||
MessageBrokerPublisher,
|
||||
} from '@mobicoop/message-broker-module';
|
||||
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||
import {
|
||||
MATCHER_AD_CREATED_MESSAGE_HANDLER,
|
||||
|
@ -10,12 +15,10 @@ import {
|
|||
MATCHER_AD_CREATION_FAILED_QUEUE,
|
||||
MATCHER_AD_CREATION_FAILED_ROUTING_KEY,
|
||||
SERVICE_NAME,
|
||||
USER_DELETED_MESSAGE_HANDLER,
|
||||
USER_DELETED_QUEUE,
|
||||
USER_DELETED_ROUTING_KEY,
|
||||
} from '@src/app.constants';
|
||||
import {
|
||||
MessageBrokerModule,
|
||||
MessageBrokerModuleOptions,
|
||||
MessageBrokerPublisher,
|
||||
} from '@mobicoop/message-broker-module';
|
||||
|
||||
const imports = [
|
||||
MessageBrokerModule.forRootAsync({
|
||||
|
@ -41,6 +44,10 @@ const imports = [
|
|||
routingKey: MATCHER_AD_CREATION_FAILED_ROUTING_KEY,
|
||||
queue: MATCHER_AD_CREATION_FAILED_QUEUE,
|
||||
},
|
||||
[USER_DELETED_MESSAGE_HANDLER]: {
|
||||
routingKey: USER_DELETED_ROUTING_KEY,
|
||||
queue: USER_DELETED_QUEUE,
|
||||
},
|
||||
},
|
||||
}),
|
||||
}),
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
import { DeleteUserAdsCommand } from '@modules/ad/core/application/commands/delete-user-ads/delete-user-ads.command';
|
||||
import { DeleteUserAdsService } from '@modules/ad/core/application/commands/delete-user-ads/delete-user-ads.service';
|
||||
import { AdEntity } from '@modules/ad/core/domain/ad.entity';
|
||||
import { CommandBus, QueryBus } from '@nestjs/cqrs';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { punctualPassengerCreateAdProps } from './ad.fixtures';
|
||||
|
||||
const userAds = [
|
||||
AdEntity.create(punctualPassengerCreateAdProps()),
|
||||
AdEntity.create(punctualPassengerCreateAdProps()),
|
||||
];
|
||||
|
||||
const mockQueryBus = {
|
||||
execute: jest.fn().mockImplementation(() => userAds),
|
||||
};
|
||||
|
||||
const mockCommandBus = {
|
||||
execute: jest.fn(),
|
||||
};
|
||||
|
||||
describe('delete-user-ads.service', () => {
|
||||
let deleteUserAdsService: DeleteUserAdsService;
|
||||
|
||||
beforeAll(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [
|
||||
{
|
||||
provide: QueryBus,
|
||||
useValue: mockQueryBus,
|
||||
},
|
||||
{
|
||||
provide: CommandBus,
|
||||
useValue: mockCommandBus,
|
||||
},
|
||||
DeleteUserAdsService,
|
||||
],
|
||||
}).compile();
|
||||
|
||||
deleteUserAdsService =
|
||||
module.get<DeleteUserAdsService>(DeleteUserAdsService);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(deleteUserAdsService).toBeDefined();
|
||||
});
|
||||
|
||||
it('should call the delete command for each ad returned by the query', async () => {
|
||||
await deleteUserAdsService.execute(
|
||||
new DeleteUserAdsCommand({ id: userAds[0].getProps().userId }),
|
||||
);
|
||||
expect(mockCommandBus.execute).toHaveBeenCalledTimes(userAds.length);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,43 @@
|
|||
import { UserDeletedMessageHandler } from '@modules/ad/interface/message-handlers/user-deleted.message-handler';
|
||||
import { CommandBus } from '@nestjs/cqrs';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
|
||||
const mockCommandBus = {
|
||||
execute: jest.fn(),
|
||||
};
|
||||
|
||||
describe('Matcher Ad Created Message Handler', () => {
|
||||
let userDeletedMessageHandler: UserDeletedMessageHandler;
|
||||
|
||||
beforeAll(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [
|
||||
{
|
||||
provide: CommandBus,
|
||||
useValue: mockCommandBus,
|
||||
},
|
||||
UserDeletedMessageHandler,
|
||||
],
|
||||
}).compile();
|
||||
|
||||
userDeletedMessageHandler = module.get<UserDeletedMessageHandler>(
|
||||
UserDeletedMessageHandler,
|
||||
);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(userDeletedMessageHandler).toBeDefined();
|
||||
});
|
||||
|
||||
it('should call the command bus', async () => {
|
||||
const userId = '4eb6a6af-ecfd-41c3-9118-473a507014d4';
|
||||
const userDeletedMessage = `{"id":"${userId}"}`;
|
||||
await userDeletedMessageHandler.userDeleted(userDeletedMessage);
|
||||
expect(mockCommandBus.execute).toHaveBeenCalledTimes(1);
|
||||
expect(mockCommandBus.execute.mock.lastCall[0].id).toBe(userId);
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue