add default params, time transformer
This commit is contained in:
		
							parent
							
								
									336ffe2cf5
								
							
						
					
					
						commit
						cde1760099
					
				| 
						 | 
					@ -1,23 +1,8 @@
 | 
				
			||||||
import { ExtendedRepositoryPort } from '@mobicoop/ddd-library';
 | 
					import { ExtendedRepositoryPort } from '@mobicoop/ddd-library';
 | 
				
			||||||
import { AdEntity } from '../../domain/ad.entity';
 | 
					import { AdEntity } from '../../domain/ad.entity';
 | 
				
			||||||
import { AlgorithmType, Candidate } from '../types/algorithm.types';
 | 
					import { Candidate } from '../types/algorithm.types';
 | 
				
			||||||
import { Frequency } from '../../domain/ad.types';
 | 
					import { MatchQuery } from '../queries/match/match.query';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type AdRepositoryPort = ExtendedRepositoryPort<AdEntity> & {
 | 
					export type AdRepositoryPort = ExtendedRepositoryPort<AdEntity> & {
 | 
				
			||||||
  getCandidates(query: CandidateQuery): Promise<Candidate[]>;
 | 
					  getCandidates(query: MatchQuery): Promise<Candidate[]>;
 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export type CandidateQuery = {
 | 
					 | 
				
			||||||
  driver: boolean;
 | 
					 | 
				
			||||||
  passenger: boolean;
 | 
					 | 
				
			||||||
  strict: boolean;
 | 
					 | 
				
			||||||
  frequency: Frequency;
 | 
					 | 
				
			||||||
  fromDate: string;
 | 
					 | 
				
			||||||
  toDate: string;
 | 
					 | 
				
			||||||
  schedule: {
 | 
					 | 
				
			||||||
    day?: number;
 | 
					 | 
				
			||||||
    time: string;
 | 
					 | 
				
			||||||
    margin?: number;
 | 
					 | 
				
			||||||
  }[];
 | 
					 | 
				
			||||||
  algorithmType: AlgorithmType;
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,3 +1,5 @@
 | 
				
			||||||
 | 
					import { AlgorithmType } from '../types/algorithm.types';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type DefaultParams = {
 | 
					export type DefaultParams = {
 | 
				
			||||||
  DRIVER: boolean;
 | 
					  DRIVER: boolean;
 | 
				
			||||||
  PASSENGER: boolean;
 | 
					  PASSENGER: boolean;
 | 
				
			||||||
| 
						 | 
					@ -5,5 +7,13 @@ export type DefaultParams = {
 | 
				
			||||||
  SEATS_REQUESTED: number;
 | 
					  SEATS_REQUESTED: number;
 | 
				
			||||||
  DEPARTURE_TIME_MARGIN: number;
 | 
					  DEPARTURE_TIME_MARGIN: number;
 | 
				
			||||||
  STRICT: boolean;
 | 
					  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;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,15 +5,44 @@ import { PassengerOrientedAlgorithm } from './passenger-oriented-algorithm';
 | 
				
			||||||
import { AlgorithmType } from '../../types/algorithm.types';
 | 
					import { AlgorithmType } from '../../types/algorithm.types';
 | 
				
			||||||
import { Inject } from '@nestjs/common';
 | 
					import { Inject } from '@nestjs/common';
 | 
				
			||||||
import { AdRepositoryPort } from '@modules/ad/core/application/ports/ad.repository.port';
 | 
					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 { 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)
 | 
					@QueryHandler(MatchQuery)
 | 
				
			||||||
export class MatchQueryHandler implements IQueryHandler {
 | 
					export class MatchQueryHandler implements IQueryHandler {
 | 
				
			||||||
 | 
					  private readonly _defaultParams: DefaultParams;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  constructor(
 | 
					  constructor(
 | 
				
			||||||
 | 
					    @Inject(PARAMS_PROVIDER)
 | 
				
			||||||
 | 
					    private readonly defaultParamsProvider: DefaultParamsProviderPort,
 | 
				
			||||||
    @Inject(AD_REPOSITORY) private readonly repository: AdRepositoryPort,
 | 
					    @Inject(AD_REPOSITORY) private readonly repository: AdRepositoryPort,
 | 
				
			||||||
  ) {}
 | 
					  ) {
 | 
				
			||||||
 | 
					    this._defaultParams = defaultParamsProvider.getParams();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  execute = async (query: MatchQuery): Promise<MatchEntity[]> => {
 | 
					  execute = async (query: MatchQuery): Promise<MatchEntity[]> => {
 | 
				
			||||||
 | 
					    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;
 | 
					    let algorithm: Algorithm;
 | 
				
			||||||
    switch (query.algorithmType) {
 | 
					    switch (query.algorithmType) {
 | 
				
			||||||
      case AlgorithmType.PASSENGER_ORIENTED:
 | 
					      case AlgorithmType.PASSENGER_ORIENTED:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,21 +1,32 @@
 | 
				
			||||||
import { QueryBase } from '@mobicoop/ddd-library';
 | 
					import { QueryBase } from '@mobicoop/ddd-library';
 | 
				
			||||||
import { AlgorithmType } from '../../types/algorithm.types';
 | 
					import { AlgorithmType } from '../../types/algorithm.types';
 | 
				
			||||||
import { Waypoint } from '../../types/waypoint.type';
 | 
					import { Waypoint } from '../../types/waypoint.type';
 | 
				
			||||||
import { ScheduleItem } from '../../types/schedule-item.type';
 | 
					 | 
				
			||||||
import { Frequency } from '@modules/ad/core/domain/ad.types';
 | 
					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 {
 | 
					export class MatchQuery extends QueryBase {
 | 
				
			||||||
  readonly driver: boolean;
 | 
					  driver?: boolean;
 | 
				
			||||||
  readonly passenger: boolean;
 | 
					  passenger?: boolean;
 | 
				
			||||||
  readonly frequency: Frequency;
 | 
					  readonly frequency: Frequency;
 | 
				
			||||||
  readonly fromDate: string;
 | 
					  readonly fromDate: string;
 | 
				
			||||||
  readonly toDate: string;
 | 
					  readonly toDate: string;
 | 
				
			||||||
  readonly schedule: ScheduleItem[];
 | 
					  schedule: ScheduleItem[];
 | 
				
			||||||
  readonly strict: boolean;
 | 
					  seatsProposed?: number;
 | 
				
			||||||
 | 
					  seatsRequested?: number;
 | 
				
			||||||
 | 
					  strict?: boolean;
 | 
				
			||||||
  readonly waypoints: Waypoint[];
 | 
					  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();
 | 
					    super();
 | 
				
			||||||
    this.driver = props.driver;
 | 
					    this.driver = props.driver;
 | 
				
			||||||
    this.passenger = props.passenger;
 | 
					    this.passenger = props.passenger;
 | 
				
			||||||
| 
						 | 
					@ -23,8 +34,98 @@ export class MatchQuery extends QueryBase {
 | 
				
			||||||
    this.fromDate = props.fromDate;
 | 
					    this.fromDate = props.fromDate;
 | 
				
			||||||
    this.toDate = props.toDate;
 | 
					    this.toDate = props.toDate;
 | 
				
			||||||
    this.schedule = props.schedule;
 | 
					    this.schedule = props.schedule;
 | 
				
			||||||
 | 
					    this.seatsProposed = props.seatsProposed;
 | 
				
			||||||
 | 
					    this.seatsRequested = props.seatsRequested;
 | 
				
			||||||
    this.strict = props.strict;
 | 
					    this.strict = props.strict;
 | 
				
			||||||
    this.waypoints = props.waypoints;
 | 
					    this.waypoints = props.waypoints;
 | 
				
			||||||
    this.algorithmType = props.algorithmType;
 | 
					    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;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,5 @@
 | 
				
			||||||
export type ScheduleItem = {
 | 
					export type ScheduleItem = {
 | 
				
			||||||
  day?: number;
 | 
					  day: number;
 | 
				
			||||||
  time: string;
 | 
					  time: string;
 | 
				
			||||||
  margin?: number;
 | 
					  margin: number;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,3 +1,5 @@
 | 
				
			||||||
 | 
					import { AlgorithmType } from '../application/types/algorithm.types';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// All properties that a Match has
 | 
					// All properties that a Match has
 | 
				
			||||||
export interface MatchProps {
 | 
					export interface MatchProps {
 | 
				
			||||||
  adId: string;
 | 
					  adId: string;
 | 
				
			||||||
| 
						 | 
					@ -7,3 +9,20 @@ export interface MatchProps {
 | 
				
			||||||
export interface CreateMatchProps {
 | 
					export interface CreateMatchProps {
 | 
				
			||||||
  adId: string;
 | 
					  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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,13 +10,13 @@ import {
 | 
				
			||||||
 * */
 | 
					 * */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface ScheduleItemProps {
 | 
					export interface ScheduleItemProps {
 | 
				
			||||||
  day?: number;
 | 
					  day: number;
 | 
				
			||||||
  time: string;
 | 
					  time: string;
 | 
				
			||||||
  margin?: number;
 | 
					  margin: number;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export class ScheduleItem extends ValueObject<ScheduleItemProps> {
 | 
					export class ScheduleItem extends ValueObject<ScheduleItemProps> {
 | 
				
			||||||
  get day(): number | undefined {
 | 
					  get day(): number {
 | 
				
			||||||
    return this.props.day;
 | 
					    return this.props.day;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,13 +24,13 @@ export class ScheduleItem extends ValueObject<ScheduleItemProps> {
 | 
				
			||||||
    return this.props.time;
 | 
					    return this.props.time;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  get margin(): number | undefined {
 | 
					  get margin(): number {
 | 
				
			||||||
    return this.props.margin;
 | 
					    return this.props.margin;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
 | 
					  // eslint-disable-next-line @typescript-eslint/no-unused-vars
 | 
				
			||||||
  protected validate(props: ScheduleItemProps): void {
 | 
					  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');
 | 
					      throw new ArgumentOutOfRangeException('day must be between 0 and 6');
 | 
				
			||||||
    if (props.time.split(':').length != 2)
 | 
					    if (props.time.split(':').length != 2)
 | 
				
			||||||
      throw new ArgumentInvalidException('time is invalid');
 | 
					      throw new ArgumentInvalidException('time is invalid');
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,9 +1,6 @@
 | 
				
			||||||
import { Inject, Injectable, Logger } from '@nestjs/common';
 | 
					import { Inject, Injectable, Logger } from '@nestjs/common';
 | 
				
			||||||
import { EventEmitter2 } from '@nestjs/event-emitter';
 | 
					import { EventEmitter2 } from '@nestjs/event-emitter';
 | 
				
			||||||
import {
 | 
					import { AdRepositoryPort } from '../core/application/ports/ad.repository.port';
 | 
				
			||||||
  AdRepositoryPort,
 | 
					 | 
				
			||||||
  CandidateQuery,
 | 
					 | 
				
			||||||
} from '../core/application/ports/ad.repository.port';
 | 
					 | 
				
			||||||
import { LoggerBase, MessagePublisherPort } from '@mobicoop/ddd-library';
 | 
					import { LoggerBase, MessagePublisherPort } from '@mobicoop/ddd-library';
 | 
				
			||||||
import { PrismaService } from './prisma.service';
 | 
					import { PrismaService } from './prisma.service';
 | 
				
			||||||
import { AD_MESSAGE_PUBLISHER } from '../ad.di-tokens';
 | 
					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 { Frequency, Role } from '../core/domain/ad.types';
 | 
				
			||||||
import { Candidate } from '../core/application/types/algorithm.types';
 | 
					import { Candidate } from '../core/application/types/algorithm.types';
 | 
				
			||||||
import { AdSelector } from './ad.selector';
 | 
					import { AdSelector } from './ad.selector';
 | 
				
			||||||
 | 
					import { MatchQuery } from '../core/application/queries/match/match.query';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type AdBaseModel = {
 | 
					export type AdBaseModel = {
 | 
				
			||||||
  uuid: string;
 | 
					  uuid: string;
 | 
				
			||||||
| 
						 | 
					@ -93,7 +91,7 @@ export class AdRepository
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  getCandidates = async (query: CandidateQuery): Promise<Candidate[]> => {
 | 
					  getCandidates = async (query: MatchQuery): Promise<Candidate[]> => {
 | 
				
			||||||
    // let candidates: Candidate[] = [];
 | 
					    // let candidates: Candidate[] = [];
 | 
				
			||||||
    const sqlQueries: QueryRole[] = [];
 | 
					    const sqlQueries: QueryRole[] = [];
 | 
				
			||||||
    if (query.driver)
 | 
					    if (query.driver)
 | 
				
			||||||
| 
						 | 
					@ -115,7 +113,7 @@ export class AdRepository
 | 
				
			||||||
          } as AdsRole),
 | 
					          } as AdsRole),
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
    console.log(results[0].ads);
 | 
					    // console.log(results[0].ads);
 | 
				
			||||||
    return [];
 | 
					    return [];
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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 { AlgorithmType } from '../core/application/types/algorithm.types';
 | 
				
			||||||
import { Role } from '../core/domain/ad.types';
 | 
					import { Role } from '../core/domain/ad.types';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export class AdSelector {
 | 
					export class AdSelector {
 | 
				
			||||||
  static select = (role: Role, query: CandidateQuery): string => {
 | 
					  static select = (role: Role, query: MatchQuery): string => {
 | 
				
			||||||
    switch (query.algorithmType) {
 | 
					    switch (query.algorithmType) {
 | 
				
			||||||
      case AlgorithmType.PASSENGER_ORIENTED:
 | 
					      case AlgorithmType.PASSENGER_ORIENTED:
 | 
				
			||||||
      default:
 | 
					      default:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,32 +2,84 @@ import { Injectable } from '@nestjs/common';
 | 
				
			||||||
import { ConfigService } from '@nestjs/config';
 | 
					import { ConfigService } from '@nestjs/config';
 | 
				
			||||||
import { DefaultParamsProviderPort } from '../core/application/ports/default-params-provider.port';
 | 
					import { DefaultParamsProviderPort } from '../core/application/ports/default-params-provider.port';
 | 
				
			||||||
import { DefaultParams } from '../core/application/ports/default-params.type';
 | 
					import { DefaultParams } from '../core/application/ports/default-params.type';
 | 
				
			||||||
 | 
					import { AlgorithmType } from '../core/application/types/algorithm.types';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const DEFAULT_SEATS_PROPOSED = 3;
 | 
					const DRIVER = false;
 | 
				
			||||||
const DEFAULT_SEATS_REQUESTED = 1;
 | 
					const PASSENGER = true;
 | 
				
			||||||
const DEFAULT_DEPARTURE_TIME_MARGIN = 900;
 | 
					const SEATS_PROPOSED = 3;
 | 
				
			||||||
const DEFAULT_TIMEZONE = 'Europe/Paris';
 | 
					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()
 | 
					@Injectable()
 | 
				
			||||||
export class DefaultParamsProvider implements DefaultParamsProviderPort {
 | 
					export class DefaultParamsProvider implements DefaultParamsProviderPort {
 | 
				
			||||||
  constructor(private readonly _configService: ConfigService) {}
 | 
					  constructor(private readonly _configService: ConfigService) {}
 | 
				
			||||||
  getParams = (): DefaultParams => ({
 | 
					  getParams = (): DefaultParams => ({
 | 
				
			||||||
    DRIVER: this._configService.get('ROLE') == 'driver',
 | 
					    DRIVER:
 | 
				
			||||||
 | 
					      this._configService.get('ROLE') !== undefined
 | 
				
			||||||
 | 
					        ? this._configService.get('ROLE') == 'driver'
 | 
				
			||||||
 | 
					        : DRIVER,
 | 
				
			||||||
    SEATS_PROPOSED:
 | 
					    SEATS_PROPOSED:
 | 
				
			||||||
      this._configService.get('SEATS_PROPOSED') !== undefined
 | 
					      this._configService.get('SEATS_PROPOSED') !== undefined
 | 
				
			||||||
        ? parseInt(this._configService.get('SEATS_PROPOSED') as string)
 | 
					        ? parseInt(this._configService.get('SEATS_PROPOSED') as string)
 | 
				
			||||||
        : DEFAULT_SEATS_PROPOSED,
 | 
					        : SEATS_PROPOSED,
 | 
				
			||||||
    PASSENGER: this._configService.get('ROLE') == 'passenger',
 | 
					    PASSENGER:
 | 
				
			||||||
 | 
					      this._configService.get('ROLE') !== undefined
 | 
				
			||||||
 | 
					        ? this._configService.get('ROLE') == 'passenger'
 | 
				
			||||||
 | 
					        : PASSENGER,
 | 
				
			||||||
    SEATS_REQUESTED:
 | 
					    SEATS_REQUESTED:
 | 
				
			||||||
      this._configService.get('SEATS_REQUESTED') !== undefined
 | 
					      this._configService.get('SEATS_REQUESTED') !== undefined
 | 
				
			||||||
        ? parseInt(this._configService.get('SEATS_REQUESTED') as string)
 | 
					        ? parseInt(this._configService.get('SEATS_REQUESTED') as string)
 | 
				
			||||||
        : DEFAULT_SEATS_REQUESTED,
 | 
					        : SEATS_REQUESTED,
 | 
				
			||||||
    DEPARTURE_TIME_MARGIN:
 | 
					    DEPARTURE_TIME_MARGIN:
 | 
				
			||||||
      this._configService.get('DEPARTURE_TIME_MARGIN') !== undefined
 | 
					      this._configService.get('DEPARTURE_TIME_MARGIN') !== undefined
 | 
				
			||||||
        ? parseInt(this._configService.get('DEPARTURE_TIME_MARGIN') as string)
 | 
					        ? parseInt(this._configService.get('DEPARTURE_TIME_MARGIN') as string)
 | 
				
			||||||
        : DEFAULT_DEPARTURE_TIME_MARGIN,
 | 
					        : DEPARTURE_TIME_MARGIN,
 | 
				
			||||||
    STRICT: this._configService.get('STRICT_FREQUENCY') == 'true',
 | 
					    STRICT: this._configService.get('STRICT_FREQUENCY') == 'true',
 | 
				
			||||||
    DEFAULT_TIMEZONE:
 | 
					    TIMEZONE: this._configService.get('TIMEZONE') ?? TIMEZONE,
 | 
				
			||||||
      this._configService.get('DEFAULT_TIMEZONE') ?? DEFAULT_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,
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,7 +23,7 @@ export class InputDateTimeTransformer implements DateTimeTransformerPort {
 | 
				
			||||||
    private readonly timezoneFinder: TimezoneFinderPort,
 | 
					    private readonly timezoneFinder: TimezoneFinderPort,
 | 
				
			||||||
    @Inject(TIME_CONVERTER) private readonly timeConverter: TimeConverterPort,
 | 
					    @Inject(TIME_CONVERTER) private readonly timeConverter: TimeConverterPort,
 | 
				
			||||||
  ) {
 | 
					  ) {
 | 
				
			||||||
    this._defaultTimezone = defaultParamsProvider.getParams().DEFAULT_TIMEZONE;
 | 
					    this._defaultTimezone = defaultParamsProvider.getParams().TIMEZONE;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,10 +2,13 @@ import {
 | 
				
			||||||
  ArrayMinSize,
 | 
					  ArrayMinSize,
 | 
				
			||||||
  IsArray,
 | 
					  IsArray,
 | 
				
			||||||
  IsBoolean,
 | 
					  IsBoolean,
 | 
				
			||||||
 | 
					  IsDecimal,
 | 
				
			||||||
  IsEnum,
 | 
					  IsEnum,
 | 
				
			||||||
  IsISO8601,
 | 
					  IsISO8601,
 | 
				
			||||||
  IsInt,
 | 
					  IsInt,
 | 
				
			||||||
  IsOptional,
 | 
					  IsOptional,
 | 
				
			||||||
 | 
					  Max,
 | 
				
			||||||
 | 
					  Min,
 | 
				
			||||||
  ValidateNested,
 | 
					  ValidateNested,
 | 
				
			||||||
} from 'class-validator';
 | 
					} from 'class-validator';
 | 
				
			||||||
import { Type } from 'class-transformer';
 | 
					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';
 | 
					import { AlgorithmType } from '@modules/ad/core/application/types/algorithm.types';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export class MatchRequestDto {
 | 
					export class MatchRequestDto {
 | 
				
			||||||
  // @IsOptional()
 | 
					  @IsOptional()
 | 
				
			||||||
  @IsBoolean()
 | 
					  @IsBoolean()
 | 
				
			||||||
  driver: boolean;
 | 
					  driver?: boolean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // @IsOptional()
 | 
					  @IsOptional()
 | 
				
			||||||
  @IsBoolean()
 | 
					  @IsBoolean()
 | 
				
			||||||
  passenger: boolean;
 | 
					  passenger?: boolean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @IsEnum(Frequency)
 | 
					  @IsEnum(Frequency)
 | 
				
			||||||
  @HasDay('schedule', {
 | 
					  @HasDay('schedule', {
 | 
				
			||||||
| 
						 | 
					@ -53,17 +56,17 @@ export class MatchRequestDto {
 | 
				
			||||||
  @ValidateNested({ each: true })
 | 
					  @ValidateNested({ each: true })
 | 
				
			||||||
  schedule: ScheduleItemDto[];
 | 
					  schedule: ScheduleItemDto[];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // @IsOptional()
 | 
					  @IsOptional()
 | 
				
			||||||
  // @IsInt()
 | 
					  @IsInt()
 | 
				
			||||||
  // seatsProposed?: number;
 | 
					  seatsProposed?: number;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // @IsOptional()
 | 
					  @IsOptional()
 | 
				
			||||||
  // @IsInt()
 | 
					  @IsInt()
 | 
				
			||||||
  // seatsRequested?: number;
 | 
					  seatsRequested?: number;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // @IsOptional()
 | 
					  @IsOptional()
 | 
				
			||||||
  @IsBoolean()
 | 
					  @IsBoolean()
 | 
				
			||||||
  strict: boolean;
 | 
					  strict?: boolean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @Type(() => WaypointDto)
 | 
					  @Type(() => WaypointDto)
 | 
				
			||||||
  @IsArray()
 | 
					  @IsArray()
 | 
				
			||||||
| 
						 | 
					@ -72,45 +75,45 @@ export class MatchRequestDto {
 | 
				
			||||||
  @ValidateNested({ each: true })
 | 
					  @ValidateNested({ each: true })
 | 
				
			||||||
  waypoints: WaypointDto[];
 | 
					  waypoints: WaypointDto[];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // @IsOptional()
 | 
					  @IsOptional()
 | 
				
			||||||
  @IsEnum(AlgorithmType)
 | 
					  @IsEnum(AlgorithmType)
 | 
				
			||||||
  algorithmType: AlgorithmType;
 | 
					  algorithmType?: AlgorithmType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // @IsOptional()
 | 
					  @IsOptional()
 | 
				
			||||||
  // @IsInt()
 | 
					  @IsInt()
 | 
				
			||||||
  // remoteness?: number;
 | 
					  remoteness?: number;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // @IsOptional()
 | 
					  @IsOptional()
 | 
				
			||||||
  // @IsBoolean()
 | 
					  @IsBoolean()
 | 
				
			||||||
  // useProportion?: boolean;
 | 
					  useProportion?: boolean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // @IsOptional()
 | 
					  @IsOptional()
 | 
				
			||||||
  // @IsDecimal()
 | 
					  @IsDecimal()
 | 
				
			||||||
  // @Min(0)
 | 
					  @Min(0)
 | 
				
			||||||
  // @Max(1)
 | 
					  @Max(1)
 | 
				
			||||||
  // proportion?: number;
 | 
					  proportion?: number;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // @IsOptional()
 | 
					  @IsOptional()
 | 
				
			||||||
  // @IsBoolean()
 | 
					  @IsBoolean()
 | 
				
			||||||
  // useAzimuth?: boolean;
 | 
					  useAzimuth?: boolean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // @IsOptional()
 | 
					  @IsOptional()
 | 
				
			||||||
  // @IsInt()
 | 
					  @IsInt()
 | 
				
			||||||
  // @Min(0)
 | 
					  @Min(0)
 | 
				
			||||||
  // @Max(359)
 | 
					  @Max(359)
 | 
				
			||||||
  // azimuthMargin?: number;
 | 
					  azimuthMargin?: number;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // @IsOptional()
 | 
					  @IsOptional()
 | 
				
			||||||
  // @IsDecimal()
 | 
					  @IsDecimal()
 | 
				
			||||||
  // @Min(0)
 | 
					  @Min(0)
 | 
				
			||||||
  // @Max(1)
 | 
					  @Max(1)
 | 
				
			||||||
  // maxDetourDistanceRatio?: number;
 | 
					  maxDetourDistanceRatio?: number;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // @IsOptional()
 | 
					  @IsOptional()
 | 
				
			||||||
  // @IsDecimal()
 | 
					  @IsDecimal()
 | 
				
			||||||
  // @Min(0)
 | 
					  @Min(0)
 | 
				
			||||||
  // @Max(1)
 | 
					  @Max(1)
 | 
				
			||||||
  // maxDetourDurationRatio?: number;
 | 
					  maxDetourDurationRatio?: number;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @IsOptional()
 | 
					  @IsOptional()
 | 
				
			||||||
  @IsInt()
 | 
					  @IsInt()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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 { MatchQuery } from '@modules/ad/core/application/queries/match/match.query';
 | 
				
			||||||
import { MatchQueryHandler } from '@modules/ad/core/application/queries/match/match.query-handler';
 | 
					import { MatchQueryHandler } from '@modules/ad/core/application/queries/match/match.query-handler';
 | 
				
			||||||
import { AlgorithmType } from '@modules/ad/core/application/types/algorithm.types';
 | 
					import { AlgorithmType } from '@modules/ad/core/application/types/algorithm.types';
 | 
				
			||||||
import { Waypoint } from '@modules/ad/core/application/types/waypoint.type';
 | 
					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 { MatchEntity } from '@modules/ad/core/domain/match.entity';
 | 
				
			||||||
import { Test, TestingModule } from '@nestjs/testing';
 | 
					import { Test, TestingModule } from '@nestjs/testing';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,7 +28,36 @@ const destinationWaypoint: Waypoint = {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const mockAdRepository = {
 | 
					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', () => {
 | 
					describe('Match Query Handler', () => {
 | 
				
			||||||
| 
						 | 
					@ -41,6 +71,10 @@ describe('Match Query Handler', () => {
 | 
				
			||||||
          provide: AD_REPOSITORY,
 | 
					          provide: AD_REPOSITORY,
 | 
				
			||||||
          useValue: mockAdRepository,
 | 
					          useValue: mockAdRepository,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          provide: PARAMS_PROVIDER,
 | 
				
			||||||
 | 
					          useValue: mockDefaultParamsProvider,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
      ],
 | 
					      ],
 | 
				
			||||||
    }).compile();
 | 
					    }).compile();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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 { PassengerOrientedAlgorithm } from '@modules/ad/core/application/queries/match/passenger-oriented-algorithm';
 | 
				
			||||||
import { AlgorithmType } from '@modules/ad/core/application/types/algorithm.types';
 | 
					import { AlgorithmType } from '@modules/ad/core/application/types/algorithm.types';
 | 
				
			||||||
import { Waypoint } from '@modules/ad/core/application/types/waypoint.type';
 | 
					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 { MatchEntity } from '@modules/ad/core/domain/match.entity';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const originWaypoint: Waypoint = {
 | 
					const originWaypoint: Waypoint = {
 | 
				
			||||||
| 
						 | 
					@ -52,7 +52,14 @@ const mockMatcherRepository: AdRepositoryPort = {
 | 
				
			||||||
  count: jest.fn(),
 | 
					  count: jest.fn(),
 | 
				
			||||||
  healthCheck: jest.fn(),
 | 
					  healthCheck: jest.fn(),
 | 
				
			||||||
  queryRawUnsafe: 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', () => {
 | 
					describe('Passenger oriented algorithm', () => {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,8 +16,24 @@ const mockConfigService = {
 | 
				
			||||||
        return 1;
 | 
					        return 1;
 | 
				
			||||||
      case 'STRICT_FREQUENCY':
 | 
					      case 'STRICT_FREQUENCY':
 | 
				
			||||||
        return 'false';
 | 
					        return 'false';
 | 
				
			||||||
      case 'DEFAULT_TIMEZONE':
 | 
					      case 'TIMEZONE':
 | 
				
			||||||
        return 'Europe/Paris';
 | 
					        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:
 | 
					      default:
 | 
				
			||||||
        return 'some_default_value';
 | 
					        return 'some_default_value';
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -53,6 +69,14 @@ describe('DefaultParamsProvider', () => {
 | 
				
			||||||
    expect(params.DEPARTURE_TIME_MARGIN).toBe(900);
 | 
					    expect(params.DEPARTURE_TIME_MARGIN).toBe(900);
 | 
				
			||||||
    expect(params.PASSENGER).toBeTruthy();
 | 
					    expect(params.PASSENGER).toBeTruthy();
 | 
				
			||||||
    expect(params.DRIVER).toBeFalsy();
 | 
					    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);
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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 { DefaultParamsProviderPort } from '@modules/ad/core/application/ports/default-params-provider.port';
 | 
				
			||||||
import { TimeConverterPort } from '@modules/ad/core/application/ports/time-converter.port';
 | 
					import { TimeConverterPort } from '@modules/ad/core/application/ports/time-converter.port';
 | 
				
			||||||
import { TimezoneFinderPort } from '@modules/ad/core/application/ports/timezone-finder.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 { InputDateTimeTransformer } from '@modules/ad/infrastructure/input-datetime-transformer';
 | 
				
			||||||
import { Test, TestingModule } from '@nestjs/testing';
 | 
					import { Test, TestingModule } from '@nestjs/testing';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,7 +20,15 @@ const mockDefaultParamsProvider: DefaultParamsProviderPort = {
 | 
				
			||||||
      PASSENGER: true,
 | 
					      PASSENGER: true,
 | 
				
			||||||
      SEATS_REQUESTED: 1,
 | 
					      SEATS_REQUESTED: 1,
 | 
				
			||||||
      STRICT: false,
 | 
					      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,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue