diff --git a/src/modules/ad/core/application/queries/match/match.query-handler.ts b/src/modules/ad/core/application/queries/match/match.query-handler.ts index 86a3b17..14a8af5 100644 --- a/src/modules/ad/core/application/queries/match/match.query-handler.ts +++ b/src/modules/ad/core/application/queries/match/match.query-handler.ts @@ -7,6 +7,7 @@ import { Inject } from '@nestjs/common'; import { AdRepositoryPort } from '@modules/ad/core/application/ports/ad.repository.port'; import { AD_REPOSITORY, + AD_ROUTE_PROVIDER, INPUT_DATETIME_TRANSFORMER, PARAMS_PROVIDER, } from '@modules/ad/ad.di-tokens'; @@ -14,6 +15,7 @@ import { MatchEntity } from '@modules/ad/core/domain/match.entity'; import { DefaultParamsProviderPort } from '../../ports/default-params-provider.port'; import { DefaultParams } from '../../ports/default-params.type'; import { DateTimeTransformerPort } from '../../ports/datetime-transformer.port'; +import { RouteProviderPort } from '../../ports/route-provider.port'; @QueryHandler(MatchQuery) export class MatchQueryHandler implements IQueryHandler { @@ -25,6 +27,8 @@ export class MatchQueryHandler implements IQueryHandler { @Inject(AD_REPOSITORY) private readonly repository: AdRepositoryPort, @Inject(INPUT_DATETIME_TRANSFORMER) private readonly datetimeTransformer: DateTimeTransformerPort, + @Inject(AD_ROUTE_PROVIDER) + private readonly routeProvider: RouteProviderPort, ) { this._defaultParams = defaultParamsProvider.getParams(); } @@ -50,6 +54,7 @@ export class MatchQueryHandler implements IQueryHandler { maxDetourDurationRatio: this._defaultParams.MAX_DETOUR_DURATION_RATIO, }) .setDatesAndSchedule(this.datetimeTransformer); + await query.setRoutes(this.routeProvider); let algorithm: Algorithm; switch (query.algorithmType) { diff --git a/src/modules/ad/core/application/queries/match/match.query.ts b/src/modules/ad/core/application/queries/match/match.query.ts index b79e613..d899c1b 100644 --- a/src/modules/ad/core/application/queries/match/match.query.ts +++ b/src/modules/ad/core/application/queries/match/match.query.ts @@ -1,9 +1,11 @@ import { QueryBase } from '@mobicoop/ddd-library'; import { AlgorithmType } from '../../types/algorithm.types'; import { Waypoint } from '../../types/waypoint.type'; -import { Frequency } from '@modules/ad/core/domain/ad.types'; +import { Frequency, Role } from '@modules/ad/core/domain/ad.types'; import { MatchRequestDto } from '@modules/ad/interface/grpc-controllers/dtos/match.request.dto'; import { DateTimeTransformerPort } from '../../ports/datetime-transformer.port'; +import { Route } from '../../types/route.type'; +import { RouteProviderPort } from '../../ports/route-provider.port'; export class MatchQuery extends QueryBase { driver?: boolean; @@ -26,6 +28,7 @@ export class MatchQuery extends QueryBase { maxDetourDurationRatio?: number; readonly page?: number; readonly perPage?: number; + route?: Route; constructor(props: MatchRequestDto) { super(); @@ -160,6 +163,18 @@ export class MatchQuery extends QueryBase { })); return this; }; + + setRoutes = async (routeProvider: RouteProviderPort): Promise => { + const roles: Role[] = []; + if (this.driver) roles.push(Role.DRIVER); + if (this.passenger) roles.push(Role.PASSENGER); + try { + this.route = await routeProvider.getBasic(roles, this.waypoints); + } catch (e: any) { + throw new Error('Unable to find a route for given waypoints'); + } + return this; + }; } type ScheduleItem = { diff --git a/src/modules/ad/core/application/queries/match/selector/passenger-oriented.selector.ts b/src/modules/ad/core/application/queries/match/selector/passenger-oriented.selector.ts index f3d202b..936c073 100644 --- a/src/modules/ad/core/application/queries/match/selector/passenger-oriented.selector.ts +++ b/src/modules/ad/core/application/queries/match/selector/passenger-oriented.selector.ts @@ -1,4 +1,4 @@ -import { Role } from '@modules/ad/core/domain/ad.types'; +import { Frequency, Role } from '@modules/ad/core/domain/ad.types'; import { Candidate } from '../../../types/algorithm.types'; import { Selector } from '../algorithm.abstract'; import { AdReadModel } from '@modules/ad/infrastructure/ad.repository'; @@ -8,15 +8,16 @@ export class PassengerOrientedSelector extends Selector { const queryStringRoles: QueryStringRole[] = []; if (this.query.driver) queryStringRoles.push({ - query: this.asDriverQueryString(), + query: this.createQueryString(Role.DRIVER), role: Role.DRIVER, }); if (this.query.passenger) queryStringRoles.push({ - query: this.asPassengerQueryString(), + query: this.createQueryString(Role.PASSENGER), role: Role.PASSENGER, }); + console.log(queryStringRoles); return ( await Promise.all( queryStringRoles.map>( @@ -42,29 +43,66 @@ export class PassengerOrientedSelector extends Selector { .flat(); }; - private asPassengerQueryString = (): string => `SELECT - ad.uuid,driver,passenger,frequency,public.st_astext(matcher.ad.waypoints) as waypoints, - "fromDate","toDate", - "seatsProposed","seatsRequested", - strict, - "driverDuration","driverDistance", - "passengerDuration","passengerDistance", - "fwdAzimuth","backAzimuth", - si.day,si.time,si.margin - FROM ad LEFT JOIN schedule_item si ON ad.uuid = si."adUuid" - WHERE driver=True`; + private createQueryString = (role: Role): string => + [ + this.createSelect(role), + this.createFrom(), + 'WHERE', + this.createWhere(role), + ].join(' '); - private asDriverQueryString = (): string => `SELECT + private createSelect = (role: Role): string => + [ + `SELECT ad.uuid,driver,passenger,frequency,public.st_astext(matcher.ad.waypoints) as waypoints, "fromDate","toDate", "seatsProposed","seatsRequested", strict, - "driverDuration","driverDistance", - "passengerDuration","passengerDistance", "fwdAzimuth","backAzimuth", - si.day,si.time,si.margin - FROM ad LEFT JOIN schedule_item si ON ad.uuid = si."adUuid" - WHERE passenger=True`; + si.day,si.time,si.margin`, + role == Role.DRIVER ? this.selectAsDriver() : this.selectAsPassenger(), + ].join(); + + private selectAsDriver = (): string => + `${this.query.route?.driverDuration} as duration,${this.query.route?.driverDistance} as distance`; + + private selectAsPassenger = (): string => + `"driverDuration" as duration,"driverDistance" as distance`; + + private createFrom = (): string => + 'FROM ad LEFT JOIN schedule_item si ON ad.uuid = si."adUuid"'; + + private createWhere = (role: Role): string => + [this.whereRole(role), this.whereStrict(), this.whereDate()].join(' AND '); + + private whereRole = (role: Role): string => + role == Role.PASSENGER ? 'driver=True' : 'passenger=True'; + + private whereStrict = (): string => + this.query.strict + ? this.query.frequency == Frequency.PUNCTUAL + ? `frequency='${Frequency.PUNCTUAL}'` + : `frequency='${Frequency.RECURRENT}'` + : ''; + + private whereDate = (): string => { + const whereDate = `( + ( + "fromDate" <= '${this.query.fromDate}' and "fromDate" <= '${this.query.toDate}' and + "toDate" >= '${this.query.toDate}' and "toDate" >= '${this.query.fromDate}' + ) OR ( + "fromDate" >= '${this.query.fromDate}' and "fromDate" <= '${this.query.toDate}' and + "toDate" <= '${this.query.toDate}' and "toDate" >= '${this.query.fromDate}' + ) OR ( + "fromDate" <= '${this.query.fromDate}' and "fromDate" <= '${this.query.toDate}' and + "toDate" <= '${this.query.toDate}' and "toDate" >= '${this.query.fromDate}' + ) OR ( + "fromDate" >= '${this.query.fromDate}' and "fromDate" <= '${this.query.toDate}' and + "toDate" >= '${this.query.toDate}' and "toDate" >= '${this.query.fromDate}' + ) + )`; + return whereDate; + }; } export type QueryStringRole = {