engine tree
This commit is contained in:
parent
65b6042561
commit
45b33f1ce1
|
@ -4,6 +4,10 @@ import { IGeorouter } from '../../domain/interfaces/georouter.interface';
|
|||
import { GraphhopperGeorouter } from './graphhopper-georouter';
|
||||
import { HttpService } from '@nestjs/axios';
|
||||
import { MatcherGeodesic } from './geodesic';
|
||||
import {
|
||||
MatcherException,
|
||||
MatcherExceptionCode,
|
||||
} from '../../exceptions/matcher.exception';
|
||||
|
||||
@Injectable()
|
||||
export class GeorouterCreator implements ICreateGeorouter {
|
||||
|
@ -17,7 +21,10 @@ export class GeorouterCreator implements ICreateGeorouter {
|
|||
case 'graphhopper':
|
||||
return new GraphhopperGeorouter(url, this.httpService, this.geodesic);
|
||||
default:
|
||||
throw new Error('Unknown geocoder');
|
||||
throw new MatcherException(
|
||||
MatcherExceptionCode.INVALID_ARGUMENT,
|
||||
'Unknown geocoder',
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -9,6 +9,10 @@ import { IGeodesic } from '../../domain/interfaces/geodesic.interface';
|
|||
import { NamedRoute } from '../../domain/entities/ecosystem/named-route';
|
||||
import { Route } from '../../domain/entities/ecosystem/route';
|
||||
import { SpacetimePoint } from '../../domain/entities/ecosystem/spacetime-point';
|
||||
import {
|
||||
MatcherException,
|
||||
MatcherExceptionCode,
|
||||
} from '../../exceptions/matcher.exception';
|
||||
|
||||
@Injectable()
|
||||
export class GraphhopperGeorouter implements IGeorouter {
|
||||
|
@ -84,7 +88,10 @@ export class GraphhopperGeorouter implements IGeorouter {
|
|||
this._httpService.get(url).pipe(
|
||||
map((res) => (res.data ? this._createRoute(res) : undefined)),
|
||||
catchError((error: AxiosError) => {
|
||||
throw new Error('Georouter unavailable : ' + error.message);
|
||||
throw new MatcherException(
|
||||
MatcherExceptionCode.INTERNAL,
|
||||
'Georouter unavailable : ' + error.message,
|
||||
);
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
import { MatcherException } from '../../../exceptions/matcher.exception';
|
||||
import {
|
||||
MatcherException,
|
||||
MatcherExceptionCode,
|
||||
} from '../../../exceptions/matcher.exception';
|
||||
import { IRequestGeography } from '../../interfaces/geography-request.interface';
|
||||
import { PointType } from '../../types/geography.enum';
|
||||
import { Point } from '../../types/point.type';
|
||||
|
@ -127,12 +130,15 @@ export class Geography {
|
|||
|
||||
_validateWaypoints = (): void => {
|
||||
if (this._geographyRequest.waypoints.length < 2) {
|
||||
throw new MatcherException(3, 'At least 2 waypoints are required');
|
||||
throw new MatcherException(
|
||||
MatcherExceptionCode.INVALID_ARGUMENT,
|
||||
'At least 2 waypoints are required',
|
||||
);
|
||||
}
|
||||
this._geographyRequest.waypoints.map((point) => {
|
||||
if (!this._isValidPoint(point)) {
|
||||
throw new MatcherException(
|
||||
3,
|
||||
MatcherExceptionCode.INVALID_ARGUMENT,
|
||||
`Waypoint { Lon: ${point.lon}, Lat: ${point.lat} } is not valid`,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
import { MatcherException } from '../../../exceptions/matcher.exception';
|
||||
import {
|
||||
MatcherException,
|
||||
MatcherExceptionCode,
|
||||
} from '../../../exceptions/matcher.exception';
|
||||
import { MarginDurations } from '../../types/margin-durations.type';
|
||||
import { IRequestTime } from '../../interfaces/time-request.interface';
|
||||
import { TimingDays, TimingFrequency, Days } from '../../types/timing';
|
||||
|
@ -45,7 +48,10 @@ export class Time {
|
|||
|
||||
_validateBaseDate = (): void => {
|
||||
if (!this._timeRequest.departure && !this._timeRequest.fromDate) {
|
||||
throw new MatcherException(3, 'departure or fromDate is required');
|
||||
throw new MatcherException(
|
||||
MatcherExceptionCode.INVALID_ARGUMENT,
|
||||
'departure or fromDate is required',
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -53,7 +59,10 @@ export class Time {
|
|||
if (this._timeRequest.departure) {
|
||||
this.fromDate = this.toDate = new Date(this._timeRequest.departure);
|
||||
if (!this._isDate(this.fromDate)) {
|
||||
throw new MatcherException(3, 'Wrong departure date');
|
||||
throw new MatcherException(
|
||||
MatcherExceptionCode.INVALID_ARGUMENT,
|
||||
'Wrong departure date',
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -62,16 +71,25 @@ export class Time {
|
|||
if (this._timeRequest.fromDate) {
|
||||
this.fromDate = new Date(this._timeRequest.fromDate);
|
||||
if (!this._isDate(this.fromDate)) {
|
||||
throw new MatcherException(3, 'Wrong fromDate');
|
||||
throw new MatcherException(
|
||||
MatcherExceptionCode.INVALID_ARGUMENT,
|
||||
'Wrong fromDate',
|
||||
);
|
||||
}
|
||||
}
|
||||
if (this._timeRequest.toDate) {
|
||||
this.toDate = new Date(this._timeRequest.toDate);
|
||||
if (!this._isDate(this.toDate)) {
|
||||
throw new MatcherException(3, 'Wrong toDate');
|
||||
throw new MatcherException(
|
||||
MatcherExceptionCode.INVALID_ARGUMENT,
|
||||
'Wrong toDate',
|
||||
);
|
||||
}
|
||||
if (this.toDate < this.fromDate) {
|
||||
throw new MatcherException(3, 'toDate must be after fromDate');
|
||||
throw new MatcherException(
|
||||
MatcherExceptionCode.INVALID_ARGUMENT,
|
||||
'toDate must be after fromDate',
|
||||
);
|
||||
}
|
||||
}
|
||||
if (this._timeRequest.fromDate) {
|
||||
|
@ -81,19 +99,28 @@ export class Time {
|
|||
|
||||
_validateSchedule = (): void => {
|
||||
if (!this._timeRequest.schedule) {
|
||||
throw new MatcherException(3, 'Schedule is required');
|
||||
throw new MatcherException(
|
||||
MatcherExceptionCode.INVALID_ARGUMENT,
|
||||
'Schedule is required',
|
||||
);
|
||||
}
|
||||
if (
|
||||
!Object.keys(this._timeRequest.schedule).some((elem) =>
|
||||
Days.includes(elem),
|
||||
)
|
||||
) {
|
||||
throw new MatcherException(3, 'No valid day in the given schedule');
|
||||
throw new MatcherException(
|
||||
MatcherExceptionCode.INVALID_ARGUMENT,
|
||||
'No valid day in the given schedule',
|
||||
);
|
||||
}
|
||||
Object.keys(this._timeRequest.schedule).map((day) => {
|
||||
const time = new Date('1970-01-01 ' + this._timeRequest.schedule[day]);
|
||||
if (!this._isDate(time)) {
|
||||
throw new MatcherException(3, `Wrong time for ${day} in schedule`);
|
||||
throw new MatcherException(
|
||||
MatcherExceptionCode.INVALID_ARGUMENT,
|
||||
`Wrong time for ${day} in schedule`,
|
||||
);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
@ -145,7 +172,7 @@ export class Time {
|
|||
)
|
||||
) {
|
||||
throw new MatcherException(
|
||||
3,
|
||||
MatcherExceptionCode.INVALID_ARGUMENT,
|
||||
'No valid day in the given margin durations',
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { MatchQuery } from 'src/modules/matcher/queries/match.query';
|
||||
import { Processor } from '../processor.abstract';
|
||||
import { Processor } from '../processor/processor.abstract';
|
||||
import { Candidate } from '../candidate';
|
||||
|
||||
export abstract class AlgorithmFactory {
|
||||
|
|
|
@ -1,9 +1,18 @@
|
|||
import { AlgorithmFactory } from './algorithm-factory.abstract';
|
||||
import { Processor } from '../processor.abstract';
|
||||
import { ClassicWaypointsCompleter } from '../processor/completer/classic-waypoint.completer.processor';
|
||||
import { RouteCompleter } from '../processor/completer/route.completer.processor';
|
||||
import { ClassicGeoFilter } from '../processor/filter/geofilter/classic.filter.processor';
|
||||
import { JourneyCompleter } from '../processor/completer/journey.completer.processor';
|
||||
import { ClassicTimeFilter } from '../processor/filter/timefilter/classic.filter.processor';
|
||||
import { Processor } from '../processor/processor.abstract';
|
||||
|
||||
export class ClassicAlgorithmFactory extends AlgorithmFactory {
|
||||
createProcessors(): Array<Processor> {
|
||||
return [new ClassicWaypointsCompleter(this._matchQuery)];
|
||||
}
|
||||
createProcessors = (): Array<Processor> => [
|
||||
new ClassicWaypointsCompleter(this._matchQuery),
|
||||
new RouteCompleter(this._matchQuery, true, true, true),
|
||||
new ClassicGeoFilter(this._matchQuery),
|
||||
new RouteCompleter(this._matchQuery),
|
||||
new JourneyCompleter(this._matchQuery),
|
||||
new ClassicTimeFilter(this._matchQuery),
|
||||
];
|
||||
}
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
import {
|
||||
MatcherException,
|
||||
MatcherExceptionCode,
|
||||
} from 'src/modules/matcher/exceptions/matcher.exception';
|
||||
import { MatchQuery } from '../../../queries/match.query';
|
||||
import { Algorithm } from '../../types/algorithm.enum';
|
||||
import { Match } from '../ecosystem/match';
|
||||
|
@ -11,6 +15,12 @@ export class Matcher {
|
|||
switch (matchQuery.algorithmSettings.algorithm) {
|
||||
case Algorithm.CLASSIC:
|
||||
algorithm = new ClassicAlgorithmFactory(matchQuery);
|
||||
break;
|
||||
default:
|
||||
throw new MatcherException(
|
||||
MatcherExceptionCode.INVALID_ARGUMENT,
|
||||
'Unknown algorithm',
|
||||
);
|
||||
}
|
||||
let candidates: Array<Candidate> = [];
|
||||
for (const processor of algorithm.createProcessors()) {
|
||||
|
|
|
@ -2,7 +2,8 @@ import { Candidate } from '../../candidate';
|
|||
import { Completer } from './completer.abstract';
|
||||
|
||||
export class ClassicWaypointsCompleter extends Completer {
|
||||
complete(candidates: Array<Candidate>): Array<Candidate> {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
complete = (candidates: Array<Candidate>): Array<Candidate> => {
|
||||
return [];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Candidate } from '../../candidate';
|
||||
import { Processor } from '../../processor.abstract';
|
||||
import { Processor } from '../processor.abstract';
|
||||
|
||||
export abstract class Completer extends Processor {
|
||||
execute = (candidates: Array<Candidate>): Array<Candidate> =>
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
import { Candidate } from '../../candidate';
|
||||
import { Completer } from './completer.abstract';
|
||||
|
||||
export class JourneyCompleter extends Completer {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
complete = (candidates: Array<Candidate>): Array<Candidate> => {
|
||||
return [];
|
||||
};
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
import { MatchQuery } from 'src/modules/matcher/queries/match.query';
|
||||
import { Candidate } from '../../candidate';
|
||||
import { Completer } from './completer.abstract';
|
||||
|
||||
export class RouteCompleter extends Completer {
|
||||
_withPoints: boolean;
|
||||
_withTime: boolean;
|
||||
_withDistance: boolean;
|
||||
|
||||
constructor(
|
||||
matchQuery: MatchQuery,
|
||||
withPoints = false,
|
||||
withTime = false,
|
||||
withDistance = false,
|
||||
) {
|
||||
super(matchQuery);
|
||||
this._withPoints = withPoints;
|
||||
this._withTime = withTime;
|
||||
this._withDistance = withDistance;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
complete = (candidates: Array<Candidate>): Array<Candidate> => {
|
||||
return [];
|
||||
};
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
import { Candidate } from '../../candidate';
|
||||
import { Processor } from '../processor.abstract';
|
||||
|
||||
export abstract class Filter extends Processor {
|
||||
execute = (candidates: Array<Candidate>): Array<Candidate> =>
|
||||
this.filter(candidates);
|
||||
|
||||
abstract filter(candidates: Array<Candidate>): Array<Candidate>;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
import { Candidate } from '../../../candidate';
|
||||
import { Filter } from '../filter.abstract';
|
||||
|
||||
export class ClassicGeoFilter extends Filter {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
filter = (candidates: Array<Candidate>): Array<Candidate> => {
|
||||
return [];
|
||||
};
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
import { Candidate } from '../../../candidate';
|
||||
import { Filter } from '../filter.abstract';
|
||||
|
||||
export class ClassicTimeFilter extends Filter {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
filter = (candidates: Array<Candidate>): Array<Candidate> => {
|
||||
return [];
|
||||
};
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
import { MatchQuery } from 'src/modules/matcher/queries/match.query';
|
||||
import { Candidate } from './candidate';
|
||||
import { Candidate } from '../candidate';
|
||||
|
||||
export abstract class Processor {
|
||||
_matchQuery: MatchQuery;
|
|
@ -0,0 +1,8 @@
|
|||
import { Candidate } from '../candidate';
|
||||
import { Selector } from './selector.abstract';
|
||||
|
||||
export class ClassicSelector extends Selector {
|
||||
select = async (): Promise<Array<Candidate>> => {
|
||||
return [];
|
||||
};
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
import { MatchQuery } from 'src/modules/matcher/queries/match.query';
|
||||
import { Candidate } from '../candidate';
|
||||
|
||||
export abstract class Selector {
|
||||
_matchQuery: MatchQuery;
|
||||
|
||||
constructor(matchQuery: MatchQuery) {
|
||||
this._matchQuery = matchQuery;
|
||||
}
|
||||
|
||||
abstract select(): Promise<Array<Candidate>>;
|
||||
}
|
|
@ -11,3 +11,23 @@ export class MatcherException implements Error {
|
|||
return this._code;
|
||||
}
|
||||
}
|
||||
|
||||
export enum MatcherExceptionCode {
|
||||
OK = 0,
|
||||
CANCELLED = 1,
|
||||
UNKNOWN = 2,
|
||||
INVALID_ARGUMENT = 3,
|
||||
DEADLINE_EXCEEDED = 4,
|
||||
NOT_FOUND = 5,
|
||||
ALREADY_EXISTS = 6,
|
||||
PERMISSION_DENIED = 7,
|
||||
RESOURCE_EXHAUSTED = 8,
|
||||
FAILED_PRECONDITION = 9,
|
||||
ABORTED = 10,
|
||||
OUT_OF_RANGE = 11,
|
||||
UNIMPLEMENTED = 12,
|
||||
INTERNAL = 13,
|
||||
UNAVAILABLE = 14,
|
||||
DATA_LOSS = 15,
|
||||
UNAUTHENTICATED = 16,
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue