diff --git a/src/modules/ad/ad.di-tokens.ts b/src/modules/ad/ad.di-tokens.ts index d4d5d64..3e2571d 100644 --- a/src/modules/ad/ad.di-tokens.ts +++ b/src/modules/ad/ad.di-tokens.ts @@ -1,4 +1,4 @@ export const AD_REPOSITORY = Symbol('AD_REPOSITORY'); -export const GEOROUTER = Symbol('GEOROUTER'); export const AD_DIRECTION_ENCODER = Symbol('AD_DIRECTION_ENCODER'); export const AD_MESSAGE_PUBLISHER = Symbol('AD_MESSAGE_PUBLISHER'); +export const AD_ROUTE_PROVIDER = Symbol('AD_ROUTE_PROVIDER'); diff --git a/src/modules/ad/ad.mapper.ts b/src/modules/ad/ad.mapper.ts index ba6dafe..4412b1e 100644 --- a/src/modules/ad/ad.mapper.ts +++ b/src/modules/ad/ad.mapper.ts @@ -6,11 +6,13 @@ import { AdReadModel, ScheduleItemModel, } from './infrastructure/ad.repository'; -import { Frequency } from './core/domain/ad.types'; +import { Frequency, Role } from './core/domain/ad.types'; import { v4 } from 'uuid'; import { ScheduleItemProps } from './core/domain/value-objects/schedule-item.value-object'; 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: @@ -26,11 +28,25 @@ export class AdMapper constructor( @Inject(AD_DIRECTION_ENCODER) private readonly directionEncoder: DirectionEncoderPort, + @Inject(AD_ROUTE_PROVIDER) + private readonly routeProvider: RouteProviderPort, ) {} toPersistence = (entity: AdEntity): AdWriteModel => { const copy = entity.getProps(); 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 = { uuid: copy.id, driver: copy.driver, @@ -57,14 +73,14 @@ export class AdMapper seatsProposed: copy.seatsProposed, seatsRequested: copy.seatsRequested, strict: copy.strict, - driverDuration: copy.driverDuration, - driverDistance: copy.driverDistance, - passengerDuration: copy.passengerDuration, - passengerDistance: copy.passengerDistance, + driverDuration: route.driverDuration, + driverDistance: route.driverDistance, + passengerDuration: route.passengerDuration, + passengerDistance: route.passengerDistance, waypoints: this.directionEncoder.encode(copy.waypoints), - direction: '', - fwdAzimuth: copy.fwdAzimuth, - backAzimuth: copy.backAzimuth, + direction: this.directionEncoder.encode(route.spacetimePoints), + fwdAzimuth: route.fwdAzimuth, + backAzimuth: route.backAzimuth, createdAt: copy.createdAt, updatedAt: copy.updatedAt, }; diff --git a/src/modules/ad/ad.module.ts b/src/modules/ad/ad.module.ts index 2106fba..a98751d 100644 --- a/src/modules/ad/ad.module.ts +++ b/src/modules/ad/ad.module.ts @@ -4,6 +4,7 @@ import { AD_MESSAGE_PUBLISHER, AD_REPOSITORY, AD_DIRECTION_ENCODER, + AD_ROUTE_PROVIDER, } from './ad.di-tokens'; import { MessageBrokerPublisher } from '@mobicoop/message-broker-module'; import { AdRepository } from './infrastructure/ad.repository'; @@ -11,6 +12,7 @@ import { PrismaService } from './infrastructure/prisma.service'; 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 { GetRouteController } from '@modules/geography/interface/controllers/get-route.controller'; const messageHandlers = [AdCreatedMessageHandler]; @@ -37,6 +39,10 @@ const adapters: Provider[] = [ provide: AD_DIRECTION_ENCODER, useClass: PostgresDirectionEncoder, }, + { + provide: AD_ROUTE_PROVIDER, + useClass: GetRouteController, + }, ]; @Module({ diff --git a/src/modules/ad/core/application/ports/route-provider.port.ts b/src/modules/ad/core/application/ports/route-provider.port.ts new file mode 100644 index 0000000..a7a60a6 --- /dev/null +++ b/src/modules/ad/core/application/ports/route-provider.port.ts @@ -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; +} diff --git a/src/modules/ad/core/domain/ad.types.ts b/src/modules/ad/core/domain/ad.types.ts index 8afef95..77fc02e 100644 --- a/src/modules/ad/core/domain/ad.types.ts +++ b/src/modules/ad/core/domain/ad.types.ts @@ -48,3 +48,8 @@ export enum PointContext { VENUE = 'VENUE', OTHER = 'OTHER', } + +export enum Role { + DRIVER = 'DRIVER', + PASSENGER = 'PASSENGER', +} diff --git a/src/modules/ad/tests/unit/ad.mapper.spec.ts b/src/modules/ad/tests/unit/ad.mapper.spec.ts index a740a4b..36f6beb 100644 --- a/src/modules/ad/tests/unit/ad.mapper.spec.ts +++ b/src/modules/ad/tests/unit/ad.mapper.spec.ts @@ -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 { RouteProviderPort } from '@modules/ad/core/application/ports/route-provider.port'; import { AdEntity } from '@modules/ad/core/domain/ad.entity'; import { Frequency } from '@modules/ad/core/domain/ad.types'; import { @@ -81,11 +85,28 @@ const adReadModel: AdReadModel = { const mockDirectionEncoder: DirectionEncoderPort = { encode: jest .fn() - .mockImplementation( + .mockImplementationOnce( () => "'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', () => { let adMapper: AdMapper; @@ -97,6 +118,10 @@ describe('Ad Mapper', () => { provide: AD_DIRECTION_ENCODER, useValue: mockDirectionEncoder, }, + { + provide: AD_ROUTE_PROVIDER, + useValue: mockRouteProvider, + }, ], }).compile(); adMapper = module.get(AdMapper); @@ -112,6 +137,11 @@ describe('Ad Mapper', () => { expect(mapped.waypoints).toBe( "'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 () => { diff --git a/src/modules/ad/tests/unit/infrastructure/ad.repository.spec.ts b/src/modules/ad/tests/unit/infrastructure/ad.repository.spec.ts index 3d12f92..1da3757 100644 --- a/src/modules/ad/tests/unit/infrastructure/ad.repository.spec.ts +++ b/src/modules/ad/tests/unit/infrastructure/ad.repository.spec.ts @@ -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 { RouteProviderPort } from '@modules/ad/core/application/ports/route-provider.port'; import { AdRepository } from '@modules/ad/infrastructure/ad.repository'; import { PrismaService } from '@modules/ad/infrastructure/prisma.service'; import { DirectionEncoderPort } from '@modules/geography/core/application/ports/direction-encoder.port'; @@ -14,6 +18,10 @@ const mockDirectionEncoder: DirectionEncoderPort = { encode: jest.fn(), }; +const mockRouteProvider: RouteProviderPort = { + get: jest.fn(), +}; + describe('Ad repository', () => { let prismaService: PrismaService; let adMapper: AdMapper; @@ -29,6 +37,10 @@ describe('Ad repository', () => { provide: AD_DIRECTION_ENCODER, useValue: mockDirectionEncoder, }, + { + provide: AD_ROUTE_PROVIDER, + useValue: mockRouteProvider, + }, ], }).compile(); diff --git a/src/modules/geography/core/application/queries/get-route/get-route.query-handler.ts b/src/modules/geography/core/application/queries/get-route/get-route.query-handler.ts new file mode 100644 index 0000000..1a255aa --- /dev/null +++ b/src/modules/geography/core/application/queries/get-route/get-route.query-handler.ts @@ -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 => + await RouteEntity.create({ + roles: query.roles, + waypoints: query.waypoints, + georouter: this.georouter, + georouterSettings: query.georouterSettings, + }); +} diff --git a/src/modules/geography/core/application/queries/get-route/get-route.query.ts b/src/modules/geography/core/application/queries/get-route/get-route.query.ts new file mode 100644 index 0000000..4b8c6fd --- /dev/null +++ b/src/modules/geography/core/application/queries/get-route/get-route.query.ts @@ -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; + } +} diff --git a/src/modules/geography/core/application/types/route.type.ts b/src/modules/geography/core/application/types/route.type.ts index f202e52..d49c2e4 100644 --- a/src/modules/geography/core/application/types/route.type.ts +++ b/src/modules/geography/core/application/types/route.type.ts @@ -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[]; }; diff --git a/src/modules/geography/core/application/types/spacetime-point.type.ts b/src/modules/geography/core/application/types/spacetime-point.type.ts new file mode 100644 index 0000000..6822b1c --- /dev/null +++ b/src/modules/geography/core/application/types/spacetime-point.type.ts @@ -0,0 +1,6 @@ +import { Point } from './point.type'; + +export type SpacetimePoint = Point & { + duration: number; + distance: number; +}; diff --git a/src/modules/geography/core/application/types/waypoint.type.ts b/src/modules/geography/core/application/types/waypoint.type.ts new file mode 100644 index 0000000..af76297 --- /dev/null +++ b/src/modules/geography/core/application/types/waypoint.type.ts @@ -0,0 +1,5 @@ +import { Point } from './point.type'; + +export type Waypoint = Point & { + position: number; +}; diff --git a/src/modules/geography/core/domain/route.entity.ts b/src/modules/geography/core/domain/route.entity.ts index d5bf02f..a4a5822 100644 --- a/src/modules/geography/core/domain/route.entity.ts +++ b/src/modules/geography/core/domain/route.entity.ts @@ -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 { protected readonly _id: AggregateID; static create = async (create: CreateRouteProps): Promise => { - 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 { 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'; diff --git a/src/modules/geography/core/domain/route.types.ts b/src/modules/geography/core/domain/route.types.ts index d9d3674..1df57c9 100644 --- a/src/modules/geography/core/domain/route.types.ts +++ b/src/modules/geography/core/domain/route.types.ts @@ -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', } diff --git a/src/modules/geography/geography.di-tokens.ts b/src/modules/geography/geography.di-tokens.ts index 647e261..98e9456 100644 --- a/src/modules/geography/geography.di-tokens.ts +++ b/src/modules/geography/geography.di-tokens.ts @@ -1,2 +1,3 @@ export const PARAMS_PROVIDER = Symbol('PARAMS_PROVIDER'); export const DIRECTION_ENCODER = Symbol('DIRECTION_ENCODER'); +export const GEOROUTER = Symbol('GEOROUTER'); diff --git a/src/modules/geography/geography.mapper.ts b/src/modules/geography/geography.mapper.ts new file mode 100644 index 0000000..0c8aaca --- /dev/null +++ b/src/modules/geography/geography.mapper.ts @@ -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 +{ + 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; + }; +} diff --git a/src/modules/geography/geography.module.ts b/src/modules/geography/geography.module.ts index c1aff74..d974d9b 100644 --- a/src/modules/geography/geography.module.ts +++ b/src/modules/geography/geography.module.ts @@ -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 {} diff --git a/src/modules/geography/interface/controllers/dtos/get-route.request.dto.ts b/src/modules/geography/interface/controllers/dtos/get-route.request.dto.ts new file mode 100644 index 0000000..b57502e --- /dev/null +++ b/src/modules/geography/interface/controllers/dtos/get-route.request.dto.ts @@ -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; +} diff --git a/src/modules/geography/interface/controllers/get-route.controller.ts b/src/modules/geography/interface/controllers/get-route.controller.ts new file mode 100644 index 0000000..8fdd2f9 --- /dev/null +++ b/src/modules/geography/interface/controllers/get-route.controller.ts @@ -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 { + 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; + } + } +} diff --git a/src/modules/geography/interface/dtos/route.response.dto.ts b/src/modules/geography/interface/dtos/route.response.dto.ts new file mode 100644 index 0000000..6829714 --- /dev/null +++ b/src/modules/geography/interface/dtos/route.response.dto.ts @@ -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[]; +}