diff --git a/old/app.constants.ts b/old/app.constants.ts deleted file mode 100644 index 28001cd..0000000 --- a/old/app.constants.ts +++ /dev/null @@ -1,2 +0,0 @@ -export const MESSAGE_BROKER_PUBLISHER = Symbol('MESSAGE_BROKER_PUBLISHER'); -export const MESSAGE_PUBLISHER = Symbol('MESSAGE_PUBLISHER'); diff --git a/old/app.module.ts b/old/app.module.ts deleted file mode 100644 index 25543ee..0000000 --- a/old/app.module.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { classes } from '@automapper/classes'; -import { AutomapperModule } from '@automapper/nestjs'; -import { Module } from '@nestjs/common'; -import { ConfigModule, ConfigService } from '@nestjs/config'; -import { HealthModule } from './modules/health/health.module'; -import { MatcherModule } from './modules/matcher/matcher.module'; -import { AdModule } from './modules/ad/ad.module'; -import { - ConfigurationModule, - ConfigurationModuleOptions, -} from '@mobicoop/configuration-module'; -import { - MessageBrokerModule, - MessageBrokerModuleOptions, -} from '@mobicoop/message-broker-module'; - -@Module({ - imports: [ - ConfigModule.forRoot({ isGlobal: true }), - ConfigurationModule.forRootAsync({ - imports: [ConfigModule], - inject: [ConfigService], - useFactory: async ( - configService: ConfigService, - ): Promise => ({ - domain: configService.get('SERVICE_CONFIGURATION_DOMAIN'), - messageBroker: { - uri: configService.get('MESSAGE_BROKER_URI'), - exchange: configService.get('MESSAGE_BROKER_EXCHANGE'), - }, - redis: { - host: configService.get('REDIS_HOST'), - password: configService.get('REDIS_PASSWORD'), - port: configService.get('REDIS_PORT'), - }, - setConfigurationBrokerQueue: 'matcher-configuration-create-update', - deleteConfigurationQueue: 'matcher-configuration-delete', - propagateConfigurationQueue: 'matcher-configuration-propagate', - }), - }), - MessageBrokerModule.forRootAsync({ - imports: [ConfigModule], - inject: [ConfigService], - useFactory: async ( - configService: ConfigService, - ): Promise => ({ - uri: configService.get('MESSAGE_BROKER_URI'), - exchange: configService.get('MESSAGE_BROKER_EXCHANGE'), - handlers: { - adCreated: { - routingKey: 'ad.created', - queue: 'matcher-ad-created', - }, - }, - name: 'matcher', - }), - }), - AutomapperModule.forRoot({ strategyInitializer: classes() }), - HealthModule, - MatcherModule, - AdModule, - ], - controllers: [], - providers: [], -}) -export class AppModule {} diff --git a/old/interfaces/message-publisher.ts b/old/interfaces/message-publisher.ts deleted file mode 100644 index 29ad456..0000000 --- a/old/interfaces/message-publisher.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface IPublishMessage { - publish(routingKey: string, message: string): void; -} diff --git a/old/modules/ad/ad.constants.ts b/old/modules/ad/ad.constants.ts deleted file mode 100644 index 2f044c9..0000000 --- a/old/modules/ad/ad.constants.ts +++ /dev/null @@ -1,4 +0,0 @@ -export const PARAMS_PROVIDER = Symbol(); -export const GEOROUTER_CREATOR = Symbol(); -export const TIMEZONE_FINDER = Symbol(); -export const DIRECTION_ENCODER = Symbol(); diff --git a/old/modules/ad/ad.module.ts b/old/modules/ad/ad.module.ts deleted file mode 100644 index 4a36f22..0000000 --- a/old/modules/ad/ad.module.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { Module } from '@nestjs/common'; -import { AdMessagerService } from './adapters/primaries/ad-messager.service'; -import { AdProfile } from './mappers/ad.profile'; -import { CreateAdUseCase } from './domain/usecases/create-ad.usecase'; -import { AdRepository } from './adapters/secondaries/ad.repository'; -import { DatabaseModule } from '../database/database.module'; -import { CqrsModule } from '@nestjs/cqrs'; -import { GeoTimezoneFinder } from '../geography/adapters/secondaries/geo-timezone-finder'; -import { DefaultParamsProvider } from './adapters/secondaries/default-params.provider'; -import { GeorouterCreator } from '../geography/adapters/secondaries/georouter-creator'; -import { GeographyModule } from '../geography/geography.module'; -import { HttpModule } from '@nestjs/axios'; -import { PostgresDirectionEncoder } from '../geography/adapters/secondaries/postgres-direction-encoder'; -import { MessageBrokerPublisher } from '@mobicoop/message-broker-module'; -import { - MESSAGE_BROKER_PUBLISHER, - MESSAGE_PUBLISHER, -} from '../../app.constants'; -import { MessagePublisher } from './adapters/secondaries/message-publisher'; -import { - DIRECTION_ENCODER, - GEOROUTER_CREATOR, - PARAMS_PROVIDER, - TIMEZONE_FINDER, -} from './ad.constants'; - -@Module({ - imports: [GeographyModule, DatabaseModule, CqrsModule, HttpModule], - providers: [ - { - provide: PARAMS_PROVIDER, - useClass: DefaultParamsProvider, - }, - { - provide: GEOROUTER_CREATOR, - useClass: GeorouterCreator, - }, - { - provide: TIMEZONE_FINDER, - useClass: GeoTimezoneFinder, - }, - { - provide: DIRECTION_ENCODER, - useClass: PostgresDirectionEncoder, - }, - { - provide: MESSAGE_BROKER_PUBLISHER, - useClass: MessageBrokerPublisher, - }, - { - provide: MESSAGE_PUBLISHER, - useClass: MessagePublisher, - }, - AdProfile, - AdRepository, - CreateAdUseCase, - AdMessagerService, - ], - exports: [], -}) -export class AdModule {} diff --git a/old/modules/ad/adapters/primaries/ad-messager.service.ts b/old/modules/ad/adapters/primaries/ad-messager.service.ts deleted file mode 100644 index d5f2b5a..0000000 --- a/old/modules/ad/adapters/primaries/ad-messager.service.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { Controller, Inject } from '@nestjs/common'; -import { CommandBus } from '@nestjs/cqrs'; -import { CreateAdCommand } from '../../commands/create-ad.command'; -import { CreateAdRequest } from '../../domain/dtos/create-ad.request'; -import { validateOrReject } from 'class-validator'; -import { plainToInstance } from 'class-transformer'; -import { DatabaseException } from 'src/modules/database/exceptions/database.exception'; -import { ExceptionCode } from 'src/modules/utils/exception-code.enum'; -import { IPublishMessage } from 'src/interfaces/message-publisher'; -import { MESSAGE_PUBLISHER } from 'src/app.constants'; -import { RabbitSubscribe } from '@mobicoop/message-broker-module'; - -@Controller() -export class AdMessagerService { - constructor( - @Inject(MESSAGE_PUBLISHER) - private readonly messagePublisher: IPublishMessage, - private readonly commandBus: CommandBus, - ) {} - - @RabbitSubscribe({ - name: 'adCreated', - }) - async adCreatedHandler(message: string): Promise { - let createAdRequest: CreateAdRequest; - // parse message to request instance - try { - createAdRequest = plainToInstance(CreateAdRequest, JSON.parse(message)); - // validate instance - await validateOrReject(createAdRequest); - // validate nested objects (fixes direct nested validation bug) - for (const waypoint of createAdRequest.addresses) { - try { - await validateOrReject(waypoint); - } catch (e) { - throw e; - } - } - } catch (e) { - this.messagePublisher.publish( - 'matcher.ad.crit', - JSON.stringify({ - message: `Can't validate message : ${message}`, - error: e, - }), - ); - } - try { - await this.commandBus.execute(new CreateAdCommand(createAdRequest)); - } catch (e) { - if (e instanceof DatabaseException) { - if (e.message.includes('already exists')) { - this.messagePublisher.publish( - 'matcher.ad.crit', - JSON.stringify({ - code: ExceptionCode.ALREADY_EXISTS, - message: 'Already exists', - uuid: createAdRequest.uuid, - }), - ); - } - if (e.message.includes("Can't reach database server")) { - this.messagePublisher.publish( - 'matcher.ad.crit', - JSON.stringify({ - code: ExceptionCode.UNAVAILABLE, - message: 'Database server unavailable', - uuid: createAdRequest.uuid, - }), - ); - } - } - this.messagePublisher.publish( - 'logging.matcher.ad.crit', - JSON.stringify({ - message, - error: e, - }), - ); - } - } -} diff --git a/old/modules/ad/adapters/secondaries/ad.repository.ts b/old/modules/ad/adapters/secondaries/ad.repository.ts deleted file mode 100644 index 51ff9e7..0000000 --- a/old/modules/ad/adapters/secondaries/ad.repository.ts +++ /dev/null @@ -1,129 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { DatabaseRepository } from '../../../database/domain/database.repository'; -import { Ad } from '../../domain/entities/ad'; -import { DatabaseException } from '../../../database/exceptions/database.exception'; - -@Injectable() -export class AdRepository extends DatabaseRepository { - protected model = 'ad'; - - createAd = async (ad: Partial): Promise => { - try { - const affectedRowNumber = await this.createWithFields( - this.createFields(ad), - ); - if (affectedRowNumber == 1) { - return this.findOneByUuid(ad.uuid); - } - throw new DatabaseException(); - } catch (e) { - throw e; - } - }; - - private createFields = (ad: Partial): Partial => ({ - uuid: `'${ad.uuid}'`, - userUuid: `'${ad.userUuid}'`, - driver: ad.driver ? 'true' : 'false', - passenger: ad.passenger ? 'true' : 'false', - frequency: `'${ad.frequency}'`, - fromDate: `'${ad.fromDate.getFullYear()}-${ - ad.fromDate.getMonth() + 1 - }-${ad.fromDate.getDate()}'`, - toDate: `'${ad.toDate.getFullYear()}-${ - ad.toDate.getMonth() + 1 - }-${ad.toDate.getDate()}'`, - monTime: ad.monTime - ? `'${ad.monTime.getFullYear()}-${ - ad.monTime.getMonth() + 1 - }-${ad.monTime.getDate()}T${ad.monTime.getHours()}:${ad.monTime.getMinutes()}Z'` - : 'NULL', - tueTime: ad.tueTime - ? `'${ad.tueTime.getFullYear()}-${ - ad.tueTime.getMonth() + 1 - }-${ad.tueTime.getDate()}T${ad.tueTime.getHours()}:${ad.tueTime.getMinutes()}Z'` - : 'NULL', - wedTime: ad.wedTime - ? `'${ad.wedTime.getFullYear()}-${ - ad.wedTime.getMonth() + 1 - }-${ad.wedTime.getDate()}T${ad.wedTime.getHours()}:${ad.wedTime.getMinutes()}Z'` - : 'NULL', - thuTime: ad.thuTime - ? `'${ad.thuTime.getFullYear()}-${ - ad.thuTime.getMonth() + 1 - }-${ad.thuTime.getDate()}T${ad.thuTime.getHours()}:${ad.thuTime.getMinutes()}Z'` - : 'NULL', - friTime: ad.friTime - ? `'${ad.friTime.getFullYear()}-${ - ad.friTime.getMonth() + 1 - }-${ad.friTime.getDate()}T${ad.friTime.getHours()}:${ad.friTime.getMinutes()}Z'` - : 'NULL', - satTime: ad.satTime - ? `'${ad.satTime.getFullYear()}-${ - ad.satTime.getMonth() + 1 - }-${ad.satTime.getDate()}T${ad.satTime.getHours()}:${ad.satTime.getMinutes()}Z'` - : 'NULL', - sunTime: ad.sunTime - ? `'${ad.sunTime.getFullYear()}-${ - ad.sunTime.getMonth() + 1 - }-${ad.sunTime.getDate()}T${ad.sunTime.getHours()}:${ad.sunTime.getMinutes()}Z'` - : 'NULL', - monMargin: ad.monMargin, - tueMargin: ad.tueMargin, - wedMargin: ad.wedMargin, - thuMargin: ad.thuMargin, - friMargin: ad.friMargin, - satMargin: ad.satMargin, - sunMargin: ad.sunMargin, - fwdAzimuth: ad.fwdAzimuth, - backAzimuth: ad.backAzimuth, - driverDuration: ad.driverDuration ?? 'NULL', - driverDistance: ad.driverDistance ?? 'NULL', - passengerDuration: ad.passengerDuration ?? 'NULL', - passengerDistance: ad.passengerDistance ?? 'NULL', - waypoints: ad.waypoints, - direction: ad.direction, - seatsDriver: ad.seatsDriver, - seatsPassenger: ad.seatsPassenger, - seatsUsed: ad.seatsUsed ?? 0, - strict: ad.strict, - }); -} - -type AdFields = { - uuid: string; - userUuid: string; - driver: string; - passenger: string; - frequency: string; - fromDate: string; - toDate: string; - monTime: string; - tueTime: string; - wedTime: string; - thuTime: string; - friTime: string; - satTime: string; - sunTime: string; - monMargin: number; - tueMargin: number; - wedMargin: number; - thuMargin: number; - friMargin: number; - satMargin: number; - sunMargin: number; - driverDuration?: number | 'NULL'; - driverDistance?: number | 'NULL'; - passengerDuration?: number | 'NULL'; - passengerDistance?: number | 'NULL'; - waypoints: string; - direction: string; - fwdAzimuth: number; - backAzimuth: number; - seatsDriver?: number; - seatsPassenger?: number; - seatsUsed?: number; - strict: boolean; - createdAt: string; - updatedAt: string; -}; diff --git a/old/modules/ad/adapters/secondaries/default-params.provider.ts b/old/modules/ad/adapters/secondaries/default-params.provider.ts deleted file mode 100644 index f0a41fb..0000000 --- a/old/modules/ad/adapters/secondaries/default-params.provider.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { ConfigService } from '@nestjs/config'; -import { DefaultParams } from '../../domain/types/default-params.type'; -import { IProvideParams } from '../../domain/interfaces/params-provider.interface'; - -@Injectable() -export class DefaultParamsProvider implements IProvideParams { - constructor(private readonly configService: ConfigService) {} - - getParams = (): DefaultParams => { - return { - DEFAULT_TIMEZONE: this.configService.get('DEFAULT_TIMEZONE'), - GEOROUTER_TYPE: this.configService.get('GEOROUTER_TYPE'), - GEOROUTER_URL: this.configService.get('GEOROUTER_URL'), - }; - }; -} diff --git a/old/modules/ad/adapters/secondaries/message-publisher.ts b/old/modules/ad/adapters/secondaries/message-publisher.ts deleted file mode 100644 index 315bb6b..0000000 --- a/old/modules/ad/adapters/secondaries/message-publisher.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Inject, Injectable } from '@nestjs/common'; -import { MESSAGE_BROKER_PUBLISHER } from '../../../../app.constants'; -import { MessageBrokerPublisher } from '@mobicoop/message-broker-module'; -import { IPublishMessage } from '../../../../interfaces/message-publisher'; - -@Injectable() -export class MessagePublisher implements IPublishMessage { - constructor( - @Inject(MESSAGE_BROKER_PUBLISHER) - private readonly messageBrokerPublisher: MessageBrokerPublisher, - ) {} - - publish = (routingKey: string, message: string): void => { - this.messageBrokerPublisher.publish(routingKey, message); - }; -} diff --git a/old/modules/ad/adapters/secondaries/timezone-finder.ts b/old/modules/ad/adapters/secondaries/timezone-finder.ts deleted file mode 100644 index 8459661..0000000 --- a/old/modules/ad/adapters/secondaries/timezone-finder.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { GeoTimezoneFinder } from '../../../geography/adapters/secondaries/geo-timezone-finder'; -import { IFindTimezone } from '../../../geography/domain/interfaces/timezone-finder.interface'; - -@Injectable() -export class TimezoneFinder implements IFindTimezone { - constructor(private readonly geoTimezoneFinder: GeoTimezoneFinder) {} - - timezones = (lon: number, lat: number): string[] => - this.geoTimezoneFinder.timezones(lon, lat); -} diff --git a/old/modules/ad/commands/create-ad.command.ts b/old/modules/ad/commands/create-ad.command.ts deleted file mode 100644 index b4f1e8d..0000000 --- a/old/modules/ad/commands/create-ad.command.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { CreateAdRequest } from '../domain/dtos/create-ad.request'; - -export class CreateAdCommand { - readonly createAdRequest: CreateAdRequest; - - constructor(request: CreateAdRequest) { - this.createAdRequest = request; - } -} diff --git a/old/modules/ad/domain/dtos/create-ad.request.ts b/old/modules/ad/domain/dtos/create-ad.request.ts deleted file mode 100644 index 06bb0d6..0000000 --- a/old/modules/ad/domain/dtos/create-ad.request.ts +++ /dev/null @@ -1,140 +0,0 @@ -import { AutoMap } from '@automapper/classes'; -import { - ArrayMinSize, - IsArray, - IsBoolean, - IsDate, - IsEnum, - IsMilitaryTime, - IsNotEmpty, - IsNumber, - IsOptional, - IsString, -} from 'class-validator'; -import { Frequency } from '../types/frequency.enum'; -import { Coordinate } from '../../../geography/domain/entities/coordinate'; -import { Type } from 'class-transformer'; -import { HasTruthyWith } from './has-truthy-with.validator'; - -export class CreateAdRequest { - @IsString() - @IsNotEmpty() - @AutoMap() - uuid: string; - - @IsString() - @IsNotEmpty() - @AutoMap() - userUuid: string; - - @HasTruthyWith('passenger', { - message: 'A role (driver or passenger) must be set to true', - }) - @IsBoolean() - @AutoMap() - driver: boolean; - - @IsBoolean() - @AutoMap() - passenger: boolean; - - @IsEnum(Frequency) - @AutoMap() - frequency: Frequency; - - @Type(() => Date) - @IsDate() - @AutoMap() - fromDate: Date; - - @Type(() => Date) - @IsDate() - @AutoMap() - toDate: Date; - - @IsOptional() - @IsMilitaryTime() - @AutoMap() - monTime?: string; - - @IsOptional() - @IsMilitaryTime() - @AutoMap() - tueTime?: string; - - @IsOptional() - @IsMilitaryTime() - @AutoMap() - wedTime?: string; - - @IsOptional() - @IsMilitaryTime() - @AutoMap() - thuTime?: string; - - @IsOptional() - @IsMilitaryTime() - @AutoMap() - friTime?: string; - - @IsOptional() - @IsMilitaryTime() - @AutoMap() - satTime?: string; - - @IsOptional() - @IsMilitaryTime() - @AutoMap() - sunTime?: string; - - @IsNumber() - @AutoMap() - monMargin: number; - - @IsNumber() - @AutoMap() - tueMargin: number; - - @IsNumber() - @AutoMap() - wedMargin: number; - - @IsNumber() - @AutoMap() - thuMargin: number; - - @IsNumber() - @AutoMap() - friMargin: number; - - @IsNumber() - @AutoMap() - satMargin: number; - - @IsNumber() - @AutoMap() - sunMargin: number; - - @Type(() => Coordinate) - @IsArray() - @ArrayMinSize(2) - @AutoMap(() => [Coordinate]) - addresses: Coordinate[]; - - @IsNumber() - @AutoMap() - seatsDriver: number; - - @IsNumber() - @AutoMap() - seatsPassenger: number; - - @IsOptional() - @IsNumber() - @AutoMap() - seatsUsed?: number; - - @IsBoolean() - @AutoMap() - strict: boolean; -} diff --git a/old/modules/ad/domain/dtos/has-truthy-with.validator.ts b/old/modules/ad/domain/dtos/has-truthy-with.validator.ts deleted file mode 100644 index 06460c6..0000000 --- a/old/modules/ad/domain/dtos/has-truthy-with.validator.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { - registerDecorator, - ValidationOptions, - ValidationArguments, -} from 'class-validator'; - -export function HasTruthyWith( - property: string, - validationOptions?: ValidationOptions, -) { - // eslint-disable-next-line @typescript-eslint/ban-types - return function (object: Object, propertyName: string) { - registerDecorator({ - name: 'hasTruthyWith', - target: object.constructor, - propertyName: propertyName, - constraints: [property], - options: validationOptions, - validator: { - validate(value: any, args: ValidationArguments) { - const [relatedPropertyName] = args.constraints; - const relatedValue = (args.object as any)[relatedPropertyName]; - return ( - typeof value === 'boolean' && - typeof relatedValue === 'boolean' && - (value || relatedValue) - ); // you can return a Promise here as well, if you want to make async validation - }, - }, - }); - }; -} diff --git a/old/modules/ad/domain/entities/ad.ts b/old/modules/ad/domain/entities/ad.ts deleted file mode 100644 index a3a7ffb..0000000 --- a/old/modules/ad/domain/entities/ad.ts +++ /dev/null @@ -1,109 +0,0 @@ -import { AutoMap } from '@automapper/classes'; -import { Frequency } from '../types/frequency.enum'; - -export class Ad { - @AutoMap() - uuid: string; - - @AutoMap() - userUuid: string; - - @AutoMap() - driver: boolean; - - @AutoMap() - passenger: boolean; - - @AutoMap() - frequency: Frequency; - - @AutoMap() - fromDate: Date; - - @AutoMap() - toDate: Date; - - @AutoMap() - monTime: Date; - - @AutoMap() - tueTime: Date; - - @AutoMap() - wedTime: Date; - - @AutoMap() - thuTime: Date; - - @AutoMap() - friTime: Date; - - @AutoMap() - satTime: Date; - - @AutoMap() - sunTime: Date; - - @AutoMap() - monMargin: number; - - @AutoMap() - tueMargin: number; - - @AutoMap() - wedMargin: number; - - @AutoMap() - thuMargin: number; - - @AutoMap() - friMargin: number; - - @AutoMap() - satMargin: number; - - @AutoMap() - sunMargin: number; - - @AutoMap() - driverDuration?: number; - - @AutoMap() - driverDistance?: number; - - @AutoMap() - passengerDuration?: number; - - @AutoMap() - passengerDistance?: number; - - @AutoMap() - waypoints: string; - - @AutoMap() - direction: string; - - @AutoMap() - fwdAzimuth: number; - - @AutoMap() - backAzimuth: number; - - @AutoMap() - seatsDriver: number; - - @AutoMap() - seatsPassenger: number; - - @AutoMap() - seatsUsed: number; - - @AutoMap() - strict: boolean; - - @AutoMap() - createdAt: Date; - - @AutoMap() - updatedAt: Date; -} diff --git a/old/modules/ad/domain/entities/geography.ts b/old/modules/ad/domain/entities/geography.ts deleted file mode 100644 index e1ba54c..0000000 --- a/old/modules/ad/domain/entities/geography.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { Coordinate } from '../../../geography/domain/entities/coordinate'; -import { Route } from '../../../geography/domain/entities/route'; -import { Role } from '../types/role.enum'; -import { IGeorouter } from '../../../geography/domain/interfaces/georouter.interface'; -import { Path } from '../../../geography/domain/types/path.type'; -import { GeorouterSettings } from '../../../geography/domain/types/georouter-settings.type'; - -export class Geography { - private coordinates: Coordinate[]; - driverRoute: Route; - passengerRoute: Route; - - constructor(coordinates: Coordinate[]) { - this.coordinates = coordinates; - } - - createRoutes = async ( - roles: Role[], - georouter: IGeorouter, - settings: GeorouterSettings, - ): Promise => { - const paths: Path[] = this.getPaths(roles); - const routes = await georouter.route(paths, settings); - if (routes.some((route) => route.key == RouteType.COMMON)) { - this.driverRoute = routes.find( - (route) => route.key == RouteType.COMMON, - ).route; - this.passengerRoute = routes.find( - (route) => route.key == RouteType.COMMON, - ).route; - } else { - if (routes.some((route) => route.key == RouteType.DRIVER)) { - this.driverRoute = routes.find( - (route) => route.key == RouteType.DRIVER, - ).route; - } - if (routes.some((route) => route.key == RouteType.PASSENGER)) { - this.passengerRoute = routes.find( - (route) => route.key == RouteType.PASSENGER, - ).route; - } - } - }; - - private getPaths = (roles: Role[]): Path[] => { - const paths: Path[] = []; - if (roles.includes(Role.DRIVER) && roles.includes(Role.PASSENGER)) { - if (this.coordinates.length == 2) { - // 2 points => same route for driver and passenger - const commonPath: Path = { - key: RouteType.COMMON, - points: this.coordinates, - }; - paths.push(commonPath); - } else { - const driverPath: Path = this.createDriverPath(); - const passengerPath: Path = this.createPassengerPath(); - paths.push(driverPath, passengerPath); - } - } else if (roles.includes(Role.DRIVER)) { - const driverPath: Path = this.createDriverPath(); - paths.push(driverPath); - } else if (roles.includes(Role.PASSENGER)) { - const passengerPath: Path = this.createPassengerPath(); - paths.push(passengerPath); - } - return paths; - }; - - private createDriverPath = (): Path => { - return { - key: RouteType.DRIVER, - points: this.coordinates, - }; - }; - - private createPassengerPath = (): Path => { - return { - key: RouteType.PASSENGER, - points: [ - this.coordinates[0], - this.coordinates[this.coordinates.length - 1], - ], - }; - }; -} - -export enum RouteType { - COMMON = 'common', - DRIVER = 'driver', - PASSENGER = 'passenger', -} diff --git a/old/modules/ad/domain/entities/time-converter.ts b/old/modules/ad/domain/entities/time-converter.ts deleted file mode 100644 index e60bf76..0000000 --- a/old/modules/ad/domain/entities/time-converter.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { DateTime, TimeZone } from 'timezonecomplete'; - -export class TimeConverter { - static toUtcDatetime = (date: Date, time: string, timezone: string): Date => { - try { - if (!date || !time || !timezone) throw new Error(); - return new Date( - new DateTime( - `${date.toISOString().split('T')[0]}T${time}:00`, - TimeZone.zone(timezone, false), - ) - .convert(TimeZone.zone('UTC')) - .toIsoString(), - ); - } catch (e) { - return undefined; - } - }; -} diff --git a/old/modules/ad/domain/interfaces/params-provider.interface.ts b/old/modules/ad/domain/interfaces/params-provider.interface.ts deleted file mode 100644 index bde5a06..0000000 --- a/old/modules/ad/domain/interfaces/params-provider.interface.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { DefaultParams } from '../types/default-params.type'; - -export interface IProvideParams { - getParams(): DefaultParams; -} diff --git a/old/modules/ad/domain/types/default-params.type.ts b/old/modules/ad/domain/types/default-params.type.ts deleted file mode 100644 index bea841b..0000000 --- a/old/modules/ad/domain/types/default-params.type.ts +++ /dev/null @@ -1,5 +0,0 @@ -export type DefaultParams = { - DEFAULT_TIMEZONE: string; - GEOROUTER_TYPE: string; - GEOROUTER_URL: string; -}; diff --git a/old/modules/ad/domain/types/frequency.enum.ts b/old/modules/ad/domain/types/frequency.enum.ts deleted file mode 100644 index 0126874..0000000 --- a/old/modules/ad/domain/types/frequency.enum.ts +++ /dev/null @@ -1,4 +0,0 @@ -export enum Frequency { - PUNCTUAL = 'PUNCTUAL', - RECURRENT = 'RECURRENT', -} diff --git a/old/modules/ad/domain/types/role.enum.ts b/old/modules/ad/domain/types/role.enum.ts deleted file mode 100644 index 7522f80..0000000 --- a/old/modules/ad/domain/types/role.enum.ts +++ /dev/null @@ -1,4 +0,0 @@ -export enum Role { - DRIVER = 'DRIVER', - PASSENGER = 'PASSENGER', -} diff --git a/old/modules/ad/domain/usecases/create-ad.usecase.ts b/old/modules/ad/domain/usecases/create-ad.usecase.ts deleted file mode 100644 index 506a82a..0000000 --- a/old/modules/ad/domain/usecases/create-ad.usecase.ts +++ /dev/null @@ -1,150 +0,0 @@ -import { CommandHandler } from '@nestjs/cqrs'; -import { CreateAdCommand } from '../../commands/create-ad.command'; -import { Ad } from '../entities/ad'; -import { AdRepository } from '../../adapters/secondaries/ad.repository'; -import { InjectMapper } from '@automapper/nestjs'; -import { Mapper } from '@automapper/core'; -import { CreateAdRequest } from '../dtos/create-ad.request'; -import { Inject } from '@nestjs/common'; -import { IProvideParams } from '../interfaces/params-provider.interface'; -import { ICreateGeorouter } from '../../../geography/domain/interfaces/georouter-creator.interface'; -import { IFindTimezone } from '../../../geography/domain/interfaces/timezone-finder.interface'; -import { IGeorouter } from '../../../geography/domain/interfaces/georouter.interface'; -import { DefaultParams } from '../types/default-params.type'; -import { Role } from '../types/role.enum'; -import { Geography } from '../entities/geography'; -import { IEncodeDirection } from '../../../geography/domain/interfaces/direction-encoder.interface'; -import { TimeConverter } from '../entities/time-converter'; -import { Coordinate } from '../../../geography/domain/entities/coordinate'; -import { - DIRECTION_ENCODER, - GEOROUTER_CREATOR, - PARAMS_PROVIDER, - TIMEZONE_FINDER, -} from '../../ad.constants'; - -@CommandHandler(CreateAdCommand) -export class CreateAdUseCase { - private readonly georouter: IGeorouter; - private readonly defaultParams: DefaultParams; - private timezone: string; - private roles: Role[]; - private geography: Geography; - private ad: Ad; - - constructor( - @InjectMapper() private readonly mapper: Mapper, - private readonly adRepository: AdRepository, - @Inject(PARAMS_PROVIDER) - private readonly defaultParamsProvider: IProvideParams, - @Inject(GEOROUTER_CREATOR) - private readonly georouterCreator: ICreateGeorouter, - @Inject(TIMEZONE_FINDER) - private readonly timezoneFinder: IFindTimezone, - @Inject(DIRECTION_ENCODER) - private readonly directionEncoder: IEncodeDirection, - ) { - this.defaultParams = defaultParamsProvider.getParams(); - this.georouter = georouterCreator.create( - this.defaultParams.GEOROUTER_TYPE, - this.defaultParams.GEOROUTER_URL, - ); - } - - async execute(command: CreateAdCommand): Promise { - try { - this.ad = this.mapper.map(command.createAdRequest, CreateAdRequest, Ad); - this.setTimezone(command.createAdRequest.addresses); - this.setGeography(command.createAdRequest.addresses); - this.setRoles(command.createAdRequest); - await this.geography.createRoutes(this.roles, this.georouter, { - withDistance: false, - withPoints: true, - withTime: false, - }); - this.setAdGeography(command); - this.setAdSchedule(command); - return await this.adRepository.createAd(this.ad); - } catch (error) { - throw error; - } - } - - private setTimezone = (coordinates: Coordinate[]): void => { - this.timezone = this.defaultParams.DEFAULT_TIMEZONE; - try { - const timezones = this.timezoneFinder.timezones( - coordinates[0].lon, - coordinates[0].lat, - ); - if (timezones.length > 0) this.timezone = timezones[0]; - } catch (e) {} - }; - - private setRoles = (createAdRequest: CreateAdRequest): void => { - this.roles = []; - if (createAdRequest.driver) this.roles.push(Role.DRIVER); - if (createAdRequest.passenger) this.roles.push(Role.PASSENGER); - }; - - private setGeography = (coordinates: Coordinate[]): void => { - this.geography = new Geography(coordinates); - }; - - private setAdGeography = (command: CreateAdCommand): void => { - this.ad.driverDistance = this.geography.driverRoute?.distance; - this.ad.driverDuration = this.geography.driverRoute?.duration; - this.ad.passengerDistance = this.geography.passengerRoute?.distance; - this.ad.passengerDuration = this.geography.passengerRoute?.duration; - this.ad.fwdAzimuth = this.geography.driverRoute - ? this.geography.driverRoute.fwdAzimuth - : this.geography.passengerRoute.fwdAzimuth; - this.ad.backAzimuth = this.geography.driverRoute - ? this.geography.driverRoute.backAzimuth - : this.geography.passengerRoute.backAzimuth; - this.ad.waypoints = this.directionEncoder.encode( - command.createAdRequest.addresses, - ); - this.ad.direction = this.geography.driverRoute - ? this.directionEncoder.encode(this.geography.driverRoute.points) - : undefined; - }; - - private setAdSchedule = (command: CreateAdCommand): void => { - this.ad.monTime = TimeConverter.toUtcDatetime( - this.ad.fromDate, - command.createAdRequest.monTime, - this.timezone, - ); - this.ad.tueTime = TimeConverter.toUtcDatetime( - this.ad.fromDate, - command.createAdRequest.tueTime, - this.timezone, - ); - this.ad.wedTime = TimeConverter.toUtcDatetime( - this.ad.fromDate, - command.createAdRequest.wedTime, - this.timezone, - ); - this.ad.thuTime = TimeConverter.toUtcDatetime( - this.ad.fromDate, - command.createAdRequest.thuTime, - this.timezone, - ); - this.ad.friTime = TimeConverter.toUtcDatetime( - this.ad.fromDate, - command.createAdRequest.friTime, - this.timezone, - ); - this.ad.satTime = TimeConverter.toUtcDatetime( - this.ad.fromDate, - command.createAdRequest.satTime, - this.timezone, - ); - this.ad.sunTime = TimeConverter.toUtcDatetime( - this.ad.fromDate, - command.createAdRequest.sunTime, - this.timezone, - ); - }; -} diff --git a/old/modules/ad/mappers/ad.profile.ts b/old/modules/ad/mappers/ad.profile.ts deleted file mode 100644 index bbc38d5..0000000 --- a/old/modules/ad/mappers/ad.profile.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { createMap, Mapper } from '@automapper/core'; -import { AutomapperProfile, InjectMapper } from '@automapper/nestjs'; -import { Injectable } from '@nestjs/common'; -import { Ad } from '../domain/entities/ad'; -import { CreateAdRequest } from '../domain/dtos/create-ad.request'; - -@Injectable() -export class AdProfile extends AutomapperProfile { - constructor(@InjectMapper() mapper: Mapper) { - super(mapper); - } - - override get profile() { - return (mapper: any) => { - createMap(mapper, CreateAdRequest, Ad); - }; - } -} diff --git a/old/modules/ad/tests/integration/ad.repository.spec.ts b/old/modules/ad/tests/integration/ad.repository.spec.ts deleted file mode 100644 index 7df5c09..0000000 --- a/old/modules/ad/tests/integration/ad.repository.spec.ts +++ /dev/null @@ -1,402 +0,0 @@ -import { TestingModule, Test } from '@nestjs/testing'; -import { DatabaseModule } from '../../../database/database.module'; -import { PrismaService } from '../../../database/adapters/secondaries/prisma.service'; -import { AdRepository } from '../../adapters/secondaries/ad.repository'; -import { Ad } from '../../domain/entities/ad'; -import { Frequency } from '../../domain/types/frequency.enum'; - -describe('AdRepository', () => { - let prismaService: PrismaService; - let adRepository: AdRepository; - - const baseUuid = { - uuid: 'be459a29-7a41-4c0b-b371-abe90bfb6f00', - }; - const baseUserUuid = { - userUuid: '4e52b54d-a729-4dbd-9283-f84a11bb2200', - }; - const driverAd = { - driver: 'true', - passenger: 'false', - fwdAzimuth: 0, - backAzimuth: 180, - waypoints: "'LINESTRING(6 47,6.1 47.1,6.2 47.2)'", - direction: "'LINESTRING(6 47,6.05 47.05,6.1 47.1,6.15 47.15,6.2 47.2)'", - seatsDriver: 3, - seatsPassenger: 1, - seatsUsed: 0, - strict: 'false', - }; - const passengerAd = { - driver: 'false', - passenger: 'true', - fwdAzimuth: 0, - backAzimuth: 180, - waypoints: "'LINESTRING(6 47,6.2 47.2)'", - direction: "'LINESTRING(6 47,6.05 47.05,6.15 47.15,6.2 47.2)'", - seatsDriver: 3, - seatsPassenger: 1, - seatsUsed: 0, - strict: 'false', - }; - const driverAndPassengerAd = { - driver: 'true', - passenger: 'true', - fwdAzimuth: 0, - backAzimuth: 180, - waypoints: "'LINESTRING(6 47,6.1 47.1,6.2 47.2)'", - direction: "'LINESTRING(6 47,6.05 47.05,6.1 47.1,6.15 47.15,6.2 47.2)'", - seatsDriver: 3, - seatsPassenger: 1, - seatsUsed: 0, - strict: 'false', - }; - const punctualAd = { - frequency: `'PUNCTUAL'`, - fromDate: `'2023-01-01'`, - toDate: `'2023-01-01'`, - monTime: 'NULL', - tueTime: 'NULL', - wedTime: 'NULL', - thuTime: 'NULL', - friTime: 'NULL', - satTime: 'NULL', - sunTime: `'2023-01-01T07:00Z'`, - monMargin: 900, - tueMargin: 900, - wedMargin: 900, - thuMargin: 900, - friMargin: 900, - satMargin: 900, - sunMargin: 900, - }; - const recurrentAd = { - frequency: `'RECURRENT'`, - fromDate: `'2023-01-01'`, - toDate: `'2023-12-31'`, - monTime: `'2023-01-01T07:00Z'`, - tueTime: `'2023-01-01T07:00Z'`, - wedTime: `'2023-01-01T07:00Z'`, - thuTime: `'2023-01-01T07:00Z'`, - friTime: `'2023-01-01T07:00Z'`, - satTime: 'NULL', - sunTime: 'NULL', - monMargin: 900, - tueMargin: 900, - wedMargin: 900, - thuMargin: 900, - friMargin: 900, - satMargin: 900, - sunMargin: 900, - }; - - const createPunctualDriverAds = async (nbToCreate = 10) => { - const adToCreate = { - ...baseUuid, - ...baseUserUuid, - ...driverAd, - ...punctualAd, - }; - for (let i = 0; i < nbToCreate; i++) { - adToCreate.uuid = `'${baseUuid.uuid.slice(0, -2)}${i - .toString(16) - .padStart(2, '0')}'`; - adToCreate.userUuid = `'${baseUserUuid.userUuid.slice(0, -2)}${i - .toString(16) - .padStart(2, '0')}'`; - await executeInsertCommand(adToCreate); - } - }; - - const createRecurrentDriverAds = async (nbToCreate = 10) => { - const adToCreate = { - ...baseUuid, - ...baseUserUuid, - ...driverAd, - ...recurrentAd, - }; - for (let i = 0; i < nbToCreate; i++) { - adToCreate.uuid = `'${baseUuid.uuid.slice(0, -2)}${i - .toString(16) - .padStart(2, '0')}'`; - adToCreate.userUuid = `'${baseUserUuid.userUuid.slice(0, -2)}${i - .toString(16) - .padStart(2, '0')}'`; - await executeInsertCommand(adToCreate); - } - }; - - const createPunctualPassengerAds = async (nbToCreate = 10) => { - const adToCreate = { - ...baseUuid, - ...baseUserUuid, - ...passengerAd, - ...punctualAd, - }; - for (let i = 0; i < nbToCreate; i++) { - adToCreate.uuid = `'${baseUuid.uuid.slice(0, -2)}${i - .toString(16) - .padStart(2, '0')}'`; - adToCreate.userUuid = `'${baseUserUuid.userUuid.slice(0, -2)}${i - .toString(16) - .padStart(2, '0')}'`; - await executeInsertCommand(adToCreate); - } - }; - - const createRecurrentPassengerAds = async (nbToCreate = 10) => { - const adToCreate = { - ...baseUuid, - ...baseUserUuid, - ...passengerAd, - ...recurrentAd, - }; - for (let i = 0; i < nbToCreate; i++) { - adToCreate.uuid = `'${baseUuid.uuid.slice(0, -2)}${i - .toString(16) - .padStart(2, '0')}'`; - adToCreate.userUuid = `'${baseUserUuid.userUuid.slice(0, -2)}${i - .toString(16) - .padStart(2, '0')}'`; - await executeInsertCommand(adToCreate); - } - }; - - const createPunctualDriverPassengerAds = async (nbToCreate = 10) => { - const adToCreate = { - ...baseUuid, - ...baseUserUuid, - ...driverAndPassengerAd, - ...punctualAd, - }; - for (let i = 0; i < nbToCreate; i++) { - adToCreate.uuid = `'${baseUuid.uuid.slice(0, -2)}${i - .toString(16) - .padStart(2, '0')}'`; - adToCreate.userUuid = `'${baseUserUuid.userUuid.slice(0, -2)}${i - .toString(16) - .padStart(2, '0')}'`; - await executeInsertCommand(adToCreate); - } - }; - - const createRecurrentDriverPassengerAds = async (nbToCreate = 10) => { - const adToCreate = { - ...baseUuid, - ...baseUserUuid, - ...driverAndPassengerAd, - ...recurrentAd, - }; - for (let i = 0; i < nbToCreate; i++) { - adToCreate.uuid = `'${baseUuid.uuid.slice(0, -2)}${i - .toString(16) - .padStart(2, '0')}'`; - adToCreate.userUuid = `'${baseUserUuid.userUuid.slice(0, -2)}${i - .toString(16) - .padStart(2, '0')}'`; - await executeInsertCommand(adToCreate); - } - }; - - const executeInsertCommand = async (object: any) => { - const command = `INSERT INTO ad ("${Object.keys(object).join( - '","', - )}") VALUES (${Object.values(object).join(',')})`; - await prismaService.$executeRawUnsafe(command); - }; - - beforeAll(async () => { - const module: TestingModule = await Test.createTestingModule({ - imports: [DatabaseModule], - providers: [AdRepository, PrismaService], - }).compile(); - - prismaService = module.get(PrismaService); - adRepository = module.get(AdRepository); - }); - - afterAll(async () => { - await prismaService.$disconnect(); - }); - - beforeEach(async () => { - await prismaService.ad.deleteMany(); - }); - - describe('findAll', () => { - it('should return an empty data array', async () => { - const res = await adRepository.findAll(); - expect(res).toEqual({ - data: [], - total: 0, - }); - }); - - describe('drivers', () => { - it('should return a data array with 8 punctual driver ads', async () => { - await createPunctualDriverAds(8); - const ads = await adRepository.findAll(); - expect(ads.data.length).toBe(8); - expect(ads.total).toBe(8); - expect(ads.data[0].driver).toBeTruthy(); - expect(ads.data[0].passenger).toBeFalsy(); - }); - - it('should return a data array limited to 10 punctual driver ads', async () => { - await createPunctualDriverAds(20); - const ads = await adRepository.findAll(); - expect(ads.data.length).toBe(10); - expect(ads.total).toBe(20); - expect(ads.data[1].driver).toBeTruthy(); - expect(ads.data[1].passenger).toBeFalsy(); - }); - - it('should return a data array with 8 recurrent driver ads', async () => { - await createRecurrentDriverAds(8); - const ads = await adRepository.findAll(); - expect(ads.data.length).toBe(8); - expect(ads.total).toBe(8); - expect(ads.data[2].driver).toBeTruthy(); - expect(ads.data[2].passenger).toBeFalsy(); - }); - - it('should return a data array limited to 10 recurrent driver ads', async () => { - await createRecurrentDriverAds(20); - const ads = await adRepository.findAll(); - expect(ads.data.length).toBe(10); - expect(ads.total).toBe(20); - expect(ads.data[3].driver).toBeTruthy(); - expect(ads.data[3].passenger).toBeFalsy(); - }); - }); - - describe('passengers', () => { - it('should return a data array with 7 punctual passenger ads', async () => { - await createPunctualPassengerAds(7); - const ads = await adRepository.findAll(); - expect(ads.data.length).toBe(7); - expect(ads.total).toBe(7); - expect(ads.data[0].passenger).toBeTruthy(); - expect(ads.data[0].driver).toBeFalsy(); - }); - - it('should return a data array limited to 10 punctual passenger ads', async () => { - await createPunctualPassengerAds(15); - const ads = await adRepository.findAll(); - expect(ads.data.length).toBe(10); - expect(ads.total).toBe(15); - expect(ads.data[1].passenger).toBeTruthy(); - expect(ads.data[1].driver).toBeFalsy(); - }); - - it('should return a data array with 7 recurrent passenger ads', async () => { - await createRecurrentPassengerAds(7); - const ads = await adRepository.findAll(); - expect(ads.data.length).toBe(7); - expect(ads.total).toBe(7); - expect(ads.data[2].passenger).toBeTruthy(); - expect(ads.data[2].driver).toBeFalsy(); - }); - - it('should return a data array limited to 10 recurrent passenger ads', async () => { - await createRecurrentPassengerAds(15); - const ads = await adRepository.findAll(); - expect(ads.data.length).toBe(10); - expect(ads.total).toBe(15); - expect(ads.data[3].passenger).toBeTruthy(); - expect(ads.data[3].driver).toBeFalsy(); - }); - }); - - describe('drivers and passengers', () => { - it('should return a data array with 6 punctual driver and passenger ads', async () => { - await createPunctualDriverPassengerAds(6); - const ads = await adRepository.findAll(); - expect(ads.data.length).toBe(6); - expect(ads.total).toBe(6); - expect(ads.data[0].passenger).toBeTruthy(); - expect(ads.data[0].driver).toBeTruthy(); - }); - - it('should return a data array limited to 10 punctual driver and passenger ads', async () => { - await createPunctualDriverPassengerAds(16); - const ads = await adRepository.findAll(); - expect(ads.data.length).toBe(10); - expect(ads.total).toBe(16); - expect(ads.data[1].passenger).toBeTruthy(); - expect(ads.data[1].driver).toBeTruthy(); - }); - - it('should return a data array with 6 recurrent driver and passenger ads', async () => { - await createRecurrentDriverPassengerAds(6); - const ads = await adRepository.findAll(); - expect(ads.data.length).toBe(6); - expect(ads.total).toBe(6); - expect(ads.data[2].passenger).toBeTruthy(); - expect(ads.data[2].driver).toBeTruthy(); - }); - - it('should return a data array limited to 10 recurrent driver and passenger ads', async () => { - await createRecurrentDriverPassengerAds(16); - const ads = await adRepository.findAll(); - expect(ads.data.length).toBe(10); - expect(ads.total).toBe(16); - expect(ads.data[3].passenger).toBeTruthy(); - expect(ads.data[3].driver).toBeTruthy(); - }); - }); - }); - - describe('findOneByUuid', () => { - it('should return an ad', async () => { - await createPunctualDriverAds(1); - const ad = await adRepository.findOneByUuid(baseUuid.uuid); - expect(ad.uuid).toBe(baseUuid.uuid); - }); - - it('should return null', async () => { - const ad = await adRepository.findOneByUuid( - '544572be-11fb-4244-8235-587221fc9104', - ); - expect(ad).toBeNull(); - }); - }); - - describe('create', () => { - it('should create an ad', async () => { - const beforeCount = await prismaService.ad.count(); - - const adToCreate: Ad = new Ad(); - adToCreate.uuid = 'be459a29-7a41-4c0b-b371-abe90bfb6f00'; - adToCreate.userUuid = '4e52b54d-a729-4dbd-9283-f84a11bb2200'; - adToCreate.driver = true; - adToCreate.passenger = false; - adToCreate.fwdAzimuth = 0; - adToCreate.backAzimuth = 180; - adToCreate.waypoints = "'LINESTRING(6 47,6.1 47.1,6.2 47.2)'"; - adToCreate.direction = - "'LINESTRING(6 47,6.05 47.05,6.1 47.1,6.15 47.15,6.2 47.2)'"; - adToCreate.seatsDriver = 3; - adToCreate.seatsPassenger = 1; - adToCreate.seatsUsed = 0; - adToCreate.strict = false; - adToCreate.frequency = Frequency.PUNCTUAL; - adToCreate.fromDate = new Date(2023, 0, 1); - adToCreate.toDate = new Date(2023, 0, 1); - adToCreate.sunTime = new Date(2023, 0, 1, 6, 0, 0); - adToCreate.monMargin = 900; - adToCreate.tueMargin = 900; - adToCreate.wedMargin = 900; - adToCreate.thuMargin = 900; - adToCreate.friMargin = 900; - adToCreate.satMargin = 900; - adToCreate.sunMargin = 900; - const ad = await adRepository.createAd(adToCreate); - - const afterCount = await prismaService.ad.count(); - - expect(afterCount - beforeCount).toBe(1); - expect(ad.uuid).toBe('be459a29-7a41-4c0b-b371-abe90bfb6f00'); - }); - }); -}); diff --git a/old/modules/ad/tests/unit/adapters/secondaries/default-params.provider.spec.ts b/old/modules/ad/tests/unit/adapters/secondaries/default-params.provider.spec.ts deleted file mode 100644 index 5b69430..0000000 --- a/old/modules/ad/tests/unit/adapters/secondaries/default-params.provider.spec.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { ConfigService } from '@nestjs/config'; -import { Test, TestingModule } from '@nestjs/testing'; -import { DefaultParamsProvider } from '../../../../adapters/secondaries/default-params.provider'; -import { DefaultParams } from '../../../../domain/types/default-params.type'; - -const mockConfigService = { - get: jest.fn().mockImplementation(() => 'some_default_value'), -}; - -describe('DefaultParamsProvider', () => { - let defaultParamsProvider: DefaultParamsProvider; - - beforeAll(async () => { - const module: TestingModule = await Test.createTestingModule({ - imports: [], - providers: [ - DefaultParamsProvider, - { - provide: ConfigService, - useValue: mockConfigService, - }, - ], - }).compile(); - - defaultParamsProvider = module.get( - DefaultParamsProvider, - ); - }); - - it('should be defined', () => { - expect(defaultParamsProvider).toBeDefined(); - }); - - it('should provide default params', async () => { - const params: DefaultParams = defaultParamsProvider.getParams(); - expect(params.GEOROUTER_URL).toBe('some_default_value'); - }); -}); diff --git a/old/modules/ad/tests/unit/adapters/secondaries/message-publisher.spec.ts b/old/modules/ad/tests/unit/adapters/secondaries/message-publisher.spec.ts deleted file mode 100644 index a60708f..0000000 --- a/old/modules/ad/tests/unit/adapters/secondaries/message-publisher.spec.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { MessagePublisher } from '../../../../adapters/secondaries/message-publisher'; -import { MESSAGE_BROKER_PUBLISHER } from '../../../../../../app.constants'; - -const mockMessageBrokerPublisher = { - publish: jest.fn().mockImplementation(), -}; - -describe('Messager', () => { - let messagePublisher: MessagePublisher; - - beforeAll(async () => { - const module: TestingModule = await Test.createTestingModule({ - imports: [], - providers: [ - MessagePublisher, - { - provide: MESSAGE_BROKER_PUBLISHER, - useValue: mockMessageBrokerPublisher, - }, - ], - }).compile(); - - messagePublisher = module.get(MessagePublisher); - }); - - it('should be defined', () => { - expect(messagePublisher).toBeDefined(); - }); - - it('should publish a message', async () => { - jest.spyOn(mockMessageBrokerPublisher, 'publish'); - messagePublisher.publish('ad.info', 'my-test'); - expect(mockMessageBrokerPublisher.publish).toHaveBeenCalledTimes(1); - }); -}); diff --git a/old/modules/ad/tests/unit/adapters/secondaries/timezone-finder.spec.ts b/old/modules/ad/tests/unit/adapters/secondaries/timezone-finder.spec.ts deleted file mode 100644 index 63d8462..0000000 --- a/old/modules/ad/tests/unit/adapters/secondaries/timezone-finder.spec.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { TimezoneFinder } from '../../../../adapters/secondaries/timezone-finder'; -import { GeoTimezoneFinder } from '../../../../../geography/adapters/secondaries/geo-timezone-finder'; - -const mockGeoTimezoneFinder = { - timezones: jest.fn().mockImplementation(() => ['Europe/Paris']), -}; - -describe('Timezone Finder', () => { - let timezoneFinder: TimezoneFinder; - - beforeAll(async () => { - const module: TestingModule = await Test.createTestingModule({ - imports: [], - providers: [ - TimezoneFinder, - { - provide: GeoTimezoneFinder, - useValue: mockGeoTimezoneFinder, - }, - ], - }).compile(); - - timezoneFinder = module.get(TimezoneFinder); - }); - - it('should be defined', () => { - expect(timezoneFinder).toBeDefined(); - }); - it('should get timezone for Nancy(France) as Europe/Paris', () => { - const timezones = timezoneFinder.timezones(6.179373, 48.687913); - expect(timezones.length).toBe(1); - expect(timezones[0]).toBe('Europe/Paris'); - }); -}); diff --git a/old/modules/ad/tests/unit/domain/create-ad.usecase.spec.ts b/old/modules/ad/tests/unit/domain/create-ad.usecase.spec.ts deleted file mode 100644 index d6819c1..0000000 --- a/old/modules/ad/tests/unit/domain/create-ad.usecase.spec.ts +++ /dev/null @@ -1,182 +0,0 @@ -import { CreateAdRequest } from '../../../domain/dtos/create-ad.request'; -import { CreateAdUseCase } from '../../../domain/usecases/create-ad.usecase'; -import { Test, TestingModule } from '@nestjs/testing'; -import { AutomapperModule } from '@automapper/nestjs'; -import { classes } from '@automapper/classes'; -import { AdRepository } from '../../../adapters/secondaries/ad.repository'; -import { CreateAdCommand } from '../../../commands/create-ad.command'; -import { Ad } from '../../../domain/entities/ad'; -import { AdProfile } from '../../../mappers/ad.profile'; -import { Frequency } from '../../../domain/types/frequency.enum'; -import { RouteType } from '../../../domain/entities/geography'; -import { DatabaseException } from '../../../../database/exceptions/database.exception'; -import { Route } from '../../../../geography/domain/entities/route'; -import { - DIRECTION_ENCODER, - GEOROUTER_CREATOR, - PARAMS_PROVIDER, - TIMEZONE_FINDER, -} from '../../../ad.constants'; - -const mockAdRepository = { - createAd: jest.fn().mockImplementation((ad) => { - if (ad.uuid == '00000000-0000-0000-0000-000000000000') - throw new DatabaseException(); - return new Ad(); - }), -}; -const mockGeorouterCreator = { - create: jest.fn().mockImplementation(() => ({ - route: jest.fn().mockImplementation(() => [ - { - key: RouteType.DRIVER, - route: { - points: [], - fwdAzimuth: 0, - backAzimuth: 180, - distance: 20000, - duration: 1800, - }, - }, - { - key: RouteType.PASSENGER, - route: { - points: [], - fwdAzimuth: 0, - backAzimuth: 180, - distance: 20000, - duration: 1800, - }, - }, - { - key: RouteType.COMMON, - route: { - points: [], - fwdAzimuth: 0, - backAzimuth: 180, - distance: 20000, - duration: 1800, - }, - }, - ]), - })), -}; -const mockParamsProvider = { - getParams: jest.fn().mockImplementation(() => ({ - DEFAULT_TIMEZONE: 'Europe/Paris', - GEOROUTER_TYPE: 'graphhopper', - GEOROUTER_URL: 'localhost', - })), -}; -const mockTimezoneFinder = { - timezones: jest.fn().mockImplementation(() => ['Europe/Paris']), -}; -const mockDirectionEncoder = { - encode: jest.fn(), -}; - -const createAdRequest: CreateAdRequest = { - uuid: '77c55dfc-c28b-4026-942e-f94e95401fb1', - userUuid: 'dfd993f6-7889-4876-9570-5e1d7b6e3f42', - driver: true, - passenger: false, - frequency: Frequency.RECURRENT, - fromDate: new Date('2023-04-26'), - toDate: new Date('2024-04-25'), - monTime: '07:00', - tueTime: '07:00', - wedTime: '07:00', - thuTime: '07:00', - friTime: '07:00', - satTime: null, - sunTime: null, - monMargin: 900, - tueMargin: 900, - wedMargin: 900, - thuMargin: 900, - friMargin: 900, - satMargin: 900, - sunMargin: 900, - seatsDriver: 3, - seatsPassenger: 1, - strict: false, - addresses: [ - { lon: 6, lat: 45 }, - { lon: 6.5, lat: 45.5 }, - ], -}; - -const setUuid = async (uuid: string): Promise => { - createAdRequest.uuid = uuid; -}; - -const setIsDriver = async (isDriver: boolean): Promise => { - createAdRequest.driver = isDriver; -}; - -const setIsPassenger = async (isPassenger: boolean): Promise => { - createAdRequest.passenger = isPassenger; -}; - -describe('CreateAdUseCase', () => { - let createAdUseCase: CreateAdUseCase; - - beforeAll(async () => { - const module: TestingModule = await Test.createTestingModule({ - imports: [AutomapperModule.forRoot({ strategyInitializer: classes() })], - providers: [ - { - provide: AdRepository, - useValue: mockAdRepository, - }, - { - provide: GEOROUTER_CREATOR, - useValue: mockGeorouterCreator, - }, - { - provide: PARAMS_PROVIDER, - useValue: mockParamsProvider, - }, - { - provide: TIMEZONE_FINDER, - useValue: mockTimezoneFinder, - }, - { - provide: DIRECTION_ENCODER, - useValue: mockDirectionEncoder, - }, - AdProfile, - CreateAdUseCase, - ], - }).compile(); - - createAdUseCase = module.get(CreateAdUseCase); - }); - - it('should be defined', () => { - expect(createAdUseCase).toBeDefined(); - }); - - describe('execute', () => { - it('should create an ad as driver', async () => { - const ad = await createAdUseCase.execute( - new CreateAdCommand(createAdRequest), - ); - expect(ad).toBeInstanceOf(Ad); - }); - it('should create an ad as passenger', async () => { - await setIsDriver(false); - await setIsPassenger(true); - const ad = await createAdUseCase.execute( - new CreateAdCommand(createAdRequest), - ); - expect(ad).toBeInstanceOf(Ad); - }); - it('should throw an exception if repository fails', async () => { - await setUuid('00000000-0000-0000-0000-000000000000'); - await expect( - createAdUseCase.execute(new CreateAdCommand(createAdRequest)), - ).rejects.toBeInstanceOf(DatabaseException); - }); - }); -}); diff --git a/old/modules/ad/tests/unit/domain/geography.spec.ts b/old/modules/ad/tests/unit/domain/geography.spec.ts deleted file mode 100644 index bf3de17..0000000 --- a/old/modules/ad/tests/unit/domain/geography.spec.ts +++ /dev/null @@ -1,138 +0,0 @@ -import { Role } from '../../../domain/types/role.enum'; -import { Geography } from '../../../domain/entities/geography'; -import { Coordinate } from '../../../../geography/domain/entities/coordinate'; -import { IGeorouter } from '../../../../geography/domain/interfaces/georouter.interface'; -import { GeorouterSettings } from '../../../../geography/domain/types/georouter-settings.type'; -import { Route } from '../../../../geography/domain/entities/route'; -import { IGeodesic } from '../../../../geography/domain/interfaces/geodesic.interface'; - -const simpleCoordinates: Coordinate[] = [ - { - lon: 6, - lat: 47, - }, - { - lon: 6.1, - lat: 47.1, - }, -]; - -const complexCoordinates: Coordinate[] = [ - { - lon: 6, - lat: 47, - }, - { - lon: 6.1, - lat: 47.1, - }, - { - lon: 6.2, - lat: 47.2, - }, -]; - -const mockGeodesic: IGeodesic = { - inverse: jest.fn(), -}; - -const driverRoute: Route = new Route(mockGeodesic); -driverRoute.distance = 25000; - -const commonRoute: Route = new Route(mockGeodesic); -commonRoute.distance = 20000; - -const mockGeorouter: IGeorouter = { - route: jest - .fn() - .mockResolvedValueOnce([ - { - key: 'driver', - route: driverRoute, - }, - ]) - .mockResolvedValueOnce([ - { - key: 'passenger', - route: commonRoute, - }, - ]) - .mockResolvedValueOnce([ - { - key: 'common', - route: commonRoute, - }, - ]) - .mockResolvedValueOnce([ - { - key: 'driver', - route: driverRoute, - }, - { - key: 'passenger', - route: commonRoute, - }, - ]), -}; - -const georouterSettings: GeorouterSettings = { - withDistance: false, - withPoints: true, - withTime: false, -}; - -describe('Geography entity', () => { - it('should be defined', () => { - expect(new Geography(simpleCoordinates)).toBeDefined(); - }); - - it('should create a route as driver', async () => { - const geography = new Geography(complexCoordinates); - await geography.createRoutes( - [Role.DRIVER], - mockGeorouter, - georouterSettings, - ); - expect(geography.driverRoute).toBeDefined(); - expect(geography.passengerRoute).toBeUndefined(); - expect(geography.driverRoute.distance).toBe(25000); - }); - - it('should create a route as passenger', async () => { - const geography = new Geography(simpleCoordinates); - await geography.createRoutes( - [Role.PASSENGER], - mockGeorouter, - georouterSettings, - ); - expect(geography.driverRoute).toBeUndefined(); - expect(geography.passengerRoute).toBeDefined(); - expect(geography.passengerRoute.distance).toBe(20000); - }); - - it('should create routes as driver and passenger with simple coordinates', async () => { - const geography = new Geography(simpleCoordinates); - await geography.createRoutes( - [Role.DRIVER, Role.PASSENGER], - mockGeorouter, - georouterSettings, - ); - expect(geography.driverRoute).toBeDefined(); - expect(geography.passengerRoute).toBeDefined(); - expect(geography.driverRoute.distance).toBe(20000); - expect(geography.passengerRoute.distance).toBe(20000); - }); - - it('should create routes as driver and passenger with complex coordinates', async () => { - const geography = new Geography(complexCoordinates); - await geography.createRoutes( - [Role.DRIVER, Role.PASSENGER], - mockGeorouter, - georouterSettings, - ); - expect(geography.driverRoute).toBeDefined(); - expect(geography.passengerRoute).toBeDefined(); - expect(geography.driverRoute.distance).toBe(25000); - expect(geography.passengerRoute.distance).toBe(20000); - }); -}); diff --git a/old/modules/ad/tests/unit/domain/time-converter.spec.ts b/old/modules/ad/tests/unit/domain/time-converter.spec.ts deleted file mode 100644 index 9c4113d..0000000 --- a/old/modules/ad/tests/unit/domain/time-converter.spec.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { TimeConverter } from '../../../domain/entities/time-converter'; - -describe('TimeConverter', () => { - it('should be defined', () => { - expect(new TimeConverter()).toBeDefined(); - }); - - it('should convert a Europe/Paris datetime to utc datetime', () => { - expect( - TimeConverter.toUtcDatetime( - new Date('2023-05-01'), - '07:00', - 'Europe/Paris', - ).getUTCHours(), - ).toBe(6); - }); - - it('should return undefined when trying to convert a Europe/Paris datetime to utc datetime without a valid date', () => { - expect( - TimeConverter.toUtcDatetime(undefined, '07:00', 'Europe/Paris'), - ).toBeUndefined(); - expect( - TimeConverter.toUtcDatetime( - new Date('2023-13-01'), - '07:00', - 'Europe/Paris', - ), - ).toBeUndefined(); - }); - - it('should return undefined when trying to convert a Europe/Paris datetime to utc datetime without a valid time', () => { - expect( - TimeConverter.toUtcDatetime( - new Date('2023-05-01'), - undefined, - 'Europe/Paris', - ), - ).toBeUndefined(); - expect( - TimeConverter.toUtcDatetime(new Date('2023-05-01'), 'a', 'Europe/Paris'), - ).toBeUndefined(); - }); - - it('should return undefined when trying to convert a datetime to utc datetime without a valid timezone', () => { - expect( - TimeConverter.toUtcDatetime( - new Date('2023-12-01'), - '07:00', - 'OlympusMons/Mars', - ), - ).toBeUndefined(); - }); -}); diff --git a/old/modules/database/adapters/secondaries/prisma.repository.abstract.ts b/old/modules/database/adapters/secondaries/prisma.repository.abstract.ts deleted file mode 100644 index 1ab4b67..0000000 --- a/old/modules/database/adapters/secondaries/prisma.repository.abstract.ts +++ /dev/null @@ -1,259 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { Prisma } from '@prisma/client'; -import { DatabaseException } from '../../exceptions/database.exception'; -import { ICollection } from '../../interfaces/collection.interface'; -import { IRepository } from '../../interfaces/repository.interface'; -import { PrismaService } from './prisma.service'; - -/** - * Child classes MUST redefined model property with appropriate model name - */ -@Injectable() -export abstract class PrismaRepository implements IRepository { - protected model: string; - - constructor(protected readonly prisma: PrismaService) {} - - findAll = async ( - page = 1, - perPage = 10, - where?: any, - include?: any, - ): Promise> => { - const [data, total] = await this.prisma.$transaction([ - this.prisma[this.model].findMany({ - where, - include, - skip: (page - 1) * perPage, - take: perPage, - }), - this.prisma[this.model].count({ - where, - }), - ]); - return Promise.resolve({ - data, - total, - }); - }; - - findOneByUuid = async (uuid: string): Promise => { - try { - const entity = await this.prisma[this.model].findUnique({ - where: { uuid }, - }); - - return entity; - } catch (e) { - if (e instanceof Prisma.PrismaClientKnownRequestError) { - throw new DatabaseException( - Prisma.PrismaClientKnownRequestError.name, - e.code, - e.message, - ); - } else { - throw new DatabaseException(); - } - } - }; - - findOne = async (where: any, include?: any): Promise => { - try { - const entity = await this.prisma[this.model].findFirst({ - where: where, - include: include, - }); - - return entity; - } catch (e) { - if (e instanceof Prisma.PrismaClientKnownRequestError) { - throw new DatabaseException( - Prisma.PrismaClientKnownRequestError.name, - e.code, - ); - } else { - throw new DatabaseException(); - } - } - }; - - // TODO : using any is not good, but needed for nested entities - // TODO : Refactor for good clean architecture ? - async create(entity: Partial | any, include?: any): Promise { - try { - const res = await this.prisma[this.model].create({ - data: entity, - include: include, - }); - - return res; - } catch (e) { - if (e instanceof Prisma.PrismaClientKnownRequestError) { - throw new DatabaseException( - Prisma.PrismaClientKnownRequestError.name, - e.code, - e.message, - ); - } else { - throw new DatabaseException(); - } - } - } - - update = async (uuid: string, entity: Partial): Promise => { - try { - const updatedEntity = await this.prisma[this.model].update({ - where: { uuid }, - data: entity, - }); - return updatedEntity; - } catch (e) { - if (e instanceof Prisma.PrismaClientKnownRequestError) { - throw new DatabaseException( - Prisma.PrismaClientKnownRequestError.name, - e.code, - e.message, - ); - } else { - throw new DatabaseException(); - } - } - }; - - updateWhere = async ( - where: any, - entity: Partial | any, - include?: any, - ): Promise => { - try { - const updatedEntity = await this.prisma[this.model].update({ - where: where, - data: entity, - include: include, - }); - - return updatedEntity; - } catch (e) { - if (e instanceof Prisma.PrismaClientKnownRequestError) { - throw new DatabaseException( - Prisma.PrismaClientKnownRequestError.name, - e.code, - e.message, - ); - } else { - throw new DatabaseException(); - } - } - }; - - delete = async (uuid: string): Promise => { - try { - const entity = await this.prisma[this.model].delete({ - where: { uuid }, - }); - - return entity; - } catch (e) { - if (e instanceof Prisma.PrismaClientKnownRequestError) { - throw new DatabaseException( - Prisma.PrismaClientKnownRequestError.name, - e.code, - e.message, - ); - } else { - throw new DatabaseException(); - } - } - }; - - deleteMany = async (where: any): Promise => { - try { - const entity = await this.prisma[this.model].deleteMany({ - where: where, - }); - - return entity; - } catch (e) { - if (e instanceof Prisma.PrismaClientKnownRequestError) { - throw new DatabaseException( - Prisma.PrismaClientKnownRequestError.name, - e.code, - e.message, - ); - } else { - throw new DatabaseException(); - } - } - }; - - findAllByQuery = async ( - include: string[], - where: string[], - ): Promise> => { - const query = `SELECT ${include.join(',')} FROM ${ - this.model - } WHERE ${where.join(' AND ')}`; - const data: T[] = await this.prisma.$queryRawUnsafe(query); - return Promise.resolve({ - data, - total: data.length, - }); - }; - - createWithFields = async (fields: object): Promise => { - try { - const command = `INSERT INTO ${this.model} ("${Object.keys(fields).join( - '","', - )}") VALUES (${Object.values(fields).join(',')})`; - return await this.prisma.$executeRawUnsafe(command); - } catch (e) { - if (e instanceof Prisma.PrismaClientKnownRequestError) { - throw new DatabaseException( - Prisma.PrismaClientKnownRequestError.name, - e.code, - e.message, - ); - } else { - throw new DatabaseException(); - } - } - }; - - updateWithFields = async (uuid: string, entity: object): Promise => { - entity['"updatedAt"'] = `to_timestamp(${Date.now()} / 1000.0)`; - const values = Object.keys(entity).map((key) => `${key} = ${entity[key]}`); - try { - const command = `UPDATE ${this.model} SET ${values.join( - ', ', - )} WHERE uuid = '${uuid}'`; - return await this.prisma.$executeRawUnsafe(command); - } catch (e) { - if (e instanceof Prisma.PrismaClientKnownRequestError) { - throw new DatabaseException( - Prisma.PrismaClientKnownRequestError.name, - e.code, - e.message, - ); - } else { - throw new DatabaseException(); - } - } - }; - - healthCheck = async (): Promise => { - try { - await this.prisma.$queryRaw`SELECT 1`; - return true; - } catch (e) { - if (e instanceof Prisma.PrismaClientKnownRequestError) { - throw new DatabaseException( - Prisma.PrismaClientKnownRequestError.name, - e.code, - e.message, - ); - } else { - throw new DatabaseException(); - } - } - }; -} diff --git a/old/modules/database/adapters/secondaries/prisma.service.ts b/old/modules/database/adapters/secondaries/prisma.service.ts deleted file mode 100644 index edf6532..0000000 --- a/old/modules/database/adapters/secondaries/prisma.service.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { INestApplication, Injectable, OnModuleInit } from '@nestjs/common'; -import { PrismaClient } from '@prisma/client'; - -@Injectable() -export class PrismaService extends PrismaClient implements OnModuleInit { - async onModuleInit() { - await this.$connect(); - } - - async enableShutdownHooks(app: INestApplication) { - this.$on('beforeExit', async () => { - await app.close(); - }); - } -} diff --git a/old/modules/database/database.module.ts b/old/modules/database/database.module.ts deleted file mode 100644 index f98fa94..0000000 --- a/old/modules/database/database.module.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Module } from '@nestjs/common'; -import { PrismaService } from './adapters/secondaries/prisma.service'; - -@Module({ - providers: [PrismaService], - exports: [PrismaService], -}) -export class DatabaseModule {} diff --git a/old/modules/database/domain/database.repository.ts b/old/modules/database/domain/database.repository.ts deleted file mode 100644 index 83f17e7..0000000 --- a/old/modules/database/domain/database.repository.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { PrismaRepository } from '../adapters/secondaries/prisma.repository.abstract'; - -export class DatabaseRepository extends PrismaRepository {} diff --git a/old/modules/database/exceptions/database.exception.ts b/old/modules/database/exceptions/database.exception.ts deleted file mode 100644 index b0782a6..0000000 --- a/old/modules/database/exceptions/database.exception.ts +++ /dev/null @@ -1,24 +0,0 @@ -export class DatabaseException implements Error { - name: string; - message: string; - - constructor( - private _type: string = 'unknown', - private _code: string = '', - message?: string, - ) { - this.name = 'DatabaseException'; - this.message = message ?? 'An error occured with the database.'; - if (this.message.includes('Unique constraint failed')) { - this.message = 'Already exists.'; - } - } - - get type(): string { - return this._type; - } - - get code(): string { - return this._code; - } -} diff --git a/old/modules/database/interfaces/collection.interface.ts b/old/modules/database/interfaces/collection.interface.ts deleted file mode 100644 index 6e9a96d..0000000 --- a/old/modules/database/interfaces/collection.interface.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface ICollection { - data: T[]; - total: number; -} diff --git a/old/modules/database/interfaces/repository.interface.ts b/old/modules/database/interfaces/repository.interface.ts deleted file mode 100644 index 1e23984..0000000 --- a/old/modules/database/interfaces/repository.interface.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { ICollection } from './collection.interface'; - -export interface IRepository { - findAll( - page: number, - perPage: number, - params?: any, - include?: any, - ): Promise>; - findOne(where: any, include?: any): Promise; - findOneByUuid(uuid: string, include?: any): Promise; - create(entity: Partial | any, include?: any): Promise; - update(uuid: string, entity: Partial, include?: any): Promise; - updateWhere(where: any, entity: Partial | any, include?: any): Promise; - delete(uuid: string): Promise; - deleteMany(where: any): Promise; - healthCheck(): Promise; -} diff --git a/old/modules/database/tests/unit/prisma-repository.spec.ts b/old/modules/database/tests/unit/prisma-repository.spec.ts deleted file mode 100644 index d27b1fe..0000000 --- a/old/modules/database/tests/unit/prisma-repository.spec.ts +++ /dev/null @@ -1,571 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { Test, TestingModule } from '@nestjs/testing'; -import { PrismaService } from '../../adapters/secondaries/prisma.service'; -import { PrismaRepository } from '../../adapters/secondaries/prisma.repository.abstract'; -import { DatabaseException } from '../../exceptions/database.exception'; -import { Prisma } from '@prisma/client'; - -class FakeEntity { - uuid?: string; - name: string; -} - -let entityId = 2; -const entityUuid = 'uuid-'; -const entityName = 'name-'; - -const createRandomEntity = (): FakeEntity => { - const entity: FakeEntity = { - uuid: `${entityUuid}${entityId}`, - name: `${entityName}${entityId}`, - }; - - entityId++; - - return entity; -}; - -const fakeEntityToCreate: FakeEntity = { - name: 'test', -}; - -const fakeEntityCreated: FakeEntity = { - ...fakeEntityToCreate, - uuid: 'some-uuid', -}; - -const fakeEntities: FakeEntity[] = []; -Array.from({ length: 10 }).forEach(() => { - fakeEntities.push(createRandomEntity()); -}); - -@Injectable() -class FakePrismaRepository extends PrismaRepository { - protected model = 'fake'; -} - -class FakePrismaService extends PrismaService { - fake: any; -} - -const mockPrismaService = { - $transaction: jest.fn().mockImplementation(async (data: any) => { - const entities = await data[0]; - if (entities.length == 1) { - return Promise.resolve([[fakeEntityCreated], 1]); - } - - return Promise.resolve([fakeEntities, fakeEntities.length]); - }), - // eslint-disable-next-line @typescript-eslint/no-unused-vars - $queryRawUnsafe: jest.fn().mockImplementation((query?: string) => { - return Promise.resolve(fakeEntities); - }), - $executeRawUnsafe: jest - .fn() - .mockResolvedValueOnce(fakeEntityCreated) - // eslint-disable-next-line @typescript-eslint/no-unused-vars - .mockImplementationOnce((fields: object) => { - throw new Prisma.PrismaClientKnownRequestError('unknown request', { - code: 'code', - clientVersion: 'version', - }); - }) - // eslint-disable-next-line @typescript-eslint/no-unused-vars - .mockImplementationOnce((fields: object) => { - throw new Error('an unknown error'); - }) - .mockResolvedValueOnce(fakeEntityCreated) - // eslint-disable-next-line @typescript-eslint/no-unused-vars - .mockImplementationOnce((fields: object) => { - throw new Prisma.PrismaClientKnownRequestError('unknown request', { - code: 'code', - clientVersion: 'version', - }); - }) - // eslint-disable-next-line @typescript-eslint/no-unused-vars - .mockImplementationOnce((fields: object) => { - throw new Error('an unknown error'); - }), - $queryRaw: jest - .fn() - .mockImplementationOnce(() => { - throw new Prisma.PrismaClientKnownRequestError('unknown request', { - code: 'code', - clientVersion: 'version', - }); - }) - .mockImplementationOnce(() => { - return true; - }) - .mockImplementation(() => { - throw new Prisma.PrismaClientKnownRequestError('Database unavailable', { - code: 'code', - clientVersion: 'version', - }); - }), - fake: { - create: jest - .fn() - .mockResolvedValueOnce(fakeEntityCreated) - // eslint-disable-next-line @typescript-eslint/no-unused-vars - .mockImplementationOnce((params?: any) => { - throw new Prisma.PrismaClientKnownRequestError('unknown request', { - code: 'code', - clientVersion: 'version', - }); - }) - // eslint-disable-next-line @typescript-eslint/no-unused-vars - .mockImplementationOnce((params?: any) => { - throw new Error('an unknown error'); - }), - - findMany: jest.fn().mockImplementation((params?: any) => { - if (params?.where?.limit == 1) { - return Promise.resolve([fakeEntityCreated]); - } - - return Promise.resolve(fakeEntities); - }), - count: jest.fn().mockResolvedValue(fakeEntities.length), - - findUnique: jest.fn().mockImplementation(async (params?: any) => { - let entity; - - if (params?.where?.uuid) { - entity = fakeEntities.find( - (entity) => entity.uuid === params?.where?.uuid, - ); - } - - if (!entity && params?.where?.uuid == 'unknown') { - throw new Prisma.PrismaClientKnownRequestError('unknown request', { - code: 'code', - clientVersion: 'version', - }); - } else if (!entity) { - throw new Error('no entity'); - } - - return entity; - }), - - findFirst: jest - .fn() - .mockImplementationOnce((params?: any) => { - if (params?.where?.name) { - return Promise.resolve( - fakeEntities.find((entity) => entity.name === params?.where?.name), - ); - } - }) - // eslint-disable-next-line @typescript-eslint/no-unused-vars - .mockImplementationOnce((params?: any) => { - throw new Prisma.PrismaClientKnownRequestError('unknown request', { - code: 'code', - clientVersion: 'version', - }); - }) - // eslint-disable-next-line @typescript-eslint/no-unused-vars - .mockImplementationOnce((params?: any) => { - throw new Error('an unknown error'); - }), - - update: jest - .fn() - // eslint-disable-next-line @typescript-eslint/no-unused-vars - .mockImplementationOnce((params?: any) => { - throw new Prisma.PrismaClientKnownRequestError('unknown request', { - code: 'code', - clientVersion: 'version', - }); - }) - // eslint-disable-next-line @typescript-eslint/no-unused-vars - .mockImplementationOnce((params?: any) => { - throw new Prisma.PrismaClientKnownRequestError('unknown request', { - code: 'code', - clientVersion: 'version', - }); - }) - .mockImplementationOnce((params: any) => { - const entity = fakeEntities.find( - (entity) => entity.name === params.where.name, - ); - Object.entries(params.data).map(([key, value]) => { - entity[key] = value; - }); - - return Promise.resolve(entity); - }) - .mockImplementation((params: any) => { - const entity = fakeEntities.find( - (entity) => entity.uuid === params.where.uuid, - ); - Object.entries(params.data).map(([key, value]) => { - entity[key] = value; - }); - - return Promise.resolve(entity); - }), - - delete: jest - .fn() - // eslint-disable-next-line @typescript-eslint/no-unused-vars - .mockImplementationOnce((params?: any) => { - throw new Prisma.PrismaClientKnownRequestError('unknown request', { - code: 'code', - clientVersion: 'version', - }); - }) - .mockImplementation((params: any) => { - let found = false; - - fakeEntities.forEach((entity, index) => { - if (entity.uuid === params?.where?.uuid) { - found = true; - fakeEntities.splice(index, 1); - } - }); - - if (!found) { - throw new Error(); - } - }), - - deleteMany: jest - .fn() - // eslint-disable-next-line @typescript-eslint/no-unused-vars - .mockImplementationOnce((params?: any) => { - throw new Prisma.PrismaClientKnownRequestError('unknown request', { - code: 'code', - clientVersion: 'version', - }); - }) - .mockImplementation((params: any) => { - let found = false; - - fakeEntities.forEach((entity, index) => { - if (entity.uuid === params?.where?.uuid) { - found = true; - fakeEntities.splice(index, 1); - } - }); - - if (!found) { - throw new Error(); - } - }), - }, -}; - -describe('PrismaRepository', () => { - let fakeRepository: FakePrismaRepository; - let prisma: FakePrismaService; - - beforeAll(async () => { - const module: TestingModule = await Test.createTestingModule({ - providers: [ - FakePrismaRepository, - { - provide: PrismaService, - useValue: mockPrismaService, - }, - ], - }).compile(); - - fakeRepository = module.get(FakePrismaRepository); - prisma = module.get(PrismaService) as FakePrismaService; - }); - - it('should be defined', () => { - expect(fakeRepository).toBeDefined(); - expect(prisma).toBeDefined(); - }); - - describe('findAll', () => { - it('should return an array of entities', async () => { - jest.spyOn(prisma.fake, 'findMany'); - jest.spyOn(prisma.fake, 'count'); - jest.spyOn(prisma, '$transaction'); - - const entities = await fakeRepository.findAll(); - expect(entities).toStrictEqual({ - data: fakeEntities, - total: fakeEntities.length, - }); - }); - - it('should return an array containing only one entity', async () => { - const entities = await fakeRepository.findAll(1, 10, { limit: 1 }); - - expect(prisma.fake.findMany).toHaveBeenCalledWith({ - skip: 0, - take: 10, - where: { limit: 1 }, - }); - expect(entities).toEqual({ - data: [fakeEntityCreated], - total: 1, - }); - }); - }); - - describe('create', () => { - it('should create an entity', async () => { - jest.spyOn(prisma.fake, 'create'); - - const newEntity = await fakeRepository.create(fakeEntityToCreate); - expect(newEntity).toBe(fakeEntityCreated); - expect(prisma.fake.create).toHaveBeenCalledTimes(1); - }); - - it('should throw a DatabaseException for client error', async () => { - await expect( - fakeRepository.create(fakeEntityToCreate), - ).rejects.toBeInstanceOf(DatabaseException); - }); - - it('should throw a DatabaseException if uuid is not found', async () => { - await expect( - fakeRepository.create(fakeEntityToCreate), - ).rejects.toBeInstanceOf(DatabaseException); - }); - }); - - describe('findOneByUuid', () => { - it('should find an entity by uuid', async () => { - const entity = await fakeRepository.findOneByUuid(fakeEntities[0].uuid); - expect(entity).toBe(fakeEntities[0]); - }); - - it('should throw a DatabaseException for client error', async () => { - await expect( - fakeRepository.findOneByUuid('unknown'), - ).rejects.toBeInstanceOf(DatabaseException); - }); - - it('should throw a DatabaseException if uuid is not found', async () => { - await expect( - fakeRepository.findOneByUuid('wrong-uuid'), - ).rejects.toBeInstanceOf(DatabaseException); - }); - }); - - describe('findOne', () => { - it('should find one entity', async () => { - const entity = await fakeRepository.findOne({ - name: fakeEntities[0].name, - }); - - expect(entity.name).toBe(fakeEntities[0].name); - }); - - it('should throw a DatabaseException for client error', async () => { - await expect( - fakeRepository.findOne({ - name: fakeEntities[0].name, - }), - ).rejects.toBeInstanceOf(DatabaseException); - }); - - it('should throw a DatabaseException for unknown error', async () => { - await expect( - fakeRepository.findOne({ - name: fakeEntities[0].name, - }), - ).rejects.toBeInstanceOf(DatabaseException); - }); - }); - - describe('update', () => { - it('should throw a DatabaseException for client error', async () => { - await expect( - fakeRepository.update('fake-uuid', { name: 'error' }), - ).rejects.toBeInstanceOf(DatabaseException); - await expect( - fakeRepository.updateWhere({ name: 'error' }, { name: 'new error' }), - ).rejects.toBeInstanceOf(DatabaseException); - }); - - it('should update an entity with name', async () => { - const newName = 'new-random-name'; - - await fakeRepository.updateWhere( - { name: fakeEntities[0].name }, - { - name: newName, - }, - ); - expect(fakeEntities[0].name).toBe(newName); - }); - - it('should update an entity with uuid', async () => { - const newName = 'random-name'; - - await fakeRepository.update(fakeEntities[0].uuid, { - name: newName, - }); - expect(fakeEntities[0].name).toBe(newName); - }); - - it("should throw an exception if an entity doesn't exist", async () => { - await expect( - fakeRepository.update('fake-uuid', { name: 'error' }), - ).rejects.toBeInstanceOf(DatabaseException); - await expect( - fakeRepository.updateWhere({ name: 'error' }, { name: 'new error' }), - ).rejects.toBeInstanceOf(DatabaseException); - }); - }); - - describe('delete', () => { - it('should throw a DatabaseException for client error', async () => { - await expect(fakeRepository.delete('fake-uuid')).rejects.toBeInstanceOf( - DatabaseException, - ); - }); - - it('should delete an entity', async () => { - const savedUuid = fakeEntities[0].uuid; - - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const res = await fakeRepository.delete(savedUuid); - - const deletedEntity = fakeEntities.find( - (entity) => entity.uuid === savedUuid, - ); - expect(deletedEntity).toBeUndefined(); - }); - - it("should throw an exception if an entity doesn't exist", async () => { - await expect(fakeRepository.delete('fake-uuid')).rejects.toBeInstanceOf( - DatabaseException, - ); - }); - }); - - describe('deleteMany', () => { - it('should throw a DatabaseException for client error', async () => { - await expect( - fakeRepository.deleteMany({ uuid: 'fake-uuid' }), - ).rejects.toBeInstanceOf(DatabaseException); - }); - - it('should delete entities based on their uuid', async () => { - const savedUuid = fakeEntities[0].uuid; - - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const res = await fakeRepository.deleteMany({ uuid: savedUuid }); - - const deletedEntity = fakeEntities.find( - (entity) => entity.uuid === savedUuid, - ); - expect(deletedEntity).toBeUndefined(); - }); - - it("should throw an exception if an entity doesn't exist", async () => { - await expect( - fakeRepository.deleteMany({ uuid: 'fake-uuid' }), - ).rejects.toBeInstanceOf(DatabaseException); - }); - }); - - describe('findAllByquery', () => { - it('should return an array of entities', async () => { - const entities = await fakeRepository.findAllByQuery( - ['uuid', 'name'], - ['name is not null'], - ); - expect(entities).toStrictEqual({ - data: fakeEntities, - total: fakeEntities.length, - }); - }); - }); - - describe('createWithFields', () => { - it('should create an entity', async () => { - jest.spyOn(prisma, '$queryRawUnsafe'); - - const newEntity = await fakeRepository.createWithFields({ - uuid: '804319b3-a09b-4491-9f82-7976bfce0aff', - name: 'my-name', - }); - expect(newEntity).toBe(fakeEntityCreated); - expect(prisma.$queryRawUnsafe).toHaveBeenCalledTimes(1); - }); - - it('should throw a DatabaseException for client error', async () => { - await expect( - fakeRepository.createWithFields({ - uuid: '804319b3-a09b-4491-9f82-7976bfce0aff', - name: 'my-name', - }), - ).rejects.toBeInstanceOf(DatabaseException); - }); - - it('should throw a DatabaseException if uuid is not found', async () => { - await expect( - fakeRepository.createWithFields({ - name: 'my-name', - }), - ).rejects.toBeInstanceOf(DatabaseException); - }); - }); - - describe('updateWithFields', () => { - it('should update an entity', async () => { - jest.spyOn(prisma, '$queryRawUnsafe'); - - const updatedEntity = await fakeRepository.updateWithFields( - '804319b3-a09b-4491-9f82-7976bfce0aff', - { - name: 'my-name', - }, - ); - expect(updatedEntity).toBe(fakeEntityCreated); - expect(prisma.$queryRawUnsafe).toHaveBeenCalledTimes(1); - }); - - it('should throw a DatabaseException for client error', async () => { - await expect( - fakeRepository.updateWithFields( - '804319b3-a09b-4491-9f82-7976bfce0aff', - { - name: 'my-name', - }, - ), - ).rejects.toBeInstanceOf(DatabaseException); - }); - - it('should throw a DatabaseException if uuid is not found', async () => { - await expect( - fakeRepository.updateWithFields( - '804319b3-a09b-4491-9f82-7976bfce0aff', - { - name: 'my-name', - }, - ), - ).rejects.toBeInstanceOf(DatabaseException); - }); - }); - - describe('healthCheck', () => { - it('should throw a DatabaseException for client error', async () => { - await expect(fakeRepository.healthCheck()).rejects.toBeInstanceOf( - DatabaseException, - ); - }); - - it('should return a healthy result', async () => { - const res = await fakeRepository.healthCheck(); - expect(res).toBeTruthy(); - }); - - it('should throw an exception if database is not available', async () => { - await expect(fakeRepository.healthCheck()).rejects.toBeInstanceOf( - DatabaseException, - ); - }); - }); -}); diff --git a/old/modules/geography/adapters/secondaries/geo-timezone-finder.ts b/old/modules/geography/adapters/secondaries/geo-timezone-finder.ts deleted file mode 100644 index bce0097..0000000 --- a/old/modules/geography/adapters/secondaries/geo-timezone-finder.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { IFindTimezone } from '../../domain/interfaces/timezone-finder.interface'; -import { find } from 'geo-tz'; - -@Injectable() -export class GeoTimezoneFinder implements IFindTimezone { - timezones = (lon: number, lat: number): string[] => find(lat, lon); -} diff --git a/old/modules/geography/adapters/secondaries/geodesic.ts b/old/modules/geography/adapters/secondaries/geodesic.ts deleted file mode 100644 index 835df8e..0000000 --- a/old/modules/geography/adapters/secondaries/geodesic.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { Geodesic as Geolib, GeodesicClass } from 'geographiclib-geodesic'; -import { IGeodesic } from '../../domain/interfaces/geodesic.interface'; - -@Injectable() -export class Geodesic implements IGeodesic { - private geod: GeodesicClass; - - constructor() { - this.geod = Geolib.WGS84; - } - - inverse = ( - lon1: number, - lat1: number, - lon2: number, - lat2: number, - ): { azimuth: number; distance: number } => { - const { azi2: azimuth, s12: distance } = this.geod.Inverse( - lat1, - lon1, - lat2, - lon2, - ); - return { azimuth, distance }; - }; -} diff --git a/old/modules/geography/adapters/secondaries/georouter-creator.ts b/old/modules/geography/adapters/secondaries/georouter-creator.ts deleted file mode 100644 index 69b5a35..0000000 --- a/old/modules/geography/adapters/secondaries/georouter-creator.ts +++ /dev/null @@ -1,28 +0,0 @@ -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'; -import { HttpService } from '@nestjs/axios'; -import { Geodesic } from './geodesic'; -import { GeographyException } from '../../exceptions/geography.exception'; -import { ExceptionCode } from '../../../utils/exception-code.enum'; - -@Injectable() -export class GeorouterCreator implements ICreateGeorouter { - constructor( - private readonly httpService: HttpService, - private readonly geodesic: Geodesic, - ) {} - - create = (type: string, url: string): IGeorouter => { - switch (type) { - case 'graphhopper': - return new GraphhopperGeorouter(url, this.httpService, this.geodesic); - default: - throw new GeographyException( - ExceptionCode.INVALID_ARGUMENT, - 'Unknown geocoder', - ); - } - }; -} diff --git a/old/modules/geography/adapters/secondaries/graphhopper-georouter.ts b/old/modules/geography/adapters/secondaries/graphhopper-georouter.ts deleted file mode 100644 index 42087c4..0000000 --- a/old/modules/geography/adapters/secondaries/graphhopper-georouter.ts +++ /dev/null @@ -1,330 +0,0 @@ -import { HttpService } from '@nestjs/axios'; -import { IGeorouter } from '../../domain/interfaces/georouter.interface'; -import { Injectable } from '@nestjs/common'; -import { catchError, lastValueFrom, map } from 'rxjs'; -import { AxiosError, AxiosResponse } from 'axios'; -import { IGeodesic } from '../../domain/interfaces/geodesic.interface'; -import { GeorouterSettings } from '../../domain/types/georouter-settings.type'; -import { Path } from '../../domain/types/path.type'; -import { NamedRoute } from '../../domain/types/named-route'; -import { GeographyException } from '../../exceptions/geography.exception'; -import { ExceptionCode } from '../../../utils/exception-code.enum'; -import { Route } from '../../domain/entities/route'; -import { SpacetimePoint } from '../../domain/entities/spacetime-point'; - -@Injectable() -export class GraphhopperGeorouter implements IGeorouter { - private url: string; - private urlArgs: string[]; - private withTime: boolean; - private withPoints: boolean; - private withDistance: boolean; - private paths: Path[]; - private httpService: HttpService; - private geodesic: IGeodesic; - - constructor(url: string, httpService: HttpService, geodesic: IGeodesic) { - this.url = url + '/route?'; - this.httpService = httpService; - this.geodesic = geodesic; - } - - route = async ( - paths: Path[], - settings: GeorouterSettings, - ): Promise => { - this.setDefaultUrlArgs(); - this.setWithTime(settings.withTime); - this.setWithPoints(settings.withPoints); - this.setWithDistance(settings.withDistance); - this.paths = paths; - return await this.getRoutes(); - }; - - private setDefaultUrlArgs = (): void => { - this.urlArgs = ['vehicle=car', 'weighting=fastest', 'points_encoded=false']; - }; - - private setWithTime = (withTime: boolean): void => { - this.withTime = withTime; - if (withTime) { - this.urlArgs.push('details=time'); - } - }; - - private setWithPoints = (withPoints: boolean): void => { - this.withPoints = withPoints; - if (!withPoints) { - this.urlArgs.push('calc_points=false'); - } - }; - - private setWithDistance = (withDistance: boolean): void => { - this.withDistance = withDistance; - if (withDistance) { - this.urlArgs.push('instructions=true'); - } else { - this.urlArgs.push('instructions=false'); - } - }; - - private getRoutes = async (): Promise => { - const routes = Promise.all( - this.paths.map(async (path) => { - const url: string = [ - this.getUrl(), - '&point=', - path.points - .map((point) => [point.lat, point.lon].join('%2C')) - .join('&point='), - ].join(''); - const route = await lastValueFrom( - this.httpService.get(url).pipe( - map((res) => (res.data ? this.createRoute(res) : undefined)), - catchError((error: AxiosError) => { - if (error.code == AxiosError.ERR_BAD_REQUEST) { - throw new GeographyException( - ExceptionCode.OUT_OF_RANGE, - 'No route found for given coordinates', - ); - } - throw new GeographyException( - ExceptionCode.UNAVAILABLE, - 'Georouter unavailable : ' + error.message, - ); - }), - ), - ); - return { - key: path.key, - route, - }; - }), - ); - return routes; - }; - - private getUrl = (): string => { - return [this.url, this.urlArgs.join('&')].join(''); - }; - - private createRoute = ( - response: AxiosResponse, - ): Route => { - const route = new Route(this.geodesic); - if (response.data.paths && response.data.paths[0]) { - const shortestPath = response.data.paths[0]; - route.distance = shortestPath.distance ?? 0; - route.duration = shortestPath.time ? shortestPath.time / 1000 : 0; - if (shortestPath.points && shortestPath.points.coordinates) { - route.setPoints( - shortestPath.points.coordinates.map((coordinate) => ({ - lon: coordinate[0], - lat: coordinate[1], - })), - ); - if ( - shortestPath.details && - shortestPath.details.time && - shortestPath.snapped_waypoints && - shortestPath.snapped_waypoints.coordinates - ) { - let instructions: GraphhopperInstruction[] = []; - if (shortestPath.instructions) - instructions = shortestPath.instructions; - route.setSpacetimePoints( - this.generateSpacetimePoints( - shortestPath.points.coordinates, - shortestPath.snapped_waypoints.coordinates, - shortestPath.details.time, - instructions, - ), - ); - } - } - } - return route; - }; - - private generateSpacetimePoints = ( - points: Array, - snappedWaypoints: Array, - durations: Array, - instructions: GraphhopperInstruction[], - ): SpacetimePoint[] => { - const indices = this.getIndices(points, snappedWaypoints); - const times = this.getTimes(durations, indices); - const distances = this.getDistances(instructions, indices); - return indices.map( - (index) => - new SpacetimePoint( - { lon: points[index][1], lat: points[index][0] }, - times.find((time) => time.index == index)?.duration, - distances.find((distance) => distance.index == index)?.distance, - ), - ); - }; - - private getIndices = ( - points: Array, - snappedWaypoints: Array, - ): number[] => { - const indices = snappedWaypoints.map((waypoint) => - points.findIndex( - (point) => point[0] == waypoint[0] && point[1] == waypoint[1], - ), - ); - if (indices.find((index) => index == -1) === undefined) return indices; - const missedWaypoints = indices - .map( - (value, index) => - < - { - index: number; - originIndex: number; - waypoint: number[]; - nearest: number; - distance: number; - } - >{ - index: value, - originIndex: index, - waypoint: snappedWaypoints[index], - nearest: undefined, - distance: 999999999, - }, - ) - .filter((element) => element.index == -1); - for (const index in points) { - for (const missedWaypoint of missedWaypoints) { - const inverse = this.geodesic.inverse( - missedWaypoint.waypoint[0], - missedWaypoint.waypoint[1], - points[index][0], - points[index][1], - ); - if (inverse.distance < missedWaypoint.distance) { - missedWaypoint.distance = inverse.distance; - missedWaypoint.nearest = parseInt(index); - } - } - } - for (const missedWaypoint of missedWaypoints) { - indices[missedWaypoint.originIndex] = missedWaypoint.nearest; - } - return indices; - }; - - private getTimes = ( - durations: Array, - indices: number[], - ): Array<{ index: number; duration: number }> => { - const times: Array<{ index: number; duration: number }> = []; - let duration = 0; - for (const [origin, destination, stepDuration] of durations) { - let indexFound = false; - const indexAsOrigin = indices.find((index) => index == origin); - if ( - indexAsOrigin !== undefined && - times.find((time) => origin == time.index) == undefined - ) { - times.push({ - index: indexAsOrigin, - duration: Math.round(stepDuration / 1000), - }); - indexFound = true; - } - if (!indexFound) { - const indexAsDestination = indices.find( - (index) => index == destination, - ); - if ( - indexAsDestination !== undefined && - times.find((time) => destination == time.index) == undefined - ) { - times.push({ - index: indexAsDestination, - duration: Math.round((duration + stepDuration) / 1000), - }); - indexFound = true; - } - } - if (!indexFound) { - const indexInBetween = indices.find( - (index) => origin < index && index < destination, - ); - if (indexInBetween !== undefined) { - times.push({ - index: indexInBetween, - duration: Math.round((duration + stepDuration / 2) / 1000), - }); - } - } - duration += stepDuration; - } - return times; - }; - - private getDistances = ( - instructions: GraphhopperInstruction[], - indices: number[], - ): Array<{ index: number; distance: number }> => { - let distance = 0; - const distances: Array<{ index: number; distance: number }> = [ - { - index: 0, - distance, - }, - ]; - for (const instruction of instructions) { - distance += instruction.distance; - if ( - (instruction.sign == GraphhopperSign.SIGN_WAYPOINT || - instruction.sign == GraphhopperSign.SIGN_FINISH) && - indices.find((index) => index == instruction.interval[0]) !== undefined - ) { - distances.push({ - index: instruction.interval[0], - distance: Math.round(distance), - }); - } - } - return distances; - }; -} - -type GraphhopperResponse = { - paths: [ - { - distance: number; - weight: number; - time: number; - points_encoded: boolean; - bbox: number[]; - points: GraphhopperCoordinates; - snapped_waypoints: GraphhopperCoordinates; - details: { - time: Array; - }; - instructions: GraphhopperInstruction[]; - }, - ]; -}; - -type GraphhopperCoordinates = { - coordinates: Array; -}; - -type GraphhopperInstruction = { - distance: number; - heading: number; - sign: GraphhopperSign; - interval: number[]; - text: string; -}; - -enum GraphhopperSign { - SIGN_START = 0, - SIGN_FINISH = 4, - SIGN_WAYPOINT = 5, -} diff --git a/old/modules/geography/adapters/secondaries/postgres-direction-encoder.ts b/old/modules/geography/adapters/secondaries/postgres-direction-encoder.ts deleted file mode 100644 index 3a85ace..0000000 --- a/old/modules/geography/adapters/secondaries/postgres-direction-encoder.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Coordinate } from '../../domain/entities/coordinate'; -import { IEncodeDirection } from '../../domain/interfaces/direction-encoder.interface'; - -export class PostgresDirectionEncoder implements IEncodeDirection { - encode = (coordinates: Coordinate[]): string => - [ - "'LINESTRING(", - coordinates.map((point) => [point.lon, point.lat].join(' ')).join(), - ")'", - ].join(''); -} diff --git a/old/modules/geography/domain/entities/coordinate.ts b/old/modules/geography/domain/entities/coordinate.ts deleted file mode 100644 index 4dd416a..0000000 --- a/old/modules/geography/domain/entities/coordinate.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { AutoMap } from '@automapper/classes'; -import { IsLatitude, IsLongitude, IsNumber } from 'class-validator'; - -export class Coordinate { - constructor(lon: number, lat: number) { - this.lon = lon; - this.lat = lat; - } - - @IsNumber() - @IsLongitude() - @AutoMap() - lon: number; - - @IsNumber() - @IsLatitude() - @AutoMap() - lat: number; -} diff --git a/old/modules/geography/domain/entities/route.ts b/old/modules/geography/domain/entities/route.ts deleted file mode 100644 index 48b8744..0000000 --- a/old/modules/geography/domain/entities/route.ts +++ /dev/null @@ -1,48 +0,0 @@ -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; - }; -} diff --git a/old/modules/geography/domain/entities/spacetime-point.ts b/old/modules/geography/domain/entities/spacetime-point.ts deleted file mode 100644 index 7d720e1..0000000 --- a/old/modules/geography/domain/entities/spacetime-point.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Coordinate } from './coordinate'; - -export class SpacetimePoint { - coordinate: Coordinate; - duration: number; - distance: number; - - constructor(coordinate: Coordinate, duration: number, distance: number) { - this.coordinate = coordinate; - this.duration = duration; - this.distance = distance; - } -} diff --git a/old/modules/geography/domain/interfaces/direction-encoder.interface.ts b/old/modules/geography/domain/interfaces/direction-encoder.interface.ts deleted file mode 100644 index 0f38a49..0000000 --- a/old/modules/geography/domain/interfaces/direction-encoder.interface.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Coordinate } from '../entities/coordinate'; - -export interface IEncodeDirection { - encode(coordinates: Coordinate[]): string; -} diff --git a/old/modules/geography/domain/interfaces/geodesic.interface.ts b/old/modules/geography/domain/interfaces/geodesic.interface.ts deleted file mode 100644 index 95680e8..0000000 --- a/old/modules/geography/domain/interfaces/geodesic.interface.ts +++ /dev/null @@ -1,11 +0,0 @@ -export interface IGeodesic { - inverse( - lon1: number, - lat1: number, - lon2: number, - lat2: number, - ): { - azimuth: number; - distance: number; - }; -} diff --git a/old/modules/geography/domain/interfaces/georouter-creator.interface.ts b/old/modules/geography/domain/interfaces/georouter-creator.interface.ts deleted file mode 100644 index 7a6bd25..0000000 --- a/old/modules/geography/domain/interfaces/georouter-creator.interface.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { IGeorouter } from './georouter.interface'; - -export interface ICreateGeorouter { - create(type: string, url: string): IGeorouter; -} diff --git a/old/modules/geography/domain/interfaces/georouter.interface.ts b/old/modules/geography/domain/interfaces/georouter.interface.ts deleted file mode 100644 index c2c2e05..0000000 --- a/old/modules/geography/domain/interfaces/georouter.interface.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { GeorouterSettings } from '../types/georouter-settings.type'; -import { NamedRoute } from '../types/named-route'; -import { Path } from '../types/path.type'; - -export interface IGeorouter { - route(paths: Path[], settings: GeorouterSettings): Promise; -} diff --git a/old/modules/geography/domain/interfaces/timezone-finder.interface.ts b/old/modules/geography/domain/interfaces/timezone-finder.interface.ts deleted file mode 100644 index 61016f7..0000000 --- a/old/modules/geography/domain/interfaces/timezone-finder.interface.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface IFindTimezone { - timezones(lon: number, lat: number): string[]; -} diff --git a/old/modules/geography/domain/types/georouter-settings.type.ts b/old/modules/geography/domain/types/georouter-settings.type.ts deleted file mode 100644 index d8f73ae..0000000 --- a/old/modules/geography/domain/types/georouter-settings.type.ts +++ /dev/null @@ -1,5 +0,0 @@ -export type GeorouterSettings = { - withPoints: boolean; - withTime: boolean; - withDistance: boolean; -}; diff --git a/old/modules/geography/domain/types/named-route.ts b/old/modules/geography/domain/types/named-route.ts deleted file mode 100644 index f1fdb2d..0000000 --- a/old/modules/geography/domain/types/named-route.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { Route } from '../entities/route'; - -export type NamedRoute = { - key: string; - route: Route; -}; diff --git a/old/modules/geography/domain/types/path.type.ts b/old/modules/geography/domain/types/path.type.ts deleted file mode 100644 index 60766e6..0000000 --- a/old/modules/geography/domain/types/path.type.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { Point } from './point.type'; - -export type Path = { - key: string; - points: Point[]; -}; diff --git a/old/modules/geography/domain/types/point-type.enum.ts b/old/modules/geography/domain/types/point-type.enum.ts deleted file mode 100644 index e1e57a2..0000000 --- a/old/modules/geography/domain/types/point-type.enum.ts +++ /dev/null @@ -1,7 +0,0 @@ -export enum PointType { - HOUSE_NUMBER = 'HOUSE_NUMBER', - STREET_ADDRESS = 'STREET_ADDRESS', - LOCALITY = 'LOCALITY', - VENUE = 'VENUE', - OTHER = 'OTHER', -} diff --git a/old/modules/geography/domain/types/point.type.ts b/old/modules/geography/domain/types/point.type.ts deleted file mode 100644 index 37c49e6..0000000 --- a/old/modules/geography/domain/types/point.type.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { PointType } from './point-type.enum'; -import { Coordinate } from '../entities/coordinate'; - -export type Point = Coordinate & { - type?: PointType; -}; diff --git a/old/modules/geography/domain/types/timezoner.ts b/old/modules/geography/domain/types/timezoner.ts deleted file mode 100644 index 8764400..0000000 --- a/old/modules/geography/domain/types/timezoner.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { IFindTimezone } from '../interfaces/timezone-finder.interface'; - -export type Timezoner = { - timezone: string; - finder: IFindTimezone; -}; diff --git a/old/modules/geography/exceptions/geography.exception.ts b/old/modules/geography/exceptions/geography.exception.ts deleted file mode 100644 index ebc1813..0000000 --- a/old/modules/geography/exceptions/geography.exception.ts +++ /dev/null @@ -1,11 +0,0 @@ -export class GeographyException implements Error { - name: string; - code: number; - message: string; - - constructor(code: number, message: string) { - this.name = 'GeographyException'; - this.code = code; - this.message = message; - } -} diff --git a/old/modules/geography/geography.module.ts b/old/modules/geography/geography.module.ts deleted file mode 100644 index d4be2c8..0000000 --- a/old/modules/geography/geography.module.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Module } from '@nestjs/common'; -import { GeoTimezoneFinder } from './adapters/secondaries/geo-timezone-finder'; -import { Geodesic } from './adapters/secondaries/geodesic'; - -@Module({ - providers: [GeoTimezoneFinder, Geodesic], - exports: [GeoTimezoneFinder, Geodesic], -}) -export class GeographyModule {} diff --git a/old/modules/geography/tests/unit/coordinate.spec.ts b/old/modules/geography/tests/unit/coordinate.spec.ts deleted file mode 100644 index 6bc92e1..0000000 --- a/old/modules/geography/tests/unit/coordinate.spec.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Coordinate } from '../../domain/entities/coordinate'; - -describe('Coordinate entity', () => { - it('should be defined', () => { - const coordinate: Coordinate = new Coordinate(6, 47); - expect(coordinate).toBeDefined(); - }); -}); diff --git a/old/modules/geography/tests/unit/geo-timezone-finder.spec.ts b/old/modules/geography/tests/unit/geo-timezone-finder.spec.ts deleted file mode 100644 index 285761f..0000000 --- a/old/modules/geography/tests/unit/geo-timezone-finder.spec.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { GeoTimezoneFinder } from '../../adapters/secondaries/geo-timezone-finder'; - -describe('Geo TZ Finder', () => { - it('should be defined', () => { - const timezoneFinder: GeoTimezoneFinder = new GeoTimezoneFinder(); - expect(timezoneFinder).toBeDefined(); - }); - it('should get timezone for Nancy(France) as Europe/Paris', () => { - const timezoneFinder: GeoTimezoneFinder = new GeoTimezoneFinder(); - const timezones = timezoneFinder.timezones(6.179373, 48.687913); - expect(timezones.length).toBe(1); - expect(timezones[0]).toBe('Europe/Paris'); - }); -}); diff --git a/old/modules/geography/tests/unit/geodesic.spec.ts b/old/modules/geography/tests/unit/geodesic.spec.ts deleted file mode 100644 index 750d7d4..0000000 --- a/old/modules/geography/tests/unit/geodesic.spec.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Geodesic } from '../../adapters/secondaries/geodesic'; - -describe('Matcher geodesic', () => { - it('should be defined', () => { - const geodesic: Geodesic = new Geodesic(); - expect(geodesic).toBeDefined(); - }); - it('should get inverse values', () => { - const geodesic: Geodesic = new Geodesic(); - const inv = geodesic.inverse(0, 0, 1, 1); - expect(Math.round(inv.azimuth)).toBe(45); - expect(Math.round(inv.distance)).toBe(156900); - }); -}); diff --git a/old/modules/geography/tests/unit/georouter-creator.spec.ts b/old/modules/geography/tests/unit/georouter-creator.spec.ts deleted file mode 100644 index 03afe6c..0000000 --- a/old/modules/geography/tests/unit/georouter-creator.spec.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { HttpService } from '@nestjs/axios'; -import { GeorouterCreator } from '../../adapters/secondaries/georouter-creator'; -import { Geodesic } from '../../adapters/secondaries/geodesic'; -import { GraphhopperGeorouter } from '../../adapters/secondaries/graphhopper-georouter'; - -const mockHttpService = jest.fn(); -const mockGeodesic = jest.fn(); - -describe('Georouter creator', () => { - let georouterCreator: GeorouterCreator; - - beforeAll(async () => { - const module: TestingModule = await Test.createTestingModule({ - imports: [], - providers: [ - GeorouterCreator, - { - provide: HttpService, - useValue: mockHttpService, - }, - { - provide: Geodesic, - useValue: mockGeodesic, - }, - ], - }).compile(); - - georouterCreator = module.get(GeorouterCreator); - }); - - it('should be defined', () => { - expect(georouterCreator).toBeDefined(); - }); - it('should create a graphhopper georouter', () => { - const georouter = georouterCreator.create( - 'graphhopper', - 'http://localhost', - ); - expect(georouter).toBeInstanceOf(GraphhopperGeorouter); - }); - it('should throw an exception if georouter type is unknown', () => { - expect(() => - georouterCreator.create('unknown', 'http://localhost'), - ).toThrow(); - }); -}); diff --git a/old/modules/geography/tests/unit/graphhopper-georouter.spec.ts b/old/modules/geography/tests/unit/graphhopper-georouter.spec.ts deleted file mode 100644 index e0e45f9..0000000 --- a/old/modules/geography/tests/unit/graphhopper-georouter.spec.ts +++ /dev/null @@ -1,456 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { HttpService } from '@nestjs/axios'; -import { of } from 'rxjs'; -import { AxiosError } from 'axios'; -import { GeorouterCreator } from '../../adapters/secondaries/georouter-creator'; -import { IGeorouter } from '../../domain/interfaces/georouter.interface'; -import { Geodesic } from '../../adapters/secondaries/geodesic'; - -const mockHttpService = { - get: jest - .fn() - .mockImplementationOnce(() => { - throw new AxiosError('Axios error !'); - }) - .mockImplementationOnce(() => { - return of({ - status: 200, - data: { - paths: [ - { - distance: 50000, - time: 1800000, - snapped_waypoints: { - coordinates: [ - [0, 0], - [10, 10], - ], - }, - }, - ], - }, - }); - }) - .mockImplementationOnce(() => { - return of({ - status: 200, - data: { - paths: [ - { - distance: 50000, - time: 1800000, - points: { - coordinates: [ - [0, 0], - [1, 1], - [2, 2], - [3, 3], - [4, 4], - [5, 5], - [6, 6], - [7, 7], - [8, 8], - [9, 9], - [10, 10], - ], - }, - snapped_waypoints: { - coordinates: [ - [0, 0], - [10, 10], - ], - }, - }, - ], - }, - }); - }) - .mockImplementationOnce(() => { - return of({ - status: 200, - data: { - paths: [ - { - distance: 50000, - time: 1800000, - points: { - coordinates: [ - [0, 0], - [1, 1], - [2, 2], - [3, 3], - [4, 4], - [5, 5], - [6, 6], - [7, 7], - [8, 8], - [9, 9], - [10, 10], - ], - }, - details: { - time: [ - [0, 1, 180000], - [1, 2, 180000], - [2, 3, 180000], - [3, 4, 180000], - [4, 5, 180000], - [5, 6, 180000], - [6, 7, 180000], - [7, 9, 360000], - [9, 10, 180000], - ], - }, - snapped_waypoints: { - coordinates: [ - [0, 0], - [10, 10], - ], - }, - }, - ], - }, - }); - }) - .mockImplementationOnce(() => { - return of({ - status: 200, - data: { - paths: [ - { - distance: 50000, - time: 1800000, - points: { - coordinates: [ - [0, 0], - [1, 1], - [2, 2], - [3, 3], - [4, 4], - [7, 7], - [8, 8], - [9, 9], - [10, 10], - ], - }, - snapped_waypoints: { - coordinates: [ - [0, 0], - [5, 5], - [10, 10], - ], - }, - details: { - time: [ - [0, 1, 180000], - [1, 2, 180000], - [2, 3, 180000], - [3, 4, 180000], - [4, 7, 540000], - [7, 9, 360000], - [9, 10, 180000], - ], - }, - }, - ], - }, - }); - }) - .mockImplementationOnce(() => { - return of({ - status: 200, - data: { - paths: [ - { - distance: 50000, - time: 1800000, - points: { - coordinates: [ - [0, 0], - [1, 1], - [2, 2], - [3, 3], - [4, 4], - [5, 5], - [6, 6], - [7, 7], - [8, 8], - [9, 9], - [10, 10], - ], - }, - snapped_waypoints: { - coordinates: [ - [0, 0], - [5, 5], - [10, 10], - ], - }, - details: { - time: [ - [0, 1, 180000], - [1, 2, 180000], - [2, 3, 180000], - [3, 4, 180000], - [4, 7, 540000], - [7, 9, 360000], - [9, 10, 180000], - ], - }, - instructions: [ - { - distance: 25000, - sign: 0, - interval: [0, 5], - text: 'Some instructions', - time: 900000, - }, - { - distance: 0, - sign: 5, - interval: [5, 5], - text: 'Waypoint 1', - time: 0, - }, - { - distance: 25000, - sign: 2, - interval: [5, 10], - text: 'Some instructions', - time: 900000, - }, - { - distance: 0.0, - sign: 4, - interval: [10, 10], - text: 'Arrive at destination', - time: 0, - }, - ], - }, - ], - }, - }); - }), -}; - -const mockGeodesic = { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - inverse: jest.fn().mockImplementation(() => ({ - azimuth: 45, - distance: 50000, - })), -}; - -describe('Graphhopper Georouter', () => { - let georouterCreator: GeorouterCreator; - let graphhopperGeorouter: IGeorouter; - - beforeAll(async () => { - const module: TestingModule = await Test.createTestingModule({ - imports: [], - providers: [ - GeorouterCreator, - { - provide: HttpService, - useValue: mockHttpService, - }, - { - provide: Geodesic, - useValue: mockGeodesic, - }, - ], - }).compile(); - - georouterCreator = module.get(GeorouterCreator); - graphhopperGeorouter = georouterCreator.create( - 'graphhopper', - 'http://localhost', - ); - }); - - it('should be defined', () => { - expect(graphhopperGeorouter).toBeDefined(); - }); - - describe('route function', () => { - it('should fail on axios error', async () => { - await expect( - graphhopperGeorouter.route( - [ - { - key: 'route1', - points: [ - { - lat: 0, - lon: 0, - }, - { - lat: 1, - lon: 1, - }, - ], - }, - ], - { - withDistance: false, - withPoints: false, - withTime: false, - }, - ), - ).rejects.toBeInstanceOf(Error); - }); - - it('should create one route with all settings to false', async () => { - const routes = await graphhopperGeorouter.route( - [ - { - key: 'route1', - points: [ - { - lat: 0, - lon: 0, - }, - { - lat: 10, - lon: 10, - }, - ], - }, - ], - { - withDistance: false, - withPoints: false, - withTime: false, - }, - ); - expect(routes).toHaveLength(1); - expect(routes[0].route.distance).toBe(50000); - }); - - it('should create one route with points', async () => { - const routes = await graphhopperGeorouter.route( - [ - { - key: 'route1', - points: [ - { - lat: 0, - lon: 0, - }, - { - lat: 10, - lon: 10, - }, - ], - }, - ], - { - withDistance: false, - withPoints: true, - withTime: false, - }, - ); - expect(routes).toHaveLength(1); - expect(routes[0].route.distance).toBe(50000); - expect(routes[0].route.duration).toBe(1800); - expect(routes[0].route.fwdAzimuth).toBe(45); - expect(routes[0].route.backAzimuth).toBe(225); - expect(routes[0].route.points.length).toBe(11); - }); - - it('should create one route with points and time', async () => { - const routes = await graphhopperGeorouter.route( - [ - { - key: 'route1', - points: [ - { - lat: 0, - lon: 0, - }, - { - lat: 10, - lon: 10, - }, - ], - }, - ], - { - withDistance: false, - withPoints: true, - withTime: true, - }, - ); - expect(routes).toHaveLength(1); - expect(routes[0].route.spacetimePoints.length).toBe(2); - expect(routes[0].route.spacetimePoints[1].duration).toBe(1800); - expect(routes[0].route.spacetimePoints[1].distance).toBeUndefined(); - }); - - it('should create one route with points and missed waypoints extrapolations', async () => { - const routes = await graphhopperGeorouter.route( - [ - { - key: 'route1', - points: [ - { - lat: 0, - lon: 0, - }, - { - lat: 5, - lon: 5, - }, - { - lat: 10, - lon: 10, - }, - ], - }, - ], - { - withDistance: false, - withPoints: true, - withTime: true, - }, - ); - expect(routes).toHaveLength(1); - expect(routes[0].route.spacetimePoints.length).toBe(3); - expect(routes[0].route.distance).toBe(50000); - expect(routes[0].route.duration).toBe(1800); - expect(routes[0].route.fwdAzimuth).toBe(45); - expect(routes[0].route.backAzimuth).toBe(225); - expect(routes[0].route.points.length).toBe(9); - }); - - it('should create one route with points, time and distance', async () => { - const routes = await graphhopperGeorouter.route( - [ - { - key: 'route1', - points: [ - { - lat: 0, - lon: 0, - }, - { - lat: 10, - lon: 10, - }, - ], - }, - ], - { - withDistance: true, - withPoints: true, - withTime: true, - }, - ); - expect(routes).toHaveLength(1); - expect(routes[0].route.spacetimePoints.length).toBe(3); - expect(routes[0].route.spacetimePoints[1].duration).toBe(990); - expect(routes[0].route.spacetimePoints[1].distance).toBe(25000); - }); - }); -}); diff --git a/old/modules/geography/tests/unit/postgres-direction-encoder.spec.ts b/old/modules/geography/tests/unit/postgres-direction-encoder.spec.ts deleted file mode 100644 index 71b8ea3..0000000 --- a/old/modules/geography/tests/unit/postgres-direction-encoder.spec.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { PostgresDirectionEncoder } from '../../adapters/secondaries/postgres-direction-encoder'; -import { Coordinate } from '../../domain/entities/coordinate'; - -describe('Postgres direction encoder', () => { - it('should be defined', () => { - const postgresDirectionEncoder: PostgresDirectionEncoder = - new PostgresDirectionEncoder(); - expect(postgresDirectionEncoder).toBeDefined(); - }); - it('should encode coordinates to a postgres direction', () => { - const postgresDirectionEncoder: PostgresDirectionEncoder = - new PostgresDirectionEncoder(); - const coordinates: Coordinate[] = [ - { - lon: 6, - lat: 47, - }, - { - lon: 6.1, - lat: 47.1, - }, - { - lon: 6.2, - lat: 47.2, - }, - ]; - const direction = postgresDirectionEncoder.encode(coordinates); - expect(direction).toBe("'LINESTRING(6 47,6.1 47.1,6.2 47.2)'"); - }); -}); diff --git a/old/modules/geography/tests/unit/route.spec.ts b/old/modules/geography/tests/unit/route.spec.ts deleted file mode 100644 index 7a8c1e4..0000000 --- a/old/modules/geography/tests/unit/route.spec.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { Route } from '../../domain/entities/route'; -import { SpacetimePoint } from '../../domain/entities/spacetime-point'; - -const mockGeodesic = { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - inverse: jest.fn().mockImplementation((lon1, lat1, lon2, lat2) => { - return lon1 == 0 - ? { - azimuth: 45, - distance: 50000, - } - : { - azimuth: -45, - distance: 60000, - }; - }), -}; - -describe('Route entity', () => { - it('should be defined', () => { - const route = new Route(mockGeodesic); - expect(route).toBeDefined(); - }); - it('should set points and geodesic values for a route', () => { - const route = new Route(mockGeodesic); - route.setPoints([ - { - lon: 10, - lat: 10, - }, - { - lon: 20, - lat: 20, - }, - ]); - expect(route.points.length).toBe(2); - expect(route.fwdAzimuth).toBe(315); - expect(route.backAzimuth).toBe(135); - expect(route.distanceAzimuth).toBe(60000); - }); - it('should set spacetimePoints for a route', () => { - const route = new Route(mockGeodesic); - const spacetimePoint1 = new SpacetimePoint({ lon: 0, lat: 0 }, 0, 0); - const spacetimePoint2 = new SpacetimePoint({ lon: 10, lat: 10 }, 500, 5000); - route.setSpacetimePoints([spacetimePoint1, spacetimePoint2]); - expect(route.spacetimePoints.length).toBe(2); - }); -}); diff --git a/old/modules/health/adapters/primaries/health-server.controller.ts b/old/modules/health/adapters/primaries/health-server.controller.ts deleted file mode 100644 index 3cdc70d..0000000 --- a/old/modules/health/adapters/primaries/health-server.controller.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { Controller } from '@nestjs/common'; -import { GrpcMethod } from '@nestjs/microservices'; -import { RepositoriesHealthIndicatorUseCase } from '../../domain/usecases/repositories.health-indicator.usecase'; - -enum ServingStatus { - UNKNOWN = 0, - SERVING = 1, - NOT_SERVING = 2, -} - -interface HealthCheckRequest { - service: string; -} - -interface HealthCheckResponse { - status: ServingStatus; -} - -@Controller() -export class HealthServerController { - constructor( - private readonly repositoriesHealthIndicatorUseCase: RepositoriesHealthIndicatorUseCase, - ) {} - - @GrpcMethod('Health', 'Check') - async check( - // eslint-disable-next-line @typescript-eslint/no-unused-vars - data: HealthCheckRequest, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - metadata: any, - ): Promise { - const healthCheck = await this.repositoriesHealthIndicatorUseCase.isHealthy( - 'repositories', - ); - return { - status: - healthCheck['repositories'].status == 'up' - ? ServingStatus.SERVING - : ServingStatus.NOT_SERVING, - }; - } -} diff --git a/old/modules/health/adapters/primaries/health.controller.ts b/old/modules/health/adapters/primaries/health.controller.ts deleted file mode 100644 index ba6ad9f..0000000 --- a/old/modules/health/adapters/primaries/health.controller.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Controller, Get, Inject } from '@nestjs/common'; -import { - HealthCheckService, - HealthCheck, - HealthCheckResult, -} from '@nestjs/terminus'; -import { MESSAGE_PUBLISHER } from 'src/app.constants'; -import { IPublishMessage } from 'src/interfaces/message-publisher'; -import { RepositoriesHealthIndicatorUseCase } from '../../domain/usecases/repositories.health-indicator.usecase'; - -@Controller('health') -export class HealthController { - constructor( - private readonly repositoriesHealthIndicatorUseCase: RepositoriesHealthIndicatorUseCase, - private healthCheckService: HealthCheckService, - @Inject(MESSAGE_PUBLISHER) - private readonly messagePublisher: IPublishMessage, - ) {} - - @Get() - @HealthCheck() - async check() { - try { - return await this.healthCheckService.check([ - async () => - this.repositoriesHealthIndicatorUseCase.isHealthy('repositories'), - ]); - } catch (error) { - const healthCheckResult: HealthCheckResult = error.response; - this.messagePublisher.publish( - 'logging.user.health.crit', - JSON.stringify(healthCheckResult.error), - ); - throw error; - } - } -} diff --git a/old/modules/health/adapters/primaries/health.proto b/old/modules/health/adapters/primaries/health.proto deleted file mode 100644 index 74e1a4c..0000000 --- a/old/modules/health/adapters/primaries/health.proto +++ /dev/null @@ -1,21 +0,0 @@ -syntax = "proto3"; - -package health; - - -service Health { - rpc Check(HealthCheckRequest) returns (HealthCheckResponse); -} - -message HealthCheckRequest { - string service = 1; -} - -message HealthCheckResponse { - enum ServingStatus { - UNKNOWN = 0; - SERVING = 1; - NOT_SERVING = 2; - } - ServingStatus status = 1; -} diff --git a/old/modules/health/adapters/secondaries/message-publisher.ts b/old/modules/health/adapters/secondaries/message-publisher.ts deleted file mode 100644 index 98a963b..0000000 --- a/old/modules/health/adapters/secondaries/message-publisher.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Inject, Injectable } from '@nestjs/common'; -import { MESSAGE_BROKER_PUBLISHER } from '../../../../app.constants'; -import { MessageBrokerPublisher } from '@mobicoop/message-broker-module'; -import { IPublishMessage } from 'src/interfaces/message-publisher'; - -@Injectable() -export class MessagePublisher implements IPublishMessage { - constructor( - @Inject(MESSAGE_BROKER_PUBLISHER) - private readonly messageBrokerPublisher: MessageBrokerPublisher, - ) {} - - publish = (routingKey: string, message: string): void => { - this.messageBrokerPublisher.publish(routingKey, message); - }; -} diff --git a/old/modules/health/domain/interfaces/check-repository.interface.ts b/old/modules/health/domain/interfaces/check-repository.interface.ts deleted file mode 100644 index 68c3178..0000000 --- a/old/modules/health/domain/interfaces/check-repository.interface.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface ICheckRepository { - healthCheck(): Promise; -} diff --git a/old/modules/health/domain/usecases/repositories.health-indicator.usecase.ts b/old/modules/health/domain/usecases/repositories.health-indicator.usecase.ts deleted file mode 100644 index 7aaecfa..0000000 --- a/old/modules/health/domain/usecases/repositories.health-indicator.usecase.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { - HealthCheckError, - HealthIndicator, - HealthIndicatorResult, -} from '@nestjs/terminus'; -import { ICheckRepository } from '../interfaces/check-repository.interface'; -import { AdRepository } from '../../../ad/adapters/secondaries/ad.repository'; - -@Injectable() -export class RepositoriesHealthIndicatorUseCase extends HealthIndicator { - private checkRepositories: ICheckRepository[]; - constructor(private readonly adRepository: AdRepository) { - super(); - this.checkRepositories = [adRepository]; - } - isHealthy = async (key: string): Promise => { - try { - await Promise.all( - this.checkRepositories.map( - async (checkRepository: ICheckRepository) => { - await checkRepository.healthCheck(); - }, - ), - ); - return this.getStatus(key, true); - } catch (e: any) { - throw new HealthCheckError('Repository', { - repository: e.message, - }); - } - }; -} diff --git a/old/modules/health/health.module.ts b/old/modules/health/health.module.ts deleted file mode 100644 index 0c2511a..0000000 --- a/old/modules/health/health.module.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { Module } from '@nestjs/common'; -import { HealthServerController } from './adapters/primaries/health-server.controller'; -import { DatabaseModule } from '../database/database.module'; -import { HealthController } from './adapters/primaries/health.controller'; -import { TerminusModule } from '@nestjs/terminus'; -import { MESSAGE_BROKER_PUBLISHER, MESSAGE_PUBLISHER } from 'src/app.constants'; -import { MessageBrokerPublisher } from '@mobicoop/message-broker-module'; -import { MessagePublisher } from './adapters/secondaries/message-publisher'; -import { RepositoriesHealthIndicatorUseCase } from './domain/usecases/repositories.health-indicator.usecase'; -import { AdRepository } from '../ad/adapters/secondaries/ad.repository'; - -@Module({ - imports: [TerminusModule, DatabaseModule], - controllers: [HealthServerController, HealthController], - providers: [ - RepositoriesHealthIndicatorUseCase, - AdRepository, - { - provide: MESSAGE_BROKER_PUBLISHER, - useClass: MessageBrokerPublisher, - }, - { - provide: MESSAGE_PUBLISHER, - useClass: MessagePublisher, - }, - ], -}) -export class HealthModule {} diff --git a/old/modules/health/tests/unit/message-publisher.spec.ts b/old/modules/health/tests/unit/message-publisher.spec.ts deleted file mode 100644 index eec02ea..0000000 --- a/old/modules/health/tests/unit/message-publisher.spec.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { MessagePublisher } from '../../adapters/secondaries/message-publisher'; -import { MESSAGE_BROKER_PUBLISHER } from '../../../../app.constants'; - -const mockMessageBrokerPublisher = { - publish: jest.fn().mockImplementation(), -}; - -describe('Messager', () => { - let messagePublisher: MessagePublisher; - - beforeAll(async () => { - const module: TestingModule = await Test.createTestingModule({ - imports: [], - providers: [ - MessagePublisher, - { - provide: MESSAGE_BROKER_PUBLISHER, - useValue: mockMessageBrokerPublisher, - }, - ], - }).compile(); - - messagePublisher = module.get(MessagePublisher); - }); - - it('should be defined', () => { - expect(messagePublisher).toBeDefined(); - }); - - it('should publish a message', async () => { - jest.spyOn(mockMessageBrokerPublisher, 'publish'); - messagePublisher.publish('health.info', 'my-test'); - expect(mockMessageBrokerPublisher.publish).toHaveBeenCalledTimes(1); - }); -}); diff --git a/old/modules/health/tests/unit/repositories.health-indicator.usecase.spec.ts b/old/modules/health/tests/unit/repositories.health-indicator.usecase.spec.ts deleted file mode 100644 index c726f27..0000000 --- a/old/modules/health/tests/unit/repositories.health-indicator.usecase.spec.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { HealthCheckError, HealthIndicatorResult } from '@nestjs/terminus'; -import { RepositoriesHealthIndicatorUseCase } from '../../domain/usecases/repositories.health-indicator.usecase'; -import { AdRepository } from '../../../ad/adapters/secondaries/ad.repository'; - -const mockAdRepository = { - healthCheck: jest - .fn() - .mockImplementationOnce(() => { - return Promise.resolve(true); - }) - .mockImplementation(() => { - throw new Error('an error occured in the repository'); - }), -}; - -describe('RepositoriesHealthIndicatorUseCase', () => { - let repositoriesHealthIndicatorUseCase: RepositoriesHealthIndicatorUseCase; - - beforeAll(async () => { - const module: TestingModule = await Test.createTestingModule({ - providers: [ - RepositoriesHealthIndicatorUseCase, - { - provide: AdRepository, - useValue: mockAdRepository, - }, - ], - }).compile(); - - repositoriesHealthIndicatorUseCase = - module.get( - RepositoriesHealthIndicatorUseCase, - ); - }); - - it('should be defined', () => { - expect(repositoriesHealthIndicatorUseCase).toBeDefined(); - }); - - describe('execute', () => { - it('should check health successfully', async () => { - const healthIndicatorResult: HealthIndicatorResult = - await repositoriesHealthIndicatorUseCase.isHealthy('repositories'); - - expect(healthIndicatorResult['repositories'].status).toBe('up'); - }); - - it('should throw an error if database is unavailable', async () => { - await expect( - repositoriesHealthIndicatorUseCase.isHealthy('repositories'), - ).rejects.toBeInstanceOf(HealthCheckError); - }); - }); -}); diff --git a/old/modules/matcher/adapters/primaries/matcher.controller.ts b/old/modules/matcher/adapters/primaries/matcher.controller.ts deleted file mode 100644 index bc926b2..0000000 --- a/old/modules/matcher/adapters/primaries/matcher.controller.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { Mapper } from '@automapper/core'; -import { InjectMapper } from '@automapper/nestjs'; -import { Controller, UsePipes } from '@nestjs/common'; -import { QueryBus } from '@nestjs/cqrs'; -import { GrpcMethod, RpcException } from '@nestjs/microservices'; -import { RpcValidationPipe } from '../../../utils/pipes/rpc.validation-pipe'; -import { MatchRequest } from '../../domain/dtos/match.request'; -import { ICollection } from '../../../database/interfaces/collection.interface'; -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'; -import { Match } from '../../domain/entities/ecosystem/match'; -import { GeoTimezoneFinder } from '../../../geography/adapters/secondaries/geo-timezone-finder'; -import { TimeConverter } from '../secondaries/time-converter'; - -@UsePipes( - new RpcValidationPipe({ - whitelist: false, - forbidUnknownValues: false, - }), -) -@Controller() -export class MatcherController { - constructor( - private readonly queryBus: QueryBus, - private readonly defaultParamsProvider: DefaultParamsProvider, - @InjectMapper() private readonly mapper: Mapper, - private readonly georouterCreator: GeorouterCreator, - private readonly timezoneFinder: GeoTimezoneFinder, - private readonly timeConverter: TimeConverter, - ) {} - - @GrpcMethod('MatcherService', 'Match') - async match(data: MatchRequest): Promise> { - try { - const matchCollection = await this.queryBus.execute( - new MatchQuery( - data, - this.defaultParamsProvider.getParams(), - this.georouterCreator, - this.timezoneFinder, - this.timeConverter, - ), - ); - return Promise.resolve({ - data: matchCollection.data.map((match: Match) => - this.mapper.map(match, Match, MatchPresenter), - ), - total: matchCollection.total, - }); - } catch (e) { - throw new RpcException({ - code: e.code, - message: e.message, - }); - } - } -} diff --git a/old/modules/matcher/adapters/primaries/matcher.proto b/old/modules/matcher/adapters/primaries/matcher.proto deleted file mode 100644 index 898e6ee..0000000 --- a/old/modules/matcher/adapters/primaries/matcher.proto +++ /dev/null @@ -1,70 +0,0 @@ -syntax = "proto3"; - -package matcher; - -service MatcherService { - rpc Match(MatchRequest) returns (Matches); -} - -message MatchRequest { - string uuid = 1; - repeated Coordinates waypoints = 2; - string departure = 3; - string fromDate = 4; - Schedule schedule = 5; - bool driver = 6; - bool passenger = 7; - string toDate = 8; - int32 marginDuration = 9; - MarginDurations marginDurations = 10; - int32 seatsPassenger = 11; - int32 seatsDriver = 12; - bool strict = 13; - Algorithm algorithm = 14; - int32 remoteness = 15; - bool useProportion = 16; - int32 proportion = 17; - bool useAzimuth = 18; - int32 azimuthMargin = 19; - float maxDetourDistanceRatio = 20; - float maxDetourDurationRatio = 21; - repeated int32 exclusions = 22; -} - -message Coordinates { - float lon = 1; - float lat = 2; -} - -message Schedule { - string mon = 1; - string tue = 2; - string wed = 3; - string thu = 4; - string fri = 5; - string sat = 6; - string sun = 7; -} - -message MarginDurations { - int32 mon = 1; - int32 tue = 2; - int32 wed = 3; - int32 thu = 4; - int32 fri = 5; - int32 sat = 6; - int32 sun = 7; -} - -enum Algorithm { - CLASSIC = 0; -} - -message Match { - string uuid = 1; -} - -message Matches { - repeated Match data = 1; - int32 total = 2; -} diff --git a/old/modules/matcher/adapters/secondaries/default-params.provider.ts b/old/modules/matcher/adapters/secondaries/default-params.provider.ts deleted file mode 100644 index d331919..0000000 --- a/old/modules/matcher/adapters/secondaries/default-params.provider.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { ConfigService } from '@nestjs/config'; -import { IDefaultParams } from '../../domain/types/default-params.type'; - -@Injectable() -export class DefaultParamsProvider { - constructor(private readonly configService: ConfigService) {} - - getParams = (): IDefaultParams => { - return { - DEFAULT_UUID: this.configService.get('DEFAULT_UUID'), - MARGIN_DURATION: parseInt(this.configService.get('MARGIN_DURATION')), - VALIDITY_DURATION: parseInt(this.configService.get('VALIDITY_DURATION')), - DEFAULT_TIMEZONE: this.configService.get('DEFAULT_TIMEZONE'), - DEFAULT_SEATS: parseInt(this.configService.get('DEFAULT_SEATS')), - DEFAULT_ALGORITHM_SETTINGS: { - ALGORITHM: this.configService.get('ALGORITHM'), - STRICT: !!parseInt(this.configService.get('STRICT_ALGORITHM')), - REMOTENESS: parseInt(this.configService.get('REMOTENESS')), - USE_PROPORTION: !!parseInt(this.configService.get('USE_PROPORTION')), - PROPORTION: parseInt(this.configService.get('PROPORTION')), - USE_AZIMUTH: !!parseInt(this.configService.get('USE_AZIMUTH')), - AZIMUTH_MARGIN: parseInt(this.configService.get('AZIMUTH_MARGIN')), - MAX_DETOUR_DISTANCE_RATIO: parseFloat( - this.configService.get('MAX_DETOUR_DISTANCE_RATIO'), - ), - MAX_DETOUR_DURATION_RATIO: parseFloat( - this.configService.get('MAX_DETOUR_DURATION_RATIO'), - ), - GEOROUTER_TYPE: this.configService.get('GEOROUTER_TYPE'), - GEOROUTER_URL: this.configService.get('GEOROUTER_URL'), - }, - }; - }; -} diff --git a/old/modules/matcher/adapters/secondaries/geodesic.ts b/old/modules/matcher/adapters/secondaries/geodesic.ts deleted file mode 100644 index deb304a..0000000 --- a/old/modules/matcher/adapters/secondaries/geodesic.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { Geodesic } from '../../../geography/adapters/secondaries/geodesic'; -import { IGeodesic } from '../../../geography/domain/interfaces/geodesic.interface'; - -@Injectable() -export class MatcherGeodesic implements IGeodesic { - constructor(private readonly geodesic: Geodesic) {} - - inverse = ( - lon1: number, - lat1: number, - lon2: number, - lat2: number, - ): { azimuth: number; distance: number } => - this.geodesic.inverse(lon1, lat1, lon2, lat2); -} diff --git a/old/modules/matcher/adapters/secondaries/georouter-creator.ts b/old/modules/matcher/adapters/secondaries/georouter-creator.ts deleted file mode 100644 index 5589e7a..0000000 --- a/old/modules/matcher/adapters/secondaries/georouter-creator.ts +++ /dev/null @@ -1,30 +0,0 @@ -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'; -import { HttpService } from '@nestjs/axios'; -import { MatcherGeodesic } from './geodesic'; -import { - MatcherException, - MatcherExceptionCode, -} from '../../exceptions/matcher.exception'; - -@Injectable() -export class GeorouterCreator implements ICreateGeorouter { - constructor( - private readonly httpService: HttpService, - private readonly geodesic: MatcherGeodesic, - ) {} - - create = (type: string, url: string): IGeorouter => { - switch (type) { - case 'graphhopper': - return new GraphhopperGeorouter(url, this.httpService, this.geodesic); - default: - throw new MatcherException( - MatcherExceptionCode.INVALID_ARGUMENT, - 'Unknown geocoder', - ); - } - }; -} diff --git a/old/modules/matcher/adapters/secondaries/graphhopper-georouter.ts b/old/modules/matcher/adapters/secondaries/graphhopper-georouter.ts deleted file mode 100644 index 472a333..0000000 --- a/old/modules/matcher/adapters/secondaries/graphhopper-georouter.ts +++ /dev/null @@ -1,326 +0,0 @@ -import { HttpService } from '@nestjs/axios'; -import { IGeorouter } from '../../domain/interfaces/georouter.interface'; -import { GeorouterSettings } from '../../domain/types/georouter-settings.type'; -import { Path } from '../../domain/types/path.type'; -import { Injectable } from '@nestjs/common'; -import { catchError, lastValueFrom, map } from 'rxjs'; -import { AxiosError, AxiosResponse } from 'axios'; -import { IGeodesic } from '../../../geography/domain/interfaces/geodesic.interface'; -import { NamedRoute } from '../../domain/entities/ecosystem/named-route'; -import { MatcherRoute } from '../../domain/entities/ecosystem/matcher-route'; -import { SpacetimePoint } from '../../domain/entities/ecosystem/spacetime-point'; -import { - MatcherException, - MatcherExceptionCode, -} from '../../exceptions/matcher.exception'; - -@Injectable() -export class GraphhopperGeorouter implements IGeorouter { - private url: string; - private urlArgs: string[]; - private withTime: boolean; - private withPoints: boolean; - private withDistance: boolean; - private paths: Path[]; - private httpService: HttpService; - private geodesic: IGeodesic; - - constructor(url: string, httpService: HttpService, geodesic: IGeodesic) { - this.url = url + '/route?'; - this.httpService = httpService; - this.geodesic = geodesic; - } - - route = async ( - paths: Path[], - settings: GeorouterSettings, - ): Promise => { - this.setDefaultUrlArgs(); - this.setWithTime(settings.withTime); - this.setWithPoints(settings.withPoints); - this.setWithDistance(settings.withDistance); - this.paths = paths; - return await this.getRoutes(); - }; - - private setDefaultUrlArgs = (): void => { - this.urlArgs = ['vehicle=car', 'weighting=fastest', 'points_encoded=false']; - }; - - private setWithTime = (withTime: boolean): void => { - this.withTime = withTime; - if (withTime) { - this.urlArgs.push('details=time'); - } - }; - - private setWithPoints = (withPoints: boolean): void => { - this.withPoints = withPoints; - if (!withPoints) { - this.urlArgs.push('calc_points=false'); - } - }; - - private setWithDistance = (withDistance: boolean): void => { - this.withDistance = withDistance; - if (withDistance) { - this.urlArgs.push('instructions=true'); - } else { - this.urlArgs.push('instructions=false'); - } - }; - - private getRoutes = async (): Promise => { - const routes = Promise.all( - this.paths.map(async (path) => { - const url: string = [ - this.getUrl(), - '&point=', - path.points - .map((point) => [point.lat, point.lon].join()) - .join('&point='), - ].join(''); - const route = await lastValueFrom( - this.httpService.get(url).pipe( - map((res) => (res.data ? this.createRoute(res) : undefined)), - catchError((error: AxiosError) => { - throw new MatcherException( - MatcherExceptionCode.INTERNAL, - 'Georouter unavailable : ' + error.message, - ); - }), - ), - ); - return { - key: path.key, - route, - }; - }), - ); - return routes; - }; - - private getUrl = (): string => { - return [this.url, this.urlArgs.join('&')].join(''); - }; - - private createRoute = ( - response: AxiosResponse, - ): MatcherRoute => { - const route = new MatcherRoute(this.geodesic); - if (response.data.paths && response.data.paths[0]) { - const shortestPath = response.data.paths[0]; - route.distance = shortestPath.distance ?? 0; - route.duration = shortestPath.time ? shortestPath.time / 1000 : 0; - if (shortestPath.points && shortestPath.points.coordinates) { - route.setPoints( - shortestPath.points.coordinates.map((coordinate) => ({ - lon: coordinate[0], - lat: coordinate[1], - })), - ); - if ( - shortestPath.details && - shortestPath.details.time && - shortestPath.snapped_waypoints && - shortestPath.snapped_waypoints.coordinates - ) { - let instructions: GraphhopperInstruction[] = []; - if (shortestPath.instructions) - instructions = shortestPath.instructions; - route.setSpacetimePoints( - this.generateSpacetimePoints( - shortestPath.points.coordinates, - shortestPath.snapped_waypoints.coordinates, - shortestPath.details.time, - instructions, - ), - ); - } - } - } - return route; - }; - - private generateSpacetimePoints = ( - points: Array, - snappedWaypoints: Array, - durations: Array, - instructions: GraphhopperInstruction[], - ): SpacetimePoint[] => { - const indices = this.getIndices(points, snappedWaypoints); - const times = this.getTimes(durations, indices); - const distances = this.getDistances(instructions, indices); - return indices.map( - (index) => - new SpacetimePoint( - { lon: points[index][1], lat: points[index][0] }, - times.find((time) => time.index == index)?.duration, - distances.find((distance) => distance.index == index)?.distance, - ), - ); - }; - - private getIndices = ( - points: Array, - snappedWaypoints: Array, - ): number[] => { - const indices = snappedWaypoints.map((waypoint) => - points.findIndex( - (point) => point[0] == waypoint[0] && point[1] == waypoint[1], - ), - ); - if (indices.find((index) => index == -1) === undefined) return indices; - const missedWaypoints = indices - .map( - (value, index) => - < - { - index: number; - originIndex: number; - waypoint: number[]; - nearest: number; - distance: number; - } - >{ - index: value, - originIndex: index, - waypoint: snappedWaypoints[index], - nearest: undefined, - distance: 999999999, - }, - ) - .filter((element) => element.index == -1); - for (const index in points) { - for (const missedWaypoint of missedWaypoints) { - const inverse = this.geodesic.inverse( - missedWaypoint.waypoint[0], - missedWaypoint.waypoint[1], - points[index][0], - points[index][1], - ); - if (inverse.distance < missedWaypoint.distance) { - missedWaypoint.distance = inverse.distance; - missedWaypoint.nearest = parseInt(index); - } - } - } - for (const missedWaypoint of missedWaypoints) { - indices[missedWaypoint.originIndex] = missedWaypoint.nearest; - } - return indices; - }; - - private getTimes = ( - durations: Array, - indices: number[], - ): Array<{ index: number; duration: number }> => { - const times: Array<{ index: number; duration: number }> = []; - let duration = 0; - for (const [origin, destination, stepDuration] of durations) { - let indexFound = false; - const indexAsOrigin = indices.find((index) => index == origin); - if ( - indexAsOrigin !== undefined && - times.find((time) => origin == time.index) == undefined - ) { - times.push({ - index: indexAsOrigin, - duration: Math.round(stepDuration / 1000), - }); - indexFound = true; - } - if (!indexFound) { - const indexAsDestination = indices.find( - (index) => index == destination, - ); - if ( - indexAsDestination !== undefined && - times.find((time) => destination == time.index) == undefined - ) { - times.push({ - index: indexAsDestination, - duration: Math.round((duration + stepDuration) / 1000), - }); - indexFound = true; - } - } - if (!indexFound) { - const indexInBetween = indices.find( - (index) => origin < index && index < destination, - ); - if (indexInBetween !== undefined) { - times.push({ - index: indexInBetween, - duration: Math.round((duration + stepDuration / 2) / 1000), - }); - } - } - duration += stepDuration; - } - return times; - }; - - private getDistances = ( - instructions: GraphhopperInstruction[], - indices: number[], - ): Array<{ index: number; distance: number }> => { - let distance = 0; - const distances: Array<{ index: number; distance: number }> = [ - { - index: 0, - distance, - }, - ]; - for (const instruction of instructions) { - distance += instruction.distance; - if ( - (instruction.sign == GraphhopperSign.SIGN_WAYPOINT || - instruction.sign == GraphhopperSign.SIGN_FINISH) && - indices.find((index) => index == instruction.interval[0]) !== undefined - ) { - distances.push({ - index: instruction.interval[0], - distance: Math.round(distance), - }); - } - } - return distances; - }; -} - -type GraphhopperResponse = { - paths: [ - { - distance: number; - weight: number; - time: number; - points_encoded: boolean; - bbox: number[]; - points: GraphhopperCoordinates; - snapped_waypoints: GraphhopperCoordinates; - details: { - time: Array; - }; - instructions: GraphhopperInstruction[]; - }, - ]; -}; - -type GraphhopperCoordinates = { - coordinates: Array; -}; - -type GraphhopperInstruction = { - distance: number; - heading: number; - sign: GraphhopperSign; - interval: number[]; - text: string; -}; - -enum GraphhopperSign { - SIGN_START = 0, - SIGN_FINISH = 4, - SIGN_WAYPOINT = 5, -} diff --git a/old/modules/matcher/adapters/secondaries/match.presenter.ts b/old/modules/matcher/adapters/secondaries/match.presenter.ts deleted file mode 100644 index 4d7fd5e..0000000 --- a/old/modules/matcher/adapters/secondaries/match.presenter.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { AutoMap } from '@automapper/classes'; - -export class MatchPresenter { - @AutoMap() - uuid: string; -} diff --git a/old/modules/matcher/adapters/secondaries/message-publisher.ts b/old/modules/matcher/adapters/secondaries/message-publisher.ts deleted file mode 100644 index 315bb6b..0000000 --- a/old/modules/matcher/adapters/secondaries/message-publisher.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Inject, Injectable } from '@nestjs/common'; -import { MESSAGE_BROKER_PUBLISHER } from '../../../../app.constants'; -import { MessageBrokerPublisher } from '@mobicoop/message-broker-module'; -import { IPublishMessage } from '../../../../interfaces/message-publisher'; - -@Injectable() -export class MessagePublisher implements IPublishMessage { - constructor( - @Inject(MESSAGE_BROKER_PUBLISHER) - private readonly messageBrokerPublisher: MessageBrokerPublisher, - ) {} - - publish = (routingKey: string, message: string): void => { - this.messageBrokerPublisher.publish(routingKey, message); - }; -} diff --git a/old/modules/matcher/adapters/secondaries/time-converter.ts b/old/modules/matcher/adapters/secondaries/time-converter.ts deleted file mode 100644 index 63e8e62..0000000 --- a/old/modules/matcher/adapters/secondaries/time-converter.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { DateTime, TimeZone } from 'timezonecomplete'; -import { IConvertTime } from '../../domain/interfaces/time-converter.interface'; - -@Injectable() -export class TimeConverter implements IConvertTime { - toUtcDate = (date: Date, timezone: string): Date => { - try { - return new Date( - new DateTime( - `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}T${date.getHours()}:${date.getMinutes()}`, - TimeZone.zone(timezone, false), - ) - .convert(TimeZone.zone('UTC')) - .toIsoString(), - ); - } catch (e) { - return undefined; - } - }; -} diff --git a/old/modules/matcher/adapters/secondaries/timezone-finder.ts b/old/modules/matcher/adapters/secondaries/timezone-finder.ts deleted file mode 100644 index 8459661..0000000 --- a/old/modules/matcher/adapters/secondaries/timezone-finder.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { GeoTimezoneFinder } from '../../../geography/adapters/secondaries/geo-timezone-finder'; -import { IFindTimezone } from '../../../geography/domain/interfaces/timezone-finder.interface'; - -@Injectable() -export class TimezoneFinder implements IFindTimezone { - constructor(private readonly geoTimezoneFinder: GeoTimezoneFinder) {} - - timezones = (lon: number, lat: number): string[] => - this.geoTimezoneFinder.timezones(lon, lat); -} diff --git a/old/modules/matcher/domain/dtos/match.request.ts b/old/modules/matcher/domain/dtos/match.request.ts deleted file mode 100644 index bcd1824..0000000 --- a/old/modules/matcher/domain/dtos/match.request.ts +++ /dev/null @@ -1,155 +0,0 @@ -import { - IsArray, - IsBoolean, - IsEnum, - IsInt, - IsNumber, - IsOptional, - IsString, - Max, - Min, -} from 'class-validator'; -import { AutoMap } from '@automapper/classes'; -import { Point } from '../../../geography/domain/types/point.type'; -import { Schedule } from '../types/schedule.type'; -import { MarginDurations } from '../types/margin-durations.type'; -import { AlgorithmType } from '../types/algorithm.enum'; -import { IRequestTime } from '../interfaces/time-request.interface'; -import { IRequestAd } from '../interfaces/ad-request.interface'; -import { IRequestGeography } from '../interfaces/geography-request.interface'; -import { IRequestRequirement } from '../interfaces/requirement-request.interface'; -import { IRequestAlgorithmSettings } from '../interfaces/algorithm-settings-request.interface'; -import { Mode } from '../types/mode.enum'; - -export class MatchRequest - implements - IRequestTime, - IRequestAd, - IRequestGeography, - IRequestRequirement, - IRequestAlgorithmSettings -{ - @IsOptional() - @IsString() - @AutoMap() - uuid: string; - - @IsOptional() - @IsEnum(Mode) - @AutoMap() - mode: Mode; - - @IsArray() - @AutoMap() - waypoints: Point[]; - - @IsOptional() - @IsString() - @AutoMap() - departure: string; - - @IsOptional() - @IsString() - @AutoMap() - fromDate: string; - - @IsOptional() - @AutoMap() - schedule: Schedule; - - @IsOptional() - @IsBoolean() - @AutoMap() - driver: boolean; - - @IsOptional() - @IsBoolean() - @AutoMap() - passenger: boolean; - - @IsOptional() - @IsString() - @AutoMap() - toDate: string; - - @IsOptional() - @IsInt() - @AutoMap() - marginDuration: number; - - @IsOptional() - @AutoMap() - marginDurations: MarginDurations; - - @IsOptional() - @IsNumber() - @Min(1) - @Max(10) - @AutoMap() - seatsPassenger: number; - - @IsOptional() - @IsNumber() - @Min(1) - @Max(10) - @AutoMap() - seatsDriver: number; - - @IsOptional() - @AutoMap() - strict: boolean; - - @IsOptional() - @IsEnum(AlgorithmType) - @AutoMap() - algorithm: AlgorithmType; - - @IsOptional() - @IsNumber() - @AutoMap() - remoteness: number; - - @IsOptional() - @IsBoolean() - @AutoMap() - useProportion: boolean; - - @IsOptional() - @IsNumber() - @Min(0) - @Max(1) - @AutoMap() - proportion: number; - - @IsOptional() - @IsBoolean() - @AutoMap() - useAzimuth: boolean; - - @IsOptional() - @IsInt() - @Min(0) - @Max(359) - @AutoMap() - azimuthMargin: number; - - @IsOptional() - @IsNumber() - @Min(0) - @Max(1) - @AutoMap() - maxDetourDistanceRatio: number; - - @IsOptional() - @IsNumber() - @Min(0) - @Max(1) - @AutoMap() - maxDetourDurationRatio: number; - - @IsOptional() - @IsArray() - exclusions: string[]; - - timezone?: string; -} diff --git a/old/modules/matcher/domain/entities/ecosystem/actor.ts b/old/modules/matcher/domain/entities/ecosystem/actor.ts deleted file mode 100644 index 78ea643..0000000 --- a/old/modules/matcher/domain/entities/ecosystem/actor.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Role } from '../../types/role.enum'; -import { Step } from '../../types/step.enum'; -import { Ad } from './ad'; - -export class Actor { - ad: Ad; - role: Role; - step: Step; - - constructor(ad: Ad, role: Role, step: Step) { - this.ad = ad; - this.role = role; - this.step = step; - } -} diff --git a/old/modules/matcher/domain/entities/ecosystem/ad.ts b/old/modules/matcher/domain/entities/ecosystem/ad.ts deleted file mode 100644 index 5046579..0000000 --- a/old/modules/matcher/domain/entities/ecosystem/ad.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { IRequestAd } from '../../interfaces/ad-request.interface'; - -export class Ad { - private adRequest: IRequestAd; - private defaultUuid: string; - private defaultMarginDuration: number; - uuid: string; - marginDurations: number[]; - - constructor( - adRequest: IRequestAd, - defaultUuid: string, - defaultMarginDuration: number, - ) { - this.adRequest = adRequest; - this.defaultUuid = defaultUuid; - this.defaultMarginDuration = defaultMarginDuration; - } - - init = (): void => { - this.setUuid(this.adRequest.uuid ?? this.defaultUuid); - this.setMarginDurations([ - this.defaultMarginDuration, - this.defaultMarginDuration, - this.defaultMarginDuration, - this.defaultMarginDuration, - this.defaultMarginDuration, - this.defaultMarginDuration, - this.defaultMarginDuration, - ]); - }; - - setUuid = (uuid: string): void => { - this.uuid = uuid; - }; - - setMarginDurations = (marginDurations: number[]): void => { - this.marginDurations = marginDurations; - }; -} diff --git a/old/modules/matcher/domain/entities/ecosystem/algorithm-settings.ts b/old/modules/matcher/domain/entities/ecosystem/algorithm-settings.ts deleted file mode 100644 index 0e5dd92..0000000 --- a/old/modules/matcher/domain/entities/ecosystem/algorithm-settings.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { IRequestAlgorithmSettings } from '../../interfaces/algorithm-settings-request.interface'; -import { DefaultAlgorithmSettings } from '../../types/default-algorithm-settings.type'; -import { AlgorithmType } from '../../types/algorithm.enum'; -import { ICreateGeorouter } from '../../interfaces/georouter-creator.interface'; -import { IGeorouter } from '../../interfaces/georouter.interface'; -import { Frequency } from '../../../../ad/domain/types/frequency.enum'; - -export class AlgorithmSettings { - private algorithmSettingsRequest: IRequestAlgorithmSettings; - private strict: boolean; - algorithmType: AlgorithmType; - restrict: Frequency; - remoteness: number; - useProportion: boolean; - proportion: number; - useAzimuth: boolean; - azimuthMargin: number; - maxDetourDurationRatio: number; - maxDetourDistanceRatio: number; - georouter: IGeorouter; - - constructor( - algorithmSettingsRequest: IRequestAlgorithmSettings, - defaultAlgorithmSettings: DefaultAlgorithmSettings, - frequency: Frequency, - georouterCreator: ICreateGeorouter, - ) { - this.algorithmSettingsRequest = algorithmSettingsRequest; - this.algorithmType = - algorithmSettingsRequest.algorithm ?? defaultAlgorithmSettings.ALGORITHM; - this.strict = - algorithmSettingsRequest.strict ?? defaultAlgorithmSettings.STRICT; - this.remoteness = algorithmSettingsRequest.remoteness - ? Math.abs(algorithmSettingsRequest.remoteness) - : defaultAlgorithmSettings.REMOTENESS; - this.useProportion = - algorithmSettingsRequest.useProportion ?? - defaultAlgorithmSettings.USE_PROPORTION; - this.proportion = algorithmSettingsRequest.proportion - ? Math.abs(algorithmSettingsRequest.proportion) - : defaultAlgorithmSettings.PROPORTION; - this.useAzimuth = - algorithmSettingsRequest.useAzimuth ?? - defaultAlgorithmSettings.USE_AZIMUTH; - this.azimuthMargin = algorithmSettingsRequest.azimuthMargin - ? Math.abs(algorithmSettingsRequest.azimuthMargin) - : defaultAlgorithmSettings.AZIMUTH_MARGIN; - this.maxDetourDistanceRatio = - algorithmSettingsRequest.maxDetourDistanceRatio ?? - defaultAlgorithmSettings.MAX_DETOUR_DISTANCE_RATIO; - this.maxDetourDurationRatio = - algorithmSettingsRequest.maxDetourDurationRatio ?? - defaultAlgorithmSettings.MAX_DETOUR_DURATION_RATIO; - this.georouter = georouterCreator.create( - defaultAlgorithmSettings.GEOROUTER_TYPE, - defaultAlgorithmSettings.GEOROUTER_URL, - ); - if (this.strict) { - this.restrict = frequency; - } - } -} diff --git a/old/modules/matcher/domain/entities/ecosystem/geography.ts b/old/modules/matcher/domain/entities/ecosystem/geography.ts deleted file mode 100644 index abf9be7..0000000 --- a/old/modules/matcher/domain/entities/ecosystem/geography.ts +++ /dev/null @@ -1,196 +0,0 @@ -import { - MatcherException, - MatcherExceptionCode, -} from '../../../exceptions/matcher.exception'; -import { IRequestGeography } from '../../interfaces/geography-request.interface'; -import { PointType } from '../../../../geography/domain/types/point-type.enum'; -import { Point } from '../../../../geography/domain/types/point.type'; -import { MatcherRoute } from './matcher-route'; -import { Role } from '../../types/role.enum'; -import { IGeorouter } from '../../interfaces/georouter.interface'; -import { Waypoint } from './waypoint'; -import { Actor } from './actor'; -import { Ad } from './ad'; -import { Step } from '../../types/step.enum'; -import { Path } from '../../types/path.type'; -import { IFindTimezone } from '../../../../geography/domain/interfaces/timezone-finder.interface'; -import { Timezoner } from './timezoner'; - -export class Geography { - private geographyRequest: IRequestGeography; - private ad: Ad; - private points: Point[]; - originType: PointType; - destinationType: PointType; - timezones: string[]; - driverRoute: MatcherRoute; - passengerRoute: MatcherRoute; - timezoneFinder: IFindTimezone; - - constructor( - geographyRequest: IRequestGeography, - timezoner: Timezoner, - ad: Ad, - ) { - this.geographyRequest = geographyRequest; - this.ad = ad; - this.points = []; - this.originType = undefined; - this.destinationType = undefined; - this.timezones = [timezoner.timezone]; - this.timezoneFinder = timezoner.finder; - } - - init = (): void => { - this.validateWaypoints(); - this.setTimezones(); - this.setPointTypes(); - }; - - createRoutes = async ( - roles: Role[], - georouter: IGeorouter, - ): Promise => { - let driverWaypoints: Waypoint[] = []; - let passengerWaypoints: Waypoint[] = []; - const paths: Path[] = []; - if (roles.includes(Role.DRIVER) && roles.includes(Role.PASSENGER)) { - if (this.points.length == 2) { - // 2 points => same route for driver and passenger - const commonPath: Path = { - key: RouteKey.COMMON, - points: this.points, - }; - driverWaypoints = this.createWaypoints(commonPath.points, Role.DRIVER); - passengerWaypoints = this.createWaypoints( - commonPath.points, - Role.PASSENGER, - ); - paths.push(commonPath); - } else { - const driverPath: Path = { - key: RouteKey.DRIVER, - points: this.points, - }; - driverWaypoints = this.createWaypoints(driverPath.points, Role.DRIVER); - const passengerPath: Path = { - key: RouteKey.PASSENGER, - points: [this.points[0], this.points[this.points.length - 1]], - }; - passengerWaypoints = this.createWaypoints( - passengerPath.points, - Role.PASSENGER, - ); - paths.push(driverPath, passengerPath); - } - } else if (roles.includes(Role.DRIVER)) { - const driverPath: Path = { - key: RouteKey.DRIVER, - points: this.points, - }; - driverWaypoints = this.createWaypoints(driverPath.points, Role.DRIVER); - paths.push(driverPath); - } else if (roles.includes(Role.PASSENGER)) { - const passengerPath: Path = { - key: RouteKey.PASSENGER, - points: [this.points[0], this.points[this.points.length - 1]], - }; - passengerWaypoints = this.createWaypoints( - passengerPath.points, - Role.PASSENGER, - ); - paths.push(passengerPath); - } - const routes = await georouter.route(paths, { - withDistance: false, - withPoints: true, - withTime: false, - }); - if (routes.some((route) => route.key == RouteKey.COMMON)) { - this.driverRoute = routes.find( - (route) => route.key == RouteKey.COMMON, - ).route; - this.passengerRoute = routes.find( - (route) => route.key == RouteKey.COMMON, - ).route; - this.driverRoute.setWaypoints(driverWaypoints); - this.passengerRoute.setWaypoints(passengerWaypoints); - } else { - if (routes.some((route) => route.key == RouteKey.DRIVER)) { - this.driverRoute = routes.find( - (route) => route.key == RouteKey.DRIVER, - ).route; - this.driverRoute.setWaypoints(driverWaypoints); - } - if (routes.some((route) => route.key == RouteKey.PASSENGER)) { - this.passengerRoute = routes.find( - (route) => route.key == RouteKey.PASSENGER, - ).route; - this.passengerRoute.setWaypoints(passengerWaypoints); - } - } - }; - - private validateWaypoints = (): void => { - if (this.geographyRequest.waypoints.length < 2) { - throw new MatcherException( - MatcherExceptionCode.INVALID_ARGUMENT, - 'At least 2 waypoints are required', - ); - } - this.geographyRequest.waypoints.map((point) => { - if (!this.isValidPoint(point)) { - throw new MatcherException( - MatcherExceptionCode.INVALID_ARGUMENT, - `Waypoint { Lon: ${point.lon}, Lat: ${point.lat} } is not valid`, - ); - } - this.points.push(point); - }); - }; - - private setTimezones = (): void => { - this.timezones = this.timezoneFinder.timezones( - this.geographyRequest.waypoints[0].lat, - this.geographyRequest.waypoints[0].lon, - ); - }; - - private setPointTypes = (): void => { - this.originType = - this.geographyRequest.waypoints[0].type ?? PointType.OTHER; - this.destinationType = - this.geographyRequest.waypoints[ - this.geographyRequest.waypoints.length - 1 - ].type ?? PointType.OTHER; - }; - - private isValidPoint = (point: Point): boolean => - this.isValidLongitude(point.lon) && this.isValidLatitude(point.lat); - - private isValidLongitude = (longitude: number): boolean => - longitude >= -180 && longitude <= 180; - - private isValidLatitude = (latitude: number): boolean => - latitude >= -90 && latitude <= 90; - - private createWaypoints = (points: Point[], role: Role): Waypoint[] => { - return points.map((point, index) => { - const waypoint = new Waypoint(point); - if (index == 0) { - waypoint.addActor(new Actor(this.ad, role, Step.START)); - } else if (index == points.length - 1) { - waypoint.addActor(new Actor(this.ad, role, Step.FINISH)); - } else { - waypoint.addActor(new Actor(this.ad, role, Step.INTERMEDIATE)); - } - return waypoint; - }); - }; -} - -export enum RouteKey { - COMMON = 'common', - DRIVER = 'driver', - PASSENGER = 'passenger', -} diff --git a/old/modules/matcher/domain/entities/ecosystem/match.ts b/old/modules/matcher/domain/entities/ecosystem/match.ts deleted file mode 100644 index 83c399c..0000000 --- a/old/modules/matcher/domain/entities/ecosystem/match.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { AutoMap } from '@automapper/classes'; - -export class Match { - @AutoMap() - uuid: string; -} diff --git a/old/modules/matcher/domain/entities/ecosystem/matcher-route.ts b/old/modules/matcher/domain/entities/ecosystem/matcher-route.ts deleted file mode 100644 index 197741d..0000000 --- a/old/modules/matcher/domain/entities/ecosystem/matcher-route.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Route } from '../../../../geography/domain/entities/route'; -import { IGeodesic } from '../../../../geography/domain/interfaces/geodesic.interface'; -import { Waypoint } from './waypoint'; - -export class MatcherRoute extends Route { - waypoints: Waypoint[]; - - constructor(geodesic: IGeodesic) { - super(geodesic); - } - - setWaypoints = (waypoints: Waypoint[]): void => { - this.waypoints = waypoints; - this.setAzimuth(waypoints.map((waypoint) => waypoint.point)); - }; -} diff --git a/old/modules/matcher/domain/entities/ecosystem/named-route.ts b/old/modules/matcher/domain/entities/ecosystem/named-route.ts deleted file mode 100644 index c026769..0000000 --- a/old/modules/matcher/domain/entities/ecosystem/named-route.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { MatcherRoute } from './matcher-route'; - -export type NamedRoute = { - key: string; - route: MatcherRoute; -}; diff --git a/old/modules/matcher/domain/entities/ecosystem/requirement.ts b/old/modules/matcher/domain/entities/ecosystem/requirement.ts deleted file mode 100644 index 7100667..0000000 --- a/old/modules/matcher/domain/entities/ecosystem/requirement.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { IRequestRequirement } from '../../interfaces/requirement-request.interface'; - -export class Requirement { - private requirementRequest: IRequestRequirement; - seatsDriver: number; - seatsPassenger: number; - - constructor(requirementRequest: IRequestRequirement, defaultSeats: number) { - this.requirementRequest = requirementRequest; - this.seatsDriver = requirementRequest.seatsDriver ?? defaultSeats; - this.seatsPassenger = requirementRequest.seatsPassenger ?? 1; - } -} diff --git a/old/modules/matcher/domain/entities/ecosystem/spacetime-point.ts b/old/modules/matcher/domain/entities/ecosystem/spacetime-point.ts deleted file mode 100644 index 8a45b80..0000000 --- a/old/modules/matcher/domain/entities/ecosystem/spacetime-point.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Coordinate } from '../../../../geography/domain/entities/coordinate'; - -export class SpacetimePoint { - coordinate: Coordinate; - duration: number; - distance: number; - - constructor(coordinate: Coordinate, duration: number, distance: number) { - this.coordinate = coordinate; - this.duration = duration; - this.distance = distance; - } -} diff --git a/old/modules/matcher/domain/entities/ecosystem/time.ts b/old/modules/matcher/domain/entities/ecosystem/time.ts deleted file mode 100644 index 83e3415..0000000 --- a/old/modules/matcher/domain/entities/ecosystem/time.ts +++ /dev/null @@ -1,206 +0,0 @@ -import { - MatcherException, - MatcherExceptionCode, -} from '../../../exceptions/matcher.exception'; -import { MarginDurations } from '../../types/margin-durations.type'; -import { IRequestTime } from '../../interfaces/time-request.interface'; -import { DAYS } from '../../types/days.const'; -import { TimeSchedule } from '../../types/time-schedule.type'; -import { Frequency } from '../../../../ad/domain/types/frequency.enum'; -import { Day } from '../../types/day.type'; -import { IConvertTime } from '../../interfaces/time-converter.interface'; - -export class Time { - private timeRequest: IRequestTime; - private defaultValidityDuration: number; - private timeConverter: IConvertTime; - frequency: Frequency; - fromDate: Date; - toDate: Date; - schedule: TimeSchedule; - marginDurations: MarginDurations; - - constructor( - timeRequest: IRequestTime, - defaultMarginDuration: number, - defaultValidityDuration: number, - timeConverter: IConvertTime, - ) { - this.timeRequest = timeRequest; - this.defaultValidityDuration = defaultValidityDuration; - this.timeConverter = timeConverter; - this.schedule = {}; - this.marginDurations = { - mon: defaultMarginDuration, - tue: defaultMarginDuration, - wed: defaultMarginDuration, - thu: defaultMarginDuration, - fri: defaultMarginDuration, - sat: defaultMarginDuration, - sun: defaultMarginDuration, - }; - } - - init = (): void => { - this.validateBaseDate(); - this.validatePunctualRequest(); - this.validateRecurrentRequest(); - this.setPunctualRequest(); - this.setRecurrentRequest(); - this.setMargindurations(); - }; - - private validateBaseDate = (): void => { - if (!this.timeRequest.departure && !this.timeRequest.fromDate) { - throw new MatcherException( - MatcherExceptionCode.INVALID_ARGUMENT, - 'departure or fromDate is required', - ); - } - }; - - private validatePunctualRequest = (): void => { - if (this.timeRequest.departure) { - this.fromDate = this.toDate = new Date(this.timeRequest.departure); - if (!this.isDate(this.fromDate)) { - throw new MatcherException( - MatcherExceptionCode.INVALID_ARGUMENT, - 'Wrong departure date', - ); - } - } - }; - - private validateRecurrentRequest = (): void => { - if (this.timeRequest.fromDate) { - this.fromDate = new Date(this.timeRequest.fromDate); - if (!this.isDate(this.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( - MatcherExceptionCode.INVALID_ARGUMENT, - 'Wrong toDate', - ); - } - if (this.toDate < this.fromDate) { - throw new MatcherException( - MatcherExceptionCode.INVALID_ARGUMENT, - 'toDate must be after fromDate', - ); - } - } - if (this.timeRequest.fromDate) { - this.validateSchedule(); - } - }; - - private validateSchedule = (): void => { - if (!this.timeRequest.schedule) { - throw new MatcherException( - MatcherExceptionCode.INVALID_ARGUMENT, - 'Schedule is required', - ); - } - if ( - !Object.keys(this.timeRequest.schedule).some((elem) => - DAYS.includes(elem), - ) - ) { - 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( - MatcherExceptionCode.INVALID_ARGUMENT, - `Wrong time for ${day} in schedule`, - ); - } - }); - }; - - private setPunctualRequest = (): void => { - if (this.timeRequest.departure) { - this.frequency = Frequency.PUNCTUAL; - this.schedule[Day[this.fromDate.getDay()]] = this.timeConverter.toUtcDate( - this.fromDate, - this.timeRequest.timezone, - ); - } - }; - - private setRecurrentRequest = (): void => { - if (this.timeRequest.fromDate) { - this.frequency = Frequency.RECURRENT; - if (!this.toDate) { - this.toDate = this.addDays(this.fromDate, this.defaultValidityDuration); - } - this.setSchedule(); - } - }; - - private setSchedule = (): void => { - Object.keys(this.timeRequest.schedule).map((day) => { - this.schedule[day] = this.timeConverter.toUtcDate( - new Date( - `${this.fromDate.getFullYear()}-${this.fromDate.getMonth()}-${this.fromDate.getDate()} ${ - this.timeRequest.schedule[day] - }`, - ), - this.timeRequest.timezone, - ); - }); - }; - - private setMargindurations = (): void => { - if (this.timeRequest.marginDuration) { - const duration = Math.abs(this.timeRequest.marginDuration); - this.marginDurations = { - mon: duration, - tue: duration, - wed: duration, - thu: duration, - fri: duration, - sat: duration, - sun: duration, - }; - } - if (this.timeRequest.marginDurations) { - if ( - !Object.keys(this.timeRequest.marginDurations).some((elem) => - DAYS.includes(elem), - ) - ) { - throw new MatcherException( - MatcherExceptionCode.INVALID_ARGUMENT, - 'No valid day in the given margin durations', - ); - } - Object.keys(this.timeRequest.marginDurations).map((day) => { - this.marginDurations[day] = Math.abs( - this.timeRequest.marginDurations[day], - ); - }); - } - }; - - private isDate = (date: Date): boolean => { - return date instanceof Date && isFinite(+date); - }; - - private addDays = (date: Date, days: number): Date => { - const result = new Date(date); - result.setDate(result.getDate() + days); - return result; - }; -} diff --git a/old/modules/matcher/domain/entities/ecosystem/timezoner.ts b/old/modules/matcher/domain/entities/ecosystem/timezoner.ts deleted file mode 100644 index 29f6e0b..0000000 --- a/old/modules/matcher/domain/entities/ecosystem/timezoner.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { IFindTimezone } from '../../../../geography/domain/interfaces/timezone-finder.interface'; - -export type Timezoner = { - timezone: string; - finder: IFindTimezone; -}; diff --git a/old/modules/matcher/domain/entities/ecosystem/waypoint.ts b/old/modules/matcher/domain/entities/ecosystem/waypoint.ts deleted file mode 100644 index 48c0899..0000000 --- a/old/modules/matcher/domain/entities/ecosystem/waypoint.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Point } from '../../../../geography/domain/types/point.type'; -import { Actor } from './actor'; - -export class Waypoint { - point: Point; - actors: Actor[]; - - constructor(point: Point) { - this.point = point; - this.actors = []; - } - - addActor = (actor: Actor) => this.actors.push(actor); -} diff --git a/old/modules/matcher/domain/entities/engine/candidate.ts b/old/modules/matcher/domain/entities/engine/candidate.ts deleted file mode 100644 index 0ace859..0000000 --- a/old/modules/matcher/domain/entities/engine/candidate.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Ad } from '../ecosystem/ad'; - -export class Candidate { - ad: Ad; -} diff --git a/old/modules/matcher/domain/entities/engine/factory/algorithm-factory-creator.ts b/old/modules/matcher/domain/entities/engine/factory/algorithm-factory-creator.ts deleted file mode 100644 index 1bce748..0000000 --- a/old/modules/matcher/domain/entities/engine/factory/algorithm-factory-creator.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { MatchQuery } from 'src/modules/matcher/queries/match.query'; -import { AlgorithmType } from '../../../types/algorithm.enum'; -import { AlgorithmFactory } from './algorithm-factory.abstract'; -import { ClassicAlgorithmFactory } from './classic'; -import { Injectable } from '@nestjs/common'; - -@Injectable() -export class AlgorithmFactoryCreator { - create = (matchQuery: MatchQuery): AlgorithmFactory => { - let algorithmFactory: AlgorithmFactory; - switch (matchQuery.algorithmSettings.algorithmType) { - case AlgorithmType.CLASSIC: - algorithmFactory = new ClassicAlgorithmFactory(matchQuery); - break; - } - return algorithmFactory; - }; -} diff --git a/old/modules/matcher/domain/entities/engine/factory/algorithm-factory.abstract.ts b/old/modules/matcher/domain/entities/engine/factory/algorithm-factory.abstract.ts deleted file mode 100644 index 9405266..0000000 --- a/old/modules/matcher/domain/entities/engine/factory/algorithm-factory.abstract.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { MatchQuery } from 'src/modules/matcher/queries/match.query'; -import { Processor } from '../processor/processor.abstract'; -import { Candidate } from '../candidate'; -import { Selector } from '../selector/selector.abstract'; - -export abstract class AlgorithmFactory { - protected matchQuery: MatchQuery; - private candidates: Candidate[]; - - constructor(matchQuery: MatchQuery) { - this.matchQuery = matchQuery; - this.candidates = []; - } - - abstract createSelector(): Selector; - abstract createProcessors(): Processor[]; -} diff --git a/old/modules/matcher/domain/entities/engine/factory/classic.ts b/old/modules/matcher/domain/entities/engine/factory/classic.ts deleted file mode 100644 index fc06888..0000000 --- a/old/modules/matcher/domain/entities/engine/factory/classic.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { AlgorithmFactory } from './algorithm-factory.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'; -import { Selector } from '../selector/selector.abstract'; -import { ClassicSelector } from '../selector/classic.selector'; - -export class ClassicAlgorithmFactory extends AlgorithmFactory { - createSelector = (): Selector => new ClassicSelector(this.matchQuery); - createProcessors = (): 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), - ]; -} diff --git a/old/modules/matcher/domain/entities/engine/matcher.ts b/old/modules/matcher/domain/entities/engine/matcher.ts deleted file mode 100644 index 923b69f..0000000 --- a/old/modules/matcher/domain/entities/engine/matcher.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { MatchQuery } from '../../../queries/match.query'; -import { Match } from '../ecosystem/match'; -import { Candidate } from './candidate'; -import { AlgorithmFactory } from './factory/algorithm-factory.abstract'; -import { AlgorithmFactoryCreator } from './factory/algorithm-factory-creator'; - -@Injectable() -export class Matcher { - constructor( - private readonly algorithmFactoryCreator: AlgorithmFactoryCreator, - ) {} - - match = async (matchQuery: MatchQuery): Promise => { - const algorithmFactory: AlgorithmFactory = - this.algorithmFactoryCreator.create(matchQuery); - let candidates: Candidate[] = await algorithmFactory - .createSelector() - .select(); - for (const processor of algorithmFactory.createProcessors()) { - candidates = processor.execute(candidates); - } - const match = new Match(); - match.uuid = 'e23f9725-2c19-49a0-9ef6-17d8b9a5ec85'; - return [match]; - }; -} diff --git a/old/modules/matcher/domain/entities/engine/processor/completer/classic-waypoint.completer.processor.ts b/old/modules/matcher/domain/entities/engine/processor/completer/classic-waypoint.completer.processor.ts deleted file mode 100644 index dee2a2f..0000000 --- a/old/modules/matcher/domain/entities/engine/processor/completer/classic-waypoint.completer.processor.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Candidate } from '../../candidate'; -import { Completer } from './completer.abstract'; - -export class ClassicWaypointsCompleter extends Completer { - complete = (candidates: Candidate[]): Candidate[] => { - return candidates; - }; -} diff --git a/old/modules/matcher/domain/entities/engine/processor/completer/completer.abstract.ts b/old/modules/matcher/domain/entities/engine/processor/completer/completer.abstract.ts deleted file mode 100644 index b72064f..0000000 --- a/old/modules/matcher/domain/entities/engine/processor/completer/completer.abstract.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Candidate } from '../../candidate'; -import { Processor } from '../processor.abstract'; - -export abstract class Completer extends Processor { - execute = (candidates: Candidate[]): Candidate[] => this.complete(candidates); - - abstract complete(candidates: Candidate[]): Candidate[]; -} diff --git a/old/modules/matcher/domain/entities/engine/processor/completer/journey.completer.processor.ts b/old/modules/matcher/domain/entities/engine/processor/completer/journey.completer.processor.ts deleted file mode 100644 index d1a028c..0000000 --- a/old/modules/matcher/domain/entities/engine/processor/completer/journey.completer.processor.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Candidate } from '../../candidate'; -import { Completer } from './completer.abstract'; - -export class JourneyCompleter extends Completer { - complete = (candidates: Candidate[]): Candidate[] => { - return candidates; - }; -} diff --git a/old/modules/matcher/domain/entities/engine/processor/completer/route.completer.processor.ts b/old/modules/matcher/domain/entities/engine/processor/completer/route.completer.processor.ts deleted file mode 100644 index 38ca7b1..0000000 --- a/old/modules/matcher/domain/entities/engine/processor/completer/route.completer.processor.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { MatchQuery } from 'src/modules/matcher/queries/match.query'; -import { Candidate } from '../../candidate'; -import { Completer } from './completer.abstract'; - -export class RouteCompleter extends Completer { - private withPoints: boolean; - private withTime: boolean; - private withDistance: boolean; - - constructor( - matchQuery: MatchQuery, - withPoints = false, - withTime = false, - withDistance = false, - ) { - super(matchQuery); - this.withPoints = withPoints; - this.withTime = withTime; - this.withDistance = withDistance; - } - - complete = (candidates: Candidate[]): Candidate[] => { - return candidates; - }; -} diff --git a/old/modules/matcher/domain/entities/engine/processor/filter/filter.abstract.ts b/old/modules/matcher/domain/entities/engine/processor/filter/filter.abstract.ts deleted file mode 100644 index 1198383..0000000 --- a/old/modules/matcher/domain/entities/engine/processor/filter/filter.abstract.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Candidate } from '../../candidate'; -import { Processor } from '../processor.abstract'; - -export abstract class Filter extends Processor { - execute = (candidates: Candidate[]): Candidate[] => this.filter(candidates); - - abstract filter(candidates: Candidate[]): Candidate[]; -} diff --git a/old/modules/matcher/domain/entities/engine/processor/filter/geofilter/classic.filter.processor.ts b/old/modules/matcher/domain/entities/engine/processor/filter/geofilter/classic.filter.processor.ts deleted file mode 100644 index 77b4663..0000000 --- a/old/modules/matcher/domain/entities/engine/processor/filter/geofilter/classic.filter.processor.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Candidate } from '../../../candidate'; -import { Filter } from '../filter.abstract'; - -export class ClassicGeoFilter extends Filter { - filter = (candidates: Candidate[]): Candidate[] => { - return candidates; - }; -} diff --git a/old/modules/matcher/domain/entities/engine/processor/filter/timefilter/classic.filter.processor.ts b/old/modules/matcher/domain/entities/engine/processor/filter/timefilter/classic.filter.processor.ts deleted file mode 100644 index 2d48c49..0000000 --- a/old/modules/matcher/domain/entities/engine/processor/filter/timefilter/classic.filter.processor.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Candidate } from '../../../candidate'; -import { Filter } from '../filter.abstract'; - -export class ClassicTimeFilter extends Filter { - filter = (candidates: Candidate[]): Candidate[] => { - return candidates; - }; -} diff --git a/old/modules/matcher/domain/entities/engine/processor/processor.abstract.ts b/old/modules/matcher/domain/entities/engine/processor/processor.abstract.ts deleted file mode 100644 index d4eeabc..0000000 --- a/old/modules/matcher/domain/entities/engine/processor/processor.abstract.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { MatchQuery } from 'src/modules/matcher/queries/match.query'; -import { Candidate } from '../candidate'; - -export abstract class Processor { - private matchQuery: MatchQuery; - - constructor(matchQuery: MatchQuery) { - this.matchQuery = matchQuery; - } - - abstract execute(candidates: Candidate[]): Candidate[]; -} diff --git a/old/modules/matcher/domain/entities/engine/selector/classic.selector.ts b/old/modules/matcher/domain/entities/engine/selector/classic.selector.ts deleted file mode 100644 index 5b1d2da..0000000 --- a/old/modules/matcher/domain/entities/engine/selector/classic.selector.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Candidate } from '../candidate'; -import { Selector } from './selector.abstract'; - -export class ClassicSelector extends Selector { - select = async (): Promise => { - return []; - }; -} diff --git a/old/modules/matcher/domain/entities/engine/selector/selector.abstract.ts b/old/modules/matcher/domain/entities/engine/selector/selector.abstract.ts deleted file mode 100644 index c1b58bf..0000000 --- a/old/modules/matcher/domain/entities/engine/selector/selector.abstract.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { MatchQuery } from 'src/modules/matcher/queries/match.query'; -import { Candidate } from '../candidate'; - -export abstract class Selector { - private matchQuery: MatchQuery; - - constructor(matchQuery: MatchQuery) { - this.matchQuery = matchQuery; - } - - abstract select(): Promise; -} diff --git a/old/modules/matcher/domain/interfaces/ad-request.interface.ts b/old/modules/matcher/domain/interfaces/ad-request.interface.ts deleted file mode 100644 index 4914482..0000000 --- a/old/modules/matcher/domain/interfaces/ad-request.interface.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface IRequestAd { - uuid?: string; -} diff --git a/old/modules/matcher/domain/interfaces/algorithm-settings-request.interface.ts b/old/modules/matcher/domain/interfaces/algorithm-settings-request.interface.ts deleted file mode 100644 index 484ec15..0000000 --- a/old/modules/matcher/domain/interfaces/algorithm-settings-request.interface.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { AlgorithmType } from '../types/algorithm.enum'; - -export interface IRequestAlgorithmSettings { - algorithm: AlgorithmType; - strict: boolean; - remoteness: number; - useProportion: boolean; - proportion: number; - useAzimuth: boolean; - azimuthMargin: number; - maxDetourDistanceRatio: number; - maxDetourDurationRatio: number; -} diff --git a/old/modules/matcher/domain/interfaces/geography-request.interface.ts b/old/modules/matcher/domain/interfaces/geography-request.interface.ts deleted file mode 100644 index 8a58ac1..0000000 --- a/old/modules/matcher/domain/interfaces/geography-request.interface.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Point } from '../../../geography/domain/types/point.type'; - -export interface IRequestGeography { - waypoints: Point[]; -} diff --git a/old/modules/matcher/domain/interfaces/georouter-creator.interface.ts b/old/modules/matcher/domain/interfaces/georouter-creator.interface.ts deleted file mode 100644 index 7a6bd25..0000000 --- a/old/modules/matcher/domain/interfaces/georouter-creator.interface.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { IGeorouter } from './georouter.interface'; - -export interface ICreateGeorouter { - create(type: string, url: string): IGeorouter; -} diff --git a/old/modules/matcher/domain/interfaces/georouter.interface.ts b/old/modules/matcher/domain/interfaces/georouter.interface.ts deleted file mode 100644 index 7c64cc2..0000000 --- a/old/modules/matcher/domain/interfaces/georouter.interface.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { NamedRoute } from '../entities/ecosystem/named-route'; -import { GeorouterSettings } from '../types/georouter-settings.type'; -import { Path } from '../types/path.type'; - -export interface IGeorouter { - route(paths: Path[], settings: GeorouterSettings): Promise; -} diff --git a/old/modules/matcher/domain/interfaces/requirement-request.interface.ts b/old/modules/matcher/domain/interfaces/requirement-request.interface.ts deleted file mode 100644 index 61e5900..0000000 --- a/old/modules/matcher/domain/interfaces/requirement-request.interface.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface IRequestRequirement { - seatsDriver?: number; - seatsPassenger?: number; -} diff --git a/old/modules/matcher/domain/interfaces/time-converter.interface.ts b/old/modules/matcher/domain/interfaces/time-converter.interface.ts deleted file mode 100644 index cbbbfb0..0000000 --- a/old/modules/matcher/domain/interfaces/time-converter.interface.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface IConvertTime { - toUtcDate(date: Date, timezone: string): Date; -} diff --git a/old/modules/matcher/domain/interfaces/time-request.interface.ts b/old/modules/matcher/domain/interfaces/time-request.interface.ts deleted file mode 100644 index d7f7df7..0000000 --- a/old/modules/matcher/domain/interfaces/time-request.interface.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { MarginDurations } from '../types/margin-durations.type'; -import { Schedule } from '../types/schedule.type'; - -export interface IRequestTime { - departure?: string; - fromDate?: string; - toDate?: string; - schedule?: Schedule; - marginDuration?: number; - marginDurations?: MarginDurations; - timezone?: string; -} diff --git a/old/modules/matcher/domain/types/actor.type..ts b/old/modules/matcher/domain/types/actor.type..ts deleted file mode 100644 index 22315f7..0000000 --- a/old/modules/matcher/domain/types/actor.type..ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Ad } from '../entities/ecosystem/ad'; -import { Role } from './role.enum'; -import { Step } from './step.enum'; - -export type Actor = { - ad: Ad; - role: Role; - step: Step; -}; diff --git a/old/modules/matcher/domain/types/algorithm.enum.ts b/old/modules/matcher/domain/types/algorithm.enum.ts deleted file mode 100644 index 52f14bd..0000000 --- a/old/modules/matcher/domain/types/algorithm.enum.ts +++ /dev/null @@ -1,3 +0,0 @@ -export enum AlgorithmType { - CLASSIC = 'CLASSIC', -} diff --git a/old/modules/matcher/domain/types/day.type.ts b/old/modules/matcher/domain/types/day.type.ts deleted file mode 100644 index c275d7a..0000000 --- a/old/modules/matcher/domain/types/day.type.ts +++ /dev/null @@ -1,9 +0,0 @@ -export enum Day { - 'sun', - 'mon', - 'tue', - 'wed', - 'thu', - 'fri', - 'sat', -} diff --git a/old/modules/matcher/domain/types/days.const.ts b/old/modules/matcher/domain/types/days.const.ts deleted file mode 100644 index 4794839..0000000 --- a/old/modules/matcher/domain/types/days.const.ts +++ /dev/null @@ -1 +0,0 @@ -export const DAYS = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun']; diff --git a/old/modules/matcher/domain/types/default-algorithm-settings.type.ts b/old/modules/matcher/domain/types/default-algorithm-settings.type.ts deleted file mode 100644 index 98fa3b1..0000000 --- a/old/modules/matcher/domain/types/default-algorithm-settings.type.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { AlgorithmType } from './algorithm.enum'; - -export type DefaultAlgorithmSettings = { - ALGORITHM: AlgorithmType; - STRICT: boolean; - REMOTENESS: number; - USE_PROPORTION: boolean; - PROPORTION: number; - USE_AZIMUTH: boolean; - AZIMUTH_MARGIN: number; - MAX_DETOUR_DISTANCE_RATIO: number; - MAX_DETOUR_DURATION_RATIO: number; - GEOROUTER_TYPE: string; - GEOROUTER_URL: string; -}; diff --git a/old/modules/matcher/domain/types/default-params.type.ts b/old/modules/matcher/domain/types/default-params.type.ts deleted file mode 100644 index c91a26a..0000000 --- a/old/modules/matcher/domain/types/default-params.type.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { DefaultAlgorithmSettings } from './default-algorithm-settings.type'; - -export type IDefaultParams = { - DEFAULT_UUID: string; - MARGIN_DURATION: number; - VALIDITY_DURATION: number; - DEFAULT_TIMEZONE: string; - DEFAULT_SEATS: number; - DEFAULT_ALGORITHM_SETTINGS: DefaultAlgorithmSettings; -}; diff --git a/old/modules/matcher/domain/types/georouter-settings.type.ts b/old/modules/matcher/domain/types/georouter-settings.type.ts deleted file mode 100644 index d8f73ae..0000000 --- a/old/modules/matcher/domain/types/georouter-settings.type.ts +++ /dev/null @@ -1,5 +0,0 @@ -export type GeorouterSettings = { - withPoints: boolean; - withTime: boolean; - withDistance: boolean; -}; diff --git a/old/modules/matcher/domain/types/margin-durations.type.ts b/old/modules/matcher/domain/types/margin-durations.type.ts deleted file mode 100644 index 8e09329..0000000 --- a/old/modules/matcher/domain/types/margin-durations.type.ts +++ /dev/null @@ -1,9 +0,0 @@ -export type MarginDurations = { - mon?: number; - tue?: number; - wed?: number; - thu?: number; - fri?: number; - sat?: number; - sun?: number; -}; diff --git a/old/modules/matcher/domain/types/mode.enum.ts b/old/modules/matcher/domain/types/mode.enum.ts deleted file mode 100644 index be6d1eb..0000000 --- a/old/modules/matcher/domain/types/mode.enum.ts +++ /dev/null @@ -1,5 +0,0 @@ -export enum Mode { - MATCH = 'MATCH', - PUBLISH = 'PUBLISH', - PUBLISH_AND_MATCH = 'PUBLISH_AND_MATCH', -} diff --git a/old/modules/matcher/domain/types/path.type.ts b/old/modules/matcher/domain/types/path.type.ts deleted file mode 100644 index 44e03b6..0000000 --- a/old/modules/matcher/domain/types/path.type.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { Point } from '../../../geography/domain/types/point.type'; - -export type Path = { - key: string; - points: Point[]; -}; diff --git a/old/modules/matcher/domain/types/role.enum.ts b/old/modules/matcher/domain/types/role.enum.ts deleted file mode 100644 index 7522f80..0000000 --- a/old/modules/matcher/domain/types/role.enum.ts +++ /dev/null @@ -1,4 +0,0 @@ -export enum Role { - DRIVER = 'DRIVER', - PASSENGER = 'PASSENGER', -} diff --git a/old/modules/matcher/domain/types/schedule.type.ts b/old/modules/matcher/domain/types/schedule.type.ts deleted file mode 100644 index 03f8485..0000000 --- a/old/modules/matcher/domain/types/schedule.type.ts +++ /dev/null @@ -1,9 +0,0 @@ -export type Schedule = { - mon?: string; - tue?: string; - wed?: string; - thu?: string; - fri?: string; - sat?: string; - sun?: string; -}; diff --git a/old/modules/matcher/domain/types/step.enum.ts b/old/modules/matcher/domain/types/step.enum.ts deleted file mode 100644 index 4b2fce4..0000000 --- a/old/modules/matcher/domain/types/step.enum.ts +++ /dev/null @@ -1,6 +0,0 @@ -export enum Step { - START = 'start', - INTERMEDIATE = 'intermediate', - NEUTRAL = 'neutral', - FINISH = 'finish', -} diff --git a/old/modules/matcher/domain/types/time-schedule.type.ts b/old/modules/matcher/domain/types/time-schedule.type.ts deleted file mode 100644 index 4bd6ea2..0000000 --- a/old/modules/matcher/domain/types/time-schedule.type.ts +++ /dev/null @@ -1,9 +0,0 @@ -export type TimeSchedule = { - mon?: Date; - tue?: Date; - wed?: Date; - thu?: Date; - fri?: Date; - sat?: Date; - sun?: Date; -}; diff --git a/old/modules/matcher/domain/types/waypoint.ts b/old/modules/matcher/domain/types/waypoint.ts deleted file mode 100644 index bc15ea5..0000000 --- a/old/modules/matcher/domain/types/waypoint.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { Actor } from './actor.type.'; -import { Point } from '../../../geography/domain/types/point.type'; - -export type Waypoint = { - point: Point; - actors: Actor[]; -}; diff --git a/old/modules/matcher/domain/usecases/match.usecase.ts b/old/modules/matcher/domain/usecases/match.usecase.ts deleted file mode 100644 index 1e0616e..0000000 --- a/old/modules/matcher/domain/usecases/match.usecase.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { Mapper } from '@automapper/core'; -import { InjectMapper } from '@automapper/nestjs'; -import { QueryHandler } from '@nestjs/cqrs'; -import { MatchQuery } from '../../queries/match.query'; -import { Match } from '../entities/ecosystem/match'; -import { ICollection } from '../../../database/interfaces/collection.interface'; -import { Matcher } from '../entities/engine/matcher'; -import { MESSAGE_PUBLISHER } from '../../../../app.constants'; -import { Inject } from '@nestjs/common'; -import { IPublishMessage } from '../../../../interfaces/message-publisher'; - -@QueryHandler(MatchQuery) -export class MatchUseCase { - constructor( - private readonly matcher: Matcher, - @Inject(MESSAGE_PUBLISHER) - private readonly messagePublisher: IPublishMessage, - @InjectMapper() private readonly mapper: Mapper, - ) {} - - execute = async (matchQuery: MatchQuery): Promise> => { - try { - const data: Match[] = await this.matcher.match(matchQuery); - this.messagePublisher.publish('matcher.match', 'match !'); - return { - data, - total: data.length, - }; - } catch (error) { - const err: Error = error; - this.messagePublisher.publish( - 'logging.matcher.match.crit', - JSON.stringify({ - matchQuery, - error: err.message, - }), - ); - throw error; - } - }; -} - -// const paths = []; -// for (let i = 0; i < 1; i++) { -// paths.push({ -// key: 'route' + i, -// points: [ -// { -// lat: 48.110899, -// lon: -1.68365, -// }, -// { -// lat: 48.131105, -// lon: -1.690067, -// }, -// { -// lat: 48.534769, -// lon: -1.894032, -// }, -// { -// lat: 48.56516, -// lon: -1.923553, -// }, -// { -// lat: 48.622813, -// lon: -1.997177, -// }, -// { -// lat: 48.67846, -// lon: -1.8554, -// }, -// ], -// }); -// } -// const routes = await matchQuery.algorithmSettings.georouter.route(paths, { -// withDistance: false, -// withPoints: true, -// withTime: true, -// }); -// routes.map((route) => console.log(route.route.spacetimePoints)); diff --git a/old/modules/matcher/exceptions/matcher.exception.ts b/old/modules/matcher/exceptions/matcher.exception.ts deleted file mode 100644 index af70214..0000000 --- a/old/modules/matcher/exceptions/matcher.exception.ts +++ /dev/null @@ -1,33 +0,0 @@ -export class MatcherException implements Error { - name: string; - message: string; - - constructor(private _code: number, private _message: string) { - this.name = 'MatcherException'; - this.message = _message; - } - - get code(): number { - 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, -} diff --git a/old/modules/matcher/mappers/match.profile.ts b/old/modules/matcher/mappers/match.profile.ts deleted file mode 100644 index c44fef8..0000000 --- a/old/modules/matcher/mappers/match.profile.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { createMap, Mapper } from '@automapper/core'; -import { AutomapperProfile, InjectMapper } from '@automapper/nestjs'; -import { Injectable } from '@nestjs/common'; -import { MatchPresenter } from '../adapters/secondaries/match.presenter'; -import { Match } from '../domain/entities/ecosystem/match'; - -@Injectable() -export class MatchProfile extends AutomapperProfile { - constructor(@InjectMapper() mapper: Mapper) { - super(mapper); - } - - override get profile() { - return (mapper: Mapper) => { - createMap(mapper, Match, MatchPresenter); - }; - } -} diff --git a/old/modules/matcher/matcher.module.ts b/old/modules/matcher/matcher.module.ts deleted file mode 100644 index 7b736aa..0000000 --- a/old/modules/matcher/matcher.module.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { Module } from '@nestjs/common'; -import { ConfigModule, ConfigService } from '@nestjs/config'; -import { CqrsModule } from '@nestjs/cqrs'; -import { DatabaseModule } from '../database/database.module'; -import { MatcherController } from './adapters/primaries/matcher.controller'; -import { MatchProfile } from './mappers/match.profile'; -import { MatchUseCase } from './domain/usecases/match.usecase'; -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'; -import { HttpModule } from '@nestjs/axios'; -import { MatcherGeodesic } from './adapters/secondaries/geodesic'; -import { Matcher } from './domain/entities/engine/matcher'; -import { AlgorithmFactoryCreator } from './domain/entities/engine/factory/algorithm-factory-creator'; -import { TimezoneFinder } from './adapters/secondaries/timezone-finder'; -import { GeoTimezoneFinder } from '../geography/adapters/secondaries/geo-timezone-finder'; -import { GeographyModule } from '../geography/geography.module'; -import { TimeConverter } from './adapters/secondaries/time-converter'; -import { MESSAGE_BROKER_PUBLISHER, MESSAGE_PUBLISHER } from 'src/app.constants'; -import { MessageBrokerPublisher } from '@mobicoop/message-broker-module'; -import { MessagePublisher } from './adapters/secondaries/message-publisher'; - -@Module({ - imports: [ - GeographyModule, - DatabaseModule, - CqrsModule, - HttpModule, - CacheModule.registerAsync({ - imports: [ConfigModule], - useFactory: async (configService: ConfigService) => ({ - store: await redisStore({ - host: configService.get('REDIS_HOST'), - port: configService.get('REDIS_PORT'), - password: configService.get('REDIS_PASSWORD'), - ttl: configService.get('CACHE_TTL'), - }), - }), - inject: [ConfigService], - }), - ], - controllers: [MatcherController], - providers: [ - MatchProfile, - DefaultParamsProvider, - MatchUseCase, - GeorouterCreator, - MatcherGeodesic, - TimezoneFinder, - TimeConverter, - Matcher, - AlgorithmFactoryCreator, - GeoTimezoneFinder, - { - provide: MESSAGE_BROKER_PUBLISHER, - useClass: MessageBrokerPublisher, - }, - { - provide: MESSAGE_PUBLISHER, - useClass: MessagePublisher, - }, - ], - exports: [], -}) -export class MatcherModule {} diff --git a/old/modules/matcher/queries/match.query.ts b/old/modules/matcher/queries/match.query.ts deleted file mode 100644 index 8ac0388..0000000 --- a/old/modules/matcher/queries/match.query.ts +++ /dev/null @@ -1,123 +0,0 @@ -import { MatchRequest } from '../domain/dtos/match.request'; -import { Geography } from '../domain/entities/ecosystem/geography'; -import { Ad } from '../domain/entities/ecosystem/ad'; -import { Requirement } from '../domain/entities/ecosystem/requirement'; -import { Role } from '../domain/types/role.enum'; -import { AlgorithmSettings } from '../domain/entities/ecosystem/algorithm-settings'; -import { Time } from '../domain/entities/ecosystem/time'; -import { IDefaultParams } from '../domain/types/default-params.type'; -import { IGeorouter } from '../domain/interfaces/georouter.interface'; -import { ICreateGeorouter } from '../domain/interfaces/georouter-creator.interface'; -import { IFindTimezone } from '../../geography/domain/interfaces/timezone-finder.interface'; -import { Mode } from '../domain/types/mode.enum'; -import { IConvertTime } from '../domain/interfaces/time-converter.interface'; - -export class MatchQuery { - private readonly matchRequest: MatchRequest; - private readonly defaultParams: IDefaultParams; - private readonly georouterCreator: ICreateGeorouter; - mode: Mode; - ad: Ad; - roles: Role[]; - time: Time; - geography: Geography; - exclusions: string[]; - requirement: Requirement; - algorithmSettings: AlgorithmSettings; - georouter: IGeorouter; - timezoneFinder: IFindTimezone; - timeConverter: IConvertTime; - - constructor( - matchRequest: MatchRequest, - defaultParams: IDefaultParams, - georouterCreator: ICreateGeorouter, - timezoneFinder: IFindTimezone, - timeConverter: IConvertTime, - ) { - this.matchRequest = matchRequest; - this.defaultParams = defaultParams; - this.georouterCreator = georouterCreator; - this.timezoneFinder = timezoneFinder; - this.timeConverter = timeConverter; - this.setMode(); - this.setAd(); - this.setRoles(); - this.setGeography(); - this.setTime(); - this.setRequirement(); - this.setAlgorithmSettings(); - this.setExclusions(); - } - - createRoutes = (): void => { - this.geography.createRoutes(this.roles, this.algorithmSettings.georouter); - }; - - private setMode = (): void => { - this.mode = this.matchRequest.mode ?? Mode.MATCH; - }; - - private setAd = (): void => { - this.ad = new Ad( - this.matchRequest, - this.defaultParams.DEFAULT_UUID, - this.defaultParams.MARGIN_DURATION, - ); - this.ad.init(); - }; - - private setRoles = (): void => { - this.roles = []; - if (this.matchRequest.driver) this.roles.push(Role.DRIVER); - if (this.matchRequest.passenger) this.roles.push(Role.PASSENGER); - if (this.roles.length == 0) this.roles.push(Role.PASSENGER); - }; - - private setGeography = (): void => { - this.geography = new Geography( - this.matchRequest, - { - timezone: this.defaultParams.DEFAULT_TIMEZONE, - finder: this.timezoneFinder, - }, - this.ad, - ); - this.geography.init(); - if (this.geography.timezones.length > 0) - this.matchRequest.timezone = this.geography.timezones[0]; - }; - - private setTime = (): void => { - this.time = new Time( - this.matchRequest, - this.defaultParams.MARGIN_DURATION, - this.defaultParams.VALIDITY_DURATION, - this.timeConverter, - ); - this.time.init(); - }; - - private setRequirement = (): void => { - this.requirement = new Requirement( - this.matchRequest, - this.defaultParams.DEFAULT_SEATS, - ); - }; - - private setAlgorithmSettings = (): void => { - this.algorithmSettings = new AlgorithmSettings( - this.matchRequest, - this.defaultParams.DEFAULT_ALGORITHM_SETTINGS, - this.time.frequency, - this.georouterCreator, - ); - }; - - private setExclusions = (): void => { - this.exclusions = []; - if (this.matchRequest.uuid) this.exclusions.push(this.matchRequest.uuid); - if (this.matchRequest.exclusions) - this.exclusions.push(...this.matchRequest.exclusions); - }; -} diff --git a/old/modules/matcher/tests/unit/adapters/secondaries/default-params.provider.spec.ts b/old/modules/matcher/tests/unit/adapters/secondaries/default-params.provider.spec.ts deleted file mode 100644 index a23a4d0..0000000 --- a/old/modules/matcher/tests/unit/adapters/secondaries/default-params.provider.spec.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { ConfigService } from '@nestjs/config'; -import { Test, TestingModule } from '@nestjs/testing'; -import { DefaultParamsProvider } from '../../../../adapters/secondaries/default-params.provider'; -import { IDefaultParams } from '../../../../domain/types/default-params.type'; - -const mockConfigService = { - get: jest.fn().mockImplementationOnce(() => 99), -}; - -describe('DefaultParamsProvider', () => { - let defaultParamsProvider: DefaultParamsProvider; - - beforeAll(async () => { - const module: TestingModule = await Test.createTestingModule({ - imports: [], - providers: [ - DefaultParamsProvider, - { - provide: ConfigService, - useValue: mockConfigService, - }, - ], - }).compile(); - - defaultParamsProvider = module.get( - DefaultParamsProvider, - ); - }); - - it('should be defined', () => { - expect(defaultParamsProvider).toBeDefined(); - }); - - it('should provide default params', async () => { - const params: IDefaultParams = defaultParamsProvider.getParams(); - expect(params.DEFAULT_UUID).toBe(99); - }); -}); diff --git a/old/modules/matcher/tests/unit/adapters/secondaries/geodesic.spec.ts b/old/modules/matcher/tests/unit/adapters/secondaries/geodesic.spec.ts deleted file mode 100644 index 6e878a9..0000000 --- a/old/modules/matcher/tests/unit/adapters/secondaries/geodesic.spec.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { MatcherGeodesic } from '../../../../adapters/secondaries/geodesic'; -import { Geodesic } from '../../../../../geography/adapters/secondaries/geodesic'; - -const mockGeodesic = { - inverse: jest.fn().mockImplementation(() => ({ - azimuth: 45, - distance: 50000, - })), -}; - -describe('Matcher geodesic', () => { - let matcherGeodesic: MatcherGeodesic; - - beforeAll(async () => { - const module: TestingModule = await Test.createTestingModule({ - imports: [], - providers: [ - MatcherGeodesic, - { - provide: Geodesic, - useValue: mockGeodesic, - }, - ], - }).compile(); - - matcherGeodesic = module.get(MatcherGeodesic); - }); - - it('should be defined', () => { - expect(matcherGeodesic).toBeDefined(); - }); - it('should get inverse values', () => { - const inv = matcherGeodesic.inverse(0, 0, 1, 1); - expect(Math.round(inv.azimuth)).toBe(45); - expect(Math.round(inv.distance)).toBe(50000); - }); -}); diff --git a/old/modules/matcher/tests/unit/adapters/secondaries/georouter-creator.spec.ts b/old/modules/matcher/tests/unit/adapters/secondaries/georouter-creator.spec.ts deleted file mode 100644 index 543991b..0000000 --- a/old/modules/matcher/tests/unit/adapters/secondaries/georouter-creator.spec.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { GeorouterCreator } from '../../../../adapters/secondaries/georouter-creator'; -import { GraphhopperGeorouter } from '../../../../adapters/secondaries/graphhopper-georouter'; -import { HttpService } from '@nestjs/axios'; -import { MatcherGeodesic } from '../../../../adapters/secondaries/geodesic'; - -const mockHttpService = jest.fn(); -const mockMatcherGeodesic = jest.fn(); - -describe('Georouter creator', () => { - let georouterCreator: GeorouterCreator; - - beforeAll(async () => { - const module: TestingModule = await Test.createTestingModule({ - imports: [], - providers: [ - GeorouterCreator, - { - provide: HttpService, - useValue: mockHttpService, - }, - { - provide: MatcherGeodesic, - useValue: mockMatcherGeodesic, - }, - ], - }).compile(); - - georouterCreator = module.get(GeorouterCreator); - }); - - it('should be defined', () => { - expect(georouterCreator).toBeDefined(); - }); - it('should create a graphhopper georouter', () => { - const georouter = georouterCreator.create( - 'graphhopper', - 'http://localhost', - ); - expect(georouter).toBeInstanceOf(GraphhopperGeorouter); - }); - it('should throw an exception if georouter type is unknown', () => { - expect(() => - georouterCreator.create('unknown', 'http://localhost'), - ).toThrow(); - }); -}); diff --git a/old/modules/matcher/tests/unit/adapters/secondaries/graphhopper-georouter.spec.ts b/old/modules/matcher/tests/unit/adapters/secondaries/graphhopper-georouter.spec.ts deleted file mode 100644 index fdfef4b..0000000 --- a/old/modules/matcher/tests/unit/adapters/secondaries/graphhopper-georouter.spec.ts +++ /dev/null @@ -1,456 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { HttpService } from '@nestjs/axios'; -import { GeorouterCreator } from '../../../../adapters/secondaries/georouter-creator'; -import { IGeorouter } from '../../../../domain/interfaces/georouter.interface'; -import { of } from 'rxjs'; -import { AxiosError } from 'axios'; -import { MatcherGeodesic } from '../../../../adapters/secondaries/geodesic'; - -const mockHttpService = { - get: jest - .fn() - .mockImplementationOnce(() => { - throw new AxiosError('Axios error !'); - }) - .mockImplementationOnce(() => { - return of({ - status: 200, - data: { - paths: [ - { - distance: 50000, - time: 1800000, - snapped_waypoints: { - coordinates: [ - [0, 0], - [10, 10], - ], - }, - }, - ], - }, - }); - }) - .mockImplementationOnce(() => { - return of({ - status: 200, - data: { - paths: [ - { - distance: 50000, - time: 1800000, - points: { - coordinates: [ - [0, 0], - [1, 1], - [2, 2], - [3, 3], - [4, 4], - [5, 5], - [6, 6], - [7, 7], - [8, 8], - [9, 9], - [10, 10], - ], - }, - snapped_waypoints: { - coordinates: [ - [0, 0], - [10, 10], - ], - }, - }, - ], - }, - }); - }) - .mockImplementationOnce(() => { - return of({ - status: 200, - data: { - paths: [ - { - distance: 50000, - time: 1800000, - points: { - coordinates: [ - [0, 0], - [1, 1], - [2, 2], - [3, 3], - [4, 4], - [5, 5], - [6, 6], - [7, 7], - [8, 8], - [9, 9], - [10, 10], - ], - }, - details: { - time: [ - [0, 1, 180000], - [1, 2, 180000], - [2, 3, 180000], - [3, 4, 180000], - [4, 5, 180000], - [5, 6, 180000], - [6, 7, 180000], - [7, 9, 360000], - [9, 10, 180000], - ], - }, - snapped_waypoints: { - coordinates: [ - [0, 0], - [10, 10], - ], - }, - }, - ], - }, - }); - }) - .mockImplementationOnce(() => { - return of({ - status: 200, - data: { - paths: [ - { - distance: 50000, - time: 1800000, - points: { - coordinates: [ - [0, 0], - [1, 1], - [2, 2], - [3, 3], - [4, 4], - [7, 7], - [8, 8], - [9, 9], - [10, 10], - ], - }, - snapped_waypoints: { - coordinates: [ - [0, 0], - [5, 5], - [10, 10], - ], - }, - details: { - time: [ - [0, 1, 180000], - [1, 2, 180000], - [2, 3, 180000], - [3, 4, 180000], - [4, 7, 540000], - [7, 9, 360000], - [9, 10, 180000], - ], - }, - }, - ], - }, - }); - }) - .mockImplementationOnce(() => { - return of({ - status: 200, - data: { - paths: [ - { - distance: 50000, - time: 1800000, - points: { - coordinates: [ - [0, 0], - [1, 1], - [2, 2], - [3, 3], - [4, 4], - [5, 5], - [6, 6], - [7, 7], - [8, 8], - [9, 9], - [10, 10], - ], - }, - snapped_waypoints: { - coordinates: [ - [0, 0], - [5, 5], - [10, 10], - ], - }, - details: { - time: [ - [0, 1, 180000], - [1, 2, 180000], - [2, 3, 180000], - [3, 4, 180000], - [4, 7, 540000], - [7, 9, 360000], - [9, 10, 180000], - ], - }, - instructions: [ - { - distance: 25000, - sign: 0, - interval: [0, 5], - text: 'Some instructions', - time: 900000, - }, - { - distance: 0, - sign: 5, - interval: [5, 5], - text: 'Waypoint 1', - time: 0, - }, - { - distance: 25000, - sign: 2, - interval: [5, 10], - text: 'Some instructions', - time: 900000, - }, - { - distance: 0.0, - sign: 4, - interval: [10, 10], - text: 'Arrive at destination', - time: 0, - }, - ], - }, - ], - }, - }); - }), -}; - -const mockMatcherGeodesic = { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - inverse: jest.fn().mockImplementation(() => ({ - azimuth: 45, - distance: 50000, - })), -}; - -describe('Graphhopper Georouter', () => { - let georouterCreator: GeorouterCreator; - let graphhopperGeorouter: IGeorouter; - - beforeAll(async () => { - const module: TestingModule = await Test.createTestingModule({ - imports: [], - providers: [ - GeorouterCreator, - { - provide: HttpService, - useValue: mockHttpService, - }, - { - provide: MatcherGeodesic, - useValue: mockMatcherGeodesic, - }, - ], - }).compile(); - - georouterCreator = module.get(GeorouterCreator); - graphhopperGeorouter = georouterCreator.create( - 'graphhopper', - 'http://localhost', - ); - }); - - it('should be defined', () => { - expect(graphhopperGeorouter).toBeDefined(); - }); - - describe('route function', () => { - it('should fail on axios error', async () => { - await expect( - graphhopperGeorouter.route( - [ - { - key: 'route1', - points: [ - { - lat: 0, - lon: 0, - }, - { - lat: 1, - lon: 1, - }, - ], - }, - ], - { - withDistance: false, - withPoints: false, - withTime: false, - }, - ), - ).rejects.toBeInstanceOf(Error); - }); - - it('should create one route with all settings to false', async () => { - const routes = await graphhopperGeorouter.route( - [ - { - key: 'route1', - points: [ - { - lat: 0, - lon: 0, - }, - { - lat: 10, - lon: 10, - }, - ], - }, - ], - { - withDistance: false, - withPoints: false, - withTime: false, - }, - ); - expect(routes).toHaveLength(1); - expect(routes[0].route.distance).toBe(50000); - }); - - it('should create one route with points', async () => { - const routes = await graphhopperGeorouter.route( - [ - { - key: 'route1', - points: [ - { - lat: 0, - lon: 0, - }, - { - lat: 10, - lon: 10, - }, - ], - }, - ], - { - withDistance: false, - withPoints: true, - withTime: false, - }, - ); - expect(routes).toHaveLength(1); - expect(routes[0].route.distance).toBe(50000); - expect(routes[0].route.duration).toBe(1800); - expect(routes[0].route.fwdAzimuth).toBe(45); - expect(routes[0].route.backAzimuth).toBe(225); - expect(routes[0].route.points.length).toBe(11); - }); - - it('should create one route with points and time', async () => { - const routes = await graphhopperGeorouter.route( - [ - { - key: 'route1', - points: [ - { - lat: 0, - lon: 0, - }, - { - lat: 10, - lon: 10, - }, - ], - }, - ], - { - withDistance: false, - withPoints: true, - withTime: true, - }, - ); - expect(routes).toHaveLength(1); - expect(routes[0].route.spacetimePoints.length).toBe(2); - expect(routes[0].route.spacetimePoints[1].duration).toBe(1800); - expect(routes[0].route.spacetimePoints[1].distance).toBeUndefined(); - }); - - it('should create one route with points and missed waypoints extrapolations', async () => { - const routes = await graphhopperGeorouter.route( - [ - { - key: 'route1', - points: [ - { - lat: 0, - lon: 0, - }, - { - lat: 5, - lon: 5, - }, - { - lat: 10, - lon: 10, - }, - ], - }, - ], - { - withDistance: false, - withPoints: true, - withTime: true, - }, - ); - expect(routes).toHaveLength(1); - expect(routes[0].route.spacetimePoints.length).toBe(3); - expect(routes[0].route.distance).toBe(50000); - expect(routes[0].route.duration).toBe(1800); - expect(routes[0].route.fwdAzimuth).toBe(45); - expect(routes[0].route.backAzimuth).toBe(225); - expect(routes[0].route.points.length).toBe(9); - }); - - it('should create one route with points, time and distance', async () => { - const routes = await graphhopperGeorouter.route( - [ - { - key: 'route1', - points: [ - { - lat: 0, - lon: 0, - }, - { - lat: 10, - lon: 10, - }, - ], - }, - ], - { - withDistance: true, - withPoints: true, - withTime: true, - }, - ); - expect(routes).toHaveLength(1); - expect(routes[0].route.spacetimePoints.length).toBe(3); - expect(routes[0].route.spacetimePoints[1].duration).toBe(990); - expect(routes[0].route.spacetimePoints[1].distance).toBe(25000); - }); - }); -}); diff --git a/old/modules/matcher/tests/unit/adapters/secondaries/message-publisher.spec.ts b/old/modules/matcher/tests/unit/adapters/secondaries/message-publisher.spec.ts deleted file mode 100644 index a60708f..0000000 --- a/old/modules/matcher/tests/unit/adapters/secondaries/message-publisher.spec.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { MessagePublisher } from '../../../../adapters/secondaries/message-publisher'; -import { MESSAGE_BROKER_PUBLISHER } from '../../../../../../app.constants'; - -const mockMessageBrokerPublisher = { - publish: jest.fn().mockImplementation(), -}; - -describe('Messager', () => { - let messagePublisher: MessagePublisher; - - beforeAll(async () => { - const module: TestingModule = await Test.createTestingModule({ - imports: [], - providers: [ - MessagePublisher, - { - provide: MESSAGE_BROKER_PUBLISHER, - useValue: mockMessageBrokerPublisher, - }, - ], - }).compile(); - - messagePublisher = module.get(MessagePublisher); - }); - - it('should be defined', () => { - expect(messagePublisher).toBeDefined(); - }); - - it('should publish a message', async () => { - jest.spyOn(mockMessageBrokerPublisher, 'publish'); - messagePublisher.publish('ad.info', 'my-test'); - expect(mockMessageBrokerPublisher.publish).toHaveBeenCalledTimes(1); - }); -}); diff --git a/old/modules/matcher/tests/unit/adapters/secondaries/timezone-finder.spec.ts b/old/modules/matcher/tests/unit/adapters/secondaries/timezone-finder.spec.ts deleted file mode 100644 index 63d8462..0000000 --- a/old/modules/matcher/tests/unit/adapters/secondaries/timezone-finder.spec.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { TimezoneFinder } from '../../../../adapters/secondaries/timezone-finder'; -import { GeoTimezoneFinder } from '../../../../../geography/adapters/secondaries/geo-timezone-finder'; - -const mockGeoTimezoneFinder = { - timezones: jest.fn().mockImplementation(() => ['Europe/Paris']), -}; - -describe('Timezone Finder', () => { - let timezoneFinder: TimezoneFinder; - - beforeAll(async () => { - const module: TestingModule = await Test.createTestingModule({ - imports: [], - providers: [ - TimezoneFinder, - { - provide: GeoTimezoneFinder, - useValue: mockGeoTimezoneFinder, - }, - ], - }).compile(); - - timezoneFinder = module.get(TimezoneFinder); - }); - - it('should be defined', () => { - expect(timezoneFinder).toBeDefined(); - }); - it('should get timezone for Nancy(France) as Europe/Paris', () => { - const timezones = timezoneFinder.timezones(6.179373, 48.687913); - expect(timezones.length).toBe(1); - expect(timezones[0]).toBe('Europe/Paris'); - }); -}); diff --git a/old/modules/matcher/tests/unit/domain/ecosystem/geography.spec.ts b/old/modules/matcher/tests/unit/domain/ecosystem/geography.spec.ts deleted file mode 100644 index 3480b2b..0000000 --- a/old/modules/matcher/tests/unit/domain/ecosystem/geography.spec.ts +++ /dev/null @@ -1,315 +0,0 @@ -import { Ad } from '../../../../domain/entities/ecosystem/ad'; -import { - Geography, - RouteKey, -} from '../../../../domain/entities/ecosystem/geography'; -import { Role } from '../../../../domain/types/role.enum'; -import { NamedRoute } from '../../../../domain/entities/ecosystem/named-route'; -import { MatcherRoute } from '../../../../domain/entities/ecosystem/matcher-route'; -import { IGeodesic } from '../../../../../geography/domain/interfaces/geodesic.interface'; -import { PointType } from '../../../../../geography/domain/types/point-type.enum'; - -const ad: Ad = new Ad( - { - uuid: '774aaab2-77df-4c6c-b70d-7b9e972e5bbc', - }, - '00000000-0000-0000-0000-000000000000', - 900, -); - -const mockGeodesic: IGeodesic = { - inverse: jest.fn().mockImplementation(() => ({ - azimuth: 45, - distance: 50000, - })), -}; - -const mockGeorouter = { - route: jest - .fn() - .mockImplementationOnce(() => { - return [ - { - key: RouteKey.COMMON, - route: new MatcherRoute(mockGeodesic), - }, - ]; - }) - .mockImplementationOnce(() => { - return [ - { - key: RouteKey.DRIVER, - route: new MatcherRoute(mockGeodesic), - }, - { - key: RouteKey.PASSENGER, - route: new MatcherRoute(mockGeodesic), - }, - ]; - }) - .mockImplementationOnce(() => { - return [ - { - key: RouteKey.DRIVER, - route: new MatcherRoute(mockGeodesic), - }, - ]; - }) - .mockImplementationOnce(() => { - return [ - { - key: RouteKey.PASSENGER, - route: new MatcherRoute(mockGeodesic), - }, - ]; - }), -}; - -const mockTimezoneFinder = { - timezones: jest.fn().mockImplementation(() => ['Europe/Paris']), -}; - -describe('Geography entity', () => { - it('should be defined', () => { - const geography = new Geography( - { - waypoints: [ - { - lat: 49.440041, - lon: 1.093912, - }, - { - lat: 50.630992, - lon: 3.045432, - }, - ], - }, - { - timezone: 'Europe/Paris', - finder: mockTimezoneFinder, - }, - ad, - ); - expect(geography).toBeDefined(); - }); - - describe('init', () => { - it('should initialize a geography request with point types', () => { - const geography = new Geography( - { - waypoints: [ - { - lat: 49.440041, - lon: 1.093912, - type: PointType.LOCALITY, - }, - { - lat: 50.630992, - lon: 3.045432, - type: PointType.LOCALITY, - }, - ], - }, - { - timezone: 'Europe/Paris', - finder: mockTimezoneFinder, - }, - ad, - ); - geography.init(); - expect(geography.originType).toBe(PointType.LOCALITY); - expect(geography.destinationType).toBe(PointType.LOCALITY); - }); - it('should throw an exception if waypoints are empty', () => { - const geography = new Geography( - { - waypoints: [], - }, - { - timezone: 'Europe/Paris', - finder: mockTimezoneFinder, - }, - ad, - ); - expect(() => geography.init()).toThrow(); - }); - it('should throw an exception if only one waypoint is provided', () => { - const geography = new Geography( - { - waypoints: [ - { - lat: 49.440041, - lon: 1.093912, - }, - ], - }, - { - timezone: 'Europe/Paris', - finder: mockTimezoneFinder, - }, - ad, - ); - expect(() => geography.init()).toThrow(); - }); - it('should throw an exception if a waypoint has invalid longitude', () => { - const geography = new Geography( - { - waypoints: [ - { - lat: 49.440041, - lon: 201.093912, - }, - { - lat: 50.630992, - lon: 3.045432, - }, - ], - }, - { - timezone: 'Europe/Paris', - finder: mockTimezoneFinder, - }, - ad, - ); - expect(() => geography.init()).toThrow(); - }); - it('should throw an exception if a waypoint has invalid latitude', () => { - const geography = new Geography( - { - waypoints: [ - { - lat: 49.440041, - lon: 1.093912, - }, - { - lat: 250.630992, - lon: 3.045432, - }, - ], - }, - { - timezone: 'Europe/Paris', - finder: mockTimezoneFinder, - }, - ad, - ); - expect(() => geography.init()).toThrow(); - }); - }); - - describe('create route', () => { - it('should create routes as driver and passenger', async () => { - const geography = new Geography( - { - waypoints: [ - { - lat: 49.440041, - lon: 1.093912, - }, - { - lat: 50.630992, - lon: 3.045432, - }, - ], - }, - { - timezone: 'Europe/Paris', - finder: mockTimezoneFinder, - }, - ad, - ); - geography.init(); - await geography.createRoutes( - [Role.DRIVER, Role.PASSENGER], - mockGeorouter, - ); - expect(geography.driverRoute.waypoints.length).toBe(2); - expect(geography.passengerRoute.waypoints.length).toBe(2); - }); - - it('should create routes as driver and passenger with 3 waypoints', async () => { - const geography = new Geography( - { - waypoints: [ - { - lat: 49.440041, - lon: 1.093912, - }, - { - lat: 49.781215, - lon: 2.198475, - }, - { - lat: 50.630992, - lon: 3.045432, - }, - ], - }, - { - timezone: 'Europe/Paris', - finder: mockTimezoneFinder, - }, - ad, - ); - geography.init(); - await geography.createRoutes( - [Role.DRIVER, Role.PASSENGER], - mockGeorouter, - ); - expect(geography.driverRoute.waypoints.length).toBe(3); - expect(geography.passengerRoute.waypoints.length).toBe(2); - }); - - it('should create routes as driver', async () => { - const geography = new Geography( - { - waypoints: [ - { - lat: 49.440041, - lon: 1.093912, - }, - { - lat: 50.630992, - lon: 3.045432, - }, - ], - }, - { - timezone: 'Europe/Paris', - finder: mockTimezoneFinder, - }, - ad, - ); - geography.init(); - await geography.createRoutes([Role.DRIVER], mockGeorouter); - expect(geography.driverRoute.waypoints.length).toBe(2); - expect(geography.passengerRoute).toBeUndefined(); - }); - - it('should create routes as passenger', async () => { - const geography = new Geography( - { - waypoints: [ - { - lat: 49.440041, - lon: 1.093912, - }, - { - lat: 50.630992, - lon: 3.045432, - }, - ], - }, - { - timezone: 'Europe/Paris', - finder: mockTimezoneFinder, - }, - ad, - ); - geography.init(); - await geography.createRoutes([Role.PASSENGER], mockGeorouter); - expect(geography.passengerRoute.waypoints.length).toBe(2); - expect(geography.driverRoute).toBeUndefined(); - }); - }); -}); diff --git a/old/modules/matcher/tests/unit/domain/ecosystem/matcher-route.spec.ts b/old/modules/matcher/tests/unit/domain/ecosystem/matcher-route.spec.ts deleted file mode 100644 index feb1b6e..0000000 --- a/old/modules/matcher/tests/unit/domain/ecosystem/matcher-route.spec.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { MatcherRoute } from '../../../../domain/entities/ecosystem/matcher-route'; -import { SpacetimePoint } from '../../../../domain/entities/ecosystem/spacetime-point'; -import { Waypoint } from '../../../../domain/entities/ecosystem/waypoint'; - -const mockGeodesic = { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - inverse: jest.fn().mockImplementation((lon1, lat1, lon2, lat2) => { - return lon1 == 0 - ? { - azimuth: 45, - distance: 50000, - } - : { - azimuth: -45, - distance: 60000, - }; - }), -}; - -describe('Matcher route entity', () => { - it('should be defined', () => { - const route = new MatcherRoute(mockGeodesic); - expect(route).toBeDefined(); - }); - it('should set waypoints and geodesic values for a route', () => { - const route = new MatcherRoute(mockGeodesic); - const waypoint1: Waypoint = new Waypoint({ - lon: 0, - lat: 0, - }); - const waypoint2: Waypoint = new Waypoint({ - lon: 10, - lat: 10, - }); - route.setWaypoints([waypoint1, waypoint2]); - expect(route.waypoints.length).toBe(2); - expect(route.fwdAzimuth).toBe(45); - expect(route.backAzimuth).toBe(225); - expect(route.distanceAzimuth).toBe(50000); - }); - it('should set points and geodesic values for a route', () => { - const route = new MatcherRoute(mockGeodesic); - route.setPoints([ - { - lon: 10, - lat: 10, - }, - { - lon: 20, - lat: 20, - }, - ]); - expect(route.points.length).toBe(2); - expect(route.fwdAzimuth).toBe(315); - expect(route.backAzimuth).toBe(135); - expect(route.distanceAzimuth).toBe(60000); - }); - it('should set spacetimePoints for a route', () => { - const route = new MatcherRoute(mockGeodesic); - const spacetimePoint1 = new SpacetimePoint({ lon: 0, lat: 0 }, 0, 0); - const spacetimePoint2 = new SpacetimePoint({ lon: 10, lat: 10 }, 500, 5000); - route.setSpacetimePoints([spacetimePoint1, spacetimePoint2]); - expect(route.spacetimePoints.length).toBe(2); - }); -}); diff --git a/old/modules/matcher/tests/unit/domain/ecosystem/person.spec.ts b/old/modules/matcher/tests/unit/domain/ecosystem/person.spec.ts deleted file mode 100644 index 974d93e..0000000 --- a/old/modules/matcher/tests/unit/domain/ecosystem/person.spec.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Ad } from '../../../../domain/entities/ecosystem/ad'; - -const DEFAULT_UUID = '00000000-0000-0000-0000-000000000000'; -const MARGIN_DURATION = 900; - -describe('Ad entity', () => { - it('should be defined', () => { - const ad = new Ad( - { - uuid: '774aaab2-77df-4c6c-b70d-7b9e972e5bbc', - }, - DEFAULT_UUID, - MARGIN_DURATION, - ); - expect(ad).toBeDefined(); - }); - - describe('init', () => { - it('should initialize an ad with a uuid', () => { - const ad = new Ad( - { - uuid: '774aaab2-77df-4c6c-b70d-7b9e972e5bbc', - }, - DEFAULT_UUID, - MARGIN_DURATION, - ); - ad.init(); - expect(ad.uuid).toBe('774aaab2-77df-4c6c-b70d-7b9e972e5bbc'); - expect(ad.marginDurations[0]).toBe(900); - expect(ad.marginDurations[6]).toBe(900); - }); - it('should initialize an ad without a uuid', () => { - const ad = new Ad({}, DEFAULT_UUID, MARGIN_DURATION); - ad.init(); - expect(ad.uuid).toBe('00000000-0000-0000-0000-000000000000'); - expect(ad.marginDurations[0]).toBe(900); - expect(ad.marginDurations[6]).toBe(900); - }); - }); -}); diff --git a/old/modules/matcher/tests/unit/domain/ecosystem/time.spec.ts b/old/modules/matcher/tests/unit/domain/ecosystem/time.spec.ts deleted file mode 100644 index 1df151d..0000000 --- a/old/modules/matcher/tests/unit/domain/ecosystem/time.spec.ts +++ /dev/null @@ -1,208 +0,0 @@ -import { Time } from '../../../../domain/entities/ecosystem/time'; - -const MARGIN_DURATION = 900; -const VALIDITY_DURATION = 365; -const mockTimeConverter = { - toUtcDate: jest.fn(), -}; - -describe('Time entity', () => { - it('should be defined', () => { - const time = new Time( - { - departure: '2023-04-01 12:24:00', - }, - MARGIN_DURATION, - VALIDITY_DURATION, - mockTimeConverter, - ); - expect(time).toBeDefined(); - }); - - describe('init', () => { - it('should initialize a punctual time request', () => { - const time = new Time( - { - departure: '2023-04-01 12:24:00', - }, - MARGIN_DURATION, - VALIDITY_DURATION, - mockTimeConverter, - ); - time.init(); - expect(time.fromDate.getFullYear()).toBe( - new Date('2023-04-01 12:24:00').getFullYear(), - ); - }); - it('should initialize a punctual time request with specific single margin duration', () => { - const time = new Time( - { - departure: '2023-04-01 12:24:00', - marginDuration: 300, - }, - MARGIN_DURATION, - VALIDITY_DURATION, - mockTimeConverter, - ); - time.init(); - expect(time.marginDurations['tue']).toBe(300); - }); - it('should initialize a punctual time request with specific margin durations', () => { - const time = new Time( - { - departure: '2023-04-01 12:24:00', - marginDurations: { - sat: 350, - }, - }, - MARGIN_DURATION, - VALIDITY_DURATION, - mockTimeConverter, - ); - time.init(); - expect(time.marginDurations['tue']).toBe(900); - expect(time.marginDurations['sat']).toBe(350); - }); - it('should initialize a punctual time request with specific single margin duration and margin durations', () => { - const time = new Time( - { - departure: '2023-04-01 12:24:00', - marginDuration: 500, - marginDurations: { - sat: 350, - }, - }, - MARGIN_DURATION, - VALIDITY_DURATION, - mockTimeConverter, - ); - time.init(); - expect(time.marginDurations['tue']).toBe(500); - expect(time.marginDurations['sat']).toBe(350); - }); - it('should initialize a recurrent time request', () => { - const time = new Time( - { - fromDate: '2023-04-01', - schedule: { - mon: '12:00', - }, - }, - MARGIN_DURATION, - VALIDITY_DURATION, - mockTimeConverter, - ); - time.init(); - expect(time.fromDate.getFullYear()).toBe( - new Date('2023-04-01').getFullYear(), - ); - }); - it('should throw an exception if no date is provided', () => { - const time = new Time( - {}, - MARGIN_DURATION, - VALIDITY_DURATION, - mockTimeConverter, - ); - expect(() => time.init()).toThrow(); - }); - it('should throw an exception if punctual date is invalid', () => { - const time = new Time( - { - departure: '2023-15-01 12:24:00', - }, - MARGIN_DURATION, - VALIDITY_DURATION, - mockTimeConverter, - ); - expect(() => time.init()).toThrow(); - }); - it('should throw an exception if recurrent fromDate is invalid', () => { - const time = new Time( - { - fromDate: '2023-15-01', - }, - MARGIN_DURATION, - VALIDITY_DURATION, - mockTimeConverter, - ); - expect(() => time.init()).toThrow(); - }); - it('should throw an exception if recurrent toDate is invalid', () => { - const time = new Time( - { - fromDate: '2023-04-01', - toDate: '2023-13-01', - }, - MARGIN_DURATION, - VALIDITY_DURATION, - mockTimeConverter, - ); - expect(() => time.init()).toThrow(); - }); - it('should throw an exception if recurrent toDate is before fromDate', () => { - const time = new Time( - { - fromDate: '2023-04-01', - toDate: '2023-03-01', - }, - MARGIN_DURATION, - VALIDITY_DURATION, - mockTimeConverter, - ); - expect(() => time.init()).toThrow(); - }); - it('should throw an exception if schedule is missing', () => { - const time = new Time( - { - fromDate: '2023-04-01', - toDate: '2024-03-31', - }, - MARGIN_DURATION, - VALIDITY_DURATION, - mockTimeConverter, - ); - expect(() => time.init()).toThrow(); - }); - it('should throw an exception if schedule is empty', () => { - const time = new Time( - { - fromDate: '2023-04-01', - toDate: '2024-03-31', - schedule: {}, - }, - MARGIN_DURATION, - VALIDITY_DURATION, - mockTimeConverter, - ); - expect(() => time.init()).toThrow(); - }); - it('should throw an exception if schedule is invalid', () => { - const time = new Time( - { - fromDate: '2023-04-01', - toDate: '2024-03-31', - schedule: { - mon: '32:78', - }, - }, - MARGIN_DURATION, - VALIDITY_DURATION, - mockTimeConverter, - ); - expect(() => time.init()).toThrow(); - }); - }); - it('should throw an exception if margin durations is provided but empty', () => { - const time = new Time( - { - departure: '2023-04-01 12:24:00', - marginDurations: {}, - }, - MARGIN_DURATION, - VALIDITY_DURATION, - mockTimeConverter, - ); - expect(() => time.init()).toThrow(); - }); -}); diff --git a/old/modules/matcher/tests/unit/domain/engine/algorithm-factory-creator.spec.ts b/old/modules/matcher/tests/unit/domain/engine/algorithm-factory-creator.spec.ts deleted file mode 100644 index 7c715a6..0000000 --- a/old/modules/matcher/tests/unit/domain/engine/algorithm-factory-creator.spec.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { AlgorithmFactoryCreator } from '../../../../domain/entities/engine/factory/algorithm-factory-creator'; -import { MatchRequest } from '../../../../domain/dtos/match.request'; -import { AlgorithmType } from '../../../../domain/types/algorithm.enum'; -import { IDefaultParams } from '../../../../domain/types/default-params.type'; -import { MatchQuery } from '../../../../queries/match.query'; -import { ClassicAlgorithmFactory } from '../../../../domain/entities/engine/factory/classic'; - -const mockGeorouterCreator = { - create: jest.fn().mockImplementation(), -}; - -const mockTimezoneFinder = { - timezones: jest.fn().mockImplementation(() => ['Europe/Paris']), -}; - -const mockTimeConverter = { - toUtcDate: jest.fn(), -}; - -const defaultParams: IDefaultParams = { - DEFAULT_UUID: '00000000-0000-0000-0000-000000000000', - MARGIN_DURATION: 900, - VALIDITY_DURATION: 365, - DEFAULT_TIMEZONE: 'Europe/Paris', - DEFAULT_SEATS: 3, - DEFAULT_ALGORITHM_SETTINGS: { - ALGORITHM: AlgorithmType.CLASSIC, - STRICT: false, - REMOTENESS: 15000, - USE_PROPORTION: true, - PROPORTION: 0.3, - USE_AZIMUTH: true, - AZIMUTH_MARGIN: 10, - MAX_DETOUR_DISTANCE_RATIO: 0.3, - MAX_DETOUR_DURATION_RATIO: 0.3, - GEOROUTER_TYPE: 'graphhopper', - GEOROUTER_URL: 'http://localhost', - }, -}; - -const matchRequest: MatchRequest = new MatchRequest(); -matchRequest.departure = '2023-04-01 12:00'; -matchRequest.waypoints = [ - { - lat: 49.440041, - lon: 1.093912, - }, - { - lat: 50.630992, - lon: 3.045432, - }, -]; -const matchQuery: MatchQuery = new MatchQuery( - matchRequest, - defaultParams, - mockGeorouterCreator, - mockTimezoneFinder, - mockTimeConverter, -); - -describe('AlgorithmFactoryCreator', () => { - it('should be defined', () => { - expect(new AlgorithmFactoryCreator()).toBeDefined(); - }); - - it('should create a classic algorithm factory', () => { - expect(new AlgorithmFactoryCreator().create(matchQuery)).toBeInstanceOf( - ClassicAlgorithmFactory, - ); - }); -}); diff --git a/old/modules/matcher/tests/unit/domain/engine/algorithm-factory.abstract.spec.ts b/old/modules/matcher/tests/unit/domain/engine/algorithm-factory.abstract.spec.ts deleted file mode 100644 index 74e2494..0000000 --- a/old/modules/matcher/tests/unit/domain/engine/algorithm-factory.abstract.spec.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { MatchRequest } from '../../../../domain/dtos/match.request'; -import { Candidate } from '../../../../domain/entities/engine/candidate'; -import { AlgorithmFactory } from '../../../../domain/entities/engine/factory/algorithm-factory.abstract'; -import { Processor } from '../../../../domain/entities/engine/processor/processor.abstract'; -import { Selector } from '../../../../domain/entities/engine/selector/selector.abstract'; -import { AlgorithmType } from '../../../../domain/types/algorithm.enum'; -import { IDefaultParams } from '../../../../domain/types/default-params.type'; -import { MatchQuery } from '../../../../queries/match.query'; - -const mockGeorouterCreator = { - create: jest.fn().mockImplementation(), -}; - -const mockTimezoneFinder = { - timezones: jest.fn().mockImplementation(() => ['Europe/Paris']), -}; - -const mockTimeConverter = { - toUtcDate: jest.fn(), -}; - -const defaultParams: IDefaultParams = { - DEFAULT_UUID: '00000000-0000-0000-0000-000000000000', - MARGIN_DURATION: 900, - VALIDITY_DURATION: 365, - DEFAULT_TIMEZONE: 'Europe/Paris', - DEFAULT_SEATS: 3, - DEFAULT_ALGORITHM_SETTINGS: { - ALGORITHM: AlgorithmType.CLASSIC, - STRICT: false, - REMOTENESS: 15000, - USE_PROPORTION: true, - PROPORTION: 0.3, - USE_AZIMUTH: true, - AZIMUTH_MARGIN: 10, - MAX_DETOUR_DISTANCE_RATIO: 0.3, - MAX_DETOUR_DURATION_RATIO: 0.3, - GEOROUTER_TYPE: 'graphhopper', - GEOROUTER_URL: 'http://localhost', - }, -}; - -const matchRequest: MatchRequest = new MatchRequest(); -matchRequest.departure = '2023-04-01 12:00'; -matchRequest.waypoints = [ - { - lat: 49.440041, - lon: 1.093912, - }, - { - lat: 50.630992, - lon: 3.045432, - }, -]; -const matchQuery: MatchQuery = new MatchQuery( - matchRequest, - defaultParams, - mockGeorouterCreator, - mockTimezoneFinder, - mockTimeConverter, -); - -class FakeSelector extends Selector { - select = (): Promise => { - return Promise.resolve([new Candidate()]); - }; -} - -class FakeProcessor extends Processor { - execute = (candidates: Candidate[]): Candidate[] => { - return candidates; - }; -} - -class FakeAlgorithmFactory extends AlgorithmFactory { - createSelector = (): Selector => { - return new FakeSelector(matchQuery); - }; - createProcessors = (): Processor[] => { - return [new FakeProcessor(matchQuery)]; - }; -} - -describe('AlgorithmFactory', () => { - it('should create an extended class', () => { - expect(new FakeAlgorithmFactory(matchQuery)).toBeDefined(); - }); -}); diff --git a/old/modules/matcher/tests/unit/domain/engine/classic-algorithm-factory.spec.ts b/old/modules/matcher/tests/unit/domain/engine/classic-algorithm-factory.spec.ts deleted file mode 100644 index 4859189..0000000 --- a/old/modules/matcher/tests/unit/domain/engine/classic-algorithm-factory.spec.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { ClassicSelector } from '../../../../domain/entities/engine/selector/classic.selector'; -import { MatchRequest } from '../../../../domain/dtos/match.request'; -import { ClassicAlgorithmFactory } from '../../../../domain/entities/engine/factory/classic'; -import { AlgorithmType } from '../../../../domain/types/algorithm.enum'; -import { IDefaultParams } from '../../../../domain/types/default-params.type'; -import { MatchQuery } from '../../../../queries/match.query'; - -const mockGeorouterCreator = { - create: jest.fn().mockImplementation(), -}; - -const mockTimezoneFinder = { - timezones: jest.fn().mockImplementation(() => ['Europe/Paris']), -}; - -const mockTimeConverter = { - toUtcDate: jest.fn(), -}; - -const defaultParams: IDefaultParams = { - DEFAULT_UUID: '00000000-0000-0000-0000-000000000000', - MARGIN_DURATION: 900, - VALIDITY_DURATION: 365, - DEFAULT_TIMEZONE: 'Europe/Paris', - DEFAULT_SEATS: 3, - DEFAULT_ALGORITHM_SETTINGS: { - ALGORITHM: AlgorithmType.CLASSIC, - STRICT: false, - REMOTENESS: 15000, - USE_PROPORTION: true, - PROPORTION: 0.3, - USE_AZIMUTH: true, - AZIMUTH_MARGIN: 10, - MAX_DETOUR_DISTANCE_RATIO: 0.3, - MAX_DETOUR_DURATION_RATIO: 0.3, - GEOROUTER_TYPE: 'graphhopper', - GEOROUTER_URL: 'http://localhost', - }, -}; - -const matchRequest: MatchRequest = new MatchRequest(); -matchRequest.departure = '2023-04-01 12:00'; -matchRequest.waypoints = [ - { - lat: 49.440041, - lon: 1.093912, - }, - { - lat: 50.630992, - lon: 3.045432, - }, -]; -const matchQuery: MatchQuery = new MatchQuery( - matchRequest, - defaultParams, - mockGeorouterCreator, - mockTimezoneFinder, - mockTimeConverter, -); - -describe('ClassicAlgorithmFactory', () => { - it('should be defined', () => { - expect(new ClassicAlgorithmFactory(matchQuery)).toBeDefined(); - }); - - it('should create a classic selector', () => { - const classicAlgorithmFactory: ClassicAlgorithmFactory = - new ClassicAlgorithmFactory(matchQuery); - expect(classicAlgorithmFactory.createSelector()).toBeInstanceOf( - ClassicSelector, - ); - }); - - it('should create processors', () => { - const classicAlgorithmFactory: ClassicAlgorithmFactory = - new ClassicAlgorithmFactory(matchQuery); - expect(classicAlgorithmFactory.createProcessors().length).toBe(6); - }); -}); diff --git a/old/modules/matcher/tests/unit/domain/engine/classic-geo.filter.processor.spec.ts b/old/modules/matcher/tests/unit/domain/engine/classic-geo.filter.processor.spec.ts deleted file mode 100644 index ea3b506..0000000 --- a/old/modules/matcher/tests/unit/domain/engine/classic-geo.filter.processor.spec.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { MatchRequest } from '../../../../domain/dtos/match.request'; -import { AlgorithmType } from '../../../../domain/types/algorithm.enum'; -import { IDefaultParams } from '../../../../domain/types/default-params.type'; -import { MatchQuery } from '../../../../queries/match.query'; -import { Candidate } from '../../../../domain/entities/engine/candidate'; -import { ClassicGeoFilter } from '../../../../domain/entities/engine/processor/filter/geofilter/classic.filter.processor'; - -const mockGeorouterCreator = { - create: jest.fn().mockImplementation(), -}; - -const mockTimezoneFinder = { - timezones: jest.fn().mockImplementation(() => ['Europe/Paris']), -}; - -const mockTimeConverter = { - toUtcDate: jest.fn(), -}; - -const defaultParams: IDefaultParams = { - DEFAULT_UUID: '00000000-0000-0000-0000-000000000000', - MARGIN_DURATION: 900, - VALIDITY_DURATION: 365, - DEFAULT_TIMEZONE: 'Europe/Paris', - DEFAULT_SEATS: 3, - DEFAULT_ALGORITHM_SETTINGS: { - ALGORITHM: AlgorithmType.CLASSIC, - STRICT: false, - REMOTENESS: 15000, - USE_PROPORTION: true, - PROPORTION: 0.3, - USE_AZIMUTH: true, - AZIMUTH_MARGIN: 10, - MAX_DETOUR_DISTANCE_RATIO: 0.3, - MAX_DETOUR_DURATION_RATIO: 0.3, - GEOROUTER_TYPE: 'graphhopper', - GEOROUTER_URL: 'http://localhost', - }, -}; - -const matchRequest: MatchRequest = new MatchRequest(); -matchRequest.departure = '2023-04-01 12:00'; -matchRequest.waypoints = [ - { - lat: 49.440041, - lon: 1.093912, - }, - { - lat: 50.630992, - lon: 3.045432, - }, -]; -const matchQuery: MatchQuery = new MatchQuery( - matchRequest, - defaultParams, - mockGeorouterCreator, - mockTimezoneFinder, - mockTimeConverter, -); - -describe('ClassicGeoFilter', () => { - it('should be defined', () => { - expect(new ClassicGeoFilter(matchQuery)).toBeDefined(); - }); - - it('should filter candidates', () => { - const candidates = [new Candidate(), new Candidate()]; - const classicWaypointCompleter: ClassicGeoFilter = new ClassicGeoFilter( - matchQuery, - ); - expect(classicWaypointCompleter.filter(candidates).length).toBe(2); - }); -}); diff --git a/old/modules/matcher/tests/unit/domain/engine/classic-time.filter.processor.spec.ts b/old/modules/matcher/tests/unit/domain/engine/classic-time.filter.processor.spec.ts deleted file mode 100644 index c489684..0000000 --- a/old/modules/matcher/tests/unit/domain/engine/classic-time.filter.processor.spec.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { MatchRequest } from '../../../../domain/dtos/match.request'; -import { AlgorithmType } from '../../../../domain/types/algorithm.enum'; -import { IDefaultParams } from '../../../../domain/types/default-params.type'; -import { MatchQuery } from '../../../../queries/match.query'; -import { Candidate } from '../../../../domain/entities/engine/candidate'; -import { ClassicTimeFilter } from '../../../../domain/entities/engine/processor/filter/timefilter/classic.filter.processor'; - -const mockGeorouterCreator = { - create: jest.fn().mockImplementation(), -}; - -const mockTimezoneFinder = { - timezones: jest.fn().mockImplementation(() => ['Europe/Paris']), -}; - -const mockTimeConverter = { - toUtcDate: jest.fn(), -}; - -const defaultParams: IDefaultParams = { - DEFAULT_UUID: '00000000-0000-0000-0000-000000000000', - MARGIN_DURATION: 900, - VALIDITY_DURATION: 365, - DEFAULT_TIMEZONE: 'Europe/Paris', - DEFAULT_SEATS: 3, - DEFAULT_ALGORITHM_SETTINGS: { - ALGORITHM: AlgorithmType.CLASSIC, - STRICT: false, - REMOTENESS: 15000, - USE_PROPORTION: true, - PROPORTION: 0.3, - USE_AZIMUTH: true, - AZIMUTH_MARGIN: 10, - MAX_DETOUR_DISTANCE_RATIO: 0.3, - MAX_DETOUR_DURATION_RATIO: 0.3, - GEOROUTER_TYPE: 'graphhopper', - GEOROUTER_URL: 'http://localhost', - }, -}; - -const matchRequest: MatchRequest = new MatchRequest(); -matchRequest.departure = '2023-04-01 12:00'; -matchRequest.waypoints = [ - { - lat: 49.440041, - lon: 1.093912, - }, - { - lat: 50.630992, - lon: 3.045432, - }, -]; -const matchQuery: MatchQuery = new MatchQuery( - matchRequest, - defaultParams, - mockGeorouterCreator, - mockTimezoneFinder, - mockTimeConverter, -); - -describe('ClassicTimeFilter', () => { - it('should be defined', () => { - expect(new ClassicTimeFilter(matchQuery)).toBeDefined(); - }); - - it('should filter candidates', () => { - const candidates = [new Candidate(), new Candidate()]; - const classicWaypointCompleter: ClassicTimeFilter = new ClassicTimeFilter( - matchQuery, - ); - expect(classicWaypointCompleter.filter(candidates).length).toBe(2); - }); -}); diff --git a/old/modules/matcher/tests/unit/domain/engine/classic-waypoint.completer.processor.spec.ts b/old/modules/matcher/tests/unit/domain/engine/classic-waypoint.completer.processor.spec.ts deleted file mode 100644 index 68cfca7..0000000 --- a/old/modules/matcher/tests/unit/domain/engine/classic-waypoint.completer.processor.spec.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { MatchRequest } from '../../../../domain/dtos/match.request'; -import { AlgorithmType } from '../../../../domain/types/algorithm.enum'; -import { IDefaultParams } from '../../../../domain/types/default-params.type'; -import { MatchQuery } from '../../../../queries/match.query'; -import { ClassicWaypointsCompleter } from '../../../../domain/entities/engine/processor/completer/classic-waypoint.completer.processor'; -import { Candidate } from '../../../../domain/entities/engine/candidate'; - -const mockGeorouterCreator = { - create: jest.fn().mockImplementation(), -}; - -const mockTimezoneFinder = { - timezones: jest.fn().mockImplementation(() => ['Europe/Paris']), -}; - -const mockTimeConverter = { - toUtcDate: jest.fn(), -}; - -const defaultParams: IDefaultParams = { - DEFAULT_UUID: '00000000-0000-0000-0000-000000000000', - MARGIN_DURATION: 900, - VALIDITY_DURATION: 365, - DEFAULT_TIMEZONE: 'Europe/Paris', - DEFAULT_SEATS: 3, - DEFAULT_ALGORITHM_SETTINGS: { - ALGORITHM: AlgorithmType.CLASSIC, - STRICT: false, - REMOTENESS: 15000, - USE_PROPORTION: true, - PROPORTION: 0.3, - USE_AZIMUTH: true, - AZIMUTH_MARGIN: 10, - MAX_DETOUR_DISTANCE_RATIO: 0.3, - MAX_DETOUR_DURATION_RATIO: 0.3, - GEOROUTER_TYPE: 'graphhopper', - GEOROUTER_URL: 'http://localhost', - }, -}; - -const matchRequest: MatchRequest = new MatchRequest(); -matchRequest.departure = '2023-04-01 12:00'; -matchRequest.waypoints = [ - { - lat: 49.440041, - lon: 1.093912, - }, - { - lat: 50.630992, - lon: 3.045432, - }, -]; -const matchQuery: MatchQuery = new MatchQuery( - matchRequest, - defaultParams, - mockGeorouterCreator, - mockTimezoneFinder, - mockTimeConverter, -); - -describe('ClassicWaypointCompleter', () => { - it('should be defined', () => { - expect(new ClassicWaypointsCompleter(matchQuery)).toBeDefined(); - }); - - it('should complete candidates', () => { - const candidates = [new Candidate(), new Candidate()]; - const classicWaypointCompleter: ClassicWaypointsCompleter = - new ClassicWaypointsCompleter(matchQuery); - expect(classicWaypointCompleter.complete(candidates).length).toBe(2); - }); -}); diff --git a/old/modules/matcher/tests/unit/domain/engine/classic.selector.spec.ts b/old/modules/matcher/tests/unit/domain/engine/classic.selector.spec.ts deleted file mode 100644 index 19dcfdb..0000000 --- a/old/modules/matcher/tests/unit/domain/engine/classic.selector.spec.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { MatchRequest } from '../../../../domain/dtos/match.request'; -import { AlgorithmType } from '../../../../domain/types/algorithm.enum'; -import { IDefaultParams } from '../../../../domain/types/default-params.type'; -import { MatchQuery } from '../../../../queries/match.query'; -import { Candidate } from '../../../../domain/entities/engine/candidate'; -import { ClassicSelector } from '../../../../domain/entities/engine/selector/classic.selector'; - -const mockGeorouterCreator = { - create: jest.fn().mockImplementation(), -}; - -const mockTimezoneFinder = { - timezones: jest.fn().mockImplementation(() => ['Europe/Paris']), -}; - -const mockTimeConverter = { - toUtcDate: jest.fn(), -}; - -const defaultParams: IDefaultParams = { - DEFAULT_UUID: '00000000-0000-0000-0000-000000000000', - MARGIN_DURATION: 900, - VALIDITY_DURATION: 365, - DEFAULT_TIMEZONE: 'Europe/Paris', - DEFAULT_SEATS: 3, - DEFAULT_ALGORITHM_SETTINGS: { - ALGORITHM: AlgorithmType.CLASSIC, - STRICT: false, - REMOTENESS: 15000, - USE_PROPORTION: true, - PROPORTION: 0.3, - USE_AZIMUTH: true, - AZIMUTH_MARGIN: 10, - MAX_DETOUR_DISTANCE_RATIO: 0.3, - MAX_DETOUR_DURATION_RATIO: 0.3, - GEOROUTER_TYPE: 'graphhopper', - GEOROUTER_URL: 'http://localhost', - }, -}; - -const matchRequest: MatchRequest = new MatchRequest(); -matchRequest.departure = '2023-04-01 12:00'; -matchRequest.waypoints = [ - { - lat: 49.440041, - lon: 1.093912, - }, - { - lat: 50.630992, - lon: 3.045432, - }, -]; -const matchQuery: MatchQuery = new MatchQuery( - matchRequest, - defaultParams, - mockGeorouterCreator, - mockTimezoneFinder, - mockTimeConverter, -); - -describe('ClassicSelector', () => { - it('should be defined', () => { - expect(new ClassicSelector(matchQuery)).toBeDefined(); - }); - - it('should select candidates', async () => { - const classicSelector: ClassicSelector = new ClassicSelector(matchQuery); - const candidates: Candidate[] = await classicSelector.select(); - expect(candidates.length).toBe(0); - }); -}); diff --git a/old/modules/matcher/tests/unit/domain/engine/completer.abstract.spec.ts b/old/modules/matcher/tests/unit/domain/engine/completer.abstract.spec.ts deleted file mode 100644 index 7d4bdb9..0000000 --- a/old/modules/matcher/tests/unit/domain/engine/completer.abstract.spec.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { Completer } from '../../../../domain/entities/engine/processor/completer/completer.abstract'; -import { MatchRequest } from '../../../../domain/dtos/match.request'; -import { Candidate } from '../../../../domain/entities/engine/candidate'; -import { AlgorithmType } from '../../../../domain/types/algorithm.enum'; -import { IDefaultParams } from '../../../../domain/types/default-params.type'; -import { MatchQuery } from '../../../../queries/match.query'; - -const mockGeorouterCreator = { - create: jest.fn().mockImplementation(), -}; - -const mockTimezoneFinder = { - timezones: jest.fn().mockImplementation(() => ['Europe/Paris']), -}; - -const mockTimeConverter = { - toUtcDate: jest.fn(), -}; - -const defaultParams: IDefaultParams = { - DEFAULT_UUID: '00000000-0000-0000-0000-000000000000', - MARGIN_DURATION: 900, - VALIDITY_DURATION: 365, - DEFAULT_TIMEZONE: 'Europe/Paris', - DEFAULT_SEATS: 3, - DEFAULT_ALGORITHM_SETTINGS: { - ALGORITHM: AlgorithmType.CLASSIC, - STRICT: false, - REMOTENESS: 15000, - USE_PROPORTION: true, - PROPORTION: 0.3, - USE_AZIMUTH: true, - AZIMUTH_MARGIN: 10, - MAX_DETOUR_DISTANCE_RATIO: 0.3, - MAX_DETOUR_DURATION_RATIO: 0.3, - GEOROUTER_TYPE: 'graphhopper', - GEOROUTER_URL: 'http://localhost', - }, -}; - -const matchRequest: MatchRequest = new MatchRequest(); -matchRequest.departure = '2023-04-01 12:00'; -matchRequest.waypoints = [ - { - lat: 49.440041, - lon: 1.093912, - }, - { - lat: 50.630992, - lon: 3.045432, - }, -]; -const matchQuery: MatchQuery = new MatchQuery( - matchRequest, - defaultParams, - mockGeorouterCreator, - mockTimezoneFinder, - mockTimeConverter, -); - -class FakeCompleter extends Completer { - complete = (candidates: Candidate[]): Candidate[] => { - return candidates; - }; -} - -describe('Completer', () => { - it('should create an extended class', () => { - expect(new FakeCompleter(matchQuery)).toBeDefined(); - }); - - it('should call complete method', () => { - const fakeCompleter: Completer = new FakeCompleter(matchQuery); - const completerSpy = jest.spyOn(fakeCompleter, 'complete'); - fakeCompleter.execute([new Candidate()]); - expect(completerSpy).toHaveBeenCalled(); - }); -}); diff --git a/old/modules/matcher/tests/unit/domain/engine/filter.abstract.spec.ts b/old/modules/matcher/tests/unit/domain/engine/filter.abstract.spec.ts deleted file mode 100644 index 3e6ceb6..0000000 --- a/old/modules/matcher/tests/unit/domain/engine/filter.abstract.spec.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { MatchRequest } from '../../../../domain/dtos/match.request'; -import { Candidate } from '../../../../domain/entities/engine/candidate'; -import { AlgorithmType } from '../../../../domain/types/algorithm.enum'; -import { IDefaultParams } from '../../../../domain/types/default-params.type'; -import { MatchQuery } from '../../../../queries/match.query'; -import { Filter } from '../../../../domain/entities/engine/processor/filter/filter.abstract'; - -const mockGeorouterCreator = { - create: jest.fn().mockImplementation(), -}; - -const mockTimezoneFinder = { - timezones: jest.fn().mockImplementation(() => ['Europe/Paris']), -}; - -const mockTimeConverter = { - toUtcDate: jest.fn(), -}; - -const defaultParams: IDefaultParams = { - DEFAULT_UUID: '00000000-0000-0000-0000-000000000000', - MARGIN_DURATION: 900, - VALIDITY_DURATION: 365, - DEFAULT_TIMEZONE: 'Europe/Paris', - DEFAULT_SEATS: 3, - DEFAULT_ALGORITHM_SETTINGS: { - ALGORITHM: AlgorithmType.CLASSIC, - STRICT: false, - REMOTENESS: 15000, - USE_PROPORTION: true, - PROPORTION: 0.3, - USE_AZIMUTH: true, - AZIMUTH_MARGIN: 10, - MAX_DETOUR_DISTANCE_RATIO: 0.3, - MAX_DETOUR_DURATION_RATIO: 0.3, - GEOROUTER_TYPE: 'graphhopper', - GEOROUTER_URL: 'http://localhost', - }, -}; - -const matchRequest: MatchRequest = new MatchRequest(); -matchRequest.departure = '2023-04-01 12:00'; -matchRequest.waypoints = [ - { - lat: 49.440041, - lon: 1.093912, - }, - { - lat: 50.630992, - lon: 3.045432, - }, -]; -const matchQuery: MatchQuery = new MatchQuery( - matchRequest, - defaultParams, - mockGeorouterCreator, - mockTimezoneFinder, - mockTimeConverter, -); - -class FakeFilter extends Filter { - filter = (candidates: Candidate[]): Candidate[] => { - return candidates; - }; -} - -describe('Filter', () => { - it('should create an extended class', () => { - expect(new FakeFilter(matchQuery)).toBeDefined(); - }); - - it('should call complete method', () => { - const fakeFilter: Filter = new FakeFilter(matchQuery); - const filterSpy = jest.spyOn(fakeFilter, 'filter'); - fakeFilter.execute([new Candidate()]); - expect(filterSpy).toHaveBeenCalled(); - }); -}); diff --git a/old/modules/matcher/tests/unit/domain/engine/journey.completer.processor.spec.ts b/old/modules/matcher/tests/unit/domain/engine/journey.completer.processor.spec.ts deleted file mode 100644 index 85bd6d8..0000000 --- a/old/modules/matcher/tests/unit/domain/engine/journey.completer.processor.spec.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { MatchRequest } from '../../../../domain/dtos/match.request'; -import { AlgorithmType } from '../../../../domain/types/algorithm.enum'; -import { IDefaultParams } from '../../../../domain/types/default-params.type'; -import { MatchQuery } from '../../../../queries/match.query'; -import { Candidate } from '../../../../domain/entities/engine/candidate'; -import { JourneyCompleter } from '../../../../domain/entities/engine/processor/completer/journey.completer.processor'; - -const mockGeorouterCreator = { - create: jest.fn().mockImplementation(), -}; - -const mockTimezoneFinder = { - timezones: jest.fn().mockImplementation(() => ['Europe/Paris']), -}; - -const mockTimeConverter = { - toUtcDate: jest.fn(), -}; - -const defaultParams: IDefaultParams = { - DEFAULT_UUID: '00000000-0000-0000-0000-000000000000', - MARGIN_DURATION: 900, - VALIDITY_DURATION: 365, - DEFAULT_TIMEZONE: 'Europe/Paris', - DEFAULT_SEATS: 3, - DEFAULT_ALGORITHM_SETTINGS: { - ALGORITHM: AlgorithmType.CLASSIC, - STRICT: false, - REMOTENESS: 15000, - USE_PROPORTION: true, - PROPORTION: 0.3, - USE_AZIMUTH: true, - AZIMUTH_MARGIN: 10, - MAX_DETOUR_DISTANCE_RATIO: 0.3, - MAX_DETOUR_DURATION_RATIO: 0.3, - GEOROUTER_TYPE: 'graphhopper', - GEOROUTER_URL: 'http://localhost', - }, -}; - -const matchRequest: MatchRequest = new MatchRequest(); -matchRequest.departure = '2023-04-01 12:00'; -matchRequest.waypoints = [ - { - lat: 49.440041, - lon: 1.093912, - }, - { - lat: 50.630992, - lon: 3.045432, - }, -]; -const matchQuery: MatchQuery = new MatchQuery( - matchRequest, - defaultParams, - mockGeorouterCreator, - mockTimezoneFinder, - mockTimeConverter, -); - -describe('JourneyCompleter', () => { - it('should be defined', () => { - expect(new JourneyCompleter(matchQuery)).toBeDefined(); - }); - - it('should complete candidates', () => { - const candidates = [new Candidate(), new Candidate()]; - const journeyCompleter: JourneyCompleter = new JourneyCompleter(matchQuery); - expect(journeyCompleter.complete(candidates).length).toBe(2); - }); -}); diff --git a/old/modules/matcher/tests/unit/domain/engine/matcher.spec.ts b/old/modules/matcher/tests/unit/domain/engine/matcher.spec.ts deleted file mode 100644 index 5b73254..0000000 --- a/old/modules/matcher/tests/unit/domain/engine/matcher.spec.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { AlgorithmType } from '../../../../domain/types/algorithm.enum'; -import { IDefaultParams } from '../../../../domain/types/default-params.type'; -import { MatchRequest } from '../../../../domain/dtos/match.request'; -import { MatchQuery } from '../../../../queries/match.query'; -import { Matcher } from '../../../../domain/entities/engine/matcher'; - -const mockAlgorithmFactoryCreator = { - create: jest.fn().mockReturnValue({ - createSelector: jest.fn().mockReturnValue({ - select: jest.fn(), - }), - createProcessors: jest.fn().mockReturnValue([ - { - execute: jest.fn(), - }, - ]), - }), -}; - -const mockGeorouterCreator = { - create: jest.fn().mockImplementation(), -}; - -const mockTimezoneFinder = { - timezones: jest.fn().mockImplementation(() => ['Europe/Paris']), -}; - -const mockTimeConverter = { - toUtcDate: jest.fn(), -}; - -const defaultParams: IDefaultParams = { - DEFAULT_UUID: '00000000-0000-0000-0000-000000000000', - MARGIN_DURATION: 900, - VALIDITY_DURATION: 365, - DEFAULT_TIMEZONE: 'Europe/Paris', - DEFAULT_SEATS: 3, - DEFAULT_ALGORITHM_SETTINGS: { - ALGORITHM: AlgorithmType.CLASSIC, - STRICT: false, - REMOTENESS: 15000, - USE_PROPORTION: true, - PROPORTION: 0.3, - USE_AZIMUTH: true, - AZIMUTH_MARGIN: 10, - MAX_DETOUR_DISTANCE_RATIO: 0.3, - MAX_DETOUR_DURATION_RATIO: 0.3, - GEOROUTER_TYPE: 'graphhopper', - GEOROUTER_URL: 'http://localhost', - }, -}; - -const matchRequest: MatchRequest = new MatchRequest(); -matchRequest.departure = '2023-04-01 12:00'; -matchRequest.waypoints = [ - { - lat: 49.440041, - lon: 1.093912, - }, - { - lat: 50.630992, - lon: 3.045432, - }, -]; -const matchQuery: MatchQuery = new MatchQuery( - matchRequest, - defaultParams, - mockGeorouterCreator, - mockTimezoneFinder, - mockTimeConverter, -); - -describe('Matcher', () => { - it('should be defined', () => { - expect(new Matcher(mockAlgorithmFactoryCreator)).toBeDefined(); - }); - - it('should return matches', async () => { - const matcher = new Matcher(mockAlgorithmFactoryCreator); - const matches = await matcher.match(matchQuery); - expect(matches.length).toBe(1); - }); -}); diff --git a/old/modules/matcher/tests/unit/domain/engine/processor.abstract.spec.ts b/old/modules/matcher/tests/unit/domain/engine/processor.abstract.spec.ts deleted file mode 100644 index c83eb82..0000000 --- a/old/modules/matcher/tests/unit/domain/engine/processor.abstract.spec.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { MatchRequest } from '../../../../domain/dtos/match.request'; -import { Candidate } from '../../../../domain/entities/engine/candidate'; -import { Processor } from '../../../../domain/entities/engine/processor/processor.abstract'; -import { AlgorithmType } from '../../../../domain/types/algorithm.enum'; -import { IDefaultParams } from '../../../../domain/types/default-params.type'; -import { MatchQuery } from '../../../../queries/match.query'; - -const mockGeorouterCreator = { - create: jest.fn().mockImplementation(), -}; - -const mockTimezoneFinder = { - timezones: jest.fn().mockImplementation(() => ['Europe/Paris']), -}; - -const mockTimeConverter = { - toUtcDate: jest.fn().mockImplementation(), -}; - -const defaultParams: IDefaultParams = { - DEFAULT_UUID: '00000000-0000-0000-0000-000000000000', - MARGIN_DURATION: 900, - VALIDITY_DURATION: 365, - DEFAULT_TIMEZONE: 'Europe/Paris', - DEFAULT_SEATS: 3, - DEFAULT_ALGORITHM_SETTINGS: { - ALGORITHM: AlgorithmType.CLASSIC, - STRICT: false, - REMOTENESS: 15000, - USE_PROPORTION: true, - PROPORTION: 0.3, - USE_AZIMUTH: true, - AZIMUTH_MARGIN: 10, - MAX_DETOUR_DISTANCE_RATIO: 0.3, - MAX_DETOUR_DURATION_RATIO: 0.3, - GEOROUTER_TYPE: 'graphhopper', - GEOROUTER_URL: 'http://localhost', - }, -}; - -const matchRequest: MatchRequest = new MatchRequest(); -matchRequest.departure = '2023-04-01 12:00'; -matchRequest.waypoints = [ - { - lat: 49.440041, - lon: 1.093912, - }, - { - lat: 50.630992, - lon: 3.045432, - }, -]; -const matchQuery: MatchQuery = new MatchQuery( - matchRequest, - defaultParams, - mockGeorouterCreator, - mockTimezoneFinder, - mockTimeConverter, -); - -class FakeProcessor extends Processor { - execute = (candidates: Candidate[]): Candidate[] => { - return candidates; - }; -} - -describe('Processor', () => { - it('should create an extended class', () => { - expect(new FakeProcessor(matchQuery)).toBeDefined(); - }); -}); diff --git a/old/modules/matcher/tests/unit/domain/engine/route.completer.processor.spec.ts b/old/modules/matcher/tests/unit/domain/engine/route.completer.processor.spec.ts deleted file mode 100644 index cdd2a5a..0000000 --- a/old/modules/matcher/tests/unit/domain/engine/route.completer.processor.spec.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { MatchRequest } from '../../../../domain/dtos/match.request'; -import { AlgorithmType } from '../../../../domain/types/algorithm.enum'; -import { IDefaultParams } from '../../../../domain/types/default-params.type'; -import { MatchQuery } from '../../../../queries/match.query'; -import { Candidate } from '../../../../domain/entities/engine/candidate'; -import { RouteCompleter } from '../../../../domain/entities/engine/processor/completer/route.completer.processor'; - -const mockGeorouterCreator = { - create: jest.fn().mockImplementation(), -}; - -const mockTimezoneFinder = { - timezones: jest.fn().mockImplementation(() => ['Europe/Paris']), -}; - -const mockTimeConverter = { - toUtcDate: jest.fn(), -}; - -const defaultParams: IDefaultParams = { - DEFAULT_UUID: '00000000-0000-0000-0000-000000000000', - MARGIN_DURATION: 900, - VALIDITY_DURATION: 365, - DEFAULT_TIMEZONE: 'Europe/Paris', - DEFAULT_SEATS: 3, - DEFAULT_ALGORITHM_SETTINGS: { - ALGORITHM: AlgorithmType.CLASSIC, - STRICT: false, - REMOTENESS: 15000, - USE_PROPORTION: true, - PROPORTION: 0.3, - USE_AZIMUTH: true, - AZIMUTH_MARGIN: 10, - MAX_DETOUR_DISTANCE_RATIO: 0.3, - MAX_DETOUR_DURATION_RATIO: 0.3, - GEOROUTER_TYPE: 'graphhopper', - GEOROUTER_URL: 'http://localhost', - }, -}; - -const matchRequest: MatchRequest = new MatchRequest(); -matchRequest.departure = '2023-04-01 12:00'; -matchRequest.waypoints = [ - { - lat: 49.440041, - lon: 1.093912, - }, - { - lat: 50.630992, - lon: 3.045432, - }, -]; -const matchQuery: MatchQuery = new MatchQuery( - matchRequest, - defaultParams, - mockGeorouterCreator, - mockTimezoneFinder, - mockTimeConverter, -); - -describe('RouteCompleter', () => { - it('should be defined', () => { - expect(new RouteCompleter(matchQuery)).toBeDefined(); - }); - - it('should complete candidates', () => { - const candidates = [new Candidate(), new Candidate()]; - const routeCompleter: RouteCompleter = new RouteCompleter(matchQuery); - expect(routeCompleter.complete(candidates).length).toBe(2); - }); -}); diff --git a/old/modules/matcher/tests/unit/domain/engine/selector.abstract.spec.ts b/old/modules/matcher/tests/unit/domain/engine/selector.abstract.spec.ts deleted file mode 100644 index 677e43f..0000000 --- a/old/modules/matcher/tests/unit/domain/engine/selector.abstract.spec.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { MatchRequest } from '../../../../domain/dtos/match.request'; -import { Candidate } from '../../../../domain/entities/engine/candidate'; -import { AlgorithmType } from '../../../../domain/types/algorithm.enum'; -import { IDefaultParams } from '../../../../domain/types/default-params.type'; -import { MatchQuery } from '../../../../queries/match.query'; -import { Selector } from '../../../../domain/entities/engine/selector/selector.abstract'; - -const mockGeorouterCreator = { - create: jest.fn().mockImplementation(), -}; - -const mockTimezoneFinder = { - timezones: jest.fn().mockImplementation(() => ['Europe/Paris']), -}; - -const mockTimeConverter = { - toUtcDate: jest.fn(), -}; - -const defaultParams: IDefaultParams = { - DEFAULT_UUID: '00000000-0000-0000-0000-000000000000', - MARGIN_DURATION: 900, - VALIDITY_DURATION: 365, - DEFAULT_TIMEZONE: 'Europe/Paris', - DEFAULT_SEATS: 3, - DEFAULT_ALGORITHM_SETTINGS: { - ALGORITHM: AlgorithmType.CLASSIC, - STRICT: false, - REMOTENESS: 15000, - USE_PROPORTION: true, - PROPORTION: 0.3, - USE_AZIMUTH: true, - AZIMUTH_MARGIN: 10, - MAX_DETOUR_DISTANCE_RATIO: 0.3, - MAX_DETOUR_DURATION_RATIO: 0.3, - GEOROUTER_TYPE: 'graphhopper', - GEOROUTER_URL: 'http://localhost', - }, -}; - -const matchRequest: MatchRequest = new MatchRequest(); -matchRequest.departure = '2023-04-01 12:00'; -matchRequest.waypoints = [ - { - lat: 49.440041, - lon: 1.093912, - }, - { - lat: 50.630992, - lon: 3.045432, - }, -]; -const matchQuery: MatchQuery = new MatchQuery( - matchRequest, - defaultParams, - mockGeorouterCreator, - mockTimezoneFinder, - mockTimeConverter, -); - -class FakeSelector extends Selector { - select = (): Promise => { - return Promise.resolve([new Candidate()]); - }; -} - -describe('Selector', () => { - it('should create an extended class', () => { - expect(new FakeSelector(matchQuery)).toBeDefined(); - }); -}); diff --git a/old/modules/matcher/tests/unit/domain/match.usecase.spec.ts b/old/modules/matcher/tests/unit/domain/match.usecase.spec.ts deleted file mode 100644 index ef7512a..0000000 --- a/old/modules/matcher/tests/unit/domain/match.usecase.spec.ts +++ /dev/null @@ -1,133 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { MatchUseCase } from '../../../domain/usecases/match.usecase'; -import { MatchRequest } from '../../../domain/dtos/match.request'; -import { MatchQuery } from '../../../queries/match.query'; -import { AutomapperModule } from '@automapper/nestjs'; -import { classes } from '@automapper/classes'; -import { IDefaultParams } from '../../../domain/types/default-params.type'; -import { AlgorithmType } from '../../../domain/types/algorithm.enum'; -import { Matcher } from '../../../domain/entities/engine/matcher'; -import { Match } from '../../../domain/entities/ecosystem/match'; -import { - MatcherException, - MatcherExceptionCode, -} from '../../../exceptions/matcher.exception'; -import { MESSAGE_PUBLISHER } from '../../../../../app.constants'; - -const mockMatcher = { - match: jest - .fn() - .mockImplementationOnce(() => [new Match(), new Match(), new Match()]) - .mockImplementationOnce(() => { - throw new MatcherException( - MatcherExceptionCode.INTERNAL, - 'Something terrible happened !', - ); - }), -}; - -const mockMessagePublisher = { - publish: jest.fn().mockImplementation(), -}; - -const mockGeorouterCreator = { - create: jest.fn().mockImplementation(), -}; - -const mockTimezoneFinder = { - timezones: jest.fn().mockImplementation(() => ['Europe/Paris']), -}; - -const mockTimeConverter = { - toUtcDate: jest.fn(), -}; - -const defaultParams: IDefaultParams = { - DEFAULT_UUID: '00000000-0000-0000-0000-000000000000', - MARGIN_DURATION: 900, - VALIDITY_DURATION: 365, - DEFAULT_TIMEZONE: 'Europe/Paris', - DEFAULT_SEATS: 3, - DEFAULT_ALGORITHM_SETTINGS: { - ALGORITHM: AlgorithmType.CLASSIC, - STRICT: false, - REMOTENESS: 15000, - USE_PROPORTION: true, - PROPORTION: 0.3, - USE_AZIMUTH: true, - AZIMUTH_MARGIN: 10, - MAX_DETOUR_DISTANCE_RATIO: 0.3, - MAX_DETOUR_DURATION_RATIO: 0.3, - GEOROUTER_TYPE: 'graphhopper', - GEOROUTER_URL: 'http://localhost', - }, -}; - -const matchRequest: MatchRequest = new MatchRequest(); -matchRequest.waypoints = [ - { - lon: 1.093912, - lat: 49.440041, - }, - { - lat: 50.630992, - lon: 3.045432, - }, -]; -matchRequest.departure = '2023-04-01 12:23:00'; - -describe('MatchUseCase', () => { - let matchUseCase: MatchUseCase; - - beforeAll(async () => { - const module: TestingModule = await Test.createTestingModule({ - imports: [AutomapperModule.forRoot({ strategyInitializer: classes() })], - providers: [ - { - provide: MESSAGE_PUBLISHER, - useValue: mockMessagePublisher, - }, - { - provide: Matcher, - useValue: mockMatcher, - }, - MatchUseCase, - ], - }).compile(); - - matchUseCase = module.get(MatchUseCase); - }); - - it('should be defined', () => { - expect(matchUseCase).toBeDefined(); - }); - - describe('execute', () => { - it('should return matches', async () => { - const matches = await matchUseCase.execute( - new MatchQuery( - matchRequest, - defaultParams, - mockGeorouterCreator, - mockTimezoneFinder, - mockTimeConverter, - ), - ); - expect(matches.total).toBe(3); - }); - - it('should throw an exception when error occurs', async () => { - await expect( - matchUseCase.execute( - new MatchQuery( - matchRequest, - defaultParams, - mockGeorouterCreator, - mockTimezoneFinder, - mockTimeConverter, - ), - ), - ).rejects.toBeInstanceOf(MatcherException); - }); - }); -}); diff --git a/old/modules/matcher/tests/unit/queries/match.query.spec.ts b/old/modules/matcher/tests/unit/queries/match.query.spec.ts deleted file mode 100644 index b11a0e5..0000000 --- a/old/modules/matcher/tests/unit/queries/match.query.spec.ts +++ /dev/null @@ -1,262 +0,0 @@ -import { MatchRequest } from '../../../domain/dtos/match.request'; -import { Role } from '../../../domain/types/role.enum'; -import { IDefaultParams } from '../../../domain/types/default-params.type'; -import { MatchQuery } from '../../../queries/match.query'; -import { AlgorithmType } from '../../../domain/types/algorithm.enum'; -import { Frequency } from '../../../../ad/domain/types/frequency.enum'; -import { Mode } from '../../../domain/types/mode.enum'; - -const defaultParams: IDefaultParams = { - DEFAULT_UUID: '00000000-0000-0000-0000-000000000000', - MARGIN_DURATION: 900, - VALIDITY_DURATION: 365, - DEFAULT_TIMEZONE: 'Europe/Paris', - DEFAULT_SEATS: 3, - DEFAULT_ALGORITHM_SETTINGS: { - ALGORITHM: AlgorithmType.CLASSIC, - STRICT: false, - REMOTENESS: 15000, - USE_PROPORTION: true, - PROPORTION: 0.3, - USE_AZIMUTH: true, - AZIMUTH_MARGIN: 10, - MAX_DETOUR_DISTANCE_RATIO: 0.3, - MAX_DETOUR_DURATION_RATIO: 0.3, - GEOROUTER_TYPE: 'graphhopper', - GEOROUTER_URL: 'http://localhost', - }, -}; - -const mockGeorouterCreator = { - create: jest.fn().mockImplementation(), -}; - -const mockTimezoneFinder = { - timezones: jest.fn().mockImplementation(() => ['Europe/Paris']), -}; - -const mockTimeConverter = { - toUtcDate: jest.fn(), -}; - -describe('Match query', () => { - it('should be defined', () => { - const matchRequest: MatchRequest = new MatchRequest(); - matchRequest.departure = '2023-04-01 12:00'; - matchRequest.waypoints = [ - { - lat: 49.440041, - lon: 1.093912, - }, - { - lat: 50.630992, - lon: 3.045432, - }, - ]; - const matchQuery: MatchQuery = new MatchQuery( - matchRequest, - defaultParams, - mockGeorouterCreator, - mockTimezoneFinder, - mockTimeConverter, - ); - expect(matchQuery).toBeDefined(); - expect(matchQuery.mode).toBe(Mode.MATCH); - }); - - it('should create a query with publish and match mode', () => { - const matchRequest: MatchRequest = new MatchRequest(); - matchRequest.departure = '2023-04-01 12:00'; - matchRequest.waypoints = [ - { - lat: 49.440041, - lon: 1.093912, - }, - { - lat: 50.630992, - lon: 3.045432, - }, - ]; - matchRequest.mode = Mode.PUBLISH_AND_MATCH; - const matchQuery: MatchQuery = new MatchQuery( - matchRequest, - defaultParams, - mockGeorouterCreator, - mockTimezoneFinder, - mockTimeConverter, - ); - expect(matchQuery.mode).toBe(Mode.PUBLISH_AND_MATCH); - }); - - it('should create a query with excluded identifiers', () => { - const matchRequest: MatchRequest = new MatchRequest(); - matchRequest.departure = '2023-04-01 12:00'; - matchRequest.waypoints = [ - { - lat: 49.440041, - lon: 1.093912, - }, - { - lat: 50.630992, - lon: 3.045432, - }, - ]; - matchRequest.uuid = '445aa6e4-99e4-4899-9456-3be8c3ada368'; - matchRequest.exclusions = [ - 'eacf5e53-e63c-4551-860c-73f95b8a8895', - 'a4098161-13a9-4e55-8999-de134fbf89c4', - 'b18f7ffa-20b9-4a1a-89bc-e238ea8289f3', - ]; - const matchQuery: MatchQuery = new MatchQuery( - matchRequest, - defaultParams, - mockGeorouterCreator, - mockTimezoneFinder, - mockTimeConverter, - ); - expect(matchQuery.exclusions.length).toBe(4); - }); - - it('should create a query with driver role only', () => { - const matchRequest: MatchRequest = new MatchRequest(); - matchRequest.departure = '2023-04-01 12:00'; - matchRequest.waypoints = [ - { - lat: 49.440041, - lon: 1.093912, - }, - { - lat: 50.630992, - lon: 3.045432, - }, - ]; - matchRequest.driver = true; - const matchQuery: MatchQuery = new MatchQuery( - matchRequest, - defaultParams, - mockGeorouterCreator, - mockTimezoneFinder, - mockTimeConverter, - ); - expect(matchQuery.roles).toEqual([Role.DRIVER]); - }); - - it('should create a query with passenger role only', () => { - const matchRequest: MatchRequest = new MatchRequest(); - matchRequest.departure = '2023-04-01 12:00'; - matchRequest.waypoints = [ - { - lat: 49.440041, - lon: 1.093912, - }, - { - lat: 50.630992, - lon: 3.045432, - }, - ]; - matchRequest.passenger = true; - const matchQuery: MatchQuery = new MatchQuery( - matchRequest, - defaultParams, - mockGeorouterCreator, - mockTimezoneFinder, - mockTimeConverter, - ); - expect(matchQuery.roles).toEqual([Role.PASSENGER]); - }); - - it('should create a query with driver and passenger roles', () => { - const matchRequest: MatchRequest = new MatchRequest(); - matchRequest.departure = '2023-04-01 12:00'; - matchRequest.waypoints = [ - { - lat: 49.440041, - lon: 1.093912, - }, - { - lat: 50.630992, - lon: 3.045432, - }, - ]; - matchRequest.passenger = true; - matchRequest.driver = true; - const matchQuery: MatchQuery = new MatchQuery( - matchRequest, - defaultParams, - mockGeorouterCreator, - mockTimezoneFinder, - mockTimeConverter, - ); - expect(matchQuery.roles.length).toBe(2); - expect(matchQuery.roles).toContain(Role.PASSENGER); - expect(matchQuery.roles).toContain(Role.DRIVER); - }); - - it('should create a query with number of seats modified', () => { - const matchRequest: MatchRequest = new MatchRequest(); - matchRequest.departure = '2023-04-01 12:00'; - matchRequest.waypoints = [ - { - lat: 49.440041, - lon: 1.093912, - }, - { - lat: 50.630992, - lon: 3.045432, - }, - ]; - matchRequest.seatsDriver = 1; - matchRequest.seatsPassenger = 2; - const matchQuery: MatchQuery = new MatchQuery( - matchRequest, - defaultParams, - mockGeorouterCreator, - mockTimezoneFinder, - mockTimeConverter, - ); - expect(matchQuery.requirement.seatsDriver).toBe(1); - expect(matchQuery.requirement.seatsPassenger).toBe(2); - }); - - it('should create a query with modified algorithm settings', () => { - const matchRequest: MatchRequest = new MatchRequest(); - matchRequest.departure = '2023-04-01 12:00'; - matchRequest.waypoints = [ - { - lat: 49.440041, - lon: 1.093912, - }, - { - lat: 50.630992, - lon: 3.045432, - }, - ]; - matchRequest.algorithm = AlgorithmType.CLASSIC; - matchRequest.strict = true; - matchRequest.useProportion = true; - matchRequest.proportion = 0.45; - matchRequest.useAzimuth = true; - matchRequest.azimuthMargin = 15; - matchRequest.remoteness = 20000; - matchRequest.maxDetourDistanceRatio = 0.41; - matchRequest.maxDetourDurationRatio = 0.42; - const matchQuery: MatchQuery = new MatchQuery( - matchRequest, - defaultParams, - mockGeorouterCreator, - mockTimezoneFinder, - mockTimeConverter, - ); - expect(matchQuery.algorithmSettings.algorithmType).toBe( - AlgorithmType.CLASSIC, - ); - expect(matchQuery.algorithmSettings.restrict).toBe(Frequency.PUNCTUAL); - expect(matchQuery.algorithmSettings.useProportion).toBeTruthy(); - expect(matchQuery.algorithmSettings.proportion).toBe(0.45); - expect(matchQuery.algorithmSettings.useAzimuth).toBeTruthy(); - expect(matchQuery.algorithmSettings.azimuthMargin).toBe(15); - expect(matchQuery.algorithmSettings.remoteness).toBe(20000); - expect(matchQuery.algorithmSettings.maxDetourDistanceRatio).toBe(0.41); - expect(matchQuery.algorithmSettings.maxDetourDurationRatio).toBe(0.42); - }); -}); diff --git a/old/modules/utils/exception-code.enum.ts b/old/modules/utils/exception-code.enum.ts deleted file mode 100644 index 59554ae..0000000 --- a/old/modules/utils/exception-code.enum.ts +++ /dev/null @@ -1,19 +0,0 @@ -export enum ExceptionCode { - 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, -} diff --git a/old/modules/utils/pipes/rpc.validation-pipe.ts b/old/modules/utils/pipes/rpc.validation-pipe.ts deleted file mode 100644 index f2b8c19..0000000 --- a/old/modules/utils/pipes/rpc.validation-pipe.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Injectable, ValidationPipe } from '@nestjs/common'; -import { RpcException } from '@nestjs/microservices'; - -@Injectable() -export class RpcValidationPipe extends ValidationPipe { - createExceptionFactory() { - return (validationErrors = []) => { - return new RpcException({ - code: 3, - message: this.flattenValidationErrors(validationErrors), - }); - }; - } -} diff --git a/old/modules/utils/tests/unit/rpc-validation-pipe.usecase.spec.ts b/old/modules/utils/tests/unit/rpc-validation-pipe.usecase.spec.ts deleted file mode 100644 index 911466c..0000000 --- a/old/modules/utils/tests/unit/rpc-validation-pipe.usecase.spec.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { ArgumentMetadata } from '@nestjs/common'; -import { RpcValidationPipe } from '../../pipes/rpc.validation-pipe'; -import { MatchRequest } from '../../../matcher/domain/dtos/match.request'; - -describe('RpcValidationPipe', () => { - it('should not validate request', async () => { - const target: RpcValidationPipe = new RpcValidationPipe({ - whitelist: true, - forbidUnknownValues: false, - }); - const metadata: ArgumentMetadata = { - type: 'body', - metatype: MatchRequest, - data: '', - }; - await target.transform({}, metadata).catch((err) => { - expect(err.message).toEqual('Rpc Exception'); - }); - }); -}); diff --git a/src/main.ts b/src/main.ts index 0daaf12..8db905d 100644 --- a/src/main.ts +++ b/src/main.ts @@ -11,11 +11,8 @@ async function bootstrap() { app.connectMicroservice({ transport: Transport.GRPC, options: { - package: ['matcher', 'health'], - protoPath: [ - join(__dirname, 'modules/matcher/adapters/primaries/matcher.proto'), - join(__dirname, 'modules/health/adapters/primaries/health.proto'), - ], + package: ['health'], + protoPath: [join(__dirname, 'health.proto')], url: process.env.SERVICE_URL + ':' + process.env.SERVICE_PORT, loader: { keepCase: true }, }, diff --git a/src/modules/ad/ad.module.ts b/src/modules/ad/ad.module.ts index a98751d..3bfdd2e 100644 --- a/src/modules/ad/ad.module.ts +++ b/src/modules/ad/ad.module.ts @@ -5,6 +5,7 @@ import { AD_REPOSITORY, AD_DIRECTION_ENCODER, AD_ROUTE_PROVIDER, + AD_GET_BASIC_ROUTE_CONTROLLER, } from './ad.di-tokens'; import { MessageBrokerPublisher } from '@mobicoop/message-broker-module'; import { AdRepository } from './infrastructure/ad.repository'; @@ -12,7 +13,9 @@ import { PrismaService } from './infrastructure/prisma.service'; import { AdMapper } from './ad.mapper'; import { AdCreatedMessageHandler } from './interface/message-handlers/ad-created.message-handler'; import { PostgresDirectionEncoder } from '@modules/geography/infrastructure/postgres-direction-encoder'; -import { GetRouteController } from '@modules/geography/interface/controllers/get-route.controller'; +import { GetBasicRouteController } from '@modules/geography/interface/controllers/get-basic-route.controller'; +import { RouteProvider } from './infrastructure/route-provider'; +import { GeographyModule } from '@modules/geography/geography.module'; const messageHandlers = [AdCreatedMessageHandler]; @@ -41,12 +44,16 @@ const adapters: Provider[] = [ }, { provide: AD_ROUTE_PROVIDER, - useClass: GetRouteController, + useClass: RouteProvider, + }, + { + provide: AD_GET_BASIC_ROUTE_CONTROLLER, + useClass: GetBasicRouteController, }, ]; @Module({ - imports: [CqrsModule], + imports: [CqrsModule, GeographyModule], providers: [ ...messageHandlers, ...mappers, diff --git a/src/modules/geography/geography.module.ts b/src/modules/geography/geography.module.ts index 192f6df..e1a0c46 100644 --- a/src/modules/geography/geography.module.ts +++ b/src/modules/geography/geography.module.ts @@ -4,6 +4,9 @@ import { DIRECTION_ENCODER, PARAMS_PROVIDER } from './geography.di-tokens'; import { DefaultParamsProvider } from './infrastructure/default-params-provider'; import { PostgresDirectionEncoder } from './infrastructure/postgres-direction-encoder'; import { GetBasicRouteController } from './interface/controllers/get-basic-route.controller'; +import { RouteMapper } from './route.mapper'; + +const mappers: Provider[] = [RouteMapper]; const adapters: Provider[] = [ { @@ -19,7 +22,7 @@ const adapters: Provider[] = [ @Module({ imports: [CqrsModule], - providers: [...adapters], - exports: [DIRECTION_ENCODER, GetBasicRouteController], + providers: [...mappers, ...adapters], + exports: [RouteMapper, DIRECTION_ENCODER, GetBasicRouteController], }) export class GeographyModule {}