add route provider in ad module
This commit is contained in:
parent
88326dcf6f
commit
bff199557a
|
@ -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');
|
||||||
|
|
|
@ -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,
|
||||||
};
|
};
|
||||||
|
|
|
@ -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({
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -48,3 +48,8 @@ export enum PointContext {
|
||||||
VENUE = 'VENUE',
|
VENUE = 'VENUE',
|
||||||
OTHER = 'OTHER',
|
OTHER = 'OTHER',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum Role {
|
||||||
|
DRIVER = 'DRIVER',
|
||||||
|
PASSENGER = 'PASSENGER',
|
||||||
|
}
|
||||||
|
|
|
@ -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 () => {
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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 { 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[];
|
||||||
};
|
};
|
||||||
|
|
|
@ -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,
|
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';
|
||||||
|
|
|
@ -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',
|
||||||
}
|
}
|
||||||
|
|
|
@ -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');
|
||||||
|
|
|
@ -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 { 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 {}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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[];
|
||||||
|
}
|
Loading…
Reference in New Issue