rename CarpoolRoute

This commit is contained in:
sbriat 2023-09-06 16:39:44 +02:00
parent 98530af14a
commit d16997a84f
18 changed files with 108 additions and 95 deletions

View File

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

View File

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

View File

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

View File

@ -0,0 +1,10 @@
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

@ -1,10 +0,0 @@
import { Role } from '../../domain/ad.types';
import { Waypoint } from '../types/waypoint.type';
import { Route } from '../types/route.type';
export interface RouteProviderPort {
/**
* Get a basic route with points and overall duration / distance
*/
getBasic(roles: Role[], 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 {
AD_REPOSITORY,
AD_ROUTE_PROVIDER,
AD_CARPOOL_ROUTE_PROVIDER,
INPUT_DATETIME_TRANSFORMER,
PARAMS_PROVIDER,
} 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 { DefaultParams } from '../../ports/default-params.type';
import { DateTimeTransformerPort } from '../../ports/datetime-transformer.port';
import { RouteProviderPort } from '../../ports/route-provider.port';
import { CarpoolRouteProviderPort } from '../../ports/carpool-route-provider.port';
@QueryHandler(MatchQuery)
export class MatchQueryHandler implements IQueryHandler {
@ -27,8 +27,8 @@ export class MatchQueryHandler implements IQueryHandler {
@Inject(AD_REPOSITORY) private readonly repository: AdRepositoryPort,
@Inject(INPUT_DATETIME_TRANSFORMER)
private readonly datetimeTransformer: DateTimeTransformerPort,
@Inject(AD_ROUTE_PROVIDER)
private readonly routeProvider: RouteProviderPort,
@Inject(AD_CARPOOL_ROUTE_PROVIDER)
private readonly routeProvider: CarpoolRouteProviderPort,
) {
this._defaultParams = defaultParamsProvider.getParams();
}
@ -54,7 +54,7 @@ export class MatchQueryHandler implements IQueryHandler {
maxDetourDurationRatio: this._defaultParams.MAX_DETOUR_DURATION_RATIO,
})
.setDatesAndSchedule(this.datetimeTransformer);
await query.setRoute(this.routeProvider);
await query.setCarpoolRoute(this.routeProvider);
let algorithm: Algorithm;
switch (query.algorithmType) {

View File

@ -4,8 +4,8 @@ import { Waypoint } from '../../types/waypoint.type';
import { Frequency, Role } from '@modules/ad/core/domain/ad.types';
import { MatchRequestDto } from '@modules/ad/interface/grpc-controllers/dtos/match.request.dto';
import { DateTimeTransformerPort } from '../../ports/datetime-transformer.port';
import { Route } from '../../types/route.type';
import { RouteProviderPort } from '../../ports/route-provider.port';
import { CarpoolRoute } from '../../types/carpool-route.type';
import { CarpoolRouteProviderPort } from '../../ports/carpool-route-provider.port';
export class MatchQuery extends QueryBase {
driver?: boolean;
@ -28,7 +28,7 @@ export class MatchQuery extends QueryBase {
maxDetourDurationRatio?: number;
readonly page?: number;
readonly perPage?: number;
route?: Route;
carpoolRoute?: CarpoolRoute;
constructor(props: MatchRequestDto) {
super();
@ -165,12 +165,17 @@ export class MatchQuery extends QueryBase {
return this;
};
setRoute = async (routeProvider: RouteProviderPort): Promise<MatchQuery> => {
setCarpoolRoute = async (
carpoolRouteProvider: CarpoolRouteProviderPort,
): Promise<MatchQuery> => {
const roles: Role[] = [];
if (this.driver) roles.push(Role.DRIVER);
if (this.passenger) roles.push(Role.PASSENGER);
try {
this.route = await routeProvider.getBasic(roles, this.waypoints);
this.carpoolRoute = await carpoolRouteProvider.getBasic(
roles,
this.waypoints,
);
} catch (e: any) {
throw new Error('Unable to find a route for given waypoints');
}

View File

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

View File

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

View File

@ -1,19 +1,22 @@
import { Inject, Injectable } from '@nestjs/common';
import { RouteProviderPort } from '../core/application/ports/route-provider.port';
import { Route } from '../core/application/types/route.type';
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';
@Injectable()
export class RouteProvider implements RouteProviderPort {
export class CarpoolRouteProvider implements CarpoolRouteProviderPort {
constructor(
@Inject(AD_GET_BASIC_ROUTE_CONTROLLER)
private readonly getBasicRouteController: GetBasicRouteControllerPort,
) {}
getBasic = async (roles: Role[], waypoints: Waypoint[]): Promise<Route> =>
getBasic = async (
roles: Role[],
waypoints: Waypoint[],
): Promise<CarpoolRoute> =>
await this.getBasicRouteController.get({
roles,
waypoints,

View File

@ -1,5 +1,8 @@
import { Test, TestingModule } from '@nestjs/testing';
import { AD_REPOSITORY, AD_ROUTE_PROVIDER } from '@modules/ad/ad.di-tokens';
import {
AD_REPOSITORY,
AD_CARPOOL_ROUTE_PROVIDER,
} from '@modules/ad/ad.di-tokens';
import { AggregateID } from '@mobicoop/ddd-library';
import { AdEntity } from '@modules/ad/core/domain/ad.entity';
import { ConflictException } from '@mobicoop/ddd-library';
@ -8,7 +11,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 { AdAlreadyExistsException } from '@modules/ad/core/domain/ad.errors';
import { WaypointProps } from '@modules/ad/core/domain/value-objects/waypoint.value-object';
import { RouteProviderPort } from '@modules/ad/core/application/ports/route-provider.port';
import { CarpoolRouteProviderPort } from '@modules/ad/core/application/ports/carpool-route-provider.port';
const originWaypoint: WaypointProps = {
position: 0,
@ -59,7 +62,7 @@ const mockAdRepository = {
}),
};
const mockRouteProvider: RouteProviderPort = {
const mockRouteProvider: CarpoolRouteProviderPort = {
getBasic: jest.fn().mockImplementation(() => ({
driverDistance: 350101,
driverDuration: 14422,
@ -96,7 +99,7 @@ describe('create-ad.service', () => {
useValue: mockAdRepository,
},
{
provide: AD_ROUTE_PROVIDER,
provide: AD_CARPOOL_ROUTE_PROVIDER,
useValue: mockRouteProvider,
},
CreateAdService,

View File

@ -1,12 +1,12 @@
import {
AD_REPOSITORY,
AD_ROUTE_PROVIDER,
AD_CARPOOL_ROUTE_PROVIDER,
INPUT_DATETIME_TRANSFORMER,
PARAMS_PROVIDER,
} from '@modules/ad/ad.di-tokens';
import { DateTimeTransformerPort } from '@modules/ad/core/application/ports/datetime-transformer.port';
import { DefaultParamsProviderPort } from '@modules/ad/core/application/ports/default-params-provider.port';
import { RouteProviderPort } from '@modules/ad/core/application/ports/route-provider.port';
import { CarpoolRouteProviderPort } from '@modules/ad/core/application/ports/carpool-route-provider.port';
import { MatchQuery } from '@modules/ad/core/application/queries/match/match.query';
import { MatchQueryHandler } from '@modules/ad/core/application/queries/match/match.query-handler';
import { AlgorithmType } from '@modules/ad/core/application/types/algorithm.types';
@ -74,7 +74,7 @@ const mockInputDateTimeTransformer: DateTimeTransformerPort = {
time: jest.fn(),
};
const mockRouteProvider: RouteProviderPort = {
const mockRouteProvider: CarpoolRouteProviderPort = {
getBasic: jest.fn(),
};
@ -98,7 +98,7 @@ describe('Match Query Handler', () => {
useValue: mockInputDateTimeTransformer,
},
{
provide: AD_ROUTE_PROVIDER,
provide: AD_CARPOOL_ROUTE_PROVIDER,
useValue: mockRouteProvider,
},
],

View File

@ -1,6 +1,6 @@
import { DateTimeTransformerPort } from '@modules/ad/core/application/ports/datetime-transformer.port';
import { DefaultParams } from '@modules/ad/core/application/ports/default-params.type';
import { RouteProviderPort } from '@modules/ad/core/application/ports/route-provider.port';
import { CarpoolRouteProviderPort } from '@modules/ad/core/application/ports/carpool-route-provider.port';
import { MatchQuery } from '@modules/ad/core/application/queries/match/match.query';
import { AlgorithmType } from '@modules/ad/core/application/types/algorithm.types';
import { Waypoint } from '@modules/ad/core/application/types/waypoint.type';
@ -50,7 +50,7 @@ const mockInputDateTimeTransformer: DateTimeTransformerPort = {
time: jest.fn().mockImplementation(() => '23:05'),
};
const mockRouteProvider: RouteProviderPort = {
const mockRouteProvider: CarpoolRouteProviderPort = {
getBasic: jest
.fn()
.mockImplementationOnce(() => ({
@ -155,9 +155,9 @@ describe('Match Query', () => {
],
waypoints: [originWaypoint, destinationWaypoint],
});
await matchQuery.setRoute(mockRouteProvider);
expect(matchQuery.route?.driverDistance).toBeUndefined();
expect(matchQuery.route?.passengerDistance).toBe(150120);
await matchQuery.setCarpoolRoute(mockRouteProvider);
expect(matchQuery.carpoolRoute?.driverDistance).toBeUndefined();
expect(matchQuery.carpoolRoute?.passengerDistance).toBe(150120);
});
it('should throw an exception if route is not found', async () => {
@ -174,8 +174,8 @@ describe('Match Query', () => {
],
waypoints: [originWaypoint, destinationWaypoint],
});
await expect(matchQuery.setRoute(mockRouteProvider)).rejects.toBeInstanceOf(
Error,
);
await expect(
matchQuery.setCarpoolRoute(mockRouteProvider),
).rejects.toBeInstanceOf(Error);
});
});

View File

@ -48,7 +48,7 @@ const matchQuery = new MatchQuery({
strict: false,
waypoints: [originWaypoint, destinationWaypoint],
});
matchQuery.route = {
matchQuery.carpoolRoute = {
driverDistance: 150120,
driverDuration: 6540,
passengerDistance: 150120,

View File

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

View File

@ -1,7 +1,7 @@
import { AD_GET_BASIC_ROUTE_CONTROLLER } from '@modules/ad/ad.di-tokens';
import { Route } from '@modules/ad/core/application/types/route.type';
import { CarpoolRoute } from '@modules/ad/core/application/types/carpool-route.type';
import { Role } from '@modules/ad/core/domain/ad.types';
import { RouteProvider } from '@modules/ad/infrastructure/route-provider';
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';
@ -27,13 +27,13 @@ const mockGetBasicRouteController: GetBasicRouteControllerPort = {
})),
};
describe('Route provider', () => {
let routeProvider: RouteProvider;
describe('Carpool route provider', () => {
let carpoolRouteProvider: CarpoolRouteProvider;
beforeAll(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
RouteProvider,
CarpoolRouteProvider,
{
provide: AD_GET_BASIC_ROUTE_CONTROLLER,
useValue: mockGetBasicRouteController,
@ -41,15 +41,16 @@ describe('Route provider', () => {
],
}).compile();
routeProvider = module.get<RouteProvider>(RouteProvider);
carpoolRouteProvider =
module.get<CarpoolRouteProvider>(CarpoolRouteProvider);
});
it('should be defined', () => {
expect(routeProvider).toBeDefined();
expect(carpoolRouteProvider).toBeDefined();
});
it('should provide a route', async () => {
const route: Route = await routeProvider.getBasic(
it('should provide a carpool route', async () => {
const carpoolRoute: CarpoolRoute = await carpoolRouteProvider.getBasic(
[Role.DRIVER],
[
{
@ -64,6 +65,6 @@ describe('Route provider', () => {
},
],
);
expect(route.driverDistance).toBe(23000);
expect(carpoolRoute.driverDistance).toBe(23000);
});
});

View File

@ -15,16 +15,11 @@ export class RouteEntity extends AggregateRoot<RouteProps> {
protected readonly _id: AggregateID;
static create = async (create: CreateRouteProps): Promise<RouteEntity> => {
let routes: Route[];
try {
routes = await create.georouter.routes(
this.getPaths(create.roles, create.waypoints),
create.georouterSettings,
);
if (!routes || routes.length == 0) throw new RouteNotFoundException();
} catch (e: any) {
throw e;
}
const routes: Route[] = await create.georouter.routes(
this.getPaths(create.roles, create.waypoints),
create.georouterSettings,
);
if (!routes || routes.length == 0) throw new RouteNotFoundException();
let baseRoute: Route;
let driverRoute: Route | undefined;
let passengerRoute: Route | undefined;

View File

@ -39,16 +39,16 @@ export class GraphhopperGeorouter implements GeorouterPort {
paths: Path[],
settings: GeorouterSettings,
): Promise<Route[]> => {
this.setDefaultUrlArgs();
this.setSettings(settings);
return this.getRoutes(paths);
this._setDefaultUrlArgs();
this._setSettings(settings);
return this._getRoutes(paths);
};
private setDefaultUrlArgs = (): void => {
private _setDefaultUrlArgs = (): void => {
this.urlArgs = ['vehicle=car', 'weighting=fastest', 'points_encoded=false'];
};
private setSettings = (settings: GeorouterSettings): void => {
private _setSettings = (settings: GeorouterSettings): void => {
if (settings.detailedDuration) {
this.urlArgs.push('details=time');
}
@ -62,7 +62,7 @@ export class GraphhopperGeorouter implements GeorouterPort {
}
};
private getRoutes = async (paths: Path[]): Promise<Route[]> => {
private _getRoutes = async (paths: Path[]): Promise<Route[]> => {
const routes = Promise.all(
paths.map(async (path) => {
const url: string = [