simpler route provider in ad module
This commit is contained in:
parent
6b4ac1792c
commit
59a2644bb4
|
@ -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');
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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>;
|
|
||||||
}
|
|
|
@ -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>;
|
||||||
|
}
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
|
};
|
||||||
|
|
|
@ -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})`,
|
||||||
),
|
),
|
||||||
|
|
|
@ -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 = {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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',
|
|
||||||
}
|
|
|
@ -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,
|
||||||
|
});
|
||||||
|
}
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
|
@ -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);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -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,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -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);
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -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);
|
||||||
|
});
|
||||||
|
});
|
|
@ -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 = {
|
||||||
|
|
|
@ -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[];
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue