mirror of
https://gitlab.com/mobicoop/v3/service/matcher.git
synced 2026-01-01 08:22:41 +00:00
add route provider in ad module
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
import { IQueryHandler, QueryHandler } from '@nestjs/cqrs';
|
||||
import { GetRouteQuery } from './get-route.query';
|
||||
import { RouteEntity } from '@modules/geography/core/domain/route.entity';
|
||||
import { Inject } from '@nestjs/common';
|
||||
import { GEOROUTER } from '@modules/geography/geography.di-tokens';
|
||||
import { GeorouterPort } from '../../ports/georouter.port';
|
||||
|
||||
@QueryHandler(GetRouteQuery)
|
||||
export class GetRouteQueryHandler implements IQueryHandler {
|
||||
constructor(@Inject(GEOROUTER) private readonly georouter: GeorouterPort) {}
|
||||
|
||||
execute = async (query: GetRouteQuery): Promise<RouteEntity> =>
|
||||
await RouteEntity.create({
|
||||
roles: query.roles,
|
||||
waypoints: query.waypoints,
|
||||
georouter: this.georouter,
|
||||
georouterSettings: query.georouterSettings,
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import { QueryBase } from '@mobicoop/ddd-library';
|
||||
import { Role } from '@modules/geography/core/domain/route.types';
|
||||
import { Waypoint } from '../../types/waypoint.type';
|
||||
import { GeorouterSettings } from '../../types/georouter-settings.type';
|
||||
|
||||
export class GetRouteQuery extends QueryBase {
|
||||
readonly roles: Role[];
|
||||
readonly waypoints: Waypoint[];
|
||||
readonly georouterSettings: GeorouterSettings;
|
||||
|
||||
constructor(
|
||||
roles: Role[],
|
||||
waypoints: Waypoint[],
|
||||
georouterSettings: GeorouterSettings,
|
||||
) {
|
||||
super();
|
||||
this.roles = roles;
|
||||
this.waypoints = waypoints;
|
||||
this.georouterSettings = georouterSettings;
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,14 @@
|
||||
import { PathType } from '../../domain/route.types';
|
||||
import { Point } from './point.type';
|
||||
import { SpacetimePoint } from './spacetime-point.type';
|
||||
|
||||
export type Route = {
|
||||
name: string;
|
||||
type: PathType;
|
||||
distance: number;
|
||||
duration: number;
|
||||
fwdAzimuth: number;
|
||||
backAzimuth: number;
|
||||
distanceAzimuth: number;
|
||||
points: Point[];
|
||||
spacetimePoints: SpacetimePoint[];
|
||||
};
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
import { Point } from './point.type';
|
||||
|
||||
export type SpacetimePoint = Point & {
|
||||
duration: number;
|
||||
distance: number;
|
||||
};
|
||||
@@ -0,0 +1,5 @@
|
||||
import { Point } from './point.type';
|
||||
|
||||
export type Waypoint = Point & {
|
||||
position: number;
|
||||
};
|
||||
@@ -5,19 +5,61 @@ import {
|
||||
Role,
|
||||
RouteProps,
|
||||
PathType,
|
||||
Direction,
|
||||
} from './route.types';
|
||||
import { WaypointProps } from './value-objects/waypoint.value-object';
|
||||
import { Route } from '../application/types/route.type';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
export class RouteEntity extends AggregateRoot<RouteProps> {
|
||||
protected readonly _id: AggregateID;
|
||||
|
||||
static create = async (create: CreateRouteProps): Promise<RouteEntity> => {
|
||||
const props: RouteProps = await create.georouter.routes(
|
||||
const directions: Direction[] = await create.georouter.routes(
|
||||
this.getPaths(create.roles, create.waypoints),
|
||||
create.georouterSettings,
|
||||
);
|
||||
const route = new RouteEntity({ props });
|
||||
return route;
|
||||
let driverRoute: Route;
|
||||
let passengerRoute: Route;
|
||||
if (directions.some((route: Route) => route.type == PathType.GENERIC)) {
|
||||
driverRoute = passengerRoute = directions.find(
|
||||
(route: Route) => route.type == PathType.GENERIC,
|
||||
);
|
||||
} else {
|
||||
driverRoute = directions.some(
|
||||
(route: Route) => route.type == PathType.DRIVER,
|
||||
)
|
||||
? directions.find((route: Route) => route.type == PathType.DRIVER)
|
||||
: undefined;
|
||||
passengerRoute = directions.some(
|
||||
(route: Route) => route.type == PathType.PASSENGER,
|
||||
)
|
||||
? directions.find((route: Route) => route.type == PathType.PASSENGER)
|
||||
: undefined;
|
||||
}
|
||||
const routeProps: RouteProps = {
|
||||
driverDistance: driverRoute?.distance,
|
||||
driverDuration: driverRoute?.duration,
|
||||
passengerDistance: passengerRoute?.distance,
|
||||
passengerDuration: passengerRoute?.duration,
|
||||
fwdAzimuth: driverRoute
|
||||
? driverRoute.fwdAzimuth
|
||||
: passengerRoute.fwdAzimuth,
|
||||
backAzimuth: driverRoute
|
||||
? driverRoute.backAzimuth
|
||||
: passengerRoute.backAzimuth,
|
||||
distanceAzimuth: driverRoute
|
||||
? driverRoute.distanceAzimuth
|
||||
: passengerRoute.distanceAzimuth,
|
||||
waypoints: create.waypoints,
|
||||
spacetimePoints: driverRoute
|
||||
? driverRoute.spacetimePoints
|
||||
: passengerRoute.spacetimePoints,
|
||||
};
|
||||
return new RouteEntity({
|
||||
id: v4(),
|
||||
props: routeProps,
|
||||
});
|
||||
};
|
||||
|
||||
validate(): void {
|
||||
@@ -32,39 +74,40 @@ export class RouteEntity extends AggregateRoot<RouteProps> {
|
||||
if (roles.includes(Role.DRIVER) && roles.includes(Role.PASSENGER)) {
|
||||
if (waypoints.length == 2) {
|
||||
// 2 points => same route for driver and passenger
|
||||
const commonPath: Path = {
|
||||
type: PathType.COMMON,
|
||||
points: waypoints,
|
||||
};
|
||||
paths.push(commonPath);
|
||||
paths.push(this.createGenericPath(waypoints));
|
||||
} else {
|
||||
const driverPath: Path = RouteEntity.createDriverPath(waypoints);
|
||||
const passengerPath: Path = RouteEntity.createPassengerPath(waypoints);
|
||||
paths.push(driverPath, passengerPath);
|
||||
paths.push(
|
||||
this.createDriverPath(waypoints),
|
||||
this.createPassengerPath(waypoints),
|
||||
);
|
||||
}
|
||||
} else if (roles.includes(Role.DRIVER)) {
|
||||
const driverPath: Path = RouteEntity.createDriverPath(waypoints);
|
||||
paths.push(driverPath);
|
||||
paths.push(this.createDriverPath(waypoints));
|
||||
} else if (roles.includes(Role.PASSENGER)) {
|
||||
const passengerPath: Path = RouteEntity.createPassengerPath(waypoints);
|
||||
paths.push(passengerPath);
|
||||
paths.push(this.createPassengerPath(waypoints));
|
||||
}
|
||||
return paths;
|
||||
};
|
||||
|
||||
private static createDriverPath = (waypoints: WaypointProps[]): Path => {
|
||||
return {
|
||||
type: PathType.DRIVER,
|
||||
points: waypoints,
|
||||
};
|
||||
};
|
||||
private static createGenericPath = (waypoints: WaypointProps[]): Path =>
|
||||
this.createPath(waypoints, PathType.GENERIC);
|
||||
|
||||
private static createPassengerPath = (waypoints: WaypointProps[]): Path => {
|
||||
return {
|
||||
type: PathType.PASSENGER,
|
||||
points: [waypoints[0], waypoints[waypoints.length - 1]],
|
||||
};
|
||||
};
|
||||
private static createDriverPath = (waypoints: WaypointProps[]): Path =>
|
||||
this.createPath(waypoints, PathType.DRIVER);
|
||||
|
||||
private static createPassengerPath = (waypoints: WaypointProps[]): Path =>
|
||||
this.createPath(
|
||||
[waypoints[0], waypoints[waypoints.length - 1]],
|
||||
PathType.PASSENGER,
|
||||
);
|
||||
|
||||
private static createPath = (
|
||||
points: WaypointProps[],
|
||||
type: PathType,
|
||||
): Path => ({
|
||||
type,
|
||||
points,
|
||||
});
|
||||
}
|
||||
|
||||
// import { IGeodesic } from '../interfaces/geodesic.interface';
|
||||
|
||||
@@ -5,9 +5,10 @@ import { WaypointProps } from './value-objects/waypoint.value-object';
|
||||
|
||||
// All properties that a Route has
|
||||
export interface RouteProps {
|
||||
name: string;
|
||||
distance: number;
|
||||
duration: number;
|
||||
driverDistance?: number;
|
||||
driverDuration?: number;
|
||||
passengerDistance?: number;
|
||||
passengerDuration?: number;
|
||||
fwdAzimuth: number;
|
||||
backAzimuth: number;
|
||||
distanceAzimuth: number;
|
||||
@@ -23,6 +24,17 @@ export interface CreateRouteProps {
|
||||
georouterSettings: GeorouterSettings;
|
||||
}
|
||||
|
||||
export type Direction = {
|
||||
type: PathType;
|
||||
distance: number;
|
||||
duration: number;
|
||||
fwdAzimuth: number;
|
||||
backAzimuth: number;
|
||||
distanceAzimuth: number;
|
||||
points: Point[];
|
||||
spacetimePoints: SpacetimePoint[];
|
||||
};
|
||||
|
||||
export type Path = {
|
||||
type: PathType;
|
||||
points: Point[];
|
||||
@@ -34,6 +46,11 @@ export type Point = {
|
||||
context?: PointContext;
|
||||
};
|
||||
|
||||
export type SpacetimePoint = Point & {
|
||||
duration: number;
|
||||
distance: number;
|
||||
};
|
||||
|
||||
export enum Role {
|
||||
DRIVER = 'DRIVER',
|
||||
PASSENGER = 'PASSENGER',
|
||||
@@ -48,7 +65,7 @@ export enum PointContext {
|
||||
}
|
||||
|
||||
export enum PathType {
|
||||
COMMON = 'common',
|
||||
GENERIC = 'generic',
|
||||
DRIVER = 'driver',
|
||||
PASSENGER = 'passenger',
|
||||
}
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
export const PARAMS_PROVIDER = Symbol('PARAMS_PROVIDER');
|
||||
export const DIRECTION_ENCODER = Symbol('DIRECTION_ENCODER');
|
||||
export const GEOROUTER = Symbol('GEOROUTER');
|
||||
|
||||
39
src/modules/geography/geography.mapper.ts
Normal file
39
src/modules/geography/geography.mapper.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { Mapper } from '@mobicoop/ddd-library';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { RouteEntity } from './core/domain/route.entity';
|
||||
import { RouteResponseDto } from './interface/dtos/route.response.dto';
|
||||
|
||||
/**
|
||||
* Mapper constructs objects that are used in different layers:
|
||||
* Record is an object that is stored in a database,
|
||||
* Entity is an object that is used in application domain layer,
|
||||
* and a ResponseDTO is an object returned to a user (usually as json).
|
||||
*/
|
||||
|
||||
@Injectable()
|
||||
export class RouteMapper
|
||||
implements Mapper<RouteEntity, undefined, undefined, RouteResponseDto>
|
||||
{
|
||||
toPersistence = (): undefined => {
|
||||
return undefined;
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
toDomain = (): undefined => {
|
||||
return undefined;
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
toResponse = (entity: RouteEntity): RouteResponseDto => {
|
||||
const response = new RouteResponseDto();
|
||||
response.driverDistance = entity.getProps().driverDistance;
|
||||
response.driverDuration = entity.getProps().driverDuration;
|
||||
response.passengerDistance = entity.getProps().passengerDistance;
|
||||
response.passengerDuration = entity.getProps().passengerDuration;
|
||||
response.fwdAzimuth = entity.getProps().fwdAzimuth;
|
||||
response.backAzimuth = entity.getProps().backAzimuth;
|
||||
response.distanceAzimuth = entity.getProps().distanceAzimuth;
|
||||
response.spacetimePoints = entity.getProps().spacetimePoints;
|
||||
return response;
|
||||
};
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import { CqrsModule } from '@nestjs/cqrs';
|
||||
import { DIRECTION_ENCODER, PARAMS_PROVIDER } from './geography.di-tokens';
|
||||
import { DefaultParamsProvider } from './infrastructure/default-params-provider';
|
||||
import { PostgresDirectionEncoder } from './infrastructure/postgres-direction-encoder';
|
||||
import { GetRouteController } from './interface/controllers/get-route.controller';
|
||||
|
||||
const adapters: Provider[] = [
|
||||
{
|
||||
@@ -13,11 +14,12 @@ const adapters: Provider[] = [
|
||||
provide: DIRECTION_ENCODER,
|
||||
useClass: PostgresDirectionEncoder,
|
||||
},
|
||||
GetRouteController,
|
||||
];
|
||||
|
||||
@Module({
|
||||
imports: [CqrsModule],
|
||||
providers: [...adapters],
|
||||
exports: [DIRECTION_ENCODER],
|
||||
exports: [DIRECTION_ENCODER, GetRouteController],
|
||||
})
|
||||
export class GeographyModule {}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import { GeorouterSettings } from '@modules/geography/core/application/types/georouter-settings.type';
|
||||
import { Waypoint } from '@modules/geography/core/application/types/waypoint.type';
|
||||
import { Role } from '@modules/geography/core/domain/route.types';
|
||||
|
||||
export class GetRouteRequestDto {
|
||||
roles: Role[];
|
||||
waypoints: Waypoint[];
|
||||
georouterSettings: GeorouterSettings;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import { QueryBus } from '@nestjs/cqrs';
|
||||
import { RouteResponseDto } from '../dtos/route.response.dto';
|
||||
import { GetRouteRequestDto } from './dtos/get-route.request.dto';
|
||||
import { RouteEntity } from '@modules/geography/core/domain/route.entity';
|
||||
import { GetRouteQuery } from '@modules/geography/core/application/queries/get-route/get-route.query';
|
||||
import { RouteMapper } from '@modules/geography/geography.mapper';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
@Injectable()
|
||||
export class GetRouteController {
|
||||
constructor(
|
||||
private readonly queryBus: QueryBus,
|
||||
private readonly mapper: RouteMapper,
|
||||
) {}
|
||||
|
||||
async get(data: GetRouteRequestDto): Promise<RouteResponseDto> {
|
||||
try {
|
||||
const route: RouteEntity = await this.queryBus.execute(
|
||||
new GetRouteQuery(data.roles, data.waypoints, data.georouterSettings),
|
||||
);
|
||||
return this.mapper.toResponse(route);
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
12
src/modules/geography/interface/dtos/route.response.dto.ts
Normal file
12
src/modules/geography/interface/dtos/route.response.dto.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { SpacetimePoint } from '@modules/geography/core/application/types/spacetime-point.type';
|
||||
|
||||
export class RouteResponseDto {
|
||||
driverDistance?: number;
|
||||
driverDuration?: number;
|
||||
passengerDistance?: number;
|
||||
passengerDuration?: number;
|
||||
fwdAzimuth: number;
|
||||
backAzimuth: number;
|
||||
distanceAzimuth: number;
|
||||
spacetimePoints: SpacetimePoint[];
|
||||
}
|
||||
Reference in New Issue
Block a user