WIP validation pipes

This commit is contained in:
Grégoire Chevalier 2023-05-09 17:28:18 +02:00
parent 1db7dc1104
commit ad10320f5f
12 changed files with 79 additions and 28 deletions

View File

@ -8,6 +8,7 @@ import { AdProfile } from './mappers/ad.profile';
import { AdsRepository } from './adapters/secondaries/ads.repository';
import { Messager } from './adapters/secondaries/messager';
import { FindAdByUuidUseCase } from './domain/usecases/find-ad-by-uuid.usecase';
import { CreateAdUseCase } from './domain/usecases/create-ad.usecase';
@Module({
imports: [
@ -29,6 +30,12 @@ import { FindAdByUuidUseCase } from './domain/usecases/find-ad-by-uuid.usecase';
}),
],
controllers: [AdController],
providers: [AdProfile, AdsRepository, Messager, FindAdByUuidUseCase],
providers: [
AdProfile,
AdsRepository,
Messager,
FindAdByUuidUseCase,
CreateAdUseCase,
],
})
export class AdModule {}

View File

@ -1,13 +1,16 @@
import { Mapper } from '@automapper/core';
import { InjectMapper } from '@automapper/nestjs';
import { Controller, UsePipes } from '@nestjs/common';
import { QueryBus } from '@nestjs/cqrs';
import { CommandBus, QueryBus } from '@nestjs/cqrs';
import { GrpcMethod, RpcException } from '@nestjs/microservices';
import { RpcValidationPipe } from '../../../../utils/pipes/rpc.validation-pipe';
import { FindAdByUuidRequest } from '../../domain/dtos/find-ad-by-uuid.request';
import { AdPresenter } from './ad.presenter';
import { FindAdByUuidQuery } from '../../queries/find-ad-by-uuid.query';
import { Ad } from '../../domain/entities/ad';
import { CreateAdRequest } from '../../domain/dtos/create-ad.request';
import { CreateAdCommand } from '../../commands/create-ad.command';
import { DatabaseException } from 'src/modules/database/exceptions/database.exception';
@UsePipes(
new RpcValidationPipe({
@ -18,6 +21,7 @@ import { Ad } from '../../domain/entities/ad';
@Controller()
export class AdController {
constructor(
private readonly _commandBus: CommandBus,
private readonly queryBus: QueryBus,
@InjectMapper() private readonly _mapper: Mapper,
) {}
@ -34,4 +38,22 @@ export class AdController {
});
}
}
@GrpcMethod('AdsService', 'Create')
async createAd(data: CreateAdRequest): Promise<AdPresenter> {
try {
const ad = await this._commandBus.execute(new CreateAdCommand(data));
return this._mapper.map(ad, Ad, AdPresenter);
} catch (e) {
if (e instanceof DatabaseException) {
if (e.message.includes('Already exists')) {
throw new RpcException({
code: 6,
message: 'Ad already exists',
});
}
}
throw new RpcException({});
}
}
}

View File

@ -19,15 +19,15 @@ message Ad {
string userUuid = 2;
bool driver = 3;
bool passenger = 4;
int32 frequency = 5;
Frequency frequency = 5;
string fromDate = 6;
string toDate = 7;
Schedule schedule = 8;
MarginDurations marginDurations = 9;
int32 seatsPassenger = 10;
int32 seatsDriver = 11;
optional int32 seatsPassenger = 10;
optional int32 seatsDriver = 11;
bool strict = 12;
Addresses addresses = 13;
repeated Address addresses = 13;
}
message Schedule {
@ -50,10 +50,6 @@ message MarginDurations {
int32 sun = 7;
}
message Addresses {
repeated Address address = 1;
}
message Address {
float lon = 1;
float lat = 2;
@ -73,6 +69,11 @@ enum AddressType {
OTHER = 5;
}
enum Frequency {
PUNCTUAL = 1;
RECURRENT = 2;
}
message AdFilter {
optional int32 page = 1;
optional int32 perPage = 2;

View File

@ -5,10 +5,12 @@ import {
IsBoolean,
IsDate,
IsInt,
MinLength,
ValidateIf,
ArrayMinSize,
IsArray,
IsEnum,
} from 'class-validator';
import { FrequencyType } from '../entities/frequencyEnum';
import { Frequency } from '../entities/frequency.enum';
import { Address } from '../entities/address';
export class CreateAdRequest {
@ -22,21 +24,26 @@ export class CreateAdRequest {
userUuid: string;
@ValidateIf((ad) => (ad.passenger ? false : true))
@IsOptional()
@IsBoolean()
@AutoMap()
driver?: boolean;
@ValidateIf((ad) => (ad.driver ? false : true))
@IsOptional()
@IsBoolean()
@AutoMap()
passenger?: boolean;
@AutoMap()
frequency: FrequencyType;
@IsEnum(Frequency)
frequency: Frequency;
@IsDate()
@AutoMap()
fromDate: Date;
@IsDate()
@AutoMap()
toDate: Date;
@ -111,11 +118,13 @@ export class CreateAdRequest {
sunMargin?: number;
@ValidateIf((ad) => (ad.passenger ? false : true))
@IsOptional()
@IsInt()
@AutoMap()
seatsDriver?: number;
@ValidateIf((ad) => (ad.driver ? false : true))
@IsOptional()
@IsInt()
@AutoMap()
seatsPassenger?: number;
@ -130,7 +139,7 @@ export class CreateAdRequest {
@AutoMap()
updatedAt?: Date;
@MinLength(2)
@AutoMap()
@IsArray()
@AutoMap(() => [Address])
addresses?: Array<Address>;
}

View File

@ -8,7 +8,7 @@ import {
MinLength,
ValidateIf,
} from 'class-validator';
import { FrequencyType } from '../entities/frequencyEnum';
import { Frequency } from './frequency.enum';
import { Address } from '../entities/address';
export class Ad {
@ -31,7 +31,7 @@ export class Ad {
passenger?: boolean;
@AutoMap()
frequency: FrequencyType;
frequency: string;
@AutoMap()
fromDate: Date;

View File

@ -1,5 +1,5 @@
import { AutoMap } from '@automapper/classes';
import { AddressType } from './addressEnum';
import { AddressType } from './address.enum';
export class Address {
@AutoMap()

View File

@ -0,0 +1,4 @@
export enum Frequency {
PUNCTUAL = 1,
RECURRENT = 2,
}

View File

@ -1,4 +0,0 @@
export enum FrequencyType {
PUNCTUAL = 'PUNCTUAL',
RECURRENT = 'RECURRENT',
}

View File

@ -1,9 +1,10 @@
import { createMap, Mapper } from '@automapper/core';
import { createMap, forMember, mapFrom, Mapper } from '@automapper/core';
import { AutomapperProfile, InjectMapper } from '@automapper/nestjs';
import { Injectable } from '@nestjs/common';
import { Ad } from '../domain/entities/ad';
import { AdPresenter } from '../adapters/primaries/ad.presenter';
import { CreateAdRequest } from '../domain/dtos/create-ad.request';
import { Frequency } from '../domain/entities/frequency.enum';
@Injectable()
export class AdProfile extends AutomapperProfile {
@ -14,7 +15,17 @@ export class AdProfile extends AutomapperProfile {
override get profile() {
return (mapper) => {
createMap(mapper, Ad, AdPresenter);
createMap(mapper, CreateAdRequest, Ad);
createMap(
mapper,
CreateAdRequest,
Ad,
forMember(
(dest) => dest.frequency,
mapFrom((source) =>
source.frequency == Frequency.PUNCTUAL ? 'PUNCTUAL' : 'RECCURENT',
),
),
);
};
}
}

View File

@ -5,10 +5,10 @@ import { Address } from '../../domain/entities/address';
import { Messager } from '../../adapters/secondaries/messager';
import { AdsRepository } from '../../adapters/secondaries/ads.repository';
import { CreateAdCommand } from '../../commands/create-ad.command';
import { AddressType } from '../../domain/entities/addressEnum';
import { AddressType } from '../../domain/entities/address.enum';
import { AutomapperModule } from '@automapper/nestjs';
import { classes } from '@automapper/classes';
import { FrequencyType } from '../../domain/entities/frequencyEnum';
import { Frequency } from '../../domain/entities/frequency.enum';
import { Ad } from '../../domain/entities/ad';
import { AdProfile } from '../../mappers/ad.profile';
@ -19,7 +19,7 @@ const mockAddress1: Address = {
houseNumber: '5',
street: 'Avenue Foch',
locality: 'Nancy',
postalCode: '75000',
postalCode: '54000',
country: 'France',
type: AddressType.HOUSE_NUMBER,
};
@ -37,7 +37,7 @@ const newAdRequest: CreateAdRequest = {
userUuid: '113e0000-0000-4000-a000-000000000000',
driver: true,
passenger: false,
frequency: FrequencyType.RECURRENT,
frequency: Frequency.RECURRENT,
fromDate: new Date('01-05-2023'),
toDate: new Date('20-08-2023'),
tueTime: new Date(''),

View File

@ -88,6 +88,7 @@ export abstract class PrismaRepository<T> implements IRepository<T> {
return res;
} catch (e) {
console.log(e);
if (e instanceof Prisma.PrismaClientKnownRequestError) {
throw new DatabaseException(
Prisma.PrismaClientKnownRequestError.name,