basic ad entity without direction

This commit is contained in:
sbriat
2023-08-18 12:47:51 +02:00
parent ce48890a66
commit db13f4d87e
47 changed files with 1122 additions and 88 deletions

View File

@@ -0,0 +1,5 @@
import { DefaultParams } from '../types/default-params.type';
export interface DefaultParamsProviderPort {
getParams(): DefaultParams;
}

View File

@@ -0,0 +1,5 @@
import { Coordinates } from '../types/coordinates.type';
export interface DirectionEncoderPort {
encode(coordinates: Coordinates[]): string;
}

View File

@@ -0,0 +1,11 @@
export interface GeodesicPort {
inverse(
lon1: number,
lat1: number,
lon2: number,
lat2: number,
): {
azimuth: number;
distance: number;
};
}

View File

@@ -0,0 +1,5 @@
import { GeorouterPort } from './georouter.port';
export interface GeorouterCreatorPort {
create(type: string, url: string): GeorouterPort;
}

View File

@@ -0,0 +1,7 @@
import { GeorouterSettings } from '../types/georouter-settings.type';
import { Path } from '../types/path.type';
import { Route } from '../types/route.type';
export interface GeorouterPort {
routes(paths: Path[], settings: GeorouterSettings): Promise<Route[]>;
}

View File

@@ -0,0 +1,4 @@
export type Coordinates = {
lon: number;
lat: number;
};

View File

@@ -0,0 +1,4 @@
export type DefaultParams = {
GEOROUTER_TYPE: string;
GEOROUTER_URL: string;
};

View File

@@ -0,0 +1,5 @@
export type GeorouterSettings = {
withPoints: boolean;
withTime: boolean;
withDistance: boolean;
};

View File

@@ -0,0 +1,7 @@
import { PathType } from '../../domain/route.types';
import { Point } from './point.type';
export type Path = {
type: PathType;
points: Point[];
};

View File

@@ -0,0 +1,6 @@
import { PointContext } from '../../domain/route.types';
import { Coordinates } from './coordinates.type';
export type Point = Coordinates & {
context?: PointContext;
};

View File

@@ -0,0 +1,11 @@
import { Point } from './point.type';
export type Route = {
name: string;
distance: number;
duration: number;
fwdAzimuth: number;
backAzimuth: number;
distanceAzimuth: number;
points: Point[];
};

View File

@@ -0,0 +1,117 @@
import { AggregateRoot, AggregateID } from '@mobicoop/ddd-library';
import {
CreateRouteProps,
Path,
Role,
RouteProps,
PathType,
} from './route.types';
import { WaypointProps } from './value-objects/waypoint.value-object';
export class RouteEntity extends AggregateRoot<RouteProps> {
protected readonly _id: AggregateID;
static create = async (create: CreateRouteProps): Promise<RouteEntity> => {
const props: RouteProps = await create.georouter.routes(
this.getPaths(create.roles, create.waypoints),
create.georouterSettings,
);
const route = new RouteEntity({ props });
return route;
};
validate(): void {
// entity business rules validation to protect it's invariant before saving entity to a database
}
private static getPaths = (
roles: Role[],
waypoints: WaypointProps[],
): Path[] => {
const paths: Path[] = [];
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);
} else {
const driverPath: Path = RouteEntity.createDriverPath(waypoints);
const passengerPath: Path = RouteEntity.createPassengerPath(waypoints);
paths.push(driverPath, passengerPath);
}
} else if (roles.includes(Role.DRIVER)) {
const driverPath: Path = RouteEntity.createDriverPath(waypoints);
paths.push(driverPath);
} else if (roles.includes(Role.PASSENGER)) {
const passengerPath: Path = RouteEntity.createPassengerPath(waypoints);
paths.push(passengerPath);
}
return paths;
};
private static createDriverPath = (waypoints: WaypointProps[]): Path => {
return {
type: PathType.DRIVER,
points: waypoints,
};
};
private static createPassengerPath = (waypoints: WaypointProps[]): Path => {
return {
type: PathType.PASSENGER,
points: [waypoints[0], waypoints[waypoints.length - 1]],
};
};
}
// import { IGeodesic } from '../interfaces/geodesic.interface';
// import { Point } from '../types/point.type';
// import { SpacetimePoint } from './spacetime-point';
// export class Route {
// distance: number;
// duration: number;
// fwdAzimuth: number;
// backAzimuth: number;
// distanceAzimuth: number;
// points: Point[];
// spacetimePoints: SpacetimePoint[];
// private geodesic: IGeodesic;
// constructor(geodesic: IGeodesic) {
// this.distance = undefined;
// this.duration = undefined;
// this.fwdAzimuth = undefined;
// this.backAzimuth = undefined;
// this.distanceAzimuth = undefined;
// this.points = [];
// this.spacetimePoints = [];
// this.geodesic = geodesic;
// }
// setPoints = (points: Point[]): void => {
// this.points = points;
// this.setAzimuth(points);
// };
// setSpacetimePoints = (spacetimePoints: SpacetimePoint[]): void => {
// this.spacetimePoints = spacetimePoints;
// };
// protected setAzimuth = (points: Point[]): void => {
// const inverse = this.geodesic.inverse(
// points[0].lon,
// points[0].lat,
// points[points.length - 1].lon,
// points[points.length - 1].lat,
// );
// this.fwdAzimuth =
// inverse.azimuth >= 0 ? inverse.azimuth : 360 - Math.abs(inverse.azimuth);
// this.backAzimuth =
// this.fwdAzimuth > 180 ? this.fwdAzimuth - 180 : this.fwdAzimuth + 180;
// this.distanceAzimuth = inverse.distance;
// };
// }

View File

@@ -0,0 +1,54 @@
import { GeorouterPort } from '../application/ports/georouter.port';
import { GeorouterSettings } from '../application/types/georouter-settings.type';
import { SpacetimePointProps } from './value-objects/timepoint.value-object';
import { WaypointProps } from './value-objects/waypoint.value-object';
// All properties that a Route has
export interface RouteProps {
name: string;
distance: number;
duration: number;
fwdAzimuth: number;
backAzimuth: number;
distanceAzimuth: number;
waypoints: WaypointProps[];
spacetimePoints: SpacetimePointProps[];
}
// Properties that are needed for a Route creation
export interface CreateRouteProps {
roles: Role[];
waypoints: WaypointProps[];
georouter: GeorouterPort;
georouterSettings: GeorouterSettings;
}
export type Path = {
type: PathType;
points: Point[];
};
export type Point = {
lon: number;
lat: number;
context?: PointContext;
};
export enum Role {
DRIVER = 'DRIVER',
PASSENGER = 'PASSENGER',
}
export enum PointContext {
HOUSE_NUMBER = 'HOUSE_NUMBER',
STREET_ADDRESS = 'STREET_ADDRESS',
LOCALITY = 'LOCALITY',
VENUE = 'VENUE',
OTHER = 'OTHER',
}
export enum PathType {
COMMON = 'common',
DRIVER = 'driver',
PASSENGER = 'passenger',
}

View File

@@ -0,0 +1,42 @@
import { ArgumentInvalidException, ValueObject } from '@mobicoop/ddd-library';
/** Note:
* Value Objects with multiple properties can contain
* other Value Objects inside if needed.
* */
export interface SpacetimePointProps {
lon: number;
lat: number;
duration: number;
distance: number;
}
export class SpacetimePoint extends ValueObject<SpacetimePointProps> {
get lon(): number {
return this.props.lon;
}
get lat(): number {
return this.props.lat;
}
get duration(): number {
return this.props.duration;
}
get distance(): number {
return this.props.distance;
}
protected validate(props: SpacetimePointProps): void {
if (props.duration < 0)
throw new ArgumentInvalidException(
'duration must be greater than or equal to 0',
);
if (props.distance < 0)
throw new ArgumentInvalidException(
'distance must be greater than or equal to 0',
);
}
}

View File

@@ -0,0 +1,47 @@
import {
ArgumentInvalidException,
ArgumentOutOfRangeException,
ValueObject,
} from '@mobicoop/ddd-library';
import { PointContext } from '../route.types';
/** Note:
* Value Objects with multiple properties can contain
* other Value Objects inside if needed.
* */
export interface WaypointProps {
position: number;
lon: number;
lat: number;
context?: PointContext;
}
export class Waypoint extends ValueObject<WaypointProps> {
get position(): number {
return this.props.position;
}
get lon(): number {
return this.props.lon;
}
get lat(): number {
return this.props.lat;
}
get context(): PointContext {
return this.props.context;
}
protected validate(props: WaypointProps): void {
if (props.position < 0)
throw new ArgumentInvalidException(
'position must be greater than or equal to 0',
);
if (props.lon > 180 || props.lon < -180)
throw new ArgumentOutOfRangeException('lon must be between -180 and 180');
if (props.lat > 90 || props.lat < -90)
throw new ArgumentOutOfRangeException('lat must be between -90 and 90');
}
}