simpler route provider in ad module

This commit is contained in:
sbriat 2023-09-08 16:19:25 +02:00
parent 6b4ac1792c
commit 59a2644bb4
25 changed files with 436 additions and 568 deletions

View File

@ -4,7 +4,7 @@ export const AD_MESSAGE_PUBLISHER = Symbol('AD_MESSAGE_PUBLISHER');
export const AD_GET_BASIC_ROUTE_CONTROLLER = Symbol( export const AD_GET_BASIC_ROUTE_CONTROLLER = Symbol(
'AD_GET_BASIC_ROUTE_CONTROLLER', 'AD_GET_BASIC_ROUTE_CONTROLLER',
); );
export const AD_CARPOOL_ROUTE_PROVIDER = Symbol('AD_CARPOOL_ROUTE_PROVIDER'); export const AD_ROUTE_PROVIDER = Symbol('AD_ROUTE_PROVIDER');
export const PARAMS_PROVIDER = Symbol('PARAMS_PROVIDER'); export const PARAMS_PROVIDER = Symbol('PARAMS_PROVIDER');
export const TIMEZONE_FINDER = Symbol('TIMEZONE_FINDER'); export const TIMEZONE_FINDER = Symbol('TIMEZONE_FINDER');
export const TIME_CONVERTER = Symbol('TIME_CONVERTER'); export const TIME_CONVERTER = Symbol('TIME_CONVERTER');

View File

@ -4,7 +4,7 @@ import {
AD_MESSAGE_PUBLISHER, AD_MESSAGE_PUBLISHER,
AD_REPOSITORY, AD_REPOSITORY,
AD_DIRECTION_ENCODER, AD_DIRECTION_ENCODER,
AD_CARPOOL_ROUTE_PROVIDER, AD_ROUTE_PROVIDER,
AD_GET_BASIC_ROUTE_CONTROLLER, AD_GET_BASIC_ROUTE_CONTROLLER,
PARAMS_PROVIDER, PARAMS_PROVIDER,
TIMEZONE_FINDER, TIMEZONE_FINDER,
@ -18,7 +18,7 @@ import { AdMapper } from './ad.mapper';
import { AdCreatedMessageHandler } from './interface/message-handlers/ad-created.message-handler'; import { AdCreatedMessageHandler } from './interface/message-handlers/ad-created.message-handler';
import { PostgresDirectionEncoder } from '@modules/geography/infrastructure/postgres-direction-encoder'; import { PostgresDirectionEncoder } from '@modules/geography/infrastructure/postgres-direction-encoder';
import { GetBasicRouteController } from '@modules/geography/interface/controllers/get-basic-route.controller'; import { GetBasicRouteController } from '@modules/geography/interface/controllers/get-basic-route.controller';
import { CarpoolRouteProvider } from './infrastructure/carpool-route-provider'; import { RouteProvider } from './infrastructure/route-provider';
import { GeographyModule } from '@modules/geography/geography.module'; import { GeographyModule } from '@modules/geography/geography.module';
import { CreateAdService } from './core/application/commands/create-ad/create-ad.service'; import { CreateAdService } from './core/application/commands/create-ad/create-ad.service';
import { MatchGrpcController } from './interface/grpc-controllers/match.grpc-controller'; import { MatchGrpcController } from './interface/grpc-controllers/match.grpc-controller';
@ -60,8 +60,8 @@ const adapters: Provider[] = [
useClass: PostgresDirectionEncoder, useClass: PostgresDirectionEncoder,
}, },
{ {
provide: AD_CARPOOL_ROUTE_PROVIDER, provide: AD_ROUTE_PROVIDER,
useClass: CarpoolRouteProvider, useClass: RouteProvider,
}, },
{ {
provide: AD_GET_BASIC_ROUTE_CONTROLLER, provide: AD_GET_BASIC_ROUTE_CONTROLLER,

View File

@ -1,35 +1,29 @@
import { CommandHandler, ICommandHandler } from '@nestjs/cqrs'; import { CommandHandler, ICommandHandler } from '@nestjs/cqrs';
import { CreateAdCommand } from './create-ad.command'; import { CreateAdCommand } from './create-ad.command';
import { Inject } from '@nestjs/common'; import { Inject } from '@nestjs/common';
import { import { AD_REPOSITORY, AD_ROUTE_PROVIDER } from '@modules/ad/ad.di-tokens';
AD_REPOSITORY,
AD_CARPOOL_ROUTE_PROVIDER,
} from '@modules/ad/ad.di-tokens';
import { AdEntity } from '@modules/ad/core/domain/ad.entity'; import { AdEntity } from '@modules/ad/core/domain/ad.entity';
import { AdRepositoryPort } from '../../ports/ad.repository.port'; import { AdRepositoryPort } from '../../ports/ad.repository.port';
import { AggregateID, ConflictException } from '@mobicoop/ddd-library'; import { AggregateID, ConflictException } from '@mobicoop/ddd-library';
import { AdAlreadyExistsException } from '@modules/ad/core/domain/ad.errors'; import { AdAlreadyExistsException } from '@modules/ad/core/domain/ad.errors';
import { CarpoolRouteProviderPort } from '../../ports/carpool-route-provider.port'; import { RouteProviderPort } from '../../ports/route-provider.port';
import { Role } from '@modules/ad/core/domain/ad.types'; import { Role } from '@modules/ad/core/domain/ad.types';
import { CarpoolRoute } from '../../types/carpool-route.type'; import { Route } from '../../types/carpool-route.type';
@CommandHandler(CreateAdCommand) @CommandHandler(CreateAdCommand)
export class CreateAdService implements ICommandHandler { export class CreateAdService implements ICommandHandler {
constructor( constructor(
@Inject(AD_REPOSITORY) @Inject(AD_REPOSITORY)
private readonly repository: AdRepositoryPort, private readonly repository: AdRepositoryPort,
@Inject(AD_CARPOOL_ROUTE_PROVIDER) @Inject(AD_ROUTE_PROVIDER)
private readonly carpoolRouteProvider: CarpoolRouteProviderPort, private readonly routeProvider: RouteProviderPort,
) {} ) {}
async execute(command: CreateAdCommand): Promise<AggregateID> { async execute(command: CreateAdCommand): Promise<AggregateID> {
const roles: Role[] = []; const roles: Role[] = [];
if (command.driver) roles.push(Role.DRIVER); if (command.driver) roles.push(Role.DRIVER);
if (command.passenger) roles.push(Role.PASSENGER); if (command.passenger) roles.push(Role.PASSENGER);
const carpoolRoute: CarpoolRoute = await this.carpoolRouteProvider.getBasic( const route: Route = await this.routeProvider.getBasic(command.waypoints);
roles,
command.waypoints,
);
const ad = AdEntity.create({ const ad = AdEntity.create({
id: command.id, id: command.id,
driver: command.driver, driver: command.driver,
@ -42,13 +36,13 @@ export class CreateAdService implements ICommandHandler {
seatsRequested: command.seatsRequested, seatsRequested: command.seatsRequested,
strict: command.strict, strict: command.strict,
waypoints: command.waypoints, waypoints: command.waypoints,
points: carpoolRoute.points, points: route.points,
driverDistance: carpoolRoute.driverDistance, driverDistance: route.driverDistance,
driverDuration: carpoolRoute.driverDuration, driverDuration: route.driverDuration,
passengerDistance: carpoolRoute.passengerDistance, passengerDistance: route.passengerDistance,
passengerDuration: carpoolRoute.passengerDuration, passengerDuration: route.passengerDuration,
fwdAzimuth: carpoolRoute.fwdAzimuth, fwdAzimuth: route.fwdAzimuth,
backAzimuth: carpoolRoute.backAzimuth, backAzimuth: route.backAzimuth,
}); });
try { try {

View File

@ -1,10 +0,0 @@
import { Role } from '../../domain/ad.types';
import { Waypoint } from '../types/waypoint.type';
import { CarpoolRoute } from '../types/carpool-route.type';
export interface CarpoolRouteProviderPort {
/**
* Get a basic carpool route with points and overall duration / distance
*/
getBasic(roles: Role[], waypoints: Waypoint[]): Promise<CarpoolRoute>;
}

View File

@ -0,0 +1,9 @@
import { Route } from '@modules/geography/core/domain/route.types';
import { Waypoint } from '../types/waypoint.type';
export interface RouteProviderPort {
/**
* Get a basic route with points and overall duration / distance
*/
getBasic(waypoints: Waypoint[]): Promise<Route>;
}

View File

@ -7,7 +7,7 @@ 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_CARPOOL_ROUTE_PROVIDER, 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 +15,7 @@ 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 { CarpoolRouteProviderPort } from '../../ports/carpool-route-provider.port'; import { RouteProviderPort } from '../../ports/route-provider.port';
@QueryHandler(MatchQuery) @QueryHandler(MatchQuery)
export class MatchQueryHandler implements IQueryHandler { export class MatchQueryHandler implements IQueryHandler {
@ -27,8 +27,8 @@ 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_CARPOOL_ROUTE_PROVIDER) @Inject(AD_ROUTE_PROVIDER)
private readonly carpoolRouteProvider: CarpoolRouteProviderPort, private readonly routeProvider: RouteProviderPort,
) { ) {
this._defaultParams = defaultParamsProvider.getParams(); this._defaultParams = defaultParamsProvider.getParams();
} }
@ -54,7 +54,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.setCarpoolRoute(this.carpoolRouteProvider); await query.setRoutes(this.routeProvider);
let algorithm: Algorithm; let algorithm: Algorithm;
switch (query.algorithmType) { switch (query.algorithmType) {

View File

@ -1,11 +1,11 @@
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 { Frequency, Role } 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'; import { MatchRequestDto } from '@modules/ad/interface/grpc-controllers/dtos/match.request.dto';
import { DateTimeTransformerPort } from '../../ports/datetime-transformer.port'; import { DateTimeTransformerPort } from '../../ports/datetime-transformer.port';
import { CarpoolRoute } from '../../types/carpool-route.type'; import { RouteProviderPort } from '../../ports/route-provider.port';
import { CarpoolRouteProviderPort } from '../../ports/carpool-route-provider.port'; import { Route } from '@modules/geography/core/domain/route.types';
export class MatchQuery extends QueryBase { export class MatchQuery extends QueryBase {
driver?: boolean; driver?: boolean;
@ -28,7 +28,9 @@ export class MatchQuery extends QueryBase {
maxDetourDurationRatio?: number; maxDetourDurationRatio?: number;
readonly page?: number; readonly page?: number;
readonly perPage?: number; readonly perPage?: number;
carpoolRoute?: CarpoolRoute; driverRoute?: Route;
passengerRoute?: Route;
backAzimuth?: number;
constructor(props: MatchRequestDto) { constructor(props: MatchRequestDto) {
super(); super();
@ -165,22 +167,68 @@ export class MatchQuery extends QueryBase {
return this; return this;
}; };
setCarpoolRoute = async ( setRoutes = async (routeProvider: RouteProviderPort): Promise<MatchQuery> => {
carpoolRouteProvider: CarpoolRouteProviderPort,
): Promise<MatchQuery> => {
const roles: Role[] = [];
if (this.driver) roles.push(Role.DRIVER);
if (this.passenger) roles.push(Role.PASSENGER);
try { try {
this.carpoolRoute = await carpoolRouteProvider.getBasic( (
roles, await Promise.all(
this.waypoints, this._getPaths().map(async (path: Path) => ({
); type: path.type,
route: await routeProvider.getBasic(path.waypoints),
})),
)
).forEach((typedRoute: TypedRoute) => {
if (typedRoute.type !== PathType.PASSENGER) {
this.driverRoute = typedRoute.route;
this.backAzimuth = typedRoute.route.backAzimuth;
}
if (typedRoute.type !== PathType.DRIVER) {
this.passengerRoute = typedRoute.route;
if (!this.backAzimuth)
this.backAzimuth = typedRoute.route.backAzimuth;
}
});
} catch (e: any) { } catch (e: any) {
throw new Error('Unable to find a route for given waypoints'); throw new Error('Unable to find a route for given waypoints');
} }
return this; return this;
}; };
private _getPaths = (): Path[] => {
const paths: Path[] = [];
if (this.driver && this.passenger) {
if (this.waypoints.length == 2) {
// 2 points => same route for driver and passenger
paths.push(this._createGenericPath(this.waypoints));
} else {
paths.push(
this._createDriverPath(this.waypoints),
this._createPassengerPath(this.waypoints),
);
}
} else if (this.driver) {
paths.push(this._createDriverPath(this.waypoints));
} else if (this.passenger) {
paths.push(this._createPassengerPath(this.waypoints));
}
return paths;
};
private _createGenericPath = (waypoints: Waypoint[]): Path =>
this._createPath(waypoints, PathType.GENERIC);
private _createDriverPath = (waypoints: Waypoint[]): Path =>
this._createPath(waypoints, PathType.DRIVER);
private _createPassengerPath = (waypoints: Waypoint[]): Path =>
this._createPath(
[waypoints[0], waypoints[waypoints.length - 1]],
PathType.PASSENGER,
);
private _createPath = (waypoints: Waypoint[], type: PathType): Path => ({
type,
waypoints,
});
} }
export type ScheduleItem = { export type ScheduleItem = {
@ -206,3 +254,19 @@ interface DefaultAlgorithmParameters {
maxDetourDistanceRatio: number; maxDetourDistanceRatio: number;
maxDetourDurationRatio: number; maxDetourDurationRatio: number;
} }
type Path = {
type: PathType;
waypoints: Waypoint[];
};
enum PathType {
GENERIC = 'generic',
DRIVER = 'driver',
PASSENGER = 'passenger',
}
type TypedRoute = {
type: PathType;
route: Route;
};

View File

@ -39,7 +39,6 @@ export class PassengerOrientedSelector extends Selector {
id: adReadModel.uuid, id: adReadModel.uuid,
}, },
role: adsRole.role, role: adsRole.role,
baseCarpoolRoute: this.query.carpoolRoute,
}, },
), ),
) )
@ -69,7 +68,7 @@ export class PassengerOrientedSelector extends Selector {
].join(); ].join();
private _selectAsDriver = (): string => private _selectAsDriver = (): string =>
`${this.query.carpoolRoute?.driverDuration} as duration,${this.query.carpoolRoute?.driverDistance} as distance`; `${this.query.driverRoute?.duration} as duration,${this.query.driverRoute?.distance} as distance`;
private _selectAsPassenger = (): string => private _selectAsPassenger = (): string =>
`"driverDuration" as duration,"driverDistance" as distance`; `"driverDuration" as duration,"driverDistance" as distance`;
@ -200,7 +199,7 @@ export class PassengerOrientedSelector extends Selector {
private _whereAzimuth = (): string => { private _whereAzimuth = (): string => {
if (!this.query.useAzimuth) return ''; if (!this.query.useAzimuth) return '';
const { minAzimuth, maxAzimuth } = this._azimuthRange( const { minAzimuth, maxAzimuth } = this._azimuthRange(
this.query.carpoolRoute?.backAzimuth as number, this.query.backAzimuth as number,
this.query.azimuthMargin as number, this.query.azimuthMargin as number,
); );
if (minAzimuth <= maxAzimuth) if (minAzimuth <= maxAzimuth)
@ -212,9 +211,9 @@ export class PassengerOrientedSelector extends Selector {
if (!this.query.useProportion) return ''; if (!this.query.useProportion) return '';
switch (role) { switch (role) {
case Role.PASSENGER: case Role.PASSENGER:
return `(${this.query.carpoolRoute?.passengerDistance}>(${this.query.proportion}*"driverDistance"))`; return `(${this.query.passengerRoute?.distance}>(${this.query.proportion}*"driverDistance"))`;
case Role.DRIVER: case Role.DRIVER:
return `("passengerDistance">(${this.query.proportion}*${this.query.carpoolRoute?.driverDistance}))`; return `("passengerDistance">(${this.query.proportion}*${this.query.driverRoute?.distance}))`;
} }
}; };
@ -238,7 +237,7 @@ export class PassengerOrientedSelector extends Selector {
${this.query.remoteness}`; ${this.query.remoteness}`;
case Role.DRIVER: case Role.DRIVER:
const lineStringPoints: string[] = []; const lineStringPoints: string[] = [];
this.query.carpoolRoute?.points.forEach((point: Point) => this.query.driverRoute?.points.forEach((point: Point) =>
lineStringPoints.push( lineStringPoints.push(
`public.st_makepoint(${point.lon},${point.lat})`, `public.st_makepoint(${point.lon},${point.lat})`,
), ),

View File

@ -1,5 +1,5 @@
import { Waypoint } from '@modules/geography/core/domain/route.types';
import { Role } from '../../domain/ad.types'; import { Role } from '../../domain/ad.types';
import { CarpoolRoute } from './carpool-route.type';
export enum AlgorithmType { export enum AlgorithmType {
PASSENGER_ORIENTED = 'PASSENGER_ORIENTED', PASSENGER_ORIENTED = 'PASSENGER_ORIENTED',
@ -11,9 +11,7 @@ export enum AlgorithmType {
export type Candidate = { export type Candidate = {
ad: Ad; ad: Ad;
role: Role; role: Role;
baseCarpoolRoute: CarpoolRoute; waypoints: Waypoint[];
// driverRoute?: Route; ?
// crewRoute?: Route; ?
}; };
export type Ad = { export type Ad = {

View File

@ -3,7 +3,7 @@ import { Point } from './point.type';
/** /**
* A carpool route is a route with distance and duration as driver and / or passenger * A carpool route is a route with distance and duration as driver and / or passenger
*/ */
export type CarpoolRoute = { export type Route = {
driverDistance?: number; driverDistance?: number;
driverDuration?: number; driverDuration?: number;
passengerDistance?: number; passengerDistance?: number;

View File

@ -1,132 +0,0 @@
import { Inject, Injectable } from '@nestjs/common';
import { CarpoolRouteProviderPort } from '../core/application/ports/carpool-route-provider.port';
import { CarpoolRoute } from '../core/application/types/carpool-route.type';
import { Waypoint } from '../core/application/types/waypoint.type';
import { Role } from '../core/domain/ad.types';
import { GetBasicRouteControllerPort } from '@modules/geography/core/application/ports/get-basic-route-controller.port';
import { AD_GET_BASIC_ROUTE_CONTROLLER } from '../ad.di-tokens';
import { Route } from '@modules/geography/core/domain/route.types';
@Injectable()
export class CarpoolRouteProvider implements CarpoolRouteProviderPort {
constructor(
@Inject(AD_GET_BASIC_ROUTE_CONTROLLER)
private readonly getBasicRouteController: GetBasicRouteControllerPort,
) {}
getBasic = async (
roles: Role[],
waypoints: Waypoint[],
): Promise<CarpoolRoute> => {
const paths: Path[] = this._getPaths(roles, waypoints);
const typeRoutes: TypeRoute[] = await Promise.all(
paths.map(
async (path: Path) =>
<TypeRoute>{
type: path.type,
route: await this.getBasicRouteController.get({
waypoints,
}),
},
),
);
return this._toCarpoolRoute(typeRoutes);
};
private _toCarpoolRoute = (typeRoutes: TypeRoute[]): CarpoolRoute => {
let baseRoute: Route;
let driverRoute: Route | undefined;
let passengerRoute: Route | undefined;
if (
typeRoutes.some(
(typeRoute: TypeRoute) => typeRoute.type == PathType.GENERIC,
)
) {
driverRoute = passengerRoute = typeRoutes.find(
(typeRoute: TypeRoute) => typeRoute.type == PathType.GENERIC,
)?.route;
} else {
driverRoute = typeRoutes.some(
(typeRoute: TypeRoute) => typeRoute.type == PathType.DRIVER,
)
? typeRoutes.find(
(typeRoute: TypeRoute) => typeRoute.type == PathType.DRIVER,
)?.route
: undefined;
passengerRoute = typeRoutes.some(
(typeRoute: TypeRoute) => typeRoute.type == PathType.PASSENGER,
)
? typeRoutes.find(
(typeRoute: TypeRoute) => typeRoute.type == PathType.PASSENGER,
)?.route
: undefined;
}
if (driverRoute) {
baseRoute = driverRoute;
} else {
baseRoute = passengerRoute as Route;
}
return {
driverDistance: driverRoute?.distance,
driverDuration: driverRoute?.duration,
passengerDistance: passengerRoute?.distance,
passengerDuration: passengerRoute?.duration,
fwdAzimuth: baseRoute.fwdAzimuth,
backAzimuth: baseRoute.backAzimuth,
points: baseRoute.points,
};
};
private _getPaths = (roles: Role[], waypoints: Waypoint[]): Path[] => {
const paths: Path[] = [];
if (roles.includes(Role.DRIVER) && roles.includes(Role.PASSENGER)) {
if (waypoints.length == 2) {
// 2 points => same route for driver and passenger
paths.push(this._createGenericPath(waypoints));
} else {
paths.push(
this._createDriverPath(waypoints),
this._createPassengerPath(waypoints),
);
}
} else if (roles.includes(Role.DRIVER)) {
paths.push(this._createDriverPath(waypoints));
} else if (roles.includes(Role.PASSENGER)) {
paths.push(this._createPassengerPath(waypoints));
}
return paths;
};
private _createGenericPath = (waypoints: Waypoint[]): Path =>
this._createPath(waypoints, PathType.GENERIC);
private _createDriverPath = (waypoints: Waypoint[]): Path =>
this._createPath(waypoints, PathType.DRIVER);
private _createPassengerPath = (waypoints: Waypoint[]): Path =>
this._createPath(
[waypoints[0], waypoints[waypoints.length - 1]],
PathType.PASSENGER,
);
private _createPath = (waypoints: Waypoint[], type: PathType): Path => ({
type,
waypoints,
});
}
type Path = {
type: PathType;
waypoints: Waypoint[];
};
type TypeRoute = {
type: PathType;
route: Route;
};
enum PathType {
GENERIC = 'generic',
DRIVER = 'driver',
PASSENGER = 'passenger',
}

View File

@ -0,0 +1,19 @@
import { Inject, Injectable } from '@nestjs/common';
import { RouteProviderPort } from '../core/application/ports/route-provider.port';
import { Waypoint } from '../core/application/types/waypoint.type';
import { GetBasicRouteControllerPort } from '@modules/geography/core/application/ports/get-basic-route-controller.port';
import { AD_GET_BASIC_ROUTE_CONTROLLER } from '../ad.di-tokens';
import { Route } from '@modules/geography/core/domain/route.types';
@Injectable()
export class RouteProvider implements RouteProviderPort {
constructor(
@Inject(AD_GET_BASIC_ROUTE_CONTROLLER)
private readonly getBasicRouteController: GetBasicRouteControllerPort,
) {}
getBasic = async (waypoints: Waypoint[]): Promise<Route> =>
await this.getBasicRouteController.get({
waypoints,
});
}

View File

@ -1,8 +1,5 @@
import { Test, TestingModule } from '@nestjs/testing'; import { Test, TestingModule } from '@nestjs/testing';
import { import { AD_REPOSITORY, AD_ROUTE_PROVIDER } from '@modules/ad/ad.di-tokens';
AD_REPOSITORY,
AD_CARPOOL_ROUTE_PROVIDER,
} from '@modules/ad/ad.di-tokens';
import { AggregateID } from '@mobicoop/ddd-library'; import { AggregateID } from '@mobicoop/ddd-library';
import { AdEntity } from '@modules/ad/core/domain/ad.entity'; import { AdEntity } from '@modules/ad/core/domain/ad.entity';
import { ConflictException } from '@mobicoop/ddd-library'; import { ConflictException } from '@mobicoop/ddd-library';
@ -11,7 +8,7 @@ import { CreateAdService } from '@modules/ad/core/application/commands/create-ad
import { CreateAdCommand } from '@modules/ad/core/application/commands/create-ad/create-ad.command'; import { CreateAdCommand } from '@modules/ad/core/application/commands/create-ad/create-ad.command';
import { AdAlreadyExistsException } from '@modules/ad/core/domain/ad.errors'; import { AdAlreadyExistsException } from '@modules/ad/core/domain/ad.errors';
import { WaypointProps } from '@modules/ad/core/domain/value-objects/waypoint.value-object'; import { WaypointProps } from '@modules/ad/core/domain/value-objects/waypoint.value-object';
import { CarpoolRouteProviderPort } from '@modules/ad/core/application/ports/carpool-route-provider.port'; import { RouteProviderPort } from '@modules/ad/core/application/ports/route-provider.port';
const originWaypoint: WaypointProps = { const originWaypoint: WaypointProps = {
position: 0, position: 0,
@ -62,12 +59,10 @@ const mockAdRepository = {
}), }),
}; };
const mockRouteProvider: CarpoolRouteProviderPort = { const mockRouteProvider: RouteProviderPort = {
getBasic: jest.fn().mockImplementation(() => ({ getBasic: jest.fn().mockImplementation(() => ({
driverDistance: 350101, distance: 350101,
driverDuration: 14422, duration: 14422,
passengerDistance: 350101,
passengerDuration: 14422,
fwdAzimuth: 273, fwdAzimuth: 273,
backAzimuth: 93, backAzimuth: 93,
distanceAzimuth: 336544, distanceAzimuth: 336544,
@ -99,7 +94,7 @@ describe('create-ad.service', () => {
useValue: mockAdRepository, useValue: mockAdRepository,
}, },
{ {
provide: AD_CARPOOL_ROUTE_PROVIDER, provide: AD_ROUTE_PROVIDER,
useValue: mockRouteProvider, useValue: mockRouteProvider,
}, },
CreateAdService, CreateAdService,

View File

@ -1,12 +1,12 @@
import { import {
AD_REPOSITORY, AD_REPOSITORY,
AD_CARPOOL_ROUTE_PROVIDER, 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';
import { DateTimeTransformerPort } from '@modules/ad/core/application/ports/datetime-transformer.port'; import { DateTimeTransformerPort } from '@modules/ad/core/application/ports/datetime-transformer.port';
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 { CarpoolRouteProviderPort } from '@modules/ad/core/application/ports/carpool-route-provider.port'; import { RouteProviderPort } from '@modules/ad/core/application/ports/route-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';
@ -74,8 +74,15 @@ const mockInputDateTimeTransformer: DateTimeTransformerPort = {
time: jest.fn(), time: jest.fn(),
}; };
const mockRouteProvider: CarpoolRouteProviderPort = { const mockRouteProvider: RouteProviderPort = {
getBasic: jest.fn(), getBasic: jest.fn().mockImplementation(() => ({
distance: 350101,
duration: 14422,
fwdAzimuth: 273,
backAzimuth: 93,
distanceAzimuth: 336544,
points: [],
})),
}; };
describe('Match Query Handler', () => { describe('Match Query Handler', () => {
@ -98,7 +105,7 @@ describe('Match Query Handler', () => {
useValue: mockInputDateTimeTransformer, useValue: mockInputDateTimeTransformer,
}, },
{ {
provide: AD_CARPOOL_ROUTE_PROVIDER, provide: AD_ROUTE_PROVIDER,
useValue: mockRouteProvider, useValue: mockRouteProvider,
}, },
], ],

View File

@ -1,6 +1,6 @@
import { DateTimeTransformerPort } from '@modules/ad/core/application/ports/datetime-transformer.port'; import { DateTimeTransformerPort } from '@modules/ad/core/application/ports/datetime-transformer.port';
import { DefaultParams } from '@modules/ad/core/application/ports/default-params.type'; import { DefaultParams } from '@modules/ad/core/application/ports/default-params.type';
import { CarpoolRouteProviderPort } from '@modules/ad/core/application/ports/carpool-route-provider.port'; import { RouteProviderPort } from '@modules/ad/core/application/ports/route-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 { 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';
@ -24,6 +24,14 @@ const destinationWaypoint: Waypoint = {
postalCode: '75000', postalCode: '75000',
country: 'France', country: 'France',
}; };
const intermediateWaypoint: Waypoint = {
position: 1,
lat: 48.966912,
lon: 4.3655,
locality: 'Châlons-en-Champagne',
postalCode: '51000',
country: 'France',
};
const defaultParams: DefaultParams = { const defaultParams: DefaultParams = {
DEPARTURE_TIME_MARGIN: 900, DEPARTURE_TIME_MARGIN: 900,
@ -50,16 +58,47 @@ const mockInputDateTimeTransformer: DateTimeTransformerPort = {
time: jest.fn().mockImplementation(() => '23:05'), time: jest.fn().mockImplementation(() => '23:05'),
}; };
const mockRouteProvider: CarpoolRouteProviderPort = { const mockRouteProvider: RouteProviderPort = {
getBasic: jest getBasic: jest
.fn() .fn()
.mockImplementationOnce(() => ({ .mockImplementationOnce(() => ({
driverDistance: undefined, distance: 350101,
driverDuration: undefined, duration: 14422,
passengerDistance: 150120, fwdAzimuth: 273,
passengerDuration: 6540, backAzimuth: 93,
fwdAzimuth: 276, distanceAzimuth: 336544,
backAzimuth: 96, points: [],
}))
.mockImplementationOnce(() => ({
distance: 340102,
duration: 13423,
fwdAzimuth: 273,
backAzimuth: 93,
distanceAzimuth: 336544,
points: [],
}))
.mockImplementationOnce(() => ({
distance: 350101,
duration: 14422,
fwdAzimuth: 273,
backAzimuth: 93,
distanceAzimuth: 336544,
points: [],
}))
.mockImplementationOnce(() => ({
distance: 350101,
duration: 14422,
fwdAzimuth: 273,
backAzimuth: 93,
distanceAzimuth: 336544,
points: [],
}))
.mockImplementationOnce(() => ({
distance: 340102,
duration: 13423,
fwdAzimuth: 273,
backAzimuth: 93,
distanceAzimuth: 336544,
points: [], points: [],
})) }))
.mockImplementationOnce(() => { .mockImplementationOnce(() => {
@ -143,8 +182,10 @@ describe('Match Query', () => {
expect(matchQuery.seatsRequested).toBe(1); expect(matchQuery.seatsRequested).toBe(1);
}); });
it('should set route', async () => { it('should set route for a driver only', async () => {
const matchQuery = new MatchQuery({ const matchQuery = new MatchQuery({
driver: true,
passenger: false,
frequency: Frequency.PUNCTUAL, frequency: Frequency.PUNCTUAL,
fromDate: '2023-08-28', fromDate: '2023-08-28',
toDate: '2023-08-28', toDate: '2023-08-28',
@ -155,9 +196,70 @@ describe('Match Query', () => {
], ],
waypoints: [originWaypoint, destinationWaypoint], waypoints: [originWaypoint, destinationWaypoint],
}); });
await matchQuery.setCarpoolRoute(mockRouteProvider); await matchQuery.setRoutes(mockRouteProvider);
expect(matchQuery.carpoolRoute?.driverDistance).toBeUndefined(); expect(matchQuery.driverRoute?.distance).toBe(350101);
expect(matchQuery.carpoolRoute?.passengerDistance).toBe(150120); expect(matchQuery.passengerRoute).toBeUndefined();
});
it('should set route for a passenger only', async () => {
const matchQuery = new MatchQuery({
driver: false,
passenger: true,
frequency: Frequency.PUNCTUAL,
fromDate: '2023-08-28',
toDate: '2023-08-28',
schedule: [
{
time: '01:05',
},
],
waypoints: [originWaypoint, destinationWaypoint],
});
await matchQuery.setRoutes(mockRouteProvider);
expect(matchQuery.passengerRoute?.distance).toBe(340102);
expect(matchQuery.driverRoute).toBeUndefined();
});
it('should set route for a driver and passenger', async () => {
const matchQuery = new MatchQuery({
driver: true,
passenger: true,
frequency: Frequency.PUNCTUAL,
fromDate: '2023-08-28',
toDate: '2023-08-28',
schedule: [
{
time: '01:05',
},
],
waypoints: [originWaypoint, destinationWaypoint],
});
await matchQuery.setRoutes(mockRouteProvider);
expect(matchQuery.driverRoute?.distance).toBe(350101);
expect(matchQuery.passengerRoute?.distance).toBe(350101);
});
it('should set route for a driver and passenger with 3 waypoints', async () => {
const matchQuery = new MatchQuery({
driver: true,
passenger: true,
frequency: Frequency.PUNCTUAL,
fromDate: '2023-08-28',
toDate: '2023-08-28',
schedule: [
{
time: '01:05',
},
],
waypoints: [
originWaypoint,
intermediateWaypoint,
{ ...destinationWaypoint, position: 2 },
],
});
await matchQuery.setRoutes(mockRouteProvider);
expect(matchQuery.driverRoute?.distance).toBe(350101);
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 () => {
@ -175,7 +277,7 @@ describe('Match Query', () => {
waypoints: [originWaypoint, destinationWaypoint], waypoints: [originWaypoint, destinationWaypoint],
}); });
await expect( await expect(
matchQuery.setCarpoolRoute(mockRouteProvider), matchQuery.setRoutes(mockRouteProvider),
).rejects.toBeInstanceOf(Error); ).rejects.toBeInstanceOf(Error);
}); });
}); });

View File

@ -48,56 +48,36 @@ const candidates: Candidate[] = [
id: 'cc260669-1c6d-441f-80a5-19cd59afb777', id: 'cc260669-1c6d-441f-80a5-19cd59afb777',
}, },
role: Role.DRIVER, role: Role.DRIVER,
baseCarpoolRoute: { waypoints: [
driverDistance: 350101, {
driverDuration: 14422, position: 0,
passengerDistance: 350101, lat: 48.68874,
passengerDuration: 14422, lon: 6.18546,
fwdAzimuth: 273, },
backAzimuth: 93, {
points: [ position: 1,
{ lat: 48.87845,
lon: 6.1765102, lon: 2.36547,
lat: 48.689445, },
}, ],
{
lon: 4.984578,
lat: 48.725687,
},
{
lon: 2.3522,
lat: 48.8566,
},
],
},
}, },
{ {
ad: { ad: {
id: '5600ccfb-ab69-4d03-aa30-0fbe84fcedc0', id: '5600ccfb-ab69-4d03-aa30-0fbe84fcedc0',
}, },
role: Role.PASSENGER, role: Role.PASSENGER,
baseCarpoolRoute: { waypoints: [
driverDistance: 350101, {
driverDuration: 14422, position: 0,
passengerDistance: 350101, lat: 48.69844,
passengerDuration: 14422, lon: 6.168484,
fwdAzimuth: 273, },
backAzimuth: 93, {
points: [ position: 1,
{ lat: 48.855648,
lon: 6.1765102, lon: 2.34645,
lat: 48.689445, },
}, ],
{
lon: 4.984578,
lat: 48.725687,
},
{
lon: 2.3522,
lat: 48.8566,
},
],
},
}, },
]; ];

View File

@ -48,13 +48,33 @@ const matchQuery = new MatchQuery({
strict: false, strict: false,
waypoints: [originWaypoint, destinationWaypoint], waypoints: [originWaypoint, destinationWaypoint],
}); });
matchQuery.carpoolRoute = { matchQuery.driverRoute = {
driverDistance: 150120, distance: 150120,
driverDuration: 6540, duration: 6540,
passengerDistance: 150120,
passengerDuration: 6540,
fwdAzimuth: 276, fwdAzimuth: 276,
backAzimuth: 96, backAzimuth: 96,
distanceAzimuth: 148321,
points: [
{
lat: 48.689445,
lon: 6.17651,
},
{
lat: 48.7566,
lon: 4.3522,
},
{
lat: 48.8566,
lon: 2.3522,
},
],
};
matchQuery.passengerRoute = {
distance: 150120,
duration: 6540,
fwdAzimuth: 276,
backAzimuth: 96,
distanceAzimuth: 148321,
points: [ points: [
{ {
lat: 48.689445, lat: 48.689445,

View File

@ -48,56 +48,36 @@ const candidates: Candidate[] = [
id: 'cc260669-1c6d-441f-80a5-19cd59afb777', id: 'cc260669-1c6d-441f-80a5-19cd59afb777',
}, },
role: Role.DRIVER, role: Role.DRIVER,
baseCarpoolRoute: { waypoints: [
driverDistance: 350101, {
driverDuration: 14422, position: 0,
passengerDistance: 350101, lat: 48.69,
passengerDuration: 14422, lon: 6.18,
fwdAzimuth: 273, },
backAzimuth: 93, {
points: [ position: 1,
{ lat: 48.87,
lon: 6.1765102, lon: 2.37,
lat: 48.689445, },
}, ],
{
lon: 4.984578,
lat: 48.725687,
},
{
lon: 2.3522,
lat: 48.8566,
},
],
},
}, },
{ {
ad: { ad: {
id: '5600ccfb-ab69-4d03-aa30-0fbe84fcedc0', id: '5600ccfb-ab69-4d03-aa30-0fbe84fcedc0',
}, },
role: Role.PASSENGER, role: Role.PASSENGER,
baseCarpoolRoute: { waypoints: [
driverDistance: 350101, {
driverDuration: 14422, position: 0,
passengerDistance: 350101, lat: 48.63584,
passengerDuration: 14422, lon: 6.148754,
fwdAzimuth: 273, },
backAzimuth: 93, {
points: [ position: 1,
{ lat: 48.89874,
lon: 6.1765102, lon: 2.368745,
lat: 48.689445, },
}, ],
{
lon: 4.984578,
lat: 48.725687,
},
{
lon: 2.3522,
lat: 48.8566,
},
],
},
}, },
]; ];

View File

@ -1,10 +1,10 @@
import { import {
AD_DIRECTION_ENCODER, AD_DIRECTION_ENCODER,
AD_MESSAGE_PUBLISHER, AD_MESSAGE_PUBLISHER,
AD_CARPOOL_ROUTE_PROVIDER, AD_ROUTE_PROVIDER,
} from '@modules/ad/ad.di-tokens'; } from '@modules/ad/ad.di-tokens';
import { AdMapper } from '@modules/ad/ad.mapper'; import { AdMapper } from '@modules/ad/ad.mapper';
import { CarpoolRouteProviderPort } from '@modules/ad/core/application/ports/carpool-route-provider.port'; import { RouteProviderPort } from '@modules/ad/core/application/ports/route-provider.port';
import { Frequency } from '@modules/ad/core/domain/ad.types'; import { Frequency } from '@modules/ad/core/domain/ad.types';
import { import {
AdReadModel, AdReadModel,
@ -24,7 +24,7 @@ const mockDirectionEncoder: DirectionEncoderPort = {
decode: jest.fn(), decode: jest.fn(),
}; };
const mockRouteProvider: CarpoolRouteProviderPort = { const mockRouteProvider: RouteProviderPort = {
getBasic: jest.fn(), getBasic: jest.fn(),
}; };
@ -173,7 +173,7 @@ describe('Ad repository', () => {
useValue: mockDirectionEncoder, useValue: mockDirectionEncoder,
}, },
{ {
provide: AD_CARPOOL_ROUTE_PROVIDER, provide: AD_ROUTE_PROVIDER,
useValue: mockRouteProvider, useValue: mockRouteProvider,
}, },
{ {

View File

@ -1,230 +0,0 @@
import { AD_GET_BASIC_ROUTE_CONTROLLER } from '@modules/ad/ad.di-tokens';
import { CarpoolRoute } from '@modules/ad/core/application/types/carpool-route.type';
import { Point } from '@modules/ad/core/application/types/point.type';
import { Role } from '@modules/ad/core/domain/ad.types';
import { CarpoolRouteProvider } from '@modules/ad/infrastructure/carpool-route-provider';
import { GetBasicRouteControllerPort } from '@modules/geography/core/application/ports/get-basic-route-controller.port';
import { Test, TestingModule } from '@nestjs/testing';
const originPoint: Point = {
lat: 48.689445,
lon: 6.17651,
};
const destinationPoint: Point = {
lat: 48.8566,
lon: 2.3522,
};
const additionalPoint: Point = {
lon: 48.7566,
lat: 4.4498,
};
const mockGetBasicRouteController: GetBasicRouteControllerPort = {
get: jest
.fn()
.mockImplementationOnce(() => ({
distance: 350101,
duration: 14422,
fwdAzimuth: 273,
backAzimuth: 93,
distanceAzimuth: 336544,
points: [
{
lon: 6.1765102,
lat: 48.689445,
},
{
lon: 4.984578,
lat: 48.725687,
},
{
lon: 2.3522,
lat: 48.8566,
},
],
}))
.mockImplementationOnce(() => ({
distance: 350102,
duration: 14423,
fwdAzimuth: 273,
backAzimuth: 93,
distanceAzimuth: 336545,
points: [
{
lon: 6.1765103,
lat: 48.689446,
},
{
lon: 4.984579,
lat: 48.725688,
},
{
lon: 2.3523,
lat: 48.8567,
},
],
}))
.mockImplementationOnce(() => ({
distance: 350100,
duration: 14421,
fwdAzimuth: 273,
backAzimuth: 93,
distanceAzimuth: 336543,
points: [
{
lon: 6.1765101,
lat: 48.689444,
},
{
lon: 4.984577,
lat: 48.725686,
},
{
lon: 2.3521,
lat: 48.8565,
},
],
}))
.mockImplementationOnce(() => ({
distance: 350107,
duration: 14427,
fwdAzimuth: 273,
backAzimuth: 93,
distanceAzimuth: 336548,
points: [
{
lon: 6.1765101,
lat: 48.689444,
},
{
lon: 4.984577,
lat: 48.725686,
},
{
lon: 2.3521,
lat: 48.8565,
},
],
}))
.mockImplementationOnce(() => ({
distance: 350108,
duration: 14428,
fwdAzimuth: 273,
backAzimuth: 93,
distanceAzimuth: 336548,
points: [
{
lon: 6.1765101,
lat: 48.689444,
},
{
lon: 4.984577,
lat: 48.725686,
},
{
lon: 2.3521,
lat: 48.8565,
},
],
}))
.mockImplementationOnce(() => []),
};
describe('Carpool route provider', () => {
let carpoolRouteProvider: CarpoolRouteProvider;
beforeAll(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
CarpoolRouteProvider,
{
provide: AD_GET_BASIC_ROUTE_CONTROLLER,
useValue: mockGetBasicRouteController,
},
],
}).compile();
carpoolRouteProvider =
module.get<CarpoolRouteProvider>(CarpoolRouteProvider);
});
it('should be defined', () => {
expect(carpoolRouteProvider).toBeDefined();
});
it('should provide a carpool route for a driver only', async () => {
const carpoolRoute: CarpoolRoute = await carpoolRouteProvider.getBasic(
[Role.DRIVER],
[
{
position: 0,
...originPoint,
},
{
position: 1,
...destinationPoint,
},
],
);
expect(carpoolRoute.driverDistance).toBe(350101);
expect(carpoolRoute.passengerDuration).toBeUndefined();
});
it('should provide a carpool route for a passenger only', async () => {
const carpoolRoute: CarpoolRoute = await carpoolRouteProvider.getBasic(
[Role.PASSENGER],
[
{
position: 0,
...originPoint,
},
{
position: 1,
...destinationPoint,
},
],
);
expect(carpoolRoute.passengerDistance).toBe(350102);
expect(carpoolRoute.driverDuration).toBeUndefined();
});
it('should provide a simple carpool route for a driver and passenger', async () => {
const carpoolRoute: CarpoolRoute = await carpoolRouteProvider.getBasic(
[Role.DRIVER, Role.PASSENGER],
[
{
position: 0,
...originPoint,
},
{
position: 1,
...destinationPoint,
},
],
);
expect(carpoolRoute.driverDuration).toBe(14421);
expect(carpoolRoute.passengerDistance).toBe(350100);
});
it('should provide a complex carpool route for a driver and passenger', async () => {
const carpoolRoute: CarpoolRoute = await carpoolRouteProvider.getBasic(
[Role.DRIVER, Role.PASSENGER],
[
{
position: 0,
...originPoint,
},
{
position: 1,
...additionalPoint,
},
{
position: 2,
...destinationPoint,
},
],
);
expect(carpoolRoute.driverDistance).toBe(350107);
expect(carpoolRoute.passengerDuration).toBe(14428);
});
});

View File

@ -0,0 +1,76 @@
import { AD_GET_BASIC_ROUTE_CONTROLLER } from '@modules/ad/ad.di-tokens';
import { Point } from '@modules/ad/core/application/types/point.type';
import { RouteProvider } from '@modules/ad/infrastructure/route-provider';
import { GetBasicRouteControllerPort } from '@modules/geography/core/application/ports/get-basic-route-controller.port';
import { Route } from '@modules/geography/core/domain/route.types';
import { Test, TestingModule } from '@nestjs/testing';
const originPoint: Point = {
lat: 48.689445,
lon: 6.17651,
};
const destinationPoint: Point = {
lat: 48.8566,
lon: 2.3522,
};
const mockGetBasicRouteController: GetBasicRouteControllerPort = {
get: jest.fn().mockImplementationOnce(() => ({
distance: 350101,
duration: 14422,
fwdAzimuth: 273,
backAzimuth: 93,
distanceAzimuth: 336544,
points: [
{
lon: 6.1765102,
lat: 48.689445,
},
{
lon: 4.984578,
lat: 48.725687,
},
{
lon: 2.3522,
lat: 48.8566,
},
],
})),
};
describe('Route provider', () => {
let routeProvider: RouteProvider;
beforeAll(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
RouteProvider,
{
provide: AD_GET_BASIC_ROUTE_CONTROLLER,
useValue: mockGetBasicRouteController,
},
],
}).compile();
routeProvider = module.get<RouteProvider>(RouteProvider);
});
it('should be defined', () => {
expect(routeProvider).toBeDefined();
});
it('should provide a route', async () => {
const route: Route = await routeProvider.getBasic([
{
position: 0,
...originPoint,
},
{
position: 1,
...destinationPoint,
},
]);
expect(route.distance).toBe(350101);
expect(route.duration).toBe(14422);
});
});

View File

@ -27,7 +27,7 @@ export type Route = {
backAzimuth: number; backAzimuth: number;
distanceAzimuth: number; distanceAzimuth: number;
points: Point[]; points: Point[];
steps: Step[]; steps?: Step[];
}; };
export type Point = { export type Point = {

View File

@ -1,10 +1,11 @@
import { Point, Step } from '@modules/geography/core/domain/route.types'; import { Point, Step } from '@modules/geography/core/domain/route.types';
export class RouteResponseDto { export class RouteResponseDto {
distance?: number; distance: number;
duration?: number; duration: number;
fwdAzimuth: number; fwdAzimuth: number;
backAzimuth: number; backAzimuth: number;
distanceAzimuth: number; distanceAzimuth: number;
points: Step[] | Point[]; points: Point[];
steps?: Step[];
} }

View File

@ -16,12 +16,8 @@ export class RouteMapper
{ {
toResponse = (entity: RouteEntity): RouteResponseDto => { toResponse = (entity: RouteEntity): RouteResponseDto => {
const response = new RouteResponseDto(); const response = new RouteResponseDto();
response.distance = entity.getProps().distance response.distance = Math.round(entity.getProps().distance);
? Math.round(entity.getProps().distance as number) response.duration = Math.round(entity.getProps().duration);
: undefined;
response.duration = entity.getProps().duration
? Math.round(entity.getProps().duration as number)
: undefined;
response.fwdAzimuth = Math.round(entity.getProps().fwdAzimuth); response.fwdAzimuth = Math.round(entity.getProps().fwdAzimuth);
response.backAzimuth = Math.round(entity.getProps().backAzimuth); response.backAzimuth = Math.round(entity.getProps().backAzimuth);
response.distanceAzimuth = Math.round(entity.getProps().distanceAzimuth); response.distanceAzimuth = Math.round(entity.getProps().distanceAzimuth);

View File

@ -4,7 +4,7 @@ import {
GeorouterUnavailableException, GeorouterUnavailableException,
RouteNotFoundException, RouteNotFoundException,
} from '@modules/geography/core/domain/route.errors'; } from '@modules/geography/core/domain/route.errors';
import { Route } from '@modules/geography/core/domain/route.types'; import { Route, Step } from '@modules/geography/core/domain/route.types';
import { import {
GEODESIC, GEODESIC,
PARAMS_PROVIDER, PARAMS_PROVIDER,
@ -411,8 +411,8 @@ describe('Graphhopper Georouter', () => {
}, },
); );
expect(route.steps).toHaveLength(2); expect(route.steps).toHaveLength(2);
expect(route.steps[1].duration).toBe(1800); expect((route.steps as Step[])[1].duration).toBe(1800);
expect(route.steps[1].distance).toBeUndefined(); expect((route.steps as Step[])[1].distance).toBeUndefined();
}); });
it('should create one route with points and missed waypoints extrapolations', async () => { it('should create one route with points and missed waypoints extrapolations', async () => {
@ -468,8 +468,8 @@ describe('Graphhopper Georouter', () => {
points: true, points: true,
}, },
); );
expect(route.steps.length).toBe(3); expect(route.steps).toHaveLength(3);
expect(route.steps[1].duration).toBe(990); expect((route.steps as Step[])[1].duration).toBe(990);
expect(route.steps[1].distance).toBe(25000); expect((route.steps as Step[])[1].distance).toBe(25000);
}); });
}); });