From bf08260403c8a795d207f0ce4573e3130b33c887 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Chevalier?= Date: Mon, 15 May 2023 13:42:48 +0200 Subject: [PATCH] adding driver and passenger seats validator --- .../ad/domain/dtos/create-ad.request.ts | 10 +- .../domain/dtos/has-driver-seats.validator.ts | 43 ++++++++ .../dtos/has-passenger-seats.validator.ts | 43 ++++++++ .../ad/domain/dtos/utils/frequency.mapping.ts | 2 +- src/modules/ad/domain/entities/ad.ts | 2 +- .../interfaces/param-provider.interface.ts | 4 + .../ad/domain/types/default-params.type.ts | 3 + .../{entities => types}/frequency.enum.ts | 0 .../ad/domain/usecases/create-ad.usecase.ts | 1 - .../ad/tests/unit/create-ad.usecase.spec.ts | 23 +++- .../unit/has-driver-seats-validator.spec.ts | 100 ++++++++++++++++++ .../has-passenger-seats-validator.spec.ts | 100 ++++++++++++++++++ 12 files changed, 321 insertions(+), 10 deletions(-) create mode 100644 src/modules/ad/domain/dtos/has-driver-seats.validator.ts create mode 100644 src/modules/ad/domain/dtos/has-passenger-seats.validator.ts create mode 100644 src/modules/ad/domain/interfaces/param-provider.interface.ts create mode 100644 src/modules/ad/domain/types/default-params.type.ts rename src/modules/ad/domain/{entities => types}/frequency.enum.ts (100%) create mode 100644 src/modules/ad/tests/unit/has-driver-seats-validator.spec.ts create mode 100644 src/modules/ad/tests/unit/has-passenger-seats-validator.spec.ts diff --git a/src/modules/ad/domain/dtos/create-ad.request.ts b/src/modules/ad/domain/dtos/create-ad.request.ts index a8b01b5..e269871 100644 --- a/src/modules/ad/domain/dtos/create-ad.request.ts +++ b/src/modules/ad/domain/dtos/create-ad.request.ts @@ -11,12 +11,14 @@ import { ArrayMinSize, IsNotEmptyObject, } from 'class-validator'; -import { Frequency } from '../entities/frequency.enum'; +import { Frequency } from '../types/frequency.enum'; import { Transform, Type } from 'class-transformer'; import { mappingKeyToFrequency } from './utils/frequency.mapping'; import { MarginDTO } from './create.margin.dto'; import { ScheduleDTO } from './create.schedule.dto'; import { AddressDTO } from './create.address.dto'; +import { HasProperPassengerSeats } from './has-passenger-seats.validator'; +import { HasProperDriverSeats } from './has-driver-seats.validator'; export class CreateAdRequest { @IsString() @@ -24,11 +26,13 @@ export class CreateAdRequest { userUuid: string; @IsOptional() + @HasProperDriverSeats() @IsBoolean() @AutoMap() driver?: boolean; @IsOptional() + @HasProperPassengerSeats() @IsBoolean() @AutoMap() passenger?: boolean; @@ -63,13 +67,13 @@ export class CreateAdRequest { @ValidateNested({ each: true }) @IsNotEmptyObject() @AutoMap() - schedule: ScheduleDTO; + schedule?: ScheduleDTO; @IsOptional() @Type(() => MarginDTO) @ValidateNested({ each: true }) @AutoMap() - marginDurations: MarginDTO; + marginDurations?: MarginDTO; @ValidateIf((ad) => ad.driver) @IsInt() diff --git a/src/modules/ad/domain/dtos/has-driver-seats.validator.ts b/src/modules/ad/domain/dtos/has-driver-seats.validator.ts new file mode 100644 index 0000000..0712f1c --- /dev/null +++ b/src/modules/ad/domain/dtos/has-driver-seats.validator.ts @@ -0,0 +1,43 @@ +import { + ValidateBy, + ValidationArguments, + ValidationOptions, + buildMessage, +} from 'class-validator'; +// TODO refactor ?? +// TODO propely set driver max limit +export function hasProperDriverSeats(value: any, args: ValidationArguments) { + console.log('here '); + console.log(value); + console.log(args.object); + if (value === true && typeof args.object['seatsDriver'] === 'number') + return args.object['seatsDriver'] > 0; + else if ( + (value === false || value === null || value === undefined) && + (args.object['seatsDriver'] === 0 || + args.object['seatsDriver'] === null || + args.object['seatsDriver'] === undefined) + ) + return true; + else return false; +} + +export function HasProperDriverSeats( + validationOptions?: ValidationOptions, +): PropertyDecorator { + return ValidateBy( + { + name: '', + constraints: [], + validator: { + validate: (value, args: ValidationArguments): boolean => + hasProperDriverSeats(value, args), + defaultMessage: buildMessage( + () => `driver and driver seats are not correct`, + validationOptions, + ), + }, + }, + validationOptions, + ); +} diff --git a/src/modules/ad/domain/dtos/has-passenger-seats.validator.ts b/src/modules/ad/domain/dtos/has-passenger-seats.validator.ts new file mode 100644 index 0000000..d403c2c --- /dev/null +++ b/src/modules/ad/domain/dtos/has-passenger-seats.validator.ts @@ -0,0 +1,43 @@ +import { + ValidateBy, + ValidationArguments, + ValidationOptions, + buildMessage, +} from 'class-validator'; +// TODO refactor ?? +// TODO propely set passenger max limit +export function hasProperPassengerSeats(value: any, args: ValidationArguments) { + console.log('here '); + console.log(value); + console.log(args.object); + if (value === true && typeof args.object['seatsPassenger'] === 'number') + return args.object['seatsPassenger'] > 0; + else if ( + (value === false || value === null || value === undefined) && + (args.object['seatsPassenger'] === 0 || + args.object['seatsPassenger'] === null || + args.object['seatsPassenger'] === undefined) + ) + return true; + else return false; +} + +export function HasProperPassengerSeats( + validationOptions?: ValidationOptions, +): PropertyDecorator { + return ValidateBy( + { + name: '', + constraints: [], + validator: { + validate: (value, args: ValidationArguments): boolean => + hasProperPassengerSeats(value, args), + defaultMessage: buildMessage( + () => `passenger and passenger seats are not correct`, + validationOptions, + ), + }, + }, + validationOptions, + ); +} diff --git a/src/modules/ad/domain/dtos/utils/frequency.mapping.ts b/src/modules/ad/domain/dtos/utils/frequency.mapping.ts index 8c41025..4d59786 100644 --- a/src/modules/ad/domain/dtos/utils/frequency.mapping.ts +++ b/src/modules/ad/domain/dtos/utils/frequency.mapping.ts @@ -1,4 +1,4 @@ -import { Frequency } from '../../entities/frequency.enum'; +import { Frequency } from '../../types/frequency.enum'; export const mappingKeyToFrequency = (index: number): string => { return Frequency[index - 1]; }; diff --git a/src/modules/ad/domain/entities/ad.ts b/src/modules/ad/domain/entities/ad.ts index 58015a6..952eed9 100644 --- a/src/modules/ad/domain/entities/ad.ts +++ b/src/modules/ad/domain/entities/ad.ts @@ -8,7 +8,7 @@ import { IsEnum, } from 'class-validator'; import { Address } from '../entities/address'; -import { Frequency } from './frequency.enum'; +import { Frequency } from '../types/frequency.enum'; export class Ad { @IsString() diff --git a/src/modules/ad/domain/interfaces/param-provider.interface.ts b/src/modules/ad/domain/interfaces/param-provider.interface.ts new file mode 100644 index 0000000..4169e3b --- /dev/null +++ b/src/modules/ad/domain/interfaces/param-provider.interface.ts @@ -0,0 +1,4 @@ +import { DefaultParams } from '../types/default-params.type'; +export interface IProvideParams { + getParams(): DefaultParams; +} diff --git a/src/modules/ad/domain/types/default-params.type.ts b/src/modules/ad/domain/types/default-params.type.ts new file mode 100644 index 0000000..26a475e --- /dev/null +++ b/src/modules/ad/domain/types/default-params.type.ts @@ -0,0 +1,3 @@ +export type DefaultParams = { + DEFAULT_MARGIN: number; +}; diff --git a/src/modules/ad/domain/entities/frequency.enum.ts b/src/modules/ad/domain/types/frequency.enum.ts similarity index 100% rename from src/modules/ad/domain/entities/frequency.enum.ts rename to src/modules/ad/domain/types/frequency.enum.ts diff --git a/src/modules/ad/domain/usecases/create-ad.usecase.ts b/src/modules/ad/domain/usecases/create-ad.usecase.ts index 5b4faa0..6569242 100644 --- a/src/modules/ad/domain/usecases/create-ad.usecase.ts +++ b/src/modules/ad/domain/usecases/create-ad.usecase.ts @@ -21,7 +21,6 @@ export class CreateAdUseCase { CreateAdRequest, Ad, ); - try { const ad = await this._repository.create(entity); // this._messager.publish('ad.create', JSON.stringify(ad)); diff --git a/src/modules/ad/tests/unit/create-ad.usecase.spec.ts b/src/modules/ad/tests/unit/create-ad.usecase.spec.ts index a32e541..d3fe379 100644 --- a/src/modules/ad/tests/unit/create-ad.usecase.spec.ts +++ b/src/modules/ad/tests/unit/create-ad.usecase.spec.ts @@ -7,9 +7,11 @@ import { AdsRepository } from '../../adapters/secondaries/ads.repository'; import { CreateAdCommand } from '../../commands/create-ad.command'; import { AutomapperModule } from '@automapper/nestjs'; import { classes } from '@automapper/classes'; -import { Frequency } from '../../domain/entities/frequency.enum'; +import { Frequency } from '../../domain/types/frequency.enum'; import { Ad } from '../../domain/entities/ad'; import { AdProfile } from '../../mappers/ad.profile'; +import { ScheduleDTO } from '../../domain/dtos/create.schedule.dto'; +import { ObjectUnsubscribedError } from 'rxjs'; const mockAddress1: Address = { position: 0, @@ -37,8 +39,19 @@ const newAdRequest: CreateAdRequest = { frequency: Frequency.RECURRENT, fromDate: new Date('01-05-2023'), toDate: new Date('20-08-2023'), - tueTime: '08:00', - wedTime: '08:30', + schedule: { + tue: '08:00', + wed: '08:30', + }, + marginDurations: { + mon: undefined, + tue: undefined, + wed: undefined, + thu: undefined, + fri: undefined, + sat: undefined, + sun: undefined, + }, seatsPassenger: 2, addresses: [mockAddress1, mockAddress2], }; @@ -63,7 +76,6 @@ const mockAdRepository = { throw new Error('Already exists'); }), }; - describe('CreateAdUseCase', () => { let createAdUseCase: CreateAdUseCase; beforeAll(async () => { @@ -89,6 +101,9 @@ describe('CreateAdUseCase', () => { expect(createAdUseCase).toBeDefined(); }); + // describe('Ad parameters validation', () => { + // it('should throw an error if '); + // }); describe('execution', () => { it('should create an new ad', async () => { const newAd: Ad = await createAdUseCase.execute(newAdCommand); diff --git a/src/modules/ad/tests/unit/has-driver-seats-validator.spec.ts b/src/modules/ad/tests/unit/has-driver-seats-validator.spec.ts new file mode 100644 index 0000000..10fa283 --- /dev/null +++ b/src/modules/ad/tests/unit/has-driver-seats-validator.spec.ts @@ -0,0 +1,100 @@ +import { hasProperDriverSeats } from '../../domain/dtos/has-driver-seats.validator'; + +describe('driver and/or driver seats validator', () => { + it('should validate if driver and drivers seats is not provided ', () => { + expect( + hasProperDriverSeats(undefined, { + value: undefined, + constraints: [], + targetName: '', + object: {}, + property: '', + }), + ).toBe(true); + expect( + hasProperDriverSeats(false, { + value: undefined, + constraints: [], + targetName: '', + object: {}, + property: '', + }), + ).toBe(true); + expect( + hasProperDriverSeats(null, { + value: undefined, + constraints: [], + targetName: '', + object: {}, + property: '', + }), + ).toBe(true); + }); + it('should not validate if driver is set to true but not the related seats is not provided or 0', () => { + expect( + hasProperDriverSeats(true, { + value: undefined, + constraints: [], + targetName: '', + object: {}, + property: '', + }), + ).toBe(false); + expect( + hasProperDriverSeats(true, { + value: undefined, + constraints: [], + targetName: '', + object: { seatsDriver: 0 }, + property: '', + }), + ).toBe(false); + expect( + hasProperDriverSeats(true, { + value: undefined, + constraints: [], + targetName: '', + object: { seatsDriver: undefined }, + property: '', + }), + ).toBe(false); + expect( + hasProperDriverSeats(true, { + value: undefined, + constraints: [], + targetName: '', + object: { seatsDriver: null }, + property: '', + }), + ).toBe(false); + }); + it('should not validate if driver seats are provided but driver is not set or set to false ', () => { + expect( + hasProperDriverSeats(false, { + value: undefined, + constraints: [], + targetName: '', + object: { seatsDriver: 1 }, + property: '', + }), + ).toBe(false); + expect( + hasProperDriverSeats(undefined, { + value: undefined, + constraints: [], + targetName: '', + object: { seatsDriver: 1 }, + property: '', + }), + ).toBe(false); + expect( + hasProperDriverSeats(null, { + value: undefined, + constraints: [], + targetName: '', + object: { seatsDriver: 1 }, + property: '', + }), + ).toBe(false); + }); +}); diff --git a/src/modules/ad/tests/unit/has-passenger-seats-validator.spec.ts b/src/modules/ad/tests/unit/has-passenger-seats-validator.spec.ts new file mode 100644 index 0000000..cec5a6e --- /dev/null +++ b/src/modules/ad/tests/unit/has-passenger-seats-validator.spec.ts @@ -0,0 +1,100 @@ +import { hasProperPassengerSeats } from '../../domain/dtos/has-passenger-seats.validator'; + +describe('driver and/or passenger seats validator', () => { + it('should validate if passenger and passengers seats is not provided ', () => { + expect( + hasProperPassengerSeats(undefined, { + value: undefined, + constraints: [], + targetName: '', + object: {}, + property: '', + }), + ).toBe(true); + expect( + hasProperPassengerSeats(false, { + value: undefined, + constraints: [], + targetName: '', + object: {}, + property: '', + }), + ).toBe(true); + expect( + hasProperPassengerSeats(null, { + value: undefined, + constraints: [], + targetName: '', + object: {}, + property: '', + }), + ).toBe(true); + }); + it('should not validate if passenger is set to true but not the related seats is not provided or 0', () => { + expect( + hasProperPassengerSeats(true, { + value: undefined, + constraints: [], + targetName: '', + object: {}, + property: '', + }), + ).toBe(false); + expect( + hasProperPassengerSeats(true, { + value: undefined, + constraints: [], + targetName: '', + object: { seatsPassenger: 0 }, + property: '', + }), + ).toBe(false); + expect( + hasProperPassengerSeats(true, { + value: undefined, + constraints: [], + targetName: '', + object: { seatsPassenger: undefined }, + property: '', + }), + ).toBe(false); + expect( + hasProperPassengerSeats(true, { + value: undefined, + constraints: [], + targetName: '', + object: { seatsPassenger: null }, + property: '', + }), + ).toBe(false); + }); + it('should not validate if passenger seats are provided but passenger is not set or set to false ', () => { + expect( + hasProperPassengerSeats(false, { + value: undefined, + constraints: [], + targetName: '', + object: { seatsPassenger: 1 }, + property: '', + }), + ).toBe(false); + expect( + hasProperPassengerSeats(undefined, { + value: undefined, + constraints: [], + targetName: '', + object: { seatsPassenger: 1 }, + property: '', + }), + ).toBe(false); + expect( + hasProperPassengerSeats(null, { + value: undefined, + constraints: [], + targetName: '', + object: { seatsPassenger: 1 }, + property: '', + }), + ).toBe(false); + }); +});