From cde1760099ec195328dc95b87e4cefe8b30f59ac Mon Sep 17 00:00:00 2001 From: sbriat Date: Wed, 30 Aug 2023 14:07:00 +0200 Subject: [PATCH] add default params, time transformer --- .../application/ports/ad.repository.port.ts | 21 +--- .../application/ports/default-params.type.ts | 12 +- .../queries/match/match.query-handler.ts | 33 ++++- .../application/queries/match/match.query.ts | 115 ++++++++++++++++-- .../application/types/schedule-item.type.ts | 4 +- src/modules/ad/core/domain/match.types.ts | 19 +++ .../schedule-item.value-object.ts | 10 +- .../ad/infrastructure/ad.repository.ts | 10 +- src/modules/ad/infrastructure/ad.selector.ts | 4 +- .../infrastructure/default-params-provider.ts | 74 +++++++++-- .../input-datetime-transformer.ts | 2 +- .../dtos/match.request.dto.ts | 89 +++++++------- .../unit/core/match.query-handler.spec.ts | 40 +++++- .../core/passenger-oriented-algorithm.spec.ts | 11 +- .../default-param.provider.spec.ts | 28 ++++- .../input-datetime-transformer.spec.ts | 11 +- 16 files changed, 377 insertions(+), 106 deletions(-) diff --git a/src/modules/ad/core/application/ports/ad.repository.port.ts b/src/modules/ad/core/application/ports/ad.repository.port.ts index af68529..8e9674b 100644 --- a/src/modules/ad/core/application/ports/ad.repository.port.ts +++ b/src/modules/ad/core/application/ports/ad.repository.port.ts @@ -1,23 +1,8 @@ import { ExtendedRepositoryPort } from '@mobicoop/ddd-library'; import { AdEntity } from '../../domain/ad.entity'; -import { AlgorithmType, Candidate } from '../types/algorithm.types'; -import { Frequency } from '../../domain/ad.types'; +import { Candidate } from '../types/algorithm.types'; +import { MatchQuery } from '../queries/match/match.query'; export type AdRepositoryPort = ExtendedRepositoryPort & { - getCandidates(query: CandidateQuery): Promise; -}; - -export type CandidateQuery = { - driver: boolean; - passenger: boolean; - strict: boolean; - frequency: Frequency; - fromDate: string; - toDate: string; - schedule: { - day?: number; - time: string; - margin?: number; - }[]; - algorithmType: AlgorithmType; + getCandidates(query: MatchQuery): Promise; }; diff --git a/src/modules/ad/core/application/ports/default-params.type.ts b/src/modules/ad/core/application/ports/default-params.type.ts index dbf0798..3bee195 100644 --- a/src/modules/ad/core/application/ports/default-params.type.ts +++ b/src/modules/ad/core/application/ports/default-params.type.ts @@ -1,3 +1,5 @@ +import { AlgorithmType } from '../types/algorithm.types'; + export type DefaultParams = { DRIVER: boolean; PASSENGER: boolean; @@ -5,5 +7,13 @@ export type DefaultParams = { SEATS_REQUESTED: number; DEPARTURE_TIME_MARGIN: number; STRICT: boolean; - DEFAULT_TIMEZONE: string; + TIMEZONE: string; + ALGORITHM_TYPE: AlgorithmType; + REMOTENESS: number; + USE_PROPORTION: boolean; + PROPORTION: number; + USE_AZIMUTH: boolean; + AZIMUTH_MARGIN: number; + MAX_DETOUR_DISTANCE_RATIO: number; + MAX_DETOUR_DURATION_RATIO: number; }; diff --git a/src/modules/ad/core/application/queries/match/match.query-handler.ts b/src/modules/ad/core/application/queries/match/match.query-handler.ts index 404402f..a0fe915 100644 --- a/src/modules/ad/core/application/queries/match/match.query-handler.ts +++ b/src/modules/ad/core/application/queries/match/match.query-handler.ts @@ -5,15 +5,44 @@ import { PassengerOrientedAlgorithm } from './passenger-oriented-algorithm'; import { AlgorithmType } from '../../types/algorithm.types'; import { Inject } from '@nestjs/common'; import { AdRepositoryPort } from '@modules/ad/core/application/ports/ad.repository.port'; -import { AD_REPOSITORY } from '@modules/ad/ad.di-tokens'; +import { AD_REPOSITORY, PARAMS_PROVIDER } from '@modules/ad/ad.di-tokens'; import { MatchEntity } from '@modules/ad/core/domain/match.entity'; +import { DefaultParamsProviderPort } from '../../ports/default-params-provider.port'; +import { DefaultParams } from '../../ports/default-params.type'; @QueryHandler(MatchQuery) export class MatchQueryHandler implements IQueryHandler { + private readonly _defaultParams: DefaultParams; + constructor( + @Inject(PARAMS_PROVIDER) + private readonly defaultParamsProvider: DefaultParamsProviderPort, @Inject(AD_REPOSITORY) private readonly repository: AdRepositoryPort, - ) {} + ) { + this._defaultParams = defaultParamsProvider.getParams(); + } + execute = async (query: MatchQuery): Promise => { + query + .setMissingMarginDurations(this._defaultParams.DEPARTURE_TIME_MARGIN) + .setMissingStrict(this._defaultParams.STRICT) + .setDefaultDriverAndPassengerParameters({ + driver: this._defaultParams.DRIVER, + passenger: this._defaultParams.PASSENGER, + seatsProposed: this._defaultParams.SEATS_PROPOSED, + seatsRequested: this._defaultParams.SEATS_REQUESTED, + }) + .setDefaultAlgorithmParameters({ + algorithmType: this._defaultParams.ALGORITHM_TYPE, + remoteness: 0, + useProportion: false, + proportion: 0, + useAzimuth: false, + azimuthMargin: 0, + maxDetourDistanceRatio: 0, + maxDetourDurationRatio: 0, + }); + let algorithm: Algorithm; switch (query.algorithmType) { case AlgorithmType.PASSENGER_ORIENTED: diff --git a/src/modules/ad/core/application/queries/match/match.query.ts b/src/modules/ad/core/application/queries/match/match.query.ts index 3b0d480..d2348ae 100644 --- a/src/modules/ad/core/application/queries/match/match.query.ts +++ b/src/modules/ad/core/application/queries/match/match.query.ts @@ -1,21 +1,32 @@ import { QueryBase } from '@mobicoop/ddd-library'; import { AlgorithmType } from '../../types/algorithm.types'; import { Waypoint } from '../../types/waypoint.type'; -import { ScheduleItem } from '../../types/schedule-item.type'; import { Frequency } from '@modules/ad/core/domain/ad.types'; +import { MatchRequestDto } from '@modules/ad/interface/grpc-controllers/dtos/match.request.dto'; export class MatchQuery extends QueryBase { - readonly driver: boolean; - readonly passenger: boolean; + driver?: boolean; + passenger?: boolean; readonly frequency: Frequency; readonly fromDate: string; readonly toDate: string; - readonly schedule: ScheduleItem[]; - readonly strict: boolean; + schedule: ScheduleItem[]; + seatsProposed?: number; + seatsRequested?: number; + strict?: boolean; readonly waypoints: Waypoint[]; - readonly algorithmType: AlgorithmType; + algorithmType?: AlgorithmType; + remoteness?: number; + useProportion?: boolean; + proportion?: number; + useAzimuth?: boolean; + azimuthMargin?: number; + maxDetourDistanceRatio?: number; + maxDetourDurationRatio?: number; + readonly page?: number; + readonly perPage?: number; - constructor(props: MatchQuery) { + constructor(props: MatchRequestDto) { super(); this.driver = props.driver; this.passenger = props.passenger; @@ -23,8 +34,98 @@ export class MatchQuery extends QueryBase { this.fromDate = props.fromDate; this.toDate = props.toDate; this.schedule = props.schedule; + this.seatsProposed = props.seatsProposed; + this.seatsRequested = props.seatsRequested; this.strict = props.strict; this.waypoints = props.waypoints; this.algorithmType = props.algorithmType; + this.remoteness = props.remoteness; + this.useProportion = props.useProportion; + this.proportion = props.proportion; + this.useAzimuth = props.useAzimuth; + this.azimuthMargin = props.azimuthMargin; + this.maxDetourDistanceRatio = props.maxDetourDistanceRatio; + this.maxDetourDurationRatio = props.maxDetourDurationRatio; + this.page = props.page ?? 1; + this.perPage = props.perPage ?? 10; } + + setMissingMarginDurations = (defaultMarginDuration: number): MatchQuery => { + this.schedule.forEach((day: ScheduleItem) => { + if (day.margin === undefined) day.margin = defaultMarginDuration; + }); + return this; + }; + + setMissingStrict = (strict: boolean): MatchQuery => { + if (this.strict === undefined) this.strict = strict; + return this; + }; + + setDefaultDriverAndPassengerParameters = ( + defaultDriverAndPassengerParameters: DefaultDriverAndPassengerParameters, + ): MatchQuery => { + this.driver = !!this.driver; + this.passenger = !!this.passenger; + if (!this.driver && !this.passenger) { + this.driver = defaultDriverAndPassengerParameters.driver; + this.seatsProposed = defaultDriverAndPassengerParameters.seatsProposed; + this.passenger = defaultDriverAndPassengerParameters.passenger; + this.seatsRequested = defaultDriverAndPassengerParameters.seatsRequested; + return this; + } + if (!this.seatsProposed || this.seatsProposed <= 0) + this.seatsProposed = defaultDriverAndPassengerParameters.seatsProposed; + if (!this.seatsRequested || this.seatsRequested <= 0) + this.seatsRequested = defaultDriverAndPassengerParameters.seatsRequested; + return this; + }; + + setDefaultAlgorithmParameters = ( + defaultAlgorithmParameters: DefaultAlgorithmParameters, + ): MatchQuery => { + if (!this.algorithmType) + this.algorithmType = defaultAlgorithmParameters.algorithmType; + if (!this.remoteness) + this.remoteness = defaultAlgorithmParameters.remoteness; + if (this.useProportion == undefined) + this.useProportion = defaultAlgorithmParameters.useProportion; + if (!this.proportion) + this.proportion = defaultAlgorithmParameters.proportion; + if (this.useAzimuth == undefined) + this.useAzimuth = defaultAlgorithmParameters.useAzimuth; + if (!this.azimuthMargin) + this.azimuthMargin = defaultAlgorithmParameters.azimuthMargin; + if (!this.maxDetourDistanceRatio) + this.maxDetourDistanceRatio = + defaultAlgorithmParameters.maxDetourDistanceRatio; + if (!this.maxDetourDurationRatio) + this.maxDetourDurationRatio = + defaultAlgorithmParameters.maxDetourDurationRatio; + return this; + }; +} + +type ScheduleItem = { + day?: number; + time: string; + margin?: number; +}; + +interface DefaultDriverAndPassengerParameters { + driver: boolean; + passenger: boolean; + seatsProposed: number; + seatsRequested: number; +} + +interface DefaultAlgorithmParameters { + algorithmType: AlgorithmType; + remoteness: number; + useProportion: boolean; + proportion: number; + useAzimuth: boolean; + azimuthMargin: number; + maxDetourDistanceRatio: number; + maxDetourDurationRatio: number; } diff --git a/src/modules/ad/core/application/types/schedule-item.type.ts b/src/modules/ad/core/application/types/schedule-item.type.ts index a40e06d..92dab99 100644 --- a/src/modules/ad/core/application/types/schedule-item.type.ts +++ b/src/modules/ad/core/application/types/schedule-item.type.ts @@ -1,5 +1,5 @@ export type ScheduleItem = { - day?: number; + day: number; time: string; - margin?: number; + margin: number; }; diff --git a/src/modules/ad/core/domain/match.types.ts b/src/modules/ad/core/domain/match.types.ts index 997f87b..911029b 100644 --- a/src/modules/ad/core/domain/match.types.ts +++ b/src/modules/ad/core/domain/match.types.ts @@ -1,3 +1,5 @@ +import { AlgorithmType } from '../application/types/algorithm.types'; + // All properties that a Match has export interface MatchProps { adId: string; @@ -7,3 +9,20 @@ export interface MatchProps { export interface CreateMatchProps { adId: string; } + +export interface DefaultMatchQueryProps { + driver: boolean; + passenger: boolean; + marginDuration: number; + strict: boolean; + seatsProposed: number; + seatsRequested: number; + algorithmType?: AlgorithmType; + remoteness?: number; + useProportion?: boolean; + proportion?: number; + useAzimuth?: boolean; + azimuthMargin?: number; + maxDetourDistanceRatio?: number; + maxDetourDurationRatio?: number; +} diff --git a/src/modules/ad/core/domain/value-objects/schedule-item.value-object.ts b/src/modules/ad/core/domain/value-objects/schedule-item.value-object.ts index 4a773a4..97fb87f 100644 --- a/src/modules/ad/core/domain/value-objects/schedule-item.value-object.ts +++ b/src/modules/ad/core/domain/value-objects/schedule-item.value-object.ts @@ -10,13 +10,13 @@ import { * */ export interface ScheduleItemProps { - day?: number; + day: number; time: string; - margin?: number; + margin: number; } export class ScheduleItem extends ValueObject { - get day(): number | undefined { + get day(): number { return this.props.day; } @@ -24,13 +24,13 @@ export class ScheduleItem extends ValueObject { return this.props.time; } - get margin(): number | undefined { + get margin(): number { return this.props.margin; } // eslint-disable-next-line @typescript-eslint/no-unused-vars protected validate(props: ScheduleItemProps): void { - if (props.day !== undefined && (props.day < 0 || props.day > 6)) + if (props.day < 0 || props.day > 6) throw new ArgumentOutOfRangeException('day must be between 0 and 6'); if (props.time.split(':').length != 2) throw new ArgumentInvalidException('time is invalid'); diff --git a/src/modules/ad/infrastructure/ad.repository.ts b/src/modules/ad/infrastructure/ad.repository.ts index 1a33b8a..551579e 100644 --- a/src/modules/ad/infrastructure/ad.repository.ts +++ b/src/modules/ad/infrastructure/ad.repository.ts @@ -1,9 +1,6 @@ import { Inject, Injectable, Logger } from '@nestjs/common'; import { EventEmitter2 } from '@nestjs/event-emitter'; -import { - AdRepositoryPort, - CandidateQuery, -} from '../core/application/ports/ad.repository.port'; +import { AdRepositoryPort } from '../core/application/ports/ad.repository.port'; import { LoggerBase, MessagePublisherPort } from '@mobicoop/ddd-library'; import { PrismaService } from './prisma.service'; import { AD_MESSAGE_PUBLISHER } from '../ad.di-tokens'; @@ -13,6 +10,7 @@ import { ExtendedPrismaRepositoryBase } from '@mobicoop/ddd-library/dist/db/pris import { Frequency, Role } from '../core/domain/ad.types'; import { Candidate } from '../core/application/types/algorithm.types'; import { AdSelector } from './ad.selector'; +import { MatchQuery } from '../core/application/queries/match/match.query'; export type AdBaseModel = { uuid: string; @@ -93,7 +91,7 @@ export class AdRepository ); } - getCandidates = async (query: CandidateQuery): Promise => { + getCandidates = async (query: MatchQuery): Promise => { // let candidates: Candidate[] = []; const sqlQueries: QueryRole[] = []; if (query.driver) @@ -115,7 +113,7 @@ export class AdRepository } as AdsRole), ), ); - console.log(results[0].ads); + // console.log(results[0].ads); return []; }; } diff --git a/src/modules/ad/infrastructure/ad.selector.ts b/src/modules/ad/infrastructure/ad.selector.ts index 74e91db..821eb52 100644 --- a/src/modules/ad/infrastructure/ad.selector.ts +++ b/src/modules/ad/infrastructure/ad.selector.ts @@ -1,9 +1,9 @@ -import { CandidateQuery } from '../core/application/ports/ad.repository.port'; +import { MatchQuery } from '../core/application/queries/match/match.query'; import { AlgorithmType } from '../core/application/types/algorithm.types'; import { Role } from '../core/domain/ad.types'; export class AdSelector { - static select = (role: Role, query: CandidateQuery): string => { + static select = (role: Role, query: MatchQuery): string => { switch (query.algorithmType) { case AlgorithmType.PASSENGER_ORIENTED: default: diff --git a/src/modules/ad/infrastructure/default-params-provider.ts b/src/modules/ad/infrastructure/default-params-provider.ts index 7244e39..81f1737 100644 --- a/src/modules/ad/infrastructure/default-params-provider.ts +++ b/src/modules/ad/infrastructure/default-params-provider.ts @@ -2,32 +2,84 @@ import { Injectable } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import { DefaultParamsProviderPort } from '../core/application/ports/default-params-provider.port'; import { DefaultParams } from '../core/application/ports/default-params.type'; +import { AlgorithmType } from '../core/application/types/algorithm.types'; -const DEFAULT_SEATS_PROPOSED = 3; -const DEFAULT_SEATS_REQUESTED = 1; -const DEFAULT_DEPARTURE_TIME_MARGIN = 900; -const DEFAULT_TIMEZONE = 'Europe/Paris'; +const DRIVER = false; +const PASSENGER = true; +const SEATS_PROPOSED = 3; +const SEATS_REQUESTED = 1; +const DEPARTURE_TIME_MARGIN = 900; +const TIMEZONE = 'Europe/Paris'; +const ALGORITHM_TYPE = 'PASSENGER_ORIENTED'; +const REMOTENESS = 15000; +const USE_PROPORTION = true; +const PROPORTION = 0.3; +const USE_AZIMUTH = true; +const AZIMUTH_MARGIN = 10; +const MAX_DETOUR_DISTANCE_RATIO = 0.3; +const MAX_DETOUR_DURATION_RATIO = 0.3; @Injectable() export class DefaultParamsProvider implements DefaultParamsProviderPort { constructor(private readonly _configService: ConfigService) {} getParams = (): DefaultParams => ({ - DRIVER: this._configService.get('ROLE') == 'driver', + DRIVER: + this._configService.get('ROLE') !== undefined + ? this._configService.get('ROLE') == 'driver' + : DRIVER, SEATS_PROPOSED: this._configService.get('SEATS_PROPOSED') !== undefined ? parseInt(this._configService.get('SEATS_PROPOSED') as string) - : DEFAULT_SEATS_PROPOSED, - PASSENGER: this._configService.get('ROLE') == 'passenger', + : SEATS_PROPOSED, + PASSENGER: + this._configService.get('ROLE') !== undefined + ? this._configService.get('ROLE') == 'passenger' + : PASSENGER, SEATS_REQUESTED: this._configService.get('SEATS_REQUESTED') !== undefined ? parseInt(this._configService.get('SEATS_REQUESTED') as string) - : DEFAULT_SEATS_REQUESTED, + : SEATS_REQUESTED, DEPARTURE_TIME_MARGIN: this._configService.get('DEPARTURE_TIME_MARGIN') !== undefined ? parseInt(this._configService.get('DEPARTURE_TIME_MARGIN') as string) - : DEFAULT_DEPARTURE_TIME_MARGIN, + : DEPARTURE_TIME_MARGIN, STRICT: this._configService.get('STRICT_FREQUENCY') == 'true', - DEFAULT_TIMEZONE: - this._configService.get('DEFAULT_TIMEZONE') ?? DEFAULT_TIMEZONE, + TIMEZONE: this._configService.get('TIMEZONE') ?? TIMEZONE, + ALGORITHM_TYPE: + AlgorithmType[ + this._configService.get('ALGORITHM_TYPE') as AlgorithmType + ] ?? AlgorithmType[ALGORITHM_TYPE], + REMOTENESS: + this._configService.get('REMOTENESS') !== undefined + ? parseInt(this._configService.get('REMOTENESS') as string) + : REMOTENESS, + USE_PROPORTION: + this._configService.get('USE_PROPORTION') !== undefined + ? this._configService.get('USE_PROPORTION') == 'true' + : USE_PROPORTION, + PROPORTION: + this._configService.get('PROPORTION') !== undefined + ? parseFloat(this._configService.get('PROPORTION') as string) + : PROPORTION, + USE_AZIMUTH: + this._configService.get('USE_AZIMUTH') !== undefined + ? this._configService.get('USE_AZIMUTH') == 'true' + : USE_AZIMUTH, + AZIMUTH_MARGIN: + this._configService.get('AZIMUTH_MARGIN') !== undefined + ? parseInt(this._configService.get('AZIMUTH_MARGIN') as string) + : AZIMUTH_MARGIN, + MAX_DETOUR_DISTANCE_RATIO: + this._configService.get('MAX_DETOUR_DISTANCE_RATIO') !== undefined + ? parseFloat( + this._configService.get('MAX_DETOUR_DISTANCE_RATIO') as string, + ) + : MAX_DETOUR_DISTANCE_RATIO, + MAX_DETOUR_DURATION_RATIO: + this._configService.get('MAX_DETOUR_DURATION_RATIO') !== undefined + ? parseFloat( + this._configService.get('MAX_DETOUR_DURATION_RATIO') as string, + ) + : MAX_DETOUR_DURATION_RATIO, }); } diff --git a/src/modules/ad/infrastructure/input-datetime-transformer.ts b/src/modules/ad/infrastructure/input-datetime-transformer.ts index faa4025..97df366 100644 --- a/src/modules/ad/infrastructure/input-datetime-transformer.ts +++ b/src/modules/ad/infrastructure/input-datetime-transformer.ts @@ -23,7 +23,7 @@ export class InputDateTimeTransformer implements DateTimeTransformerPort { private readonly timezoneFinder: TimezoneFinderPort, @Inject(TIME_CONVERTER) private readonly timeConverter: TimeConverterPort, ) { - this._defaultTimezone = defaultParamsProvider.getParams().DEFAULT_TIMEZONE; + this._defaultTimezone = defaultParamsProvider.getParams().TIMEZONE; } /** diff --git a/src/modules/ad/interface/grpc-controllers/dtos/match.request.dto.ts b/src/modules/ad/interface/grpc-controllers/dtos/match.request.dto.ts index 86f9826..c073e44 100644 --- a/src/modules/ad/interface/grpc-controllers/dtos/match.request.dto.ts +++ b/src/modules/ad/interface/grpc-controllers/dtos/match.request.dto.ts @@ -2,10 +2,13 @@ import { ArrayMinSize, IsArray, IsBoolean, + IsDecimal, IsEnum, IsISO8601, IsInt, IsOptional, + Max, + Min, ValidateNested, } from 'class-validator'; import { Type } from 'class-transformer'; @@ -18,13 +21,13 @@ import { Frequency } from '@modules/ad/core/domain/ad.types'; import { AlgorithmType } from '@modules/ad/core/application/types/algorithm.types'; export class MatchRequestDto { - // @IsOptional() + @IsOptional() @IsBoolean() - driver: boolean; + driver?: boolean; - // @IsOptional() + @IsOptional() @IsBoolean() - passenger: boolean; + passenger?: boolean; @IsEnum(Frequency) @HasDay('schedule', { @@ -53,17 +56,17 @@ export class MatchRequestDto { @ValidateNested({ each: true }) schedule: ScheduleItemDto[]; - // @IsOptional() - // @IsInt() - // seatsProposed?: number; + @IsOptional() + @IsInt() + seatsProposed?: number; - // @IsOptional() - // @IsInt() - // seatsRequested?: number; + @IsOptional() + @IsInt() + seatsRequested?: number; - // @IsOptional() + @IsOptional() @IsBoolean() - strict: boolean; + strict?: boolean; @Type(() => WaypointDto) @IsArray() @@ -72,45 +75,45 @@ export class MatchRequestDto { @ValidateNested({ each: true }) waypoints: WaypointDto[]; - // @IsOptional() + @IsOptional() @IsEnum(AlgorithmType) - algorithmType: AlgorithmType; + algorithmType?: AlgorithmType; - // @IsOptional() - // @IsInt() - // remoteness?: number; + @IsOptional() + @IsInt() + remoteness?: number; - // @IsOptional() - // @IsBoolean() - // useProportion?: boolean; + @IsOptional() + @IsBoolean() + useProportion?: boolean; - // @IsOptional() - // @IsDecimal() - // @Min(0) - // @Max(1) - // proportion?: number; + @IsOptional() + @IsDecimal() + @Min(0) + @Max(1) + proportion?: number; - // @IsOptional() - // @IsBoolean() - // useAzimuth?: boolean; + @IsOptional() + @IsBoolean() + useAzimuth?: boolean; - // @IsOptional() - // @IsInt() - // @Min(0) - // @Max(359) - // azimuthMargin?: number; + @IsOptional() + @IsInt() + @Min(0) + @Max(359) + azimuthMargin?: number; - // @IsOptional() - // @IsDecimal() - // @Min(0) - // @Max(1) - // maxDetourDistanceRatio?: number; + @IsOptional() + @IsDecimal() + @Min(0) + @Max(1) + maxDetourDistanceRatio?: number; - // @IsOptional() - // @IsDecimal() - // @Min(0) - // @Max(1) - // maxDetourDurationRatio?: number; + @IsOptional() + @IsDecimal() + @Min(0) + @Max(1) + maxDetourDurationRatio?: number; @IsOptional() @IsInt() diff --git a/src/modules/ad/tests/unit/core/match.query-handler.spec.ts b/src/modules/ad/tests/unit/core/match.query-handler.spec.ts index 98220ac..394cf41 100644 --- a/src/modules/ad/tests/unit/core/match.query-handler.spec.ts +++ b/src/modules/ad/tests/unit/core/match.query-handler.spec.ts @@ -1,9 +1,10 @@ -import { AD_REPOSITORY } from '@modules/ad/ad.di-tokens'; +import { AD_REPOSITORY, PARAMS_PROVIDER } from '@modules/ad/ad.di-tokens'; +import { DefaultParamsProviderPort } from '@modules/ad/core/application/ports/default-params-provider.port'; import { MatchQuery } from '@modules/ad/core/application/queries/match/match.query'; import { MatchQueryHandler } from '@modules/ad/core/application/queries/match/match.query-handler'; import { AlgorithmType } from '@modules/ad/core/application/types/algorithm.types'; import { Waypoint } from '@modules/ad/core/application/types/waypoint.type'; -import { Frequency } from '@modules/ad/core/domain/ad.types'; +import { Frequency, Role } from '@modules/ad/core/domain/ad.types'; import { MatchEntity } from '@modules/ad/core/domain/match.entity'; import { Test, TestingModule } from '@nestjs/testing'; @@ -27,7 +28,36 @@ const destinationWaypoint: Waypoint = { }; const mockAdRepository = { - getCandidates: jest.fn(), + getCandidates: jest.fn().mockImplementation(() => [ + { + ad: { + id: 'cc260669-1c6d-441f-80a5-19cd59afb777', + }, + role: Role.DRIVER, + }, + ]), +}; + +const mockDefaultParamsProvider: DefaultParamsProviderPort = { + getParams: () => { + return { + DEPARTURE_TIME_MARGIN: 900, + DRIVER: false, + SEATS_PROPOSED: 3, + PASSENGER: true, + SEATS_REQUESTED: 1, + STRICT: false, + TIMEZONE: 'Europe/Paris', + ALGORITHM_TYPE: AlgorithmType.PASSENGER_ORIENTED, + REMOTENESS: 15000, + USE_PROPORTION: true, + PROPORTION: 0.3, + USE_AZIMUTH: true, + AZIMUTH_MARGIN: 10, + MAX_DETOUR_DISTANCE_RATIO: 0.3, + MAX_DETOUR_DURATION_RATIO: 0.3, + }; + }, }; describe('Match Query Handler', () => { @@ -41,6 +71,10 @@ describe('Match Query Handler', () => { provide: AD_REPOSITORY, useValue: mockAdRepository, }, + { + provide: PARAMS_PROVIDER, + useValue: mockDefaultParamsProvider, + }, ], }).compile(); diff --git a/src/modules/ad/tests/unit/core/passenger-oriented-algorithm.spec.ts b/src/modules/ad/tests/unit/core/passenger-oriented-algorithm.spec.ts index 4aae63c..cc35ac0 100644 --- a/src/modules/ad/tests/unit/core/passenger-oriented-algorithm.spec.ts +++ b/src/modules/ad/tests/unit/core/passenger-oriented-algorithm.spec.ts @@ -3,7 +3,7 @@ import { MatchQuery } from '@modules/ad/core/application/queries/match/match.que import { PassengerOrientedAlgorithm } from '@modules/ad/core/application/queries/match/passenger-oriented-algorithm'; import { AlgorithmType } from '@modules/ad/core/application/types/algorithm.types'; import { Waypoint } from '@modules/ad/core/application/types/waypoint.type'; -import { Frequency } from '@modules/ad/core/domain/ad.types'; +import { Frequency, Role } from '@modules/ad/core/domain/ad.types'; import { MatchEntity } from '@modules/ad/core/domain/match.entity'; const originWaypoint: Waypoint = { @@ -52,7 +52,14 @@ const mockMatcherRepository: AdRepositoryPort = { count: jest.fn(), healthCheck: jest.fn(), queryRawUnsafe: jest.fn(), - getCandidates: jest.fn(), + getCandidates: jest.fn().mockImplementation(() => [ + { + ad: { + id: 'cc260669-1c6d-441f-80a5-19cd59afb777', + }, + role: Role.DRIVER, + }, + ]), }; describe('Passenger oriented algorithm', () => { diff --git a/src/modules/ad/tests/unit/infrastructure/default-param.provider.spec.ts b/src/modules/ad/tests/unit/infrastructure/default-param.provider.spec.ts index 5d017e5..cfc0b1f 100644 --- a/src/modules/ad/tests/unit/infrastructure/default-param.provider.spec.ts +++ b/src/modules/ad/tests/unit/infrastructure/default-param.provider.spec.ts @@ -16,8 +16,24 @@ const mockConfigService = { return 1; case 'STRICT_FREQUENCY': return 'false'; - case 'DEFAULT_TIMEZONE': + case 'TIMEZONE': return 'Europe/Paris'; + case 'ALGORITHM_TYPE': + return 'PASSENGER_ORIENTED'; + case 'REMOTENESS': + return 15000; + case 'USE_PROPORTION': + return 'true'; + case 'PROPORTION': + return 0.3; + case 'USE_AZIMUTH': + return 'true'; + case 'AZIMUTH_MARGIN': + return 10; + case 'MAX_DETOUR_DISTANCE_RATIO': + return 0.3; + case 'MAX_DETOUR_DURATION_RATIO': + return 0.3; default: return 'some_default_value'; } @@ -53,6 +69,14 @@ describe('DefaultParamsProvider', () => { expect(params.DEPARTURE_TIME_MARGIN).toBe(900); expect(params.PASSENGER).toBeTruthy(); expect(params.DRIVER).toBeFalsy(); - expect(params.DEFAULT_TIMEZONE).toBe('Europe/Paris'); + expect(params.TIMEZONE).toBe('Europe/Paris'); + expect(params.ALGORITHM_TYPE).toBe('PASSENGER_ORIENTED'); + expect(params.REMOTENESS).toBe(15000); + expect(params.USE_PROPORTION).toBeTruthy(); + expect(params.PROPORTION).toBe(0.3); + expect(params.USE_AZIMUTH).toBeTruthy(); + expect(params.AZIMUTH_MARGIN).toBe(10); + expect(params.MAX_DETOUR_DISTANCE_RATIO).toBe(0.3); + expect(params.MAX_DETOUR_DURATION_RATIO).toBe(0.3); }); }); diff --git a/src/modules/ad/tests/unit/infrastructure/input-datetime-transformer.spec.ts b/src/modules/ad/tests/unit/infrastructure/input-datetime-transformer.spec.ts index 11733a0..bc4bce3 100644 --- a/src/modules/ad/tests/unit/infrastructure/input-datetime-transformer.spec.ts +++ b/src/modules/ad/tests/unit/infrastructure/input-datetime-transformer.spec.ts @@ -7,6 +7,7 @@ import { Frequency } from '@modules/ad/core/application/ports/datetime-transform import { DefaultParamsProviderPort } from '@modules/ad/core/application/ports/default-params-provider.port'; import { TimeConverterPort } from '@modules/ad/core/application/ports/time-converter.port'; import { TimezoneFinderPort } from '@modules/ad/core/application/ports/timezone-finder.port'; +import { AlgorithmType } from '@modules/ad/core/application/types/algorithm.types'; import { InputDateTimeTransformer } from '@modules/ad/infrastructure/input-datetime-transformer'; import { Test, TestingModule } from '@nestjs/testing'; @@ -19,7 +20,15 @@ const mockDefaultParamsProvider: DefaultParamsProviderPort = { PASSENGER: true, SEATS_REQUESTED: 1, STRICT: false, - DEFAULT_TIMEZONE: 'Europe/Paris', + TIMEZONE: 'Europe/Paris', + ALGORITHM_TYPE: AlgorithmType.PASSENGER_ORIENTED, + REMOTENESS: 15000, + USE_PROPORTION: true, + PROPORTION: 0.3, + USE_AZIMUTH: true, + AZIMUTH_MARGIN: 10, + MAX_DETOUR_DISTANCE_RATIO: 0.3, + MAX_DETOUR_DURATION_RATIO: 0.3, }; }, };