basic RouteCompleter
This commit is contained in:
		
							parent
							
								
									a277a9547f
								
							
						
					
					
						commit
						067854b697
					
				|  | @ -20,6 +20,7 @@ export abstract class Algorithm { | ||||||
|     for (const processor of this.processors) { |     for (const processor of this.processors) { | ||||||
|       this.candidates = await processor.execute(this.candidates); |       this.candidates = await processor.execute(this.candidates); | ||||||
|     } |     } | ||||||
|  |     // console.log(JSON.stringify(this.candidates, null, 2));
 | ||||||
|     return this.candidates.map((candidate: CandidateEntity) => |     return this.candidates.map((candidate: CandidateEntity) => | ||||||
|       MatchEntity.create({ adId: candidate.id }), |       MatchEntity.create({ adId: candidate.id }), | ||||||
|     ); |     ); | ||||||
|  | @ -43,9 +44,6 @@ export abstract class Selector { | ||||||
|  * A processor processes candidates information |  * A processor processes candidates information | ||||||
|  */ |  */ | ||||||
| export abstract class Processor { | export abstract class Processor { | ||||||
|   protected readonly query: MatchQuery; |   constructor(protected readonly query: MatchQuery) {} | ||||||
|   constructor(query: MatchQuery) { |  | ||||||
|     this.query = query; |  | ||||||
|   } |  | ||||||
|   abstract execute(candidates: CandidateEntity[]): Promise<CandidateEntity[]>; |   abstract execute(candidates: CandidateEntity[]): Promise<CandidateEntity[]>; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -49,7 +49,6 @@ export class PassengerOrientedCarpoolPathCompleter extends Completer { | ||||||
|             ), |             ), | ||||||
|       ); |       ); | ||||||
|       candidate.setCarpoolPath(carpoolPathCreator.carpoolPath()); |       candidate.setCarpoolPath(carpoolPathCreator.carpoolPath()); | ||||||
|       // console.log(JSON.stringify(candidate, null, 2));
 |  | ||||||
|     }); |     }); | ||||||
|     return candidates; |     return candidates; | ||||||
|   }; |   }; | ||||||
|  |  | ||||||
|  | @ -0,0 +1,34 @@ | ||||||
|  | import { CandidateEntity } from '@modules/ad/core/domain/candidate.entity'; | ||||||
|  | import { Completer } from './completer.abstract'; | ||||||
|  | import { MatchQuery } from '../match.query'; | ||||||
|  | import { WayStep } from '@modules/ad/core/domain/value-objects/waystep.value-object'; | ||||||
|  | 
 | ||||||
|  | export class RouteCompleter extends Completer { | ||||||
|  |   protected readonly type: RouteCompleterType; | ||||||
|  |   constructor(query: MatchQuery, type: RouteCompleterType) { | ||||||
|  |     super(query); | ||||||
|  |     this.type = type; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   complete = async ( | ||||||
|  |     candidates: CandidateEntity[], | ||||||
|  |   ): Promise<CandidateEntity[]> => { | ||||||
|  |     await Promise.all( | ||||||
|  |       candidates.map(async (candidate: CandidateEntity) => { | ||||||
|  |         const candidateRoute = await this.query.routeProvider.getBasic( | ||||||
|  |           (candidate.getProps().carpoolSteps as WayStep[]).map( | ||||||
|  |             (wayStep: WayStep) => wayStep.point, | ||||||
|  |           ), | ||||||
|  |         ); | ||||||
|  |         candidate.setMetrics(candidateRoute.distance, candidateRoute.duration); | ||||||
|  |         return candidate; | ||||||
|  |       }), | ||||||
|  |     ); | ||||||
|  |     return candidates; | ||||||
|  |   }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export enum RouteCompleterType { | ||||||
|  |   BASIC = 'basic', | ||||||
|  |   DETAILED = 'detailed', | ||||||
|  | } | ||||||
|  | @ -7,7 +7,6 @@ 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 { | import { | ||||||
|   AD_REPOSITORY, |   AD_REPOSITORY, | ||||||
|   AD_ROUTE_PROVIDER, |  | ||||||
|   INPUT_DATETIME_TRANSFORMER, |   INPUT_DATETIME_TRANSFORMER, | ||||||
|   PARAMS_PROVIDER, |   PARAMS_PROVIDER, | ||||||
| } from '@modules/ad/ad.di-tokens'; | } from '@modules/ad/ad.di-tokens'; | ||||||
|  | @ -15,7 +14,6 @@ import { MatchEntity } from '@modules/ad/core/domain/match.entity'; | ||||||
| import { DefaultParamsProviderPort } from '../../ports/default-params-provider.port'; | import { DefaultParamsProviderPort } from '../../ports/default-params-provider.port'; | ||||||
| import { DefaultParams } from '../../ports/default-params.type'; | import { DefaultParams } from '../../ports/default-params.type'; | ||||||
| import { DateTimeTransformerPort } from '../../ports/datetime-transformer.port'; | import { DateTimeTransformerPort } from '../../ports/datetime-transformer.port'; | ||||||
| import { RouteProviderPort } from '../../ports/route-provider.port'; |  | ||||||
| 
 | 
 | ||||||
| @QueryHandler(MatchQuery) | @QueryHandler(MatchQuery) | ||||||
| export class MatchQueryHandler implements IQueryHandler { | export class MatchQueryHandler implements IQueryHandler { | ||||||
|  | @ -27,8 +25,6 @@ export class MatchQueryHandler implements IQueryHandler { | ||||||
|     @Inject(AD_REPOSITORY) private readonly repository: AdRepositoryPort, |     @Inject(AD_REPOSITORY) private readonly repository: AdRepositoryPort, | ||||||
|     @Inject(INPUT_DATETIME_TRANSFORMER) |     @Inject(INPUT_DATETIME_TRANSFORMER) | ||||||
|     private readonly datetimeTransformer: DateTimeTransformerPort, |     private readonly datetimeTransformer: DateTimeTransformerPort, | ||||||
|     @Inject(AD_ROUTE_PROVIDER) |  | ||||||
|     private readonly routeProvider: RouteProviderPort, |  | ||||||
|   ) { |   ) { | ||||||
|     this._defaultParams = defaultParamsProvider.getParams(); |     this._defaultParams = defaultParamsProvider.getParams(); | ||||||
|   } |   } | ||||||
|  | @ -54,7 +50,7 @@ export class MatchQueryHandler implements IQueryHandler { | ||||||
|         maxDetourDurationRatio: this._defaultParams.MAX_DETOUR_DURATION_RATIO, |         maxDetourDurationRatio: this._defaultParams.MAX_DETOUR_DURATION_RATIO, | ||||||
|       }) |       }) | ||||||
|       .setDatesAndSchedule(this.datetimeTransformer); |       .setDatesAndSchedule(this.datetimeTransformer); | ||||||
|     await query.setRoutes(this.routeProvider); |     await query.setRoutes(); | ||||||
| 
 | 
 | ||||||
|     let algorithm: Algorithm; |     let algorithm: Algorithm; | ||||||
|     switch (query.algorithmType) { |     switch (query.algorithmType) { | ||||||
|  |  | ||||||
|  | @ -39,8 +39,9 @@ export class MatchQuery extends QueryBase { | ||||||
|   passengerRoute?: Route; |   passengerRoute?: Route; | ||||||
|   backAzimuth?: number; |   backAzimuth?: number; | ||||||
|   private readonly originWaypoint: Waypoint; |   private readonly originWaypoint: Waypoint; | ||||||
|  |   routeProvider: RouteProviderPort; | ||||||
| 
 | 
 | ||||||
|   constructor(props: MatchRequestDto) { |   constructor(props: MatchRequestDto, routeProvider: RouteProviderPort) { | ||||||
|     super(); |     super(); | ||||||
|     this.driver = props.driver; |     this.driver = props.driver; | ||||||
|     this.passenger = props.passenger; |     this.passenger = props.passenger; | ||||||
|  | @ -65,6 +66,7 @@ export class MatchQuery extends QueryBase { | ||||||
|     this.originWaypoint = this.waypoints.filter( |     this.originWaypoint = this.waypoints.filter( | ||||||
|       (waypoint: Waypoint) => waypoint.position == 0, |       (waypoint: Waypoint) => waypoint.position == 0, | ||||||
|     )[0]; |     )[0]; | ||||||
|  |     this.routeProvider = routeProvider; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   setMissingMarginDurations = (defaultMarginDuration: number): MatchQuery => { |   setMissingMarginDurations = (defaultMarginDuration: number): MatchQuery => { | ||||||
|  | @ -178,7 +180,7 @@ export class MatchQuery extends QueryBase { | ||||||
|     return this; |     return this; | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   setRoutes = async (routeProvider: RouteProviderPort): Promise<MatchQuery> => { |   setRoutes = async (): Promise<MatchQuery> => { | ||||||
|     const roles: Role[] = []; |     const roles: Role[] = []; | ||||||
|     if (this.driver) roles.push(Role.DRIVER); |     if (this.driver) roles.push(Role.DRIVER); | ||||||
|     if (this.passenger) roles.push(Role.PASSENGER); |     if (this.passenger) roles.push(Role.PASSENGER); | ||||||
|  | @ -197,7 +199,7 @@ export class MatchQuery extends QueryBase { | ||||||
|         await Promise.all( |         await Promise.all( | ||||||
|           pathCreator.getBasePaths().map(async (path: Path) => ({ |           pathCreator.getBasePaths().map(async (path: Path) => ({ | ||||||
|             type: path.type, |             type: path.type, | ||||||
|             route: await routeProvider.getBasic(path.waypoints), |             route: await this.routeProvider.getBasic(path.waypoints), | ||||||
|           })), |           })), | ||||||
|         ) |         ) | ||||||
|       ).forEach((typedRoute: TypedRoute) => { |       ).forEach((typedRoute: TypedRoute) => { | ||||||
|  |  | ||||||
|  | @ -4,6 +4,10 @@ import { PassengerOrientedCarpoolPathCompleter } from './completer/passenger-ori | ||||||
| import { PassengerOrientedGeoFilter } from './filter/passenger-oriented-geo.filter'; | import { PassengerOrientedGeoFilter } from './filter/passenger-oriented-geo.filter'; | ||||||
| import { AdRepositoryPort } from '../../ports/ad.repository.port'; | import { AdRepositoryPort } from '../../ports/ad.repository.port'; | ||||||
| import { PassengerOrientedSelector } from './selector/passenger-oriented.selector'; | import { PassengerOrientedSelector } from './selector/passenger-oriented.selector'; | ||||||
|  | import { | ||||||
|  |   RouteCompleter, | ||||||
|  |   RouteCompleterType, | ||||||
|  | } from './completer/route.completer'; | ||||||
| 
 | 
 | ||||||
| export class PassengerOrientedAlgorithm extends Algorithm { | export class PassengerOrientedAlgorithm extends Algorithm { | ||||||
|   constructor( |   constructor( | ||||||
|  | @ -14,6 +18,7 @@ export class PassengerOrientedAlgorithm extends Algorithm { | ||||||
|     this.selector = new PassengerOrientedSelector(query, repository); |     this.selector = new PassengerOrientedSelector(query, repository); | ||||||
|     this.processors = [ |     this.processors = [ | ||||||
|       new PassengerOrientedCarpoolPathCompleter(query), |       new PassengerOrientedCarpoolPathCompleter(query), | ||||||
|  |       new RouteCompleter(query, RouteCompleterType.BASIC), | ||||||
|       new PassengerOrientedGeoFilter(query), |       new PassengerOrientedGeoFilter(query), | ||||||
|     ]; |     ]; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  | @ -14,6 +14,11 @@ export class CandidateEntity extends AggregateRoot<CandidateProps> { | ||||||
|     this.props.carpoolSteps = waySteps; |     this.props.carpoolSteps = waySteps; | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|  |   setMetrics = (distance: number, duration: number): void => { | ||||||
|  |     this.props.distance = distance; | ||||||
|  |     this.props.duration = duration; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|   validate(): void { |   validate(): void { | ||||||
|     // entity business rules validation to protect it's invariant before saving entity to a database
 |     // entity business rules validation to protect it's invariant before saving entity to a database
 | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  | @ -10,6 +10,8 @@ export interface CandidateProps { | ||||||
|   driverDistance: number; |   driverDistance: number; | ||||||
|   driverDuration: number; |   driverDuration: number; | ||||||
|   carpoolSteps?: WayStepProps[]; // carpool path for the crew (driver + passenger)
 |   carpoolSteps?: WayStepProps[]; // carpool path for the crew (driver + passenger)
 | ||||||
|  |   distance?: number; | ||||||
|  |   duration?: number; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Properties that are needed for a Candidate creation
 | // Properties that are needed for a Candidate creation
 | ||||||
|  | @ -22,11 +24,6 @@ export interface CreateCandidateProps { | ||||||
|   passengerWaypoints: PointProps[]; |   passengerWaypoints: PointProps[]; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export type Spacetime = { |  | ||||||
|   duration: number; |  | ||||||
|   distance?: number; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| export enum Target { | export enum Target { | ||||||
|   START = 'START', |   START = 'START', | ||||||
|   INTERMEDIATE = 'INTERMEDIATE', |   INTERMEDIATE = 'INTERMEDIATE', | ||||||
|  |  | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| import { Controller, UsePipes } from '@nestjs/common'; | import { Controller, Inject, UsePipes } from '@nestjs/common'; | ||||||
| import { GrpcMethod, RpcException } from '@nestjs/microservices'; | import { GrpcMethod, RpcException } from '@nestjs/microservices'; | ||||||
| import { ResponseBase, RpcValidationPipe } from '@mobicoop/ddd-library'; | import { ResponseBase, RpcValidationPipe } from '@mobicoop/ddd-library'; | ||||||
| import { RpcExceptionCode } from '@mobicoop/ddd-library'; | import { RpcExceptionCode } from '@mobicoop/ddd-library'; | ||||||
|  | @ -7,6 +7,8 @@ import { QueryBus } from '@nestjs/cqrs'; | ||||||
| import { MatchRequestDto } from './dtos/match.request.dto'; | import { MatchRequestDto } from './dtos/match.request.dto'; | ||||||
| import { MatchQuery } from '@modules/ad/core/application/queries/match/match.query'; | import { MatchQuery } from '@modules/ad/core/application/queries/match/match.query'; | ||||||
| import { MatchEntity } from '@modules/ad/core/domain/match.entity'; | import { MatchEntity } from '@modules/ad/core/domain/match.entity'; | ||||||
|  | import { AD_ROUTE_PROVIDER } from '@modules/ad/ad.di-tokens'; | ||||||
|  | import { RouteProviderPort } from '@modules/ad/core/application/ports/route-provider.port'; | ||||||
| 
 | 
 | ||||||
| @UsePipes( | @UsePipes( | ||||||
|   new RpcValidationPipe({ |   new RpcValidationPipe({ | ||||||
|  | @ -16,13 +18,17 @@ import { MatchEntity } from '@modules/ad/core/domain/match.entity'; | ||||||
| ) | ) | ||||||
| @Controller() | @Controller() | ||||||
| export class MatchGrpcController { | export class MatchGrpcController { | ||||||
|   constructor(private readonly queryBus: QueryBus) {} |   constructor( | ||||||
|  |     private readonly queryBus: QueryBus, | ||||||
|  |     @Inject(AD_ROUTE_PROVIDER) | ||||||
|  |     private readonly routeProvider: RouteProviderPort, | ||||||
|  |   ) {} | ||||||
| 
 | 
 | ||||||
|   @GrpcMethod('MatcherService', 'Match') |   @GrpcMethod('MatcherService', 'Match') | ||||||
|   async match(data: MatchRequestDto): Promise<MatchPaginatedResponseDto> { |   async match(data: MatchRequestDto): Promise<MatchPaginatedResponseDto> { | ||||||
|     try { |     try { | ||||||
|       const matches: MatchEntity[] = await this.queryBus.execute( |       const matches: MatchEntity[] = await this.queryBus.execute( | ||||||
|         new MatchQuery(data), |         new MatchQuery(data, this.routeProvider), | ||||||
|       ); |       ); | ||||||
|       return new MatchPaginatedResponseDto({ |       return new MatchPaginatedResponseDto({ | ||||||
|         data: matches.map((match: MatchEntity) => ({ |         data: matches.map((match: MatchEntity) => ({ | ||||||
|  |  | ||||||
|  | @ -1,6 +1,5 @@ | ||||||
| import { | import { | ||||||
|   AD_REPOSITORY, |   AD_REPOSITORY, | ||||||
|   AD_ROUTE_PROVIDER, |  | ||||||
|   INPUT_DATETIME_TRANSFORMER, |   INPUT_DATETIME_TRANSFORMER, | ||||||
|   PARAMS_PROVIDER, |   PARAMS_PROVIDER, | ||||||
| } from '@modules/ad/ad.di-tokens'; | } from '@modules/ad/ad.di-tokens'; | ||||||
|  | @ -114,10 +113,6 @@ describe('Match Query Handler', () => { | ||||||
|           provide: INPUT_DATETIME_TRANSFORMER, |           provide: INPUT_DATETIME_TRANSFORMER, | ||||||
|           useValue: mockInputDateTimeTransformer, |           useValue: mockInputDateTimeTransformer, | ||||||
|         }, |         }, | ||||||
|         { |  | ||||||
|           provide: AD_ROUTE_PROVIDER, |  | ||||||
|           useValue: mockRouteProvider, |  | ||||||
|         }, |  | ||||||
|       ], |       ], | ||||||
|     }).compile(); |     }).compile(); | ||||||
| 
 | 
 | ||||||
|  | @ -129,23 +124,26 @@ describe('Match Query Handler', () => { | ||||||
|   }); |   }); | ||||||
| 
 | 
 | ||||||
|   it('should return a Match entity', async () => { |   it('should return a Match entity', async () => { | ||||||
|     const matchQuery = new MatchQuery({ |     const matchQuery = new MatchQuery( | ||||||
|       algorithmType: AlgorithmType.PASSENGER_ORIENTED, |       { | ||||||
|       driver: false, |         algorithmType: AlgorithmType.PASSENGER_ORIENTED, | ||||||
|       passenger: true, |         driver: false, | ||||||
|       frequency: Frequency.PUNCTUAL, |         passenger: true, | ||||||
|       fromDate: '2023-08-28', |         frequency: Frequency.PUNCTUAL, | ||||||
|       toDate: '2023-08-28', |         fromDate: '2023-08-28', | ||||||
|       schedule: [ |         toDate: '2023-08-28', | ||||||
|         { |         schedule: [ | ||||||
|           time: '07:05', |           { | ||||||
|           day: 1, |             time: '07:05', | ||||||
|           margin: 900, |             day: 1, | ||||||
|         }, |             margin: 900, | ||||||
|       ], |           }, | ||||||
|       strict: false, |         ], | ||||||
|       waypoints: [originWaypoint, destinationWaypoint], |         strict: false, | ||||||
|     }); |         waypoints: [originWaypoint, destinationWaypoint], | ||||||
|  |       }, | ||||||
|  |       mockRouteProvider, | ||||||
|  |     ); | ||||||
|     const matches: MatchEntity[] = await matchQueryHandler.execute(matchQuery); |     const matches: MatchEntity[] = await matchQueryHandler.execute(matchQuery); | ||||||
|     expect(matches.length).toBeGreaterThanOrEqual(0); |     expect(matches.length).toBeGreaterThanOrEqual(0); | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|  | @ -108,17 +108,20 @@ const mockRouteProvider: RouteProviderPort = { | ||||||
| 
 | 
 | ||||||
| describe('Match Query', () => { | describe('Match Query', () => { | ||||||
|   it('should set default values', async () => { |   it('should set default values', async () => { | ||||||
|     const matchQuery = new MatchQuery({ |     const matchQuery = new MatchQuery( | ||||||
|       frequency: Frequency.PUNCTUAL, |       { | ||||||
|       fromDate: '2023-08-28', |         frequency: Frequency.PUNCTUAL, | ||||||
|       toDate: '2023-08-28', |         fromDate: '2023-08-28', | ||||||
|       schedule: [ |         toDate: '2023-08-28', | ||||||
|         { |         schedule: [ | ||||||
|           time: '01:05', |           { | ||||||
|         }, |             time: '01:05', | ||||||
|       ], |           }, | ||||||
|       waypoints: [originWaypoint, destinationWaypoint], |         ], | ||||||
|     }); |         waypoints: [originWaypoint, destinationWaypoint], | ||||||
|  |       }, | ||||||
|  |       mockRouteProvider, | ||||||
|  |     ); | ||||||
|     matchQuery |     matchQuery | ||||||
|       .setMissingMarginDurations(defaultParams.DEPARTURE_TIME_MARGIN) |       .setMissingMarginDurations(defaultParams.DEPARTURE_TIME_MARGIN) | ||||||
|       .setMissingStrict(defaultParams.STRICT) |       .setMissingStrict(defaultParams.STRICT) | ||||||
|  | @ -159,19 +162,22 @@ describe('Match Query', () => { | ||||||
|   }); |   }); | ||||||
| 
 | 
 | ||||||
|   it('should set good values for seats', async () => { |   it('should set good values for seats', async () => { | ||||||
|     const matchQuery = new MatchQuery({ |     const matchQuery = new MatchQuery( | ||||||
|       frequency: Frequency.PUNCTUAL, |       { | ||||||
|       fromDate: '2023-08-28', |         frequency: Frequency.PUNCTUAL, | ||||||
|       toDate: '2023-08-28', |         fromDate: '2023-08-28', | ||||||
|       seatsProposed: -1, |         toDate: '2023-08-28', | ||||||
|       seatsRequested: -1, |         seatsProposed: -1, | ||||||
|       schedule: [ |         seatsRequested: -1, | ||||||
|         { |         schedule: [ | ||||||
|           time: '07:05', |           { | ||||||
|         }, |             time: '07:05', | ||||||
|       ], |           }, | ||||||
|       waypoints: [originWaypoint, destinationWaypoint], |         ], | ||||||
|     }); |         waypoints: [originWaypoint, destinationWaypoint], | ||||||
|  |       }, | ||||||
|  |       mockRouteProvider, | ||||||
|  |     ); | ||||||
|     matchQuery.setDefaultDriverAndPassengerParameters({ |     matchQuery.setDefaultDriverAndPassengerParameters({ | ||||||
|       driver: defaultParams.DRIVER, |       driver: defaultParams.DRIVER, | ||||||
|       passenger: defaultParams.PASSENGER, |       passenger: defaultParams.PASSENGER, | ||||||
|  | @ -183,101 +189,114 @@ describe('Match Query', () => { | ||||||
|   }); |   }); | ||||||
| 
 | 
 | ||||||
|   it('should set route for a driver only', async () => { |   it('should set route for a driver only', async () => { | ||||||
|     const matchQuery = new MatchQuery({ |     const matchQuery = new MatchQuery( | ||||||
|       driver: true, |       { | ||||||
|       passenger: false, |         driver: true, | ||||||
|       frequency: Frequency.PUNCTUAL, |         passenger: false, | ||||||
|       fromDate: '2023-08-28', |         frequency: Frequency.PUNCTUAL, | ||||||
|       toDate: '2023-08-28', |         fromDate: '2023-08-28', | ||||||
|       schedule: [ |         toDate: '2023-08-28', | ||||||
|         { |         schedule: [ | ||||||
|           time: '01:05', |           { | ||||||
|         }, |             time: '01:05', | ||||||
|       ], |           }, | ||||||
|       waypoints: [originWaypoint, destinationWaypoint], |         ], | ||||||
|     }); |         waypoints: [originWaypoint, destinationWaypoint], | ||||||
|     await matchQuery.setRoutes(mockRouteProvider); |       }, | ||||||
|  |       mockRouteProvider, | ||||||
|  |     ); | ||||||
|  |     await matchQuery.setRoutes(); | ||||||
|     expect(matchQuery.driverRoute?.distance).toBe(350101); |     expect(matchQuery.driverRoute?.distance).toBe(350101); | ||||||
|     expect(matchQuery.passengerRoute).toBeUndefined(); |     expect(matchQuery.passengerRoute).toBeUndefined(); | ||||||
|   }); |   }); | ||||||
| 
 | 
 | ||||||
|   it('should set route for a passenger only', async () => { |   it('should set route for a passenger only', async () => { | ||||||
|     const matchQuery = new MatchQuery({ |     const matchQuery = new MatchQuery( | ||||||
|       driver: false, |       { | ||||||
|       passenger: true, |         driver: false, | ||||||
|       frequency: Frequency.PUNCTUAL, |         passenger: true, | ||||||
|       fromDate: '2023-08-28', |         frequency: Frequency.PUNCTUAL, | ||||||
|       toDate: '2023-08-28', |         fromDate: '2023-08-28', | ||||||
|       schedule: [ |         toDate: '2023-08-28', | ||||||
|         { |         schedule: [ | ||||||
|           time: '01:05', |           { | ||||||
|         }, |             time: '01:05', | ||||||
|       ], |           }, | ||||||
|       waypoints: [originWaypoint, destinationWaypoint], |         ], | ||||||
|     }); |         waypoints: [originWaypoint, destinationWaypoint], | ||||||
|     await matchQuery.setRoutes(mockRouteProvider); |       }, | ||||||
|  |       mockRouteProvider, | ||||||
|  |     ); | ||||||
|  |     await matchQuery.setRoutes(); | ||||||
|     expect(matchQuery.passengerRoute?.distance).toBe(340102); |     expect(matchQuery.passengerRoute?.distance).toBe(340102); | ||||||
|     expect(matchQuery.driverRoute).toBeUndefined(); |     expect(matchQuery.driverRoute).toBeUndefined(); | ||||||
|   }); |   }); | ||||||
| 
 | 
 | ||||||
|   it('should set route for a driver and passenger', async () => { |   it('should set route for a driver and passenger', async () => { | ||||||
|     const matchQuery = new MatchQuery({ |     const matchQuery = new MatchQuery( | ||||||
|       driver: true, |       { | ||||||
|       passenger: true, |         driver: true, | ||||||
|       frequency: Frequency.PUNCTUAL, |         passenger: true, | ||||||
|       fromDate: '2023-08-28', |         frequency: Frequency.PUNCTUAL, | ||||||
|       toDate: '2023-08-28', |         fromDate: '2023-08-28', | ||||||
|       schedule: [ |         toDate: '2023-08-28', | ||||||
|         { |         schedule: [ | ||||||
|           time: '01:05', |           { | ||||||
|         }, |             time: '01:05', | ||||||
|       ], |           }, | ||||||
|       waypoints: [originWaypoint, destinationWaypoint], |         ], | ||||||
|     }); |         waypoints: [originWaypoint, destinationWaypoint], | ||||||
|     await matchQuery.setRoutes(mockRouteProvider); |       }, | ||||||
|  |       mockRouteProvider, | ||||||
|  |     ); | ||||||
|  |     await matchQuery.setRoutes(); | ||||||
|     expect(matchQuery.driverRoute?.distance).toBe(350101); |     expect(matchQuery.driverRoute?.distance).toBe(350101); | ||||||
|     expect(matchQuery.passengerRoute?.distance).toBe(350101); |     expect(matchQuery.passengerRoute?.distance).toBe(350101); | ||||||
|   }); |   }); | ||||||
| 
 | 
 | ||||||
|   it('should set route for a driver and passenger with 3 waypoints', async () => { |   it('should set route for a driver and passenger with 3 waypoints', async () => { | ||||||
|     const matchQuery = new MatchQuery({ |     const matchQuery = new MatchQuery( | ||||||
|       driver: true, |       { | ||||||
|       passenger: true, |         driver: true, | ||||||
|       frequency: Frequency.PUNCTUAL, |         passenger: true, | ||||||
|       fromDate: '2023-08-28', |         frequency: Frequency.PUNCTUAL, | ||||||
|       toDate: '2023-08-28', |         fromDate: '2023-08-28', | ||||||
|       schedule: [ |         toDate: '2023-08-28', | ||||||
|         { |         schedule: [ | ||||||
|           time: '01:05', |           { | ||||||
|         }, |             time: '01:05', | ||||||
|       ], |           }, | ||||||
|       waypoints: [ |         ], | ||||||
|         originWaypoint, |         waypoints: [ | ||||||
|         intermediateWaypoint, |           originWaypoint, | ||||||
|         { ...destinationWaypoint, position: 2 }, |           intermediateWaypoint, | ||||||
|       ], |           { ...destinationWaypoint, position: 2 }, | ||||||
|     }); |         ], | ||||||
|     await matchQuery.setRoutes(mockRouteProvider); |       }, | ||||||
|  |       mockRouteProvider, | ||||||
|  |     ); | ||||||
|  |     await matchQuery.setRoutes(); | ||||||
|     expect(matchQuery.driverRoute?.distance).toBe(350101); |     expect(matchQuery.driverRoute?.distance).toBe(350101); | ||||||
|     expect(matchQuery.passengerRoute?.distance).toBe(340102); |     expect(matchQuery.passengerRoute?.distance).toBe(340102); | ||||||
|   }); |   }); | ||||||
| 
 | 
 | ||||||
|   it('should throw an exception if route is not found', async () => { |   it('should throw an exception if route is not found', async () => { | ||||||
|     const matchQuery = new MatchQuery({ |     const matchQuery = new MatchQuery( | ||||||
|       driver: true, |       { | ||||||
|       passenger: false, |         driver: true, | ||||||
|       frequency: Frequency.PUNCTUAL, |         passenger: false, | ||||||
|       fromDate: '2023-08-28', |         frequency: Frequency.PUNCTUAL, | ||||||
|       toDate: '2023-08-28', |         fromDate: '2023-08-28', | ||||||
|       schedule: [ |         toDate: '2023-08-28', | ||||||
|         { |         schedule: [ | ||||||
|           time: '01:05', |           { | ||||||
|         }, |             time: '01:05', | ||||||
|       ], |           }, | ||||||
|       waypoints: [originWaypoint, destinationWaypoint], |         ], | ||||||
|     }); |         waypoints: [originWaypoint, destinationWaypoint], | ||||||
|     await expect( |       }, | ||||||
|       matchQuery.setRoutes(mockRouteProvider), |       mockRouteProvider, | ||||||
|     ).rejects.toBeInstanceOf(Error); |     ); | ||||||
|  |     await expect(matchQuery.setRoutes()).rejects.toBeInstanceOf(Error); | ||||||
|   }); |   }); | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  | @ -25,21 +25,29 @@ const destinationWaypoint: Waypoint = { | ||||||
|   country: 'France', |   country: 'France', | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| const matchQuery = new MatchQuery({ | const matchQuery = new MatchQuery( | ||||||
|   algorithmType: AlgorithmType.PASSENGER_ORIENTED, |   { | ||||||
|   driver: false, |     algorithmType: AlgorithmType.PASSENGER_ORIENTED, | ||||||
|   passenger: true, |     driver: false, | ||||||
|   frequency: Frequency.PUNCTUAL, |     passenger: true, | ||||||
|   fromDate: '2023-08-28', |     frequency: Frequency.PUNCTUAL, | ||||||
|   toDate: '2023-08-28', |     fromDate: '2023-08-28', | ||||||
|   schedule: [ |     toDate: '2023-08-28', | ||||||
|     { |     schedule: [ | ||||||
|       time: '07:05', |       { | ||||||
|     }, |         time: '07:05', | ||||||
|   ], |       }, | ||||||
|   strict: false, |     ], | ||||||
|   waypoints: [originWaypoint, destinationWaypoint], |     strict: false, | ||||||
| }); |     waypoints: [originWaypoint, destinationWaypoint], | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     getBasic: jest.fn().mockImplementation(() => ({ | ||||||
|  |       duration: 6500, | ||||||
|  |       distance: 89745, | ||||||
|  |     })), | ||||||
|  |   }, | ||||||
|  | ); | ||||||
| 
 | 
 | ||||||
| const mockMatcherRepository: AdRepositoryPort = { | const mockMatcherRepository: AdRepositoryPort = { | ||||||
|   insertExtra: jest.fn(), |   insertExtra: jest.fn(), | ||||||
|  |  | ||||||
|  | @ -24,21 +24,26 @@ const destinationWaypoint: Waypoint = { | ||||||
|   country: 'France', |   country: 'France', | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| const matchQuery = new MatchQuery({ | const matchQuery = new MatchQuery( | ||||||
|   algorithmType: AlgorithmType.PASSENGER_ORIENTED, |   { | ||||||
|   driver: true, |     algorithmType: AlgorithmType.PASSENGER_ORIENTED, | ||||||
|   passenger: true, |     driver: true, | ||||||
|   frequency: Frequency.PUNCTUAL, |     passenger: true, | ||||||
|   fromDate: '2023-08-28', |     frequency: Frequency.PUNCTUAL, | ||||||
|   toDate: '2023-08-28', |     fromDate: '2023-08-28', | ||||||
|   schedule: [ |     toDate: '2023-08-28', | ||||||
|     { |     schedule: [ | ||||||
|       time: '07:05', |       { | ||||||
|     }, |         time: '07:05', | ||||||
|   ], |       }, | ||||||
|   strict: false, |     ], | ||||||
|   waypoints: [originWaypoint, destinationWaypoint], |     strict: false, | ||||||
| }); |     waypoints: [originWaypoint, destinationWaypoint], | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     getBasic: jest.fn(), | ||||||
|  |   }, | ||||||
|  | ); | ||||||
| 
 | 
 | ||||||
| const candidates: CandidateEntity[] = [ | const candidates: CandidateEntity[] = [ | ||||||
|   CandidateEntity.create({ |   CandidateEntity.create({ | ||||||
|  |  | ||||||
|  | @ -24,21 +24,26 @@ const destinationWaypoint: Waypoint = { | ||||||
|   country: 'France', |   country: 'France', | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| const matchQuery = new MatchQuery({ | const matchQuery = new MatchQuery( | ||||||
|   algorithmType: AlgorithmType.PASSENGER_ORIENTED, |   { | ||||||
|   driver: true, |     algorithmType: AlgorithmType.PASSENGER_ORIENTED, | ||||||
|   passenger: true, |     driver: true, | ||||||
|   frequency: Frequency.PUNCTUAL, |     passenger: true, | ||||||
|   fromDate: '2023-08-28', |     frequency: Frequency.PUNCTUAL, | ||||||
|   toDate: '2023-08-28', |     fromDate: '2023-08-28', | ||||||
|   schedule: [ |     toDate: '2023-08-28', | ||||||
|     { |     schedule: [ | ||||||
|       time: '07:05', |       { | ||||||
|     }, |         time: '07:05', | ||||||
|   ], |       }, | ||||||
|   strict: false, |     ], | ||||||
|   waypoints: [originWaypoint, destinationWaypoint], |     strict: false, | ||||||
| }); |     waypoints: [originWaypoint, destinationWaypoint], | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     getBasic: jest.fn(), | ||||||
|  |   }, | ||||||
|  | ); | ||||||
| 
 | 
 | ||||||
| const candidates: CandidateEntity[] = [ | const candidates: CandidateEntity[] = [ | ||||||
|   CandidateEntity.create({ |   CandidateEntity.create({ | ||||||
|  |  | ||||||
|  | @ -25,27 +25,32 @@ const destinationWaypoint: Waypoint = { | ||||||
|   country: 'France', |   country: 'France', | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| const matchQuery = new MatchQuery({ | const matchQuery = new MatchQuery( | ||||||
|   algorithmType: AlgorithmType.PASSENGER_ORIENTED, |   { | ||||||
|   driver: true, |     algorithmType: AlgorithmType.PASSENGER_ORIENTED, | ||||||
|   passenger: true, |     driver: true, | ||||||
|   frequency: Frequency.PUNCTUAL, |     passenger: true, | ||||||
|   fromDate: '2023-06-21', |     frequency: Frequency.PUNCTUAL, | ||||||
|   toDate: '2023-06-21', |     fromDate: '2023-06-21', | ||||||
|   useAzimuth: true, |     toDate: '2023-06-21', | ||||||
|   azimuthMargin: 10, |     useAzimuth: true, | ||||||
|   useProportion: true, |     azimuthMargin: 10, | ||||||
|   proportion: 0.3, |     useProportion: true, | ||||||
|   schedule: [ |     proportion: 0.3, | ||||||
|     { |     schedule: [ | ||||||
|       day: 3, |       { | ||||||
|       time: '07:05', |         day: 3, | ||||||
|       margin: 900, |         time: '07:05', | ||||||
|     }, |         margin: 900, | ||||||
|   ], |       }, | ||||||
|   strict: false, |     ], | ||||||
|   waypoints: [originWaypoint, destinationWaypoint], |     strict: false, | ||||||
| }); |     waypoints: [originWaypoint, destinationWaypoint], | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     getBasic: jest.fn(), | ||||||
|  |   }, | ||||||
|  | ); | ||||||
| matchQuery.driverRoute = { | matchQuery.driverRoute = { | ||||||
|   distance: 150120, |   distance: 150120, | ||||||
|   duration: 6540, |   duration: 6540, | ||||||
|  |  | ||||||
|  | @ -1,4 +1,6 @@ | ||||||
| import { RpcExceptionCode } from '@mobicoop/ddd-library'; | import { RpcExceptionCode } from '@mobicoop/ddd-library'; | ||||||
|  | import { AD_ROUTE_PROVIDER } from '@modules/ad/ad.di-tokens'; | ||||||
|  | import { RouteProviderPort } from '@modules/ad/core/application/ports/route-provider.port'; | ||||||
| import { AlgorithmType } from '@modules/ad/core/application/types/algorithm.types'; | import { AlgorithmType } from '@modules/ad/core/application/types/algorithm.types'; | ||||||
| import { Frequency } from '@modules/ad/core/domain/ad.types'; | import { Frequency } 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'; | ||||||
|  | @ -62,6 +64,10 @@ const mockQueryBus = { | ||||||
|     }), |     }), | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | const mockRouteProvider: RouteProviderPort = { | ||||||
|  |   getBasic: jest.fn(), | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| describe('Match Grpc Controller', () => { | describe('Match Grpc Controller', () => { | ||||||
|   let matchGrpcController: MatchGrpcController; |   let matchGrpcController: MatchGrpcController; | ||||||
| 
 | 
 | ||||||
|  | @ -73,6 +79,10 @@ describe('Match Grpc Controller', () => { | ||||||
|           provide: QueryBus, |           provide: QueryBus, | ||||||
|           useValue: mockQueryBus, |           useValue: mockQueryBus, | ||||||
|         }, |         }, | ||||||
|  |         { | ||||||
|  |           provide: AD_ROUTE_PROVIDER, | ||||||
|  |           useValue: mockRouteProvider, | ||||||
|  |         }, | ||||||
|       ], |       ], | ||||||
|     }).compile(); |     }).compile(); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue