diff --git a/src/modules/matcher/adapters/primaries/matcher.controller.ts b/src/modules/matcher/adapters/primaries/matcher.controller.ts index 7e001d5..959910c 100644 --- a/src/modules/matcher/adapters/primaries/matcher.controller.ts +++ b/src/modules/matcher/adapters/primaries/matcher.controller.ts @@ -10,6 +10,7 @@ import { Match } from '../../domain/entities/match'; import { MatchQuery } from '../../queries/match.query'; import { MatchPresenter } from '../secondaries/match.presenter'; import { DefaultParamsProvider } from '../secondaries/default-params.provider'; +import { GeorouterCreator } from '../secondaries/georouter-creator'; @UsePipes( new RpcValidationPipe({ @@ -23,13 +24,18 @@ export class MatcherController { private readonly _queryBus: QueryBus, private readonly _defaultParamsProvider: DefaultParamsProvider, @InjectMapper() private readonly _mapper: Mapper, + private readonly _georouterCreator: GeorouterCreator, ) {} @GrpcMethod('MatcherService', 'Match') async match(data: MatchRequest): Promise> { try { const matchCollection = await this._queryBus.execute( - new MatchQuery(data, this._defaultParamsProvider.getParams()), + new MatchQuery( + data, + this._defaultParamsProvider.getParams(), + this._georouterCreator, + ), ); return Promise.resolve({ data: matchCollection.data.map((match: Match) => diff --git a/src/modules/matcher/adapters/primaries/matcher.proto b/src/modules/matcher/adapters/primaries/matcher.proto index f610b21..af4e083 100644 --- a/src/modules/matcher/adapters/primaries/matcher.proto +++ b/src/modules/matcher/adapters/primaries/matcher.proto @@ -25,8 +25,8 @@ message MatchRequest { int32 proportion = 16; bool useAzimuth = 17; int32 azimuthMargin = 18; - int32 maxDetourDistanceRatio = 19; - int32 maxDetourDurationRatio = 20; + float maxDetourDistanceRatio = 19; + float maxDetourDurationRatio = 20; repeated int32 exclusions = 21; int32 identifier = 22; } diff --git a/src/modules/matcher/adapters/secondaries/georouter-creator.ts b/src/modules/matcher/adapters/secondaries/georouter-creator.ts index b82b938..005fe12 100644 --- a/src/modules/matcher/adapters/secondaries/georouter-creator.ts +++ b/src/modules/matcher/adapters/secondaries/georouter-creator.ts @@ -1,8 +1,11 @@ -import { Georouter } from '../../domain/interfaces/georouter.interface'; +import { Injectable } from '@nestjs/common'; +import { ICreateGeorouter } from '../../domain/interfaces/georouter-creator.interface'; +import { IGeorouter } from '../../domain/interfaces/georouter.interface'; import { GraphhopperGeorouter } from './graphhopper-georouter'; -export class GeorouterCreator { - create(type: string, url: string): Georouter { +@Injectable() +export class GeorouterCreator implements ICreateGeorouter { + create(type: string, url: string): IGeorouter { switch (type) { case 'graphhopper': return new GraphhopperGeorouter(url); diff --git a/src/modules/matcher/adapters/secondaries/graphhopper-georouter.ts b/src/modules/matcher/adapters/secondaries/graphhopper-georouter.ts index 06df223..edc6c31 100644 --- a/src/modules/matcher/adapters/secondaries/graphhopper-georouter.ts +++ b/src/modules/matcher/adapters/secondaries/graphhopper-georouter.ts @@ -1,19 +1,15 @@ import { Route } from '../../domain/entities/route'; -import { Georouter } from '../../domain/interfaces/georouter.interface'; +import { IGeorouter } from '../../domain/interfaces/georouter.interface'; +import { GeorouterSettings } from '../../domain/types/georouter-settings.type'; -export class GraphhopperGeorouter implements Georouter { +export class GraphhopperGeorouter implements IGeorouter { _url: string; constructor(url: string) { this._url = url + '/route?'; } - route( - routesRequested: [], - withPoints: boolean, - withTime: boolean, - withDistance: boolean, - ): Route[] { + route(routesRequested: [], settings: GeorouterSettings): Route[] { throw new Error('Method not implemented.'); } } diff --git a/src/modules/matcher/domain/entities/algorithm-settings.ts b/src/modules/matcher/domain/entities/algorithm-settings.ts index 1a79bb5..7378baa 100644 --- a/src/modules/matcher/domain/entities/algorithm-settings.ts +++ b/src/modules/matcher/domain/entities/algorithm-settings.ts @@ -2,6 +2,8 @@ import { IRequestAlgorithmSettings } from '../interfaces/algorithm-settings-requ import { DefaultAlgorithmSettings } from '../types/default-algorithm-settings.type'; import { Algorithm } from '../types/algorithm.enum'; import { TimingFrequency } from '../types/timing'; +import { ICreateGeorouter } from '../interfaces/georouter-creator.interface'; +import { IGeorouter } from '../interfaces/georouter.interface'; export class AlgorithmSettings { _algorithmSettingsRequest: IRequestAlgorithmSettings; @@ -15,13 +17,13 @@ export class AlgorithmSettings { azimuthMargin: number; maxDetourDurationRatio: number; maxDetourDistanceRatio: number; - georouterType: string; - georouterUrl: string; + georouter: IGeorouter; constructor( algorithmSettingsRequest: IRequestAlgorithmSettings, defaultAlgorithmSettings: DefaultAlgorithmSettings, frequency: TimingFrequency, + georouterCreator: ICreateGeorouter, ) { this._algorithmSettingsRequest = algorithmSettingsRequest; this.algorithm = @@ -49,8 +51,10 @@ export class AlgorithmSettings { this.maxDetourDurationRatio = algorithmSettingsRequest.maxDetourDurationRatio ?? defaultAlgorithmSettings.maxDetourDurationRatio; - this.georouterType = defaultAlgorithmSettings.georouterType; - this.georouterUrl = defaultAlgorithmSettings.georouterUrl; + this.georouter = georouterCreator.create( + defaultAlgorithmSettings.georouterType, + defaultAlgorithmSettings.georouterUrl, + ); if (this._strict) { this.restrict = frequency; } diff --git a/src/modules/matcher/domain/interfaces/georouter-creator.interface.ts b/src/modules/matcher/domain/interfaces/georouter-creator.interface.ts new file mode 100644 index 0000000..7a6bd25 --- /dev/null +++ b/src/modules/matcher/domain/interfaces/georouter-creator.interface.ts @@ -0,0 +1,5 @@ +import { IGeorouter } from './georouter.interface'; + +export interface ICreateGeorouter { + create(type: string, url: string): IGeorouter; +} diff --git a/src/modules/matcher/domain/interfaces/georouter.interface.ts b/src/modules/matcher/domain/interfaces/georouter.interface.ts index c3046e3..05494a4 100644 --- a/src/modules/matcher/domain/interfaces/georouter.interface.ts +++ b/src/modules/matcher/domain/interfaces/georouter.interface.ts @@ -1,10 +1,6 @@ import { Route } from '../entities/route'; +import { GeorouterSettings } from '../types/georouter-settings.type'; -export interface Georouter { - route( - routesRequested: [], - withPoints: boolean, - withTime: boolean, - withDistance: boolean, - ): Array; +export interface IGeorouter { + route(routesRequested: [], settings: GeorouterSettings): Array; } diff --git a/src/modules/matcher/domain/types/georouter-settings.type.ts b/src/modules/matcher/domain/types/georouter-settings.type.ts new file mode 100644 index 0000000..d8f73ae --- /dev/null +++ b/src/modules/matcher/domain/types/georouter-settings.type.ts @@ -0,0 +1,5 @@ +export type GeorouterSettings = { + withPoints: boolean; + withTime: boolean; + withDistance: boolean; +}; diff --git a/src/modules/matcher/matcher.module.ts b/src/modules/matcher/matcher.module.ts index 2bb67a3..25fde2c 100644 --- a/src/modules/matcher/matcher.module.ts +++ b/src/modules/matcher/matcher.module.ts @@ -12,6 +12,7 @@ import { CacheModule } from '@nestjs/cache-manager'; import { RedisClientOptions } from '@liaoliaots/nestjs-redis'; import { redisStore } from 'cache-manager-ioredis-yet'; import { DefaultParamsProvider } from './adapters/secondaries/default-params.provider'; +import { GeorouterCreator } from './adapters/secondaries/georouter-creator'; @Module({ imports: [ @@ -51,6 +52,7 @@ import { DefaultParamsProvider } from './adapters/secondaries/default-params.pro Messager, DefaultParamsProvider, MatchUseCase, + GeorouterCreator, ], exports: [], }) diff --git a/src/modules/matcher/queries/match.query.ts b/src/modules/matcher/queries/match.query.ts index fdec447..55381ab 100644 --- a/src/modules/matcher/queries/match.query.ts +++ b/src/modules/matcher/queries/match.query.ts @@ -6,10 +6,13 @@ import { Role } from '../domain/types/role.enum'; import { AlgorithmSettings } from '../domain/entities/algorithm-settings'; import { Time } from '../domain/entities/time'; import { IDefaultParams } from '../domain/types/default-params.type'; +import { IGeorouter } from '../domain/interfaces/georouter.interface'; +import { ICreateGeorouter } from '../domain/interfaces/georouter-creator.interface'; export class MatchQuery { private readonly _matchRequest: MatchRequest; private readonly _defaultParams: IDefaultParams; + private readonly _georouterCreator: ICreateGeorouter; person: Person; roles: Array; time: Time; @@ -17,10 +20,16 @@ export class MatchQuery { exclusions: Array; requirement: Requirement; algorithmSettings: AlgorithmSettings; + georouter: IGeorouter; - constructor(matchRequest: MatchRequest, defaultParams: IDefaultParams) { + constructor( + matchRequest: MatchRequest, + defaultParams: IDefaultParams, + georouterCreator: ICreateGeorouter, + ) { this._matchRequest = matchRequest; this._defaultParams = defaultParams; + this._georouterCreator = georouterCreator; this._setPerson(); this._setRoles(); this._setTime(); @@ -75,6 +84,7 @@ export class MatchQuery { this._matchRequest, this._defaultParams.DEFAULT_ALGORITHM_SETTINGS, this.time.frequency, + this._georouterCreator, ); } diff --git a/src/modules/matcher/tests/unit/graphhopper-georouter.spec.ts b/src/modules/matcher/tests/unit/graphhopper-georouter.spec.ts index 40e3ec6..fb94d14 100644 --- a/src/modules/matcher/tests/unit/graphhopper-georouter.spec.ts +++ b/src/modules/matcher/tests/unit/graphhopper-georouter.spec.ts @@ -11,6 +11,12 @@ describe('Graphhopper Georouter', () => { const graphhopperGeorouter: GraphhopperGeorouter = new GraphhopperGeorouter( 'http://localhost', ); - expect(() => graphhopperGeorouter.route([], false, false, false)).toThrow(); + expect(() => + graphhopperGeorouter.route([], { + withDistance: false, + withPoints: false, + withTime: false, + }), + ).toThrow(); }); }); diff --git a/src/modules/matcher/tests/unit/match.query.spec.ts b/src/modules/matcher/tests/unit/match.query.spec.ts index a48c541..6e9182f 100644 --- a/src/modules/matcher/tests/unit/match.query.spec.ts +++ b/src/modules/matcher/tests/unit/match.query.spec.ts @@ -26,6 +26,10 @@ const defaultParams: IDefaultParams = { }, }; +const mockGeorouterCreator = { + create: jest.fn().mockImplementation(), +}; + describe('Match query', () => { it('should be defined', () => { const matchRequest: MatchRequest = new MatchRequest(); @@ -40,7 +44,11 @@ describe('Match query', () => { lon: 3.045432, }, ]; - const matchQuery: MatchQuery = new MatchQuery(matchRequest, defaultParams); + const matchQuery: MatchQuery = new MatchQuery( + matchRequest, + defaultParams, + mockGeorouterCreator, + ); expect(matchQuery).toBeDefined(); }); @@ -59,7 +67,11 @@ describe('Match query', () => { ]; matchRequest.identifier = 125; matchRequest.exclusions = [126, 127, 128]; - const matchQuery: MatchQuery = new MatchQuery(matchRequest, defaultParams); + const matchQuery: MatchQuery = new MatchQuery( + matchRequest, + defaultParams, + mockGeorouterCreator, + ); expect(matchQuery.exclusions.length).toBe(4); }); @@ -77,7 +89,11 @@ describe('Match query', () => { }, ]; matchRequest.driver = true; - const matchQuery: MatchQuery = new MatchQuery(matchRequest, defaultParams); + const matchQuery: MatchQuery = new MatchQuery( + matchRequest, + defaultParams, + mockGeorouterCreator, + ); expect(matchQuery.roles).toEqual([Role.DRIVER]); }); @@ -95,7 +111,11 @@ describe('Match query', () => { }, ]; matchRequest.passenger = true; - const matchQuery: MatchQuery = new MatchQuery(matchRequest, defaultParams); + const matchQuery: MatchQuery = new MatchQuery( + matchRequest, + defaultParams, + mockGeorouterCreator, + ); expect(matchQuery.roles).toEqual([Role.PASSENGER]); }); @@ -114,7 +134,11 @@ describe('Match query', () => { ]; matchRequest.passenger = true; matchRequest.driver = true; - const matchQuery: MatchQuery = new MatchQuery(matchRequest, defaultParams); + const matchQuery: MatchQuery = new MatchQuery( + matchRequest, + defaultParams, + mockGeorouterCreator, + ); expect(matchQuery.roles.length).toBe(2); expect(matchQuery.roles).toContain(Role.PASSENGER); expect(matchQuery.roles).toContain(Role.DRIVER); @@ -135,7 +159,11 @@ describe('Match query', () => { ]; matchRequest.seatsDriver = 1; matchRequest.seatsPassenger = 2; - const matchQuery: MatchQuery = new MatchQuery(matchRequest, defaultParams); + const matchQuery: MatchQuery = new MatchQuery( + matchRequest, + defaultParams, + mockGeorouterCreator, + ); expect(matchQuery.requirement.seatsDriver).toBe(1); expect(matchQuery.requirement.seatsPassenger).toBe(2); }); @@ -162,7 +190,11 @@ describe('Match query', () => { matchRequest.remoteness = 20000; matchRequest.maxDetourDistanceRatio = 0.41; matchRequest.maxDetourDurationRatio = 0.42; - const matchQuery: MatchQuery = new MatchQuery(matchRequest, defaultParams); + const matchQuery: MatchQuery = new MatchQuery( + matchRequest, + defaultParams, + mockGeorouterCreator, + ); expect(matchQuery.algorithmSettings.algorithm).toBe(Algorithm.CLASSIC); expect(matchQuery.algorithmSettings.restrict).toBe( TimingFrequency.FREQUENCY_PUNCTUAL, diff --git a/src/modules/matcher/tests/unit/match.usecase.spec.ts b/src/modules/matcher/tests/unit/match.usecase.spec.ts index 8d59092..dace03d 100644 --- a/src/modules/matcher/tests/unit/match.usecase.spec.ts +++ b/src/modules/matcher/tests/unit/match.usecase.spec.ts @@ -15,6 +15,10 @@ const mockMessager = { publish: jest.fn().mockImplementation(), }; +const mockGeorouterCreator = { + create: jest.fn().mockImplementation(), +}; + const defaultParams: IDefaultParams = { DEFAULT_IDENTIFIER: 0, MARGIN_DURATION: 900, @@ -77,7 +81,7 @@ describe('MatchUseCase', () => { ]; matchRequest.departure = '2023-04-01 12:23:00'; const matches = await matchUseCase.execute( - new MatchQuery(matchRequest, defaultParams), + new MatchQuery(matchRequest, defaultParams, mockGeorouterCreator), ); expect(matches.total).toBe(1); });