diff --git a/src/modules/matcher/adapters/secondaries/georouter-creator.ts b/src/modules/matcher/adapters/secondaries/georouter-creator.ts index 379920a..5589e7a 100644 --- a/src/modules/matcher/adapters/secondaries/georouter-creator.ts +++ b/src/modules/matcher/adapters/secondaries/georouter-creator.ts @@ -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', + ); } }; } diff --git a/src/modules/matcher/adapters/secondaries/graphhopper-georouter.ts b/src/modules/matcher/adapters/secondaries/graphhopper-georouter.ts index 26d2e23..f660632 100644 --- a/src/modules/matcher/adapters/secondaries/graphhopper-georouter.ts +++ b/src/modules/matcher/adapters/secondaries/graphhopper-georouter.ts @@ -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, + ); }), ), ); diff --git a/src/modules/matcher/domain/entities/ecosystem/geography.ts b/src/modules/matcher/domain/entities/ecosystem/geography.ts index 592ef31..e7cf586 100644 --- a/src/modules/matcher/domain/entities/ecosystem/geography.ts +++ b/src/modules/matcher/domain/entities/ecosystem/geography.ts @@ -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`, ); } diff --git a/src/modules/matcher/domain/entities/ecosystem/time.ts b/src/modules/matcher/domain/entities/ecosystem/time.ts index c4a39c5..7195cf2 100644 --- a/src/modules/matcher/domain/entities/ecosystem/time.ts +++ b/src/modules/matcher/domain/entities/ecosystem/time.ts @@ -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', ); } diff --git a/src/modules/matcher/domain/entities/engine/factory/algorithm-factory.abstract.ts b/src/modules/matcher/domain/entities/engine/factory/algorithm-factory.abstract.ts index 67206e8..e934f1d 100644 --- a/src/modules/matcher/domain/entities/engine/factory/algorithm-factory.abstract.ts +++ b/src/modules/matcher/domain/entities/engine/factory/algorithm-factory.abstract.ts @@ -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 { diff --git a/src/modules/matcher/domain/entities/engine/factory/classic.ts b/src/modules/matcher/domain/entities/engine/factory/classic.ts index 77a2d04..688f8f1 100644 --- a/src/modules/matcher/domain/entities/engine/factory/classic.ts +++ b/src/modules/matcher/domain/entities/engine/factory/classic.ts @@ -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 { - return [new ClassicWaypointsCompleter(this._matchQuery)]; - } + createProcessors = (): Array => [ + 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), + ]; } diff --git a/src/modules/matcher/domain/entities/engine/matcher.ts b/src/modules/matcher/domain/entities/engine/matcher.ts index bc6da9c..68b59cb 100644 --- a/src/modules/matcher/domain/entities/engine/matcher.ts +++ b/src/modules/matcher/domain/entities/engine/matcher.ts @@ -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 = []; for (const processor of algorithm.createProcessors()) { diff --git a/src/modules/matcher/domain/entities/engine/processor/completer/classic-waypoint.completer.processor.ts b/src/modules/matcher/domain/entities/engine/processor/completer/classic-waypoint.completer.processor.ts index b55522a..bec51b6 100644 --- a/src/modules/matcher/domain/entities/engine/processor/completer/classic-waypoint.completer.processor.ts +++ b/src/modules/matcher/domain/entities/engine/processor/completer/classic-waypoint.completer.processor.ts @@ -2,7 +2,8 @@ import { Candidate } from '../../candidate'; import { Completer } from './completer.abstract'; export class ClassicWaypointsCompleter extends Completer { - complete(candidates: Array): Array { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + complete = (candidates: Array): Array => { return []; - } + }; } diff --git a/src/modules/matcher/domain/entities/engine/processor/completer/completer.abstract.ts b/src/modules/matcher/domain/entities/engine/processor/completer/completer.abstract.ts index 29f408d..e11bfee 100644 --- a/src/modules/matcher/domain/entities/engine/processor/completer/completer.abstract.ts +++ b/src/modules/matcher/domain/entities/engine/processor/completer/completer.abstract.ts @@ -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): Array => diff --git a/src/modules/matcher/domain/entities/engine/processor/completer/journey.completer.processor.ts b/src/modules/matcher/domain/entities/engine/processor/completer/journey.completer.processor.ts new file mode 100644 index 0000000..34559a5 --- /dev/null +++ b/src/modules/matcher/domain/entities/engine/processor/completer/journey.completer.processor.ts @@ -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): Array => { + return []; + }; +} diff --git a/src/modules/matcher/domain/entities/engine/processor/completer/route.completer.processor.ts b/src/modules/matcher/domain/entities/engine/processor/completer/route.completer.processor.ts new file mode 100644 index 0000000..a95fff8 --- /dev/null +++ b/src/modules/matcher/domain/entities/engine/processor/completer/route.completer.processor.ts @@ -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): Array => { + return []; + }; +} diff --git a/src/modules/matcher/domain/entities/engine/processor/filter/filter.abstract.ts b/src/modules/matcher/domain/entities/engine/processor/filter/filter.abstract.ts new file mode 100644 index 0000000..87cd490 --- /dev/null +++ b/src/modules/matcher/domain/entities/engine/processor/filter/filter.abstract.ts @@ -0,0 +1,9 @@ +import { Candidate } from '../../candidate'; +import { Processor } from '../processor.abstract'; + +export abstract class Filter extends Processor { + execute = (candidates: Array): Array => + this.filter(candidates); + + abstract filter(candidates: Array): Array; +} diff --git a/src/modules/matcher/domain/entities/engine/processor/filter/geofilter/classic.filter.processor.ts b/src/modules/matcher/domain/entities/engine/processor/filter/geofilter/classic.filter.processor.ts new file mode 100644 index 0000000..3c9b60c --- /dev/null +++ b/src/modules/matcher/domain/entities/engine/processor/filter/geofilter/classic.filter.processor.ts @@ -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): Array => { + return []; + }; +} diff --git a/src/modules/matcher/domain/entities/engine/processor/filter/timefilter/classic.filter.processor.ts b/src/modules/matcher/domain/entities/engine/processor/filter/timefilter/classic.filter.processor.ts new file mode 100644 index 0000000..c10336f --- /dev/null +++ b/src/modules/matcher/domain/entities/engine/processor/filter/timefilter/classic.filter.processor.ts @@ -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): Array => { + return []; + }; +} diff --git a/src/modules/matcher/domain/entities/engine/processor.abstract.ts b/src/modules/matcher/domain/entities/engine/processor/processor.abstract.ts similarity index 87% rename from src/modules/matcher/domain/entities/engine/processor.abstract.ts rename to src/modules/matcher/domain/entities/engine/processor/processor.abstract.ts index c5df1a6..ac679cf 100644 --- a/src/modules/matcher/domain/entities/engine/processor.abstract.ts +++ b/src/modules/matcher/domain/entities/engine/processor/processor.abstract.ts @@ -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; diff --git a/src/modules/matcher/domain/entities/engine/selector/classic.selector.ts b/src/modules/matcher/domain/entities/engine/selector/classic.selector.ts new file mode 100644 index 0000000..e87403c --- /dev/null +++ b/src/modules/matcher/domain/entities/engine/selector/classic.selector.ts @@ -0,0 +1,8 @@ +import { Candidate } from '../candidate'; +import { Selector } from './selector.abstract'; + +export class ClassicSelector extends Selector { + select = async (): Promise> => { + return []; + }; +} diff --git a/src/modules/matcher/domain/entities/engine/selector/selector.abstract.ts b/src/modules/matcher/domain/entities/engine/selector/selector.abstract.ts new file mode 100644 index 0000000..e406925 --- /dev/null +++ b/src/modules/matcher/domain/entities/engine/selector/selector.abstract.ts @@ -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>; +} diff --git a/src/modules/matcher/exceptions/matcher.exception.ts b/src/modules/matcher/exceptions/matcher.exception.ts index c72c694..af70214 100644 --- a/src/modules/matcher/exceptions/matcher.exception.ts +++ b/src/modules/matcher/exceptions/matcher.exception.ts @@ -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, +}