basic RouteCompleter

This commit is contained in:
sbriat 2023-09-18 14:09:33 +02:00
parent a277a9547f
commit 067854b697
16 changed files with 301 additions and 209 deletions

View File

@ -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[]>;
} }

View File

@ -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;
}; };

View File

@ -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',
}

View File

@ -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) {

View File

@ -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) => {

View File

@ -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),
]; ];
} }

View File

@ -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
} }

View File

@ -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',

View File

@ -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) => ({

View File

@ -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);
}); });

View File

@ -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);
}); });
}); });

View File

@ -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(),

View File

@ -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({

View File

@ -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({

View File

@ -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,

View File

@ -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();