add route provider in ad module

This commit is contained in:
sbriat 2023-08-21 14:40:04 +02:00
parent 88326dcf6f
commit bff199557a
20 changed files with 330 additions and 46 deletions

View File

@ -1,4 +1,4 @@
export const AD_REPOSITORY = Symbol('AD_REPOSITORY'); export const AD_REPOSITORY = Symbol('AD_REPOSITORY');
export const GEOROUTER = Symbol('GEOROUTER');
export const AD_DIRECTION_ENCODER = Symbol('AD_DIRECTION_ENCODER'); export const AD_DIRECTION_ENCODER = Symbol('AD_DIRECTION_ENCODER');
export const AD_MESSAGE_PUBLISHER = Symbol('AD_MESSAGE_PUBLISHER'); export const AD_MESSAGE_PUBLISHER = Symbol('AD_MESSAGE_PUBLISHER');
export const AD_ROUTE_PROVIDER = Symbol('AD_ROUTE_PROVIDER');

View File

@ -6,11 +6,13 @@ import {
AdReadModel, AdReadModel,
ScheduleItemModel, ScheduleItemModel,
} from './infrastructure/ad.repository'; } from './infrastructure/ad.repository';
import { Frequency } from './core/domain/ad.types'; import { Frequency, Role } from './core/domain/ad.types';
import { v4 } from 'uuid'; import { v4 } from 'uuid';
import { ScheduleItemProps } from './core/domain/value-objects/schedule-item.value-object'; import { ScheduleItemProps } from './core/domain/value-objects/schedule-item.value-object';
import { DirectionEncoderPort } from '@modules/geography/core/application/ports/direction-encoder.port'; import { DirectionEncoderPort } from '@modules/geography/core/application/ports/direction-encoder.port';
import { AD_DIRECTION_ENCODER } from './ad.di-tokens'; import { AD_DIRECTION_ENCODER, AD_ROUTE_PROVIDER } from './ad.di-tokens';
import { RouteProviderPort } from './core/application/ports/route-provider.port';
import { RouteResponseDto } from '@modules/geography/interface/dtos/route.response.dto';
/** /**
* Mapper constructs objects that are used in different layers: * Mapper constructs objects that are used in different layers:
@ -26,11 +28,25 @@ export class AdMapper
constructor( constructor(
@Inject(AD_DIRECTION_ENCODER) @Inject(AD_DIRECTION_ENCODER)
private readonly directionEncoder: DirectionEncoderPort, private readonly directionEncoder: DirectionEncoderPort,
@Inject(AD_ROUTE_PROVIDER)
private readonly routeProvider: RouteProviderPort,
) {} ) {}
toPersistence = (entity: AdEntity): AdWriteModel => { toPersistence = (entity: AdEntity): AdWriteModel => {
const copy = entity.getProps(); const copy = entity.getProps();
const now = new Date(); const now = new Date();
const roles: Role[] = [];
if (copy.driver) roles.push(Role.DRIVER);
if (copy.passenger) roles.push(Role.PASSENGER);
const route: RouteResponseDto = this.routeProvider.get(
roles,
copy.waypoints,
{
withDistance: true,
withPoints: true,
withTime: false,
},
);
const record: AdWriteModel = { const record: AdWriteModel = {
uuid: copy.id, uuid: copy.id,
driver: copy.driver, driver: copy.driver,
@ -57,14 +73,14 @@ export class AdMapper
seatsProposed: copy.seatsProposed, seatsProposed: copy.seatsProposed,
seatsRequested: copy.seatsRequested, seatsRequested: copy.seatsRequested,
strict: copy.strict, strict: copy.strict,
driverDuration: copy.driverDuration, driverDuration: route.driverDuration,
driverDistance: copy.driverDistance, driverDistance: route.driverDistance,
passengerDuration: copy.passengerDuration, passengerDuration: route.passengerDuration,
passengerDistance: copy.passengerDistance, passengerDistance: route.passengerDistance,
waypoints: this.directionEncoder.encode(copy.waypoints), waypoints: this.directionEncoder.encode(copy.waypoints),
direction: '', direction: this.directionEncoder.encode(route.spacetimePoints),
fwdAzimuth: copy.fwdAzimuth, fwdAzimuth: route.fwdAzimuth,
backAzimuth: copy.backAzimuth, backAzimuth: route.backAzimuth,
createdAt: copy.createdAt, createdAt: copy.createdAt,
updatedAt: copy.updatedAt, updatedAt: copy.updatedAt,
}; };

View File

@ -4,6 +4,7 @@ import {
AD_MESSAGE_PUBLISHER, AD_MESSAGE_PUBLISHER,
AD_REPOSITORY, AD_REPOSITORY,
AD_DIRECTION_ENCODER, AD_DIRECTION_ENCODER,
AD_ROUTE_PROVIDER,
} from './ad.di-tokens'; } from './ad.di-tokens';
import { MessageBrokerPublisher } from '@mobicoop/message-broker-module'; import { MessageBrokerPublisher } from '@mobicoop/message-broker-module';
import { AdRepository } from './infrastructure/ad.repository'; import { AdRepository } from './infrastructure/ad.repository';
@ -11,6 +12,7 @@ import { PrismaService } from './infrastructure/prisma.service';
import { AdMapper } from './ad.mapper'; 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 { GetRouteController } from '@modules/geography/interface/controllers/get-route.controller';
const messageHandlers = [AdCreatedMessageHandler]; const messageHandlers = [AdCreatedMessageHandler];
@ -37,6 +39,10 @@ const adapters: Provider[] = [
provide: AD_DIRECTION_ENCODER, provide: AD_DIRECTION_ENCODER,
useClass: PostgresDirectionEncoder, useClass: PostgresDirectionEncoder,
}, },
{
provide: AD_ROUTE_PROVIDER,
useClass: GetRouteController,
},
]; ];
@Module({ @Module({

View File

@ -0,0 +1,12 @@
import { GeorouterSettings } from '@modules/geography/core/application/types/georouter-settings.type';
import { Waypoint } from '@modules/geography/core/application/types/waypoint.type';
import { RouteResponseDto } from '@modules/geography/interface/dtos/route.response.dto';
import { Role } from '../../domain/ad.types';
export interface RouteProviderPort {
get(
roles: Role[],
waypoints: Waypoint[],
georouterSettings: GeorouterSettings,
): RouteResponseDto;
}

View File

@ -48,3 +48,8 @@ export enum PointContext {
VENUE = 'VENUE', VENUE = 'VENUE',
OTHER = 'OTHER', OTHER = 'OTHER',
} }
export enum Role {
DRIVER = 'DRIVER',
PASSENGER = 'PASSENGER',
}

View File

@ -1,5 +1,9 @@
import { AD_DIRECTION_ENCODER } from '@modules/ad/ad.di-tokens'; import {
AD_DIRECTION_ENCODER,
AD_ROUTE_PROVIDER,
} from '@modules/ad/ad.di-tokens';
import { AdMapper } from '@modules/ad/ad.mapper'; import { AdMapper } from '@modules/ad/ad.mapper';
import { RouteProviderPort } from '@modules/ad/core/application/ports/route-provider.port';
import { AdEntity } from '@modules/ad/core/domain/ad.entity'; import { AdEntity } from '@modules/ad/core/domain/ad.entity';
import { Frequency } from '@modules/ad/core/domain/ad.types'; import { Frequency } from '@modules/ad/core/domain/ad.types';
import { import {
@ -81,11 +85,28 @@ const adReadModel: AdReadModel = {
const mockDirectionEncoder: DirectionEncoderPort = { const mockDirectionEncoder: DirectionEncoderPort = {
encode: jest encode: jest
.fn() .fn()
.mockImplementation( .mockImplementationOnce(
() => "'LINESTRING(6.1765102 48.689445,2.3522 48.8566)'", () => "'LINESTRING(6.1765102 48.689445,2.3522 48.8566)'",
)
.mockImplementationOnce(
() =>
"'LINESTRING(6.1765102 48.689445,4.984578 48.725687,2.3522 48.8566)'",
), ),
}; };
const mockRouteProvider: RouteProviderPort = {
get: jest.fn().mockImplementation(() => ({
driverDistance: 350101,
driverDuration: 14422,
passengerDistance: 350101,
passengerDuration: 14422,
fwdAzimuth: 273,
backAzimuth: 93,
distanceAzimuth: 336544,
spacetimePoints: [],
})),
};
describe('Ad Mapper', () => { describe('Ad Mapper', () => {
let adMapper: AdMapper; let adMapper: AdMapper;
@ -97,6 +118,10 @@ describe('Ad Mapper', () => {
provide: AD_DIRECTION_ENCODER, provide: AD_DIRECTION_ENCODER,
useValue: mockDirectionEncoder, useValue: mockDirectionEncoder,
}, },
{
provide: AD_ROUTE_PROVIDER,
useValue: mockRouteProvider,
},
], ],
}).compile(); }).compile();
adMapper = module.get<AdMapper>(AdMapper); adMapper = module.get<AdMapper>(AdMapper);
@ -112,6 +137,11 @@ describe('Ad Mapper', () => {
expect(mapped.waypoints).toBe( expect(mapped.waypoints).toBe(
"'LINESTRING(6.1765102 48.689445,2.3522 48.8566)'", "'LINESTRING(6.1765102 48.689445,2.3522 48.8566)'",
); );
expect(mapped.direction).toBe(
"'LINESTRING(6.1765102 48.689445,4.984578 48.725687,2.3522 48.8566)'",
);
expect(mapped.driverDuration).toBe(14422);
expect(mapped.fwdAzimuth).toBe(273);
}); });
it('should map persisted data to domain entity', async () => { it('should map persisted data to domain entity', async () => {

View File

@ -1,5 +1,9 @@
import { AD_DIRECTION_ENCODER } from '@modules/ad/ad.di-tokens'; import {
AD_DIRECTION_ENCODER,
AD_ROUTE_PROVIDER,
} from '@modules/ad/ad.di-tokens';
import { AdMapper } from '@modules/ad/ad.mapper'; import { AdMapper } from '@modules/ad/ad.mapper';
import { RouteProviderPort } from '@modules/ad/core/application/ports/route-provider.port';
import { AdRepository } from '@modules/ad/infrastructure/ad.repository'; import { AdRepository } from '@modules/ad/infrastructure/ad.repository';
import { PrismaService } from '@modules/ad/infrastructure/prisma.service'; import { PrismaService } from '@modules/ad/infrastructure/prisma.service';
import { DirectionEncoderPort } from '@modules/geography/core/application/ports/direction-encoder.port'; import { DirectionEncoderPort } from '@modules/geography/core/application/ports/direction-encoder.port';
@ -14,6 +18,10 @@ const mockDirectionEncoder: DirectionEncoderPort = {
encode: jest.fn(), encode: jest.fn(),
}; };
const mockRouteProvider: RouteProviderPort = {
get: jest.fn(),
};
describe('Ad repository', () => { describe('Ad repository', () => {
let prismaService: PrismaService; let prismaService: PrismaService;
let adMapper: AdMapper; let adMapper: AdMapper;
@ -29,6 +37,10 @@ describe('Ad repository', () => {
provide: AD_DIRECTION_ENCODER, provide: AD_DIRECTION_ENCODER,
useValue: mockDirectionEncoder, useValue: mockDirectionEncoder,
}, },
{
provide: AD_ROUTE_PROVIDER,
useValue: mockRouteProvider,
},
], ],
}).compile(); }).compile();

View File

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

View File

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

View File

@ -1,11 +1,14 @@
import { PathType } from '../../domain/route.types';
import { Point } from './point.type'; import { Point } from './point.type';
import { SpacetimePoint } from './spacetime-point.type';
export type Route = { export type Route = {
name: string; type: PathType;
distance: number; distance: number;
duration: number; duration: number;
fwdAzimuth: number; fwdAzimuth: number;
backAzimuth: number; backAzimuth: number;
distanceAzimuth: number; distanceAzimuth: number;
points: Point[]; points: Point[];
spacetimePoints: SpacetimePoint[];
}; };

View File

@ -0,0 +1,6 @@
import { Point } from './point.type';
export type SpacetimePoint = Point & {
duration: number;
distance: number;
};

View File

@ -0,0 +1,5 @@
import { Point } from './point.type';
export type Waypoint = Point & {
position: number;
};

View File

@ -5,19 +5,61 @@ import {
Role, Role,
RouteProps, RouteProps,
PathType, PathType,
Direction,
} from './route.types'; } from './route.types';
import { WaypointProps } from './value-objects/waypoint.value-object'; 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> { export class RouteEntity extends AggregateRoot<RouteProps> {
protected readonly _id: AggregateID; protected readonly _id: AggregateID;
static create = async (create: CreateRouteProps): Promise<RouteEntity> => { 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), this.getPaths(create.roles, create.waypoints),
create.georouterSettings, create.georouterSettings,
); );
const route = new RouteEntity({ props }); let driverRoute: Route;
return 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 { validate(): void {
@ -32,39 +74,40 @@ export class RouteEntity extends AggregateRoot<RouteProps> {
if (roles.includes(Role.DRIVER) && roles.includes(Role.PASSENGER)) { if (roles.includes(Role.DRIVER) && roles.includes(Role.PASSENGER)) {
if (waypoints.length == 2) { if (waypoints.length == 2) {
// 2 points => same route for driver and passenger // 2 points => same route for driver and passenger
const commonPath: Path = { paths.push(this.createGenericPath(waypoints));
type: PathType.COMMON,
points: waypoints,
};
paths.push(commonPath);
} else { } else {
const driverPath: Path = RouteEntity.createDriverPath(waypoints); paths.push(
const passengerPath: Path = RouteEntity.createPassengerPath(waypoints); this.createDriverPath(waypoints),
paths.push(driverPath, passengerPath); this.createPassengerPath(waypoints),
);
} }
} else if (roles.includes(Role.DRIVER)) { } else if (roles.includes(Role.DRIVER)) {
const driverPath: Path = RouteEntity.createDriverPath(waypoints); paths.push(this.createDriverPath(waypoints));
paths.push(driverPath);
} else if (roles.includes(Role.PASSENGER)) { } else if (roles.includes(Role.PASSENGER)) {
const passengerPath: Path = RouteEntity.createPassengerPath(waypoints); paths.push(this.createPassengerPath(waypoints));
paths.push(passengerPath);
} }
return paths; return paths;
}; };
private static createDriverPath = (waypoints: WaypointProps[]): Path => { private static createGenericPath = (waypoints: WaypointProps[]): Path =>
return { this.createPath(waypoints, PathType.GENERIC);
type: PathType.DRIVER,
points: waypoints,
};
};
private static createPassengerPath = (waypoints: WaypointProps[]): Path => { private static createDriverPath = (waypoints: WaypointProps[]): Path =>
return { this.createPath(waypoints, PathType.DRIVER);
type: PathType.PASSENGER,
points: [waypoints[0], waypoints[waypoints.length - 1]], 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'; // import { IGeodesic } from '../interfaces/geodesic.interface';

View File

@ -5,9 +5,10 @@ import { WaypointProps } from './value-objects/waypoint.value-object';
// All properties that a Route has // All properties that a Route has
export interface RouteProps { export interface RouteProps {
name: string; driverDistance?: number;
distance: number; driverDuration?: number;
duration: number; passengerDistance?: number;
passengerDuration?: number;
fwdAzimuth: number; fwdAzimuth: number;
backAzimuth: number; backAzimuth: number;
distanceAzimuth: number; distanceAzimuth: number;
@ -23,6 +24,17 @@ export interface CreateRouteProps {
georouterSettings: GeorouterSettings; georouterSettings: GeorouterSettings;
} }
export type Direction = {
type: PathType;
distance: number;
duration: number;
fwdAzimuth: number;
backAzimuth: number;
distanceAzimuth: number;
points: Point[];
spacetimePoints: SpacetimePoint[];
};
export type Path = { export type Path = {
type: PathType; type: PathType;
points: Point[]; points: Point[];
@ -34,6 +46,11 @@ export type Point = {
context?: PointContext; context?: PointContext;
}; };
export type SpacetimePoint = Point & {
duration: number;
distance: number;
};
export enum Role { export enum Role {
DRIVER = 'DRIVER', DRIVER = 'DRIVER',
PASSENGER = 'PASSENGER', PASSENGER = 'PASSENGER',
@ -48,7 +65,7 @@ export enum PointContext {
} }
export enum PathType { export enum PathType {
COMMON = 'common', GENERIC = 'generic',
DRIVER = 'driver', DRIVER = 'driver',
PASSENGER = 'passenger', PASSENGER = 'passenger',
} }

View File

@ -1,2 +1,3 @@
export const PARAMS_PROVIDER = Symbol('PARAMS_PROVIDER'); export const PARAMS_PROVIDER = Symbol('PARAMS_PROVIDER');
export const DIRECTION_ENCODER = Symbol('DIRECTION_ENCODER'); export const DIRECTION_ENCODER = Symbol('DIRECTION_ENCODER');
export const GEOROUTER = Symbol('GEOROUTER');

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

View File

@ -3,6 +3,7 @@ import { CqrsModule } from '@nestjs/cqrs';
import { DIRECTION_ENCODER, PARAMS_PROVIDER } from './geography.di-tokens'; import { DIRECTION_ENCODER, PARAMS_PROVIDER } from './geography.di-tokens';
import { DefaultParamsProvider } from './infrastructure/default-params-provider'; import { DefaultParamsProvider } from './infrastructure/default-params-provider';
import { PostgresDirectionEncoder } from './infrastructure/postgres-direction-encoder'; import { PostgresDirectionEncoder } from './infrastructure/postgres-direction-encoder';
import { GetRouteController } from './interface/controllers/get-route.controller';
const adapters: Provider[] = [ const adapters: Provider[] = [
{ {
@ -13,11 +14,12 @@ const adapters: Provider[] = [
provide: DIRECTION_ENCODER, provide: DIRECTION_ENCODER,
useClass: PostgresDirectionEncoder, useClass: PostgresDirectionEncoder,
}, },
GetRouteController,
]; ];
@Module({ @Module({
imports: [CqrsModule], imports: [CqrsModule],
providers: [...adapters], providers: [...adapters],
exports: [DIRECTION_ENCODER], exports: [DIRECTION_ENCODER, GetRouteController],
}) })
export class GeographyModule {} export class GeographyModule {}

View File

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

View File

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

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