create ad WIP, extract geography methods to dedicated module
This commit is contained in:
parent
ca693087d2
commit
aeead7fb62
|
@ -1,65 +0,0 @@
|
||||||
-- CreateExtension
|
|
||||||
CREATE EXTENSION IF NOT EXISTS "postgis";
|
|
||||||
|
|
||||||
-- Required to use postgis extension :
|
|
||||||
-- set the search_path to both public and territory (where is postgis) AND the current schema
|
|
||||||
SET search_path TO matcher, territory, public;
|
|
||||||
|
|
||||||
-- CreateTable
|
|
||||||
CREATE TABLE "ad" (
|
|
||||||
"uuid" UUID NOT NULL,
|
|
||||||
"driver" BOOLEAN NOT NULL,
|
|
||||||
"passenger" BOOLEAN NOT NULL,
|
|
||||||
"frequency" INTEGER NOT NULL,
|
|
||||||
"from_date" DATE NOT NULL,
|
|
||||||
"to_date" DATE NOT NULL,
|
|
||||||
"mon_time" TIMESTAMPTZ NOT NULL,
|
|
||||||
"tue_time" TIMESTAMPTZ NOT NULL,
|
|
||||||
"wed_time" TIMESTAMPTZ NOT NULL,
|
|
||||||
"thu_time" TIMESTAMPTZ NOT NULL,
|
|
||||||
"fri_time" TIMESTAMPTZ NOT NULL,
|
|
||||||
"sat_time" TIMESTAMPTZ NOT NULL,
|
|
||||||
"sun_time" TIMESTAMPTZ NOT NULL,
|
|
||||||
"mon_margin" INTEGER NOT NULL,
|
|
||||||
"tue_margin" INTEGER NOT NULL,
|
|
||||||
"wed_margin" INTEGER NOT NULL,
|
|
||||||
"thu_margin" INTEGER NOT NULL,
|
|
||||||
"fri_margin" INTEGER NOT NULL,
|
|
||||||
"sat_margin" INTEGER NOT NULL,
|
|
||||||
"sun_margin" INTEGER NOT NULL,
|
|
||||||
"driver_duration" INTEGER NOT NULL,
|
|
||||||
"driver_distance" INTEGER NOT NULL,
|
|
||||||
"passenger_duration" INTEGER NOT NULL,
|
|
||||||
"passenger_distance" INTEGER NOT NULL,
|
|
||||||
"origin_type" SMALLINT NOT NULL,
|
|
||||||
"destination_type" SMALLINT NOT NULL,
|
|
||||||
"waypoints" geography(LINESTRING) NOT NULL,
|
|
||||||
"direction" geography(LINESTRING) NOT NULL,
|
|
||||||
"fwd_azimuth" INTEGER NOT NULL,
|
|
||||||
"back_azimuth" INTEGER NOT NULL,
|
|
||||||
"seats_driver" SMALLINT NOT NULL,
|
|
||||||
"seats_passenger" SMALLINT NOT NULL,
|
|
||||||
"seats_used" SMALLINT NOT NULL,
|
|
||||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
|
|
||||||
CONSTRAINT "ad_pkey" PRIMARY KEY ("uuid")
|
|
||||||
);
|
|
||||||
|
|
||||||
-- CreateIndex
|
|
||||||
CREATE INDEX "ad_driver_idx" ON "ad"("driver");
|
|
||||||
|
|
||||||
-- CreateIndex
|
|
||||||
CREATE INDEX "ad_passenger_idx" ON "ad"("passenger");
|
|
||||||
|
|
||||||
-- CreateIndex
|
|
||||||
CREATE INDEX "ad_from_date_idx" ON "ad"("from_date");
|
|
||||||
|
|
||||||
-- CreateIndex
|
|
||||||
CREATE INDEX "ad_to_date_idx" ON "ad"("to_date");
|
|
||||||
|
|
||||||
-- CreateIndex
|
|
||||||
CREATE INDEX "ad_fwd_azimuth_idx" ON "ad"("fwd_azimuth");
|
|
||||||
|
|
||||||
-- CreateIndex
|
|
||||||
CREATE INDEX "direction_idx" ON "ad" USING GIST ("direction");
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
-- CreateExtension
|
||||||
|
CREATE EXTENSION IF NOT EXISTS "postgis";
|
||||||
|
|
||||||
|
-- Required to use postgis extension :
|
||||||
|
-- set the search_path to both public and territory (where is postgis) AND the current schema
|
||||||
|
SET search_path TO matcher, territory, public;
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "ad" (
|
||||||
|
"uuid" UUID NOT NULL,
|
||||||
|
"driver" BOOLEAN NOT NULL,
|
||||||
|
"passenger" BOOLEAN NOT NULL,
|
||||||
|
"frequency" INTEGER NOT NULL,
|
||||||
|
"fromDate" DATE NOT NULL,
|
||||||
|
"toDate" DATE NOT NULL,
|
||||||
|
"monTime" TIMESTAMPTZ NOT NULL,
|
||||||
|
"tueTime" TIMESTAMPTZ NOT NULL,
|
||||||
|
"wedTime" TIMESTAMPTZ NOT NULL,
|
||||||
|
"thuTime" TIMESTAMPTZ NOT NULL,
|
||||||
|
"friTime" TIMESTAMPTZ NOT NULL,
|
||||||
|
"satTime" TIMESTAMPTZ NOT NULL,
|
||||||
|
"sunTime" TIMESTAMPTZ NOT NULL,
|
||||||
|
"monMargin" INTEGER NOT NULL,
|
||||||
|
"tueMargin" INTEGER NOT NULL,
|
||||||
|
"wedMargin" INTEGER NOT NULL,
|
||||||
|
"thuMargin" INTEGER NOT NULL,
|
||||||
|
"friMargin" INTEGER NOT NULL,
|
||||||
|
"satMargin" INTEGER NOT NULL,
|
||||||
|
"sunMargin" INTEGER NOT NULL,
|
||||||
|
"driverDuration" INTEGER NOT NULL,
|
||||||
|
"driverDistance" INTEGER NOT NULL,
|
||||||
|
"passengerDuration" INTEGER NOT NULL,
|
||||||
|
"passengerDistance" INTEGER NOT NULL,
|
||||||
|
"originType" SMALLINT NOT NULL,
|
||||||
|
"destinationType" SMALLINT NOT NULL,
|
||||||
|
"waypoints" geography(LINESTRING),
|
||||||
|
"direction" geography(LINESTRING),
|
||||||
|
"fwdAzimuth" INTEGER NOT NULL,
|
||||||
|
"backAzimuth" INTEGER NOT NULL,
|
||||||
|
"seatsDriver" SMALLINT NOT NULL,
|
||||||
|
"seatsPassenger" SMALLINT NOT NULL,
|
||||||
|
"seatsUsed" SMALLINT NOT NULL,
|
||||||
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
|
||||||
|
CONSTRAINT "ad_pkey" PRIMARY KEY ("uuid")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "ad_driver_idx" ON "ad"("driver");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "ad_passenger_idx" ON "ad"("passenger");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "ad_fromDate_idx" ON "ad"("fromDate");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "ad_toDate_idx" ON "ad"("toDate");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "ad_fwdAzimuth_idx" ON "ad"("fwdAzimuth");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "direction_idx" ON "ad" USING GIST ("direction");
|
|
@ -17,43 +17,43 @@ model Ad {
|
||||||
driver Boolean
|
driver Boolean
|
||||||
passenger Boolean
|
passenger Boolean
|
||||||
frequency Int
|
frequency Int
|
||||||
from_date DateTime @db.Date
|
fromDate DateTime @db.Date
|
||||||
to_date DateTime @db.Date
|
toDate DateTime @db.Date
|
||||||
mon_time DateTime @db.Timestamptz()
|
monTime DateTime @db.Timestamptz()
|
||||||
tue_time DateTime @db.Timestamptz()
|
tueTime DateTime @db.Timestamptz()
|
||||||
wed_time DateTime @db.Timestamptz()
|
wedTime DateTime @db.Timestamptz()
|
||||||
thu_time DateTime @db.Timestamptz()
|
thuTime DateTime @db.Timestamptz()
|
||||||
fri_time DateTime @db.Timestamptz()
|
friTime DateTime @db.Timestamptz()
|
||||||
sat_time DateTime @db.Timestamptz()
|
satTime DateTime @db.Timestamptz()
|
||||||
sun_time DateTime @db.Timestamptz()
|
sunTime DateTime @db.Timestamptz()
|
||||||
mon_margin Int
|
monMargin Int
|
||||||
tue_margin Int
|
tueMargin Int
|
||||||
wed_margin Int
|
wedMargin Int
|
||||||
thu_margin Int
|
thuMargin Int
|
||||||
fri_margin Int
|
friMargin Int
|
||||||
sat_margin Int
|
satMargin Int
|
||||||
sun_margin Int
|
sunMargin Int
|
||||||
driver_duration Int
|
driverDuration Int
|
||||||
driver_distance Int
|
driverDistance Int
|
||||||
passenger_duration Int
|
passengerDuration Int
|
||||||
passenger_distance Int
|
passengerDistance Int
|
||||||
origin_type Int @db.SmallInt
|
originType Int @db.SmallInt
|
||||||
destination_type Int @db.SmallInt
|
destinationType Int @db.SmallInt
|
||||||
waypoints Unsupported("geography(LINESTRING)")
|
waypoints Unsupported("geography(LINESTRING)")?
|
||||||
direction Unsupported("geography(LINESTRING)")
|
direction Unsupported("geography(LINESTRING)")?
|
||||||
fwd_azimuth Int
|
fwdAzimuth Int
|
||||||
back_azimuth Int
|
backAzimuth Int
|
||||||
seats_driver Int @db.SmallInt
|
seatsDriver Int @db.SmallInt
|
||||||
seats_passenger Int @db.SmallInt
|
seatsPassenger Int @db.SmallInt
|
||||||
seats_used Int @db.SmallInt
|
seatsUsed Int @db.SmallInt
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @default(now()) @updatedAt
|
updatedAt DateTime @default(now()) @updatedAt
|
||||||
|
|
||||||
@@index([driver])
|
@@index([driver])
|
||||||
@@index([passenger])
|
@@index([passenger])
|
||||||
@@index([from_date])
|
@@index([fromDate])
|
||||||
@@index([to_date])
|
@@index([toDate])
|
||||||
@@index([fwd_azimuth])
|
@@index([fwdAzimuth])
|
||||||
@@index([direction], name: "direction_idx", type: Gist)
|
@@index([direction], name: "direction_idx", type: Gist)
|
||||||
@@map("ad")
|
@@map("ad")
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,16 @@ import { RabbitMQModule } from '@golevelup/nestjs-rabbitmq';
|
||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
import { ConfigModule, ConfigService } from '@nestjs/config';
|
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||||
import { AdMessagerController } from './adapters/primaries/ad-messager.controller';
|
import { AdMessagerController } from './adapters/primaries/ad-messager.controller';
|
||||||
|
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';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
|
DatabaseModule,
|
||||||
|
CqrsModule,
|
||||||
RabbitMQModule.forRootAsync(RabbitMQModule, {
|
RabbitMQModule.forRootAsync(RabbitMQModule, {
|
||||||
imports: [ConfigModule],
|
imports: [ConfigModule],
|
||||||
useFactory: async (configService: ConfigService) => ({
|
useFactory: async (configService: ConfigService) => ({
|
||||||
|
@ -18,9 +25,7 @@ import { AdMessagerController } from './adapters/primaries/ad-messager.controlle
|
||||||
adCreated: {
|
adCreated: {
|
||||||
exchange: configService.get<string>('RMQ_EXCHANGE'),
|
exchange: configService.get<string>('RMQ_EXCHANGE'),
|
||||||
routingKey: 'ad.created',
|
routingKey: 'ad.created',
|
||||||
queue: `${configService.get<string>(
|
queue: 'matcher-ad-created',
|
||||||
'RMQ_EXCHANGE',
|
|
||||||
)}-matcher-ad-created`,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
uri: configService.get<string>('RMQ_URI'),
|
uri: configService.get<string>('RMQ_URI'),
|
||||||
|
@ -31,7 +36,7 @@ import { AdMessagerController } from './adapters/primaries/ad-messager.controlle
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
controllers: [AdMessagerController],
|
controllers: [AdMessagerController],
|
||||||
providers: [],
|
providers: [AdProfile, AdRepository, CreateAdUseCase],
|
||||||
exports: [],
|
exports: [],
|
||||||
})
|
})
|
||||||
export class AdModule {}
|
export class AdModule {}
|
||||||
|
|
|
@ -1,19 +1,32 @@
|
||||||
import { RabbitSubscribe } from '@golevelup/nestjs-rabbitmq';
|
import { RabbitSubscribe } from '@golevelup/nestjs-rabbitmq';
|
||||||
import { Controller } from '@nestjs/common';
|
import { Controller } from '@nestjs/common';
|
||||||
// import { Ad } from '../../domain/entities/ad';
|
import { Ad } from '../../domain/entities/ad';
|
||||||
|
import { InjectMapper } from '@automapper/nestjs';
|
||||||
|
import { Mapper } from '@automapper/core';
|
||||||
|
import { CommandBus } from '@nestjs/cqrs';
|
||||||
|
import { CreateAdCommand } from '../../commands/create-ad.command';
|
||||||
|
import { AdPresenter } from './ad.presenter';
|
||||||
|
import { CreateAdRequest } from '../../domain/dtos/create-ad.request';
|
||||||
|
|
||||||
@Controller()
|
@Controller()
|
||||||
export class AdMessagerController {
|
export class AdMessagerController {
|
||||||
|
constructor(
|
||||||
|
private readonly _commandBus: CommandBus,
|
||||||
|
@InjectMapper() private readonly _mapper: Mapper,
|
||||||
|
) {}
|
||||||
|
|
||||||
@RabbitSubscribe({
|
@RabbitSubscribe({
|
||||||
name: 'adCreated',
|
name: 'adCreated',
|
||||||
})
|
})
|
||||||
public adCreatedHandler(message: string) {
|
async adCreatedHandler(message: string): Promise<AdPresenter> {
|
||||||
console.log(JSON.parse(message));
|
try {
|
||||||
// try {
|
const createAdRequest: CreateAdRequest = JSON.parse(message);
|
||||||
// const createdAd: Ad = JSON.parse(message);
|
const ad: Ad = await this._commandBus.execute(
|
||||||
// console.log(createdAd);
|
new CreateAdCommand(createAdRequest),
|
||||||
// } catch (e) {
|
);
|
||||||
// console.log('error', e);
|
return this._mapper.map(ad, Ad, AdPresenter);
|
||||||
// }
|
} catch (e) {
|
||||||
|
console.log('error', e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { AutoMap } from '@automapper/classes';
|
import { AutoMap } from '@automapper/classes';
|
||||||
|
|
||||||
export class Ad {
|
export class AdPresenter {
|
||||||
@AutoMap()
|
@AutoMap()
|
||||||
uuid: string;
|
uuid: string;
|
||||||
}
|
}
|
|
@ -0,0 +1,79 @@
|
||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { MatcherRepository } from '../../../database/src/domain/matcher-repository';
|
||||||
|
import { Ad } from '../../domain/entities/ad';
|
||||||
|
import { DatabaseException } from '../../../database/src/exceptions/database.exception';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class AdRepository extends MatcherRepository<Ad> {
|
||||||
|
protected _model = 'ad';
|
||||||
|
|
||||||
|
async createAd(ad: Partial<Ad>): Promise<Ad> {
|
||||||
|
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<Ad>): Partial<AdFields> {
|
||||||
|
return {
|
||||||
|
uuid: `'${ad.uuid}'`,
|
||||||
|
driver: ad.driver ? 'true' : 'false',
|
||||||
|
passenger: ad.passenger ? 'true' : 'false',
|
||||||
|
frequency: ad.frequency,
|
||||||
|
fromDate: `'${ad.fromDate}'`,
|
||||||
|
toDate: `'${ad.toDate}'`,
|
||||||
|
monTime: `'${ad.monTime}'`,
|
||||||
|
tueTime: `'${ad.tueTime}'`,
|
||||||
|
wedTime: `'${ad.wedTime}'`,
|
||||||
|
thuTime: `'${ad.thuTime}'`,
|
||||||
|
friTime: `'${ad.friTime}'`,
|
||||||
|
satTime: `'${ad.satTime}'`,
|
||||||
|
sunTime: `'${ad.sunTime}'`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type AdFields = {
|
||||||
|
uuid: string;
|
||||||
|
driver: string;
|
||||||
|
passenger: string;
|
||||||
|
frequency: number;
|
||||||
|
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;
|
||||||
|
driverDistance: number;
|
||||||
|
passengerDuration: number;
|
||||||
|
passengerDistance: number;
|
||||||
|
originType: number;
|
||||||
|
destinationType: number;
|
||||||
|
waypoints: string;
|
||||||
|
direction: string;
|
||||||
|
fwdAzimuth: number;
|
||||||
|
backAzimuth: number;
|
||||||
|
seatsDriver: number;
|
||||||
|
seatsPassenger: number;
|
||||||
|
seatsUsed: number;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
};
|
|
@ -0,0 +1,9 @@
|
||||||
|
import { CreateAdRequest } from '../domain/dtos/create-ad.request';
|
||||||
|
|
||||||
|
export class CreateAdCommand {
|
||||||
|
readonly createAdRequest: CreateAdRequest;
|
||||||
|
|
||||||
|
constructor(request: CreateAdRequest) {
|
||||||
|
this.createAdRequest = request;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,116 @@
|
||||||
|
import { AutoMap } from '@automapper/classes';
|
||||||
|
import { IsBoolean, IsNotEmpty, IsNumber, IsString } from 'class-validator';
|
||||||
|
|
||||||
|
export class CreateAdRequest {
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
@AutoMap()
|
||||||
|
uuid: string;
|
||||||
|
|
||||||
|
@IsBoolean()
|
||||||
|
@AutoMap()
|
||||||
|
driver: boolean;
|
||||||
|
|
||||||
|
@IsBoolean()
|
||||||
|
@AutoMap()
|
||||||
|
passenger: boolean;
|
||||||
|
|
||||||
|
@IsNumber()
|
||||||
|
@AutoMap()
|
||||||
|
frequency: number;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@AutoMap()
|
||||||
|
fromDate: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@AutoMap()
|
||||||
|
toDate: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@AutoMap()
|
||||||
|
monTime: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@AutoMap()
|
||||||
|
tueTime: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@AutoMap()
|
||||||
|
wedTime: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@AutoMap()
|
||||||
|
thuTime: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@AutoMap()
|
||||||
|
friTime: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@AutoMap()
|
||||||
|
satTime: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@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;
|
||||||
|
|
||||||
|
@IsNumber()
|
||||||
|
@AutoMap()
|
||||||
|
originType: number;
|
||||||
|
|
||||||
|
@IsNumber()
|
||||||
|
@AutoMap()
|
||||||
|
destinationType: number;
|
||||||
|
|
||||||
|
@AutoMap()
|
||||||
|
waypoints: [];
|
||||||
|
|
||||||
|
@IsNumber()
|
||||||
|
@AutoMap()
|
||||||
|
seatsDriver: number;
|
||||||
|
|
||||||
|
@IsNumber()
|
||||||
|
@AutoMap()
|
||||||
|
seatsPassenger: number;
|
||||||
|
|
||||||
|
@IsNumber()
|
||||||
|
@AutoMap()
|
||||||
|
seatsUsed: number;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@AutoMap()
|
||||||
|
createdAt: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@AutoMap()
|
||||||
|
updatedAt: string;
|
||||||
|
}
|
|
@ -4,38 +4,105 @@ export class Ad {
|
||||||
@AutoMap()
|
@AutoMap()
|
||||||
uuid: string;
|
uuid: string;
|
||||||
|
|
||||||
|
@AutoMap()
|
||||||
driver: boolean;
|
driver: boolean;
|
||||||
|
|
||||||
|
@AutoMap()
|
||||||
passenger: boolean;
|
passenger: boolean;
|
||||||
|
|
||||||
|
@AutoMap()
|
||||||
frequency: number;
|
frequency: number;
|
||||||
|
|
||||||
|
@AutoMap()
|
||||||
fromDate: string;
|
fromDate: string;
|
||||||
|
|
||||||
|
@AutoMap()
|
||||||
toDate: string;
|
toDate: string;
|
||||||
|
|
||||||
|
@AutoMap()
|
||||||
monTime: string;
|
monTime: string;
|
||||||
|
|
||||||
|
@AutoMap()
|
||||||
tueTime: string;
|
tueTime: string;
|
||||||
|
|
||||||
|
@AutoMap()
|
||||||
wedTime: string;
|
wedTime: string;
|
||||||
|
|
||||||
|
@AutoMap()
|
||||||
thuTime: string;
|
thuTime: string;
|
||||||
|
|
||||||
|
@AutoMap()
|
||||||
friTime: string;
|
friTime: string;
|
||||||
|
|
||||||
|
@AutoMap()
|
||||||
satTime: string;
|
satTime: string;
|
||||||
|
|
||||||
|
@AutoMap()
|
||||||
sunTime: string;
|
sunTime: string;
|
||||||
|
|
||||||
|
@AutoMap()
|
||||||
monMargin: number;
|
monMargin: number;
|
||||||
|
|
||||||
|
@AutoMap()
|
||||||
tueMargin: number;
|
tueMargin: number;
|
||||||
|
|
||||||
|
@AutoMap()
|
||||||
wedMargin: number;
|
wedMargin: number;
|
||||||
|
|
||||||
|
@AutoMap()
|
||||||
thuMargin: number;
|
thuMargin: number;
|
||||||
|
|
||||||
|
@AutoMap()
|
||||||
friMargin: number;
|
friMargin: number;
|
||||||
|
|
||||||
|
@AutoMap()
|
||||||
satMargin: number;
|
satMargin: number;
|
||||||
|
|
||||||
|
@AutoMap()
|
||||||
sunMargin: number;
|
sunMargin: number;
|
||||||
|
|
||||||
|
@AutoMap()
|
||||||
driverDuration: number;
|
driverDuration: number;
|
||||||
|
|
||||||
|
@AutoMap()
|
||||||
driverDistance: number;
|
driverDistance: number;
|
||||||
|
|
||||||
|
@AutoMap()
|
||||||
passengerDuration: number;
|
passengerDuration: number;
|
||||||
|
|
||||||
|
@AutoMap()
|
||||||
passengerDistance: number;
|
passengerDistance: number;
|
||||||
|
|
||||||
|
@AutoMap()
|
||||||
originType: number;
|
originType: number;
|
||||||
|
|
||||||
|
@AutoMap()
|
||||||
destinationType: number;
|
destinationType: number;
|
||||||
|
|
||||||
|
@AutoMap()
|
||||||
waypoints: [];
|
waypoints: [];
|
||||||
|
|
||||||
|
@AutoMap()
|
||||||
direction: string;
|
direction: string;
|
||||||
|
|
||||||
|
@AutoMap()
|
||||||
fwdAzimuth: number;
|
fwdAzimuth: number;
|
||||||
|
|
||||||
|
@AutoMap()
|
||||||
backAzimuth: number;
|
backAzimuth: number;
|
||||||
|
|
||||||
|
@AutoMap()
|
||||||
seatsDriver: number;
|
seatsDriver: number;
|
||||||
|
|
||||||
|
@AutoMap()
|
||||||
seatsPassenger: number;
|
seatsPassenger: number;
|
||||||
|
|
||||||
|
@AutoMap()
|
||||||
seatsUsed: number;
|
seatsUsed: number;
|
||||||
|
|
||||||
|
@AutoMap()
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
|
|
||||||
|
@AutoMap()
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
import { CommandHandler } from '@nestjs/cqrs';
|
||||||
|
import { CreateAdCommand } from '../../commands/create-ad.command';
|
||||||
|
import { Ad } from '../entities/ad';
|
||||||
|
import { AdRepository } from '../../adapters/secondaries/ad.repository';
|
||||||
|
|
||||||
|
@CommandHandler(CreateAdCommand)
|
||||||
|
export class CreateAdUseCase {
|
||||||
|
constructor(private readonly adRepository: AdRepository) {}
|
||||||
|
|
||||||
|
async execute(command: CreateAdCommand): Promise<Ad> {
|
||||||
|
try {
|
||||||
|
return await this.adRepository.createAd(command.createAdRequest);
|
||||||
|
} catch (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
import { createMap, Mapper } from '@automapper/core';
|
||||||
|
import { AutomapperProfile, InjectMapper } from '@automapper/nestjs';
|
||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { Ad } from '../domain/entities/ad';
|
||||||
|
import { AdPresenter } from '../adapters/primaries/ad.presenter';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class AdProfile extends AutomapperProfile {
|
||||||
|
constructor(@InjectMapper() mapper: Mapper) {
|
||||||
|
super(mapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
override get profile() {
|
||||||
|
return (mapper: any) => {
|
||||||
|
createMap(mapper, Ad, AdPresenter);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,9 @@
|
||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
import { PrismaService } from './src/adapters/secondaries/prisma-service';
|
import { PrismaService } from './src/adapters/secondaries/prisma-service';
|
||||||
import { MatcherRepository } from './src/domain/matcher-repository';
|
import { AdRepository } from '../ad/adapters/secondaries/ad.repository';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
providers: [PrismaService, MatcherRepository],
|
providers: [PrismaService, AdRepository],
|
||||||
exports: [PrismaService, MatcherRepository],
|
exports: [PrismaService, AdRepository],
|
||||||
})
|
})
|
||||||
export class DatabaseModule {}
|
export class DatabaseModule {}
|
||||||
|
|
|
@ -202,9 +202,9 @@ export abstract class PrismaRepository<T> implements IRepository<T> {
|
||||||
|
|
||||||
async createWithFields(fields: object): Promise<number> {
|
async createWithFields(fields: object): Promise<number> {
|
||||||
try {
|
try {
|
||||||
const command = `INSERT INTO ${this._model} (${Object.keys(fields).join(
|
const command = `INSERT INTO ${this._model} ("${Object.keys(fields).join(
|
||||||
',',
|
'","',
|
||||||
)}) VALUES (${Object.values(fields).join(',')})`;
|
)}") VALUES (${Object.values(fields).join(',')})`;
|
||||||
return await this._prisma.$executeRawUnsafe(command);
|
return await this._prisma.$executeRawUnsafe(command);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof Prisma.PrismaClientKnownRequestError) {
|
if (e instanceof Prisma.PrismaClientKnownRequestError) {
|
||||||
|
@ -219,7 +219,7 @@ export abstract class PrismaRepository<T> implements IRepository<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateWithFields(uuid: string, entity: Partial<T>): Promise<number> {
|
async updateWithFields(uuid: string, entity: object): Promise<number> {
|
||||||
entity['"updatedAt"'] = `to_timestamp(${Date.now()} / 1000.0)`;
|
entity['"updatedAt"'] = `to_timestamp(${Date.now()} / 1000.0)`;
|
||||||
const values = Object.keys(entity).map((key) => `${key} = ${entity[key]}`);
|
const values = Object.keys(entity).map((key) => `${key} = ${entity[key]}`);
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
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): Array<string> => find(lat, lon);
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
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 };
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
export interface IFindTimezone {
|
||||||
|
timezones(lon: number, lat: number): Array<string>;
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
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 {}
|
|
@ -0,0 +1,14 @@
|
||||||
|
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');
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,14 @@
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
});
|
|
@ -4,7 +4,7 @@ import {
|
||||||
HealthIndicator,
|
HealthIndicator,
|
||||||
HealthIndicatorResult,
|
HealthIndicatorResult,
|
||||||
} from '@nestjs/terminus';
|
} from '@nestjs/terminus';
|
||||||
import { AdRepository } from '../../../matcher/adapters/secondaries/ad.repository';
|
import { AdRepository } from '../../../ad/adapters/secondaries/ad.repository';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class PrismaHealthIndicatorUseCase extends HealthIndicator {
|
export class PrismaHealthIndicatorUseCase extends HealthIndicator {
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { TerminusModule } from '@nestjs/terminus';
|
||||||
import { RabbitMQModule } from '@golevelup/nestjs-rabbitmq';
|
import { RabbitMQModule } from '@golevelup/nestjs-rabbitmq';
|
||||||
import { ConfigModule, ConfigService } from '@nestjs/config';
|
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||||
import { Messager } from './adapters/secondaries/messager';
|
import { Messager } from './adapters/secondaries/messager';
|
||||||
import { AdRepository } from '../matcher/adapters/secondaries/ad.repository';
|
import { AdRepository } from '../ad/adapters/secondaries/ad.repository';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { Test, TestingModule } from '@nestjs/testing';
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
import { PrismaHealthIndicatorUseCase } from '../../domain/usecases/prisma.health-indicator.usecase';
|
import { PrismaHealthIndicatorUseCase } from '../../domain/usecases/prisma.health-indicator.usecase';
|
||||||
import { HealthCheckError, HealthIndicatorResult } from '@nestjs/terminus';
|
import { HealthCheckError, HealthIndicatorResult } from '@nestjs/terminus';
|
||||||
import { AdRepository } from '../../../matcher/adapters/secondaries/ad.repository';
|
import { AdRepository } from '../../../ad/adapters/secondaries/ad.repository';
|
||||||
import { PrismaClientKnownRequestError } from '@prisma/client/runtime/library';
|
import { PrismaClientKnownRequestError } from '@prisma/client/runtime/library';
|
||||||
|
|
||||||
const mockAdRepository = {
|
const mockAdRepository = {
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { MatchPresenter } from '../secondaries/match.presenter';
|
||||||
import { DefaultParamsProvider } from '../secondaries/default-params.provider';
|
import { DefaultParamsProvider } from '../secondaries/default-params.provider';
|
||||||
import { GeorouterCreator } from '../secondaries/georouter-creator';
|
import { GeorouterCreator } from '../secondaries/georouter-creator';
|
||||||
import { Match } from '../../domain/entities/ecosystem/match';
|
import { Match } from '../../domain/entities/ecosystem/match';
|
||||||
|
import { GeoTimezoneFinder } from '../../../geography/adapters/secondaries/geo-timezone-finder';
|
||||||
|
|
||||||
@UsePipes(
|
@UsePipes(
|
||||||
new RpcValidationPipe({
|
new RpcValidationPipe({
|
||||||
|
@ -21,20 +22,22 @@ import { Match } from '../../domain/entities/ecosystem/match';
|
||||||
@Controller()
|
@Controller()
|
||||||
export class MatcherController {
|
export class MatcherController {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly _queryBus: QueryBus,
|
private readonly queryBus: QueryBus,
|
||||||
private readonly _defaultParamsProvider: DefaultParamsProvider,
|
private readonly defaultParamsProvider: DefaultParamsProvider,
|
||||||
@InjectMapper() private readonly _mapper: Mapper,
|
@InjectMapper() private readonly _mapper: Mapper,
|
||||||
private readonly _georouterCreator: GeorouterCreator,
|
private readonly georouterCreator: GeorouterCreator,
|
||||||
|
private readonly timezoneFinder: GeoTimezoneFinder,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@GrpcMethod('MatcherService', 'Match')
|
@GrpcMethod('MatcherService', 'Match')
|
||||||
async match(data: MatchRequest): Promise<ICollection<Match>> {
|
async match(data: MatchRequest): Promise<ICollection<Match>> {
|
||||||
try {
|
try {
|
||||||
const matchCollection = await this._queryBus.execute(
|
const matchCollection = await this.queryBus.execute(
|
||||||
new MatchQuery(
|
new MatchQuery(
|
||||||
data,
|
data,
|
||||||
this._defaultParamsProvider.getParams(),
|
this.defaultParamsProvider.getParams(),
|
||||||
this._georouterCreator,
|
this.georouterCreator,
|
||||||
|
this.timezoneFinder,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
import { Injectable } from '@nestjs/common';
|
|
||||||
import { MatcherRepository } from '../../../database/src/domain/matcher-repository';
|
|
||||||
import { Ad } from '../../domain/entities/ecosystem/ad';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class AdRepository extends MatcherRepository<Ad> {
|
|
||||||
protected _model = 'ad';
|
|
||||||
}
|
|
|
@ -1,27 +1,16 @@
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { IGeodesic } from '../../domain/interfaces/geodesic.interface';
|
import { Geodesic } from '../../../geography/adapters/secondaries/geodesic';
|
||||||
import { Geodesic, GeodesicClass } from 'geographiclib-geodesic';
|
import { IGeodesic } from '../../../geography/domain/interfaces/geodesic.interface';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class MatcherGeodesic implements IGeodesic {
|
export class MatcherGeodesic implements IGeodesic {
|
||||||
private geod: GeodesicClass;
|
constructor(private readonly geodesic: Geodesic) {}
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.geod = Geodesic.WGS84;
|
|
||||||
}
|
|
||||||
|
|
||||||
inverse = (
|
inverse = (
|
||||||
lon1: number,
|
lon1: number,
|
||||||
lat1: number,
|
lat1: number,
|
||||||
lon2: number,
|
lon2: number,
|
||||||
lat2: number,
|
lat2: number,
|
||||||
): { azimuth: number; distance: number } => {
|
): { azimuth: number; distance: number } =>
|
||||||
const { azi2: azimuth, s12: distance } = this.geod.Inverse(
|
this.geodesic.inverse(lon1, lat1, lon2, lat2);
|
||||||
lat1,
|
|
||||||
lon1,
|
|
||||||
lat2,
|
|
||||||
lon2,
|
|
||||||
);
|
|
||||||
return { azimuth, distance };
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { Path } from '../../domain/types/path.type';
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { catchError, lastValueFrom, map } from 'rxjs';
|
import { catchError, lastValueFrom, map } from 'rxjs';
|
||||||
import { AxiosError, AxiosResponse } from 'axios';
|
import { AxiosError, AxiosResponse } from 'axios';
|
||||||
import { IGeodesic } from '../../domain/interfaces/geodesic.interface';
|
import { IGeodesic } from '../../../geography/domain/interfaces/geodesic.interface';
|
||||||
import { NamedRoute } from '../../domain/entities/ecosystem/named-route';
|
import { NamedRoute } from '../../domain/entities/ecosystem/named-route';
|
||||||
import { Route } from '../../domain/entities/ecosystem/route';
|
import { Route } from '../../domain/entities/ecosystem/route';
|
||||||
import { SpacetimePoint } from '../../domain/entities/ecosystem/spacetime-point';
|
import { SpacetimePoint } from '../../domain/entities/ecosystem/spacetime-point';
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
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): Array<string> =>
|
||||||
|
this.geoTimezoneFinder.timezones(lon, lat);
|
||||||
|
}
|
|
@ -5,7 +5,6 @@ import {
|
||||||
import { IRequestGeography } from '../../interfaces/geography-request.interface';
|
import { IRequestGeography } from '../../interfaces/geography-request.interface';
|
||||||
import { PointType } from '../../types/geography.enum';
|
import { PointType } from '../../types/geography.enum';
|
||||||
import { Point } from '../../types/point.type';
|
import { Point } from '../../types/point.type';
|
||||||
import { find } from 'geo-tz';
|
|
||||||
import { Route } from './route';
|
import { Route } from './route';
|
||||||
import { Role } from '../../types/role.enum';
|
import { Role } from '../../types/role.enum';
|
||||||
import { IGeorouter } from '../../interfaces/georouter.interface';
|
import { IGeorouter } from '../../interfaces/georouter.interface';
|
||||||
|
@ -14,6 +13,8 @@ import { Actor } from './actor';
|
||||||
import { Person } from './person';
|
import { Person } from './person';
|
||||||
import { Step } from '../../types/step.enum';
|
import { Step } from '../../types/step.enum';
|
||||||
import { Path } from '../../types/path.type';
|
import { Path } from '../../types/path.type';
|
||||||
|
import { IFindTimezone } from '../../../../geography/domain/interfaces/timezone-finder.interface';
|
||||||
|
import { Timezoner } from './timezoner';
|
||||||
|
|
||||||
export class Geography {
|
export class Geography {
|
||||||
private geographyRequest: IRequestGeography;
|
private geographyRequest: IRequestGeography;
|
||||||
|
@ -24,10 +25,11 @@ export class Geography {
|
||||||
timezones: Array<string>;
|
timezones: Array<string>;
|
||||||
driverRoute: Route;
|
driverRoute: Route;
|
||||||
passengerRoute: Route;
|
passengerRoute: Route;
|
||||||
|
timezoneFinder: IFindTimezone;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
geographyRequest: IRequestGeography,
|
geographyRequest: IRequestGeography,
|
||||||
defaultTimezone: string,
|
timezoner: Timezoner,
|
||||||
person: Person,
|
person: Person,
|
||||||
) {
|
) {
|
||||||
this.geographyRequest = geographyRequest;
|
this.geographyRequest = geographyRequest;
|
||||||
|
@ -35,7 +37,8 @@ export class Geography {
|
||||||
this.points = [];
|
this.points = [];
|
||||||
this.originType = undefined;
|
this.originType = undefined;
|
||||||
this.destinationType = undefined;
|
this.destinationType = undefined;
|
||||||
this.timezones = [defaultTimezone];
|
this.timezones = [timezoner.timezone];
|
||||||
|
this.timezoneFinder = timezoner.finder;
|
||||||
}
|
}
|
||||||
|
|
||||||
init = (): void => {
|
init = (): void => {
|
||||||
|
@ -147,7 +150,7 @@ export class Geography {
|
||||||
};
|
};
|
||||||
|
|
||||||
private setTimezones = (): void => {
|
private setTimezones = (): void => {
|
||||||
this.timezones = find(
|
this.timezones = this.timezoneFinder.timezones(
|
||||||
this.geographyRequest.waypoints[0].lat,
|
this.geographyRequest.waypoints[0].lat,
|
||||||
this.geographyRequest.waypoints[0].lon,
|
this.geographyRequest.waypoints[0].lon,
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { IGeodesic } from '../../interfaces/geodesic.interface';
|
import { IGeodesic } from '../../../../geography/domain/interfaces/geodesic.interface';
|
||||||
import { Point } from '../../types/point.type';
|
import { Point } from '../../types/point.type';
|
||||||
import { SpacetimePoint } from './spacetime-point';
|
import { SpacetimePoint } from './spacetime-point';
|
||||||
import { Waypoint } from './waypoint';
|
import { Waypoint } from './waypoint';
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
import { IFindTimezone } from '../../../../geography/domain/interfaces/timezone-finder.interface';
|
||||||
|
|
||||||
|
export type Timezoner = {
|
||||||
|
timezone: string;
|
||||||
|
finder: IFindTimezone;
|
||||||
|
};
|
|
@ -5,7 +5,6 @@ import { CqrsModule } from '@nestjs/cqrs';
|
||||||
import { DatabaseModule } from '../database/database.module';
|
import { DatabaseModule } from '../database/database.module';
|
||||||
import { MatcherController } from './adapters/primaries/matcher.controller';
|
import { MatcherController } from './adapters/primaries/matcher.controller';
|
||||||
import { MatchProfile } from './mappers/match.profile';
|
import { MatchProfile } from './mappers/match.profile';
|
||||||
import { AdRepository } from './adapters/secondaries/ad.repository';
|
|
||||||
import { MatchUseCase } from './domain/usecases/match.usecase';
|
import { MatchUseCase } from './domain/usecases/match.usecase';
|
||||||
import { Messager } from './adapters/secondaries/messager';
|
import { Messager } from './adapters/secondaries/messager';
|
||||||
import { CacheModule } from '@nestjs/cache-manager';
|
import { CacheModule } from '@nestjs/cache-manager';
|
||||||
|
@ -17,9 +16,13 @@ import { HttpModule } from '@nestjs/axios';
|
||||||
import { MatcherGeodesic } from './adapters/secondaries/geodesic';
|
import { MatcherGeodesic } from './adapters/secondaries/geodesic';
|
||||||
import { Matcher } from './domain/entities/engine/matcher';
|
import { Matcher } from './domain/entities/engine/matcher';
|
||||||
import { AlgorithmFactoryCreator } from './domain/entities/engine/factory/algorithm-factory-creator';
|
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';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
|
GeographyModule,
|
||||||
DatabaseModule,
|
DatabaseModule,
|
||||||
CqrsModule,
|
CqrsModule,
|
||||||
HttpModule,
|
HttpModule,
|
||||||
|
@ -53,14 +56,15 @@ import { AlgorithmFactoryCreator } from './domain/entities/engine/factory/algori
|
||||||
controllers: [MatcherController],
|
controllers: [MatcherController],
|
||||||
providers: [
|
providers: [
|
||||||
MatchProfile,
|
MatchProfile,
|
||||||
AdRepository,
|
|
||||||
Messager,
|
Messager,
|
||||||
DefaultParamsProvider,
|
DefaultParamsProvider,
|
||||||
MatchUseCase,
|
MatchUseCase,
|
||||||
GeorouterCreator,
|
GeorouterCreator,
|
||||||
MatcherGeodesic,
|
MatcherGeodesic,
|
||||||
|
TimezoneFinder,
|
||||||
Matcher,
|
Matcher,
|
||||||
AlgorithmFactoryCreator,
|
AlgorithmFactoryCreator,
|
||||||
|
GeoTimezoneFinder,
|
||||||
],
|
],
|
||||||
exports: [],
|
exports: [],
|
||||||
})
|
})
|
||||||
|
|
|
@ -8,11 +8,12 @@ import { Time } from '../domain/entities/ecosystem/time';
|
||||||
import { IDefaultParams } from '../domain/types/default-params.type';
|
import { IDefaultParams } from '../domain/types/default-params.type';
|
||||||
import { IGeorouter } from '../domain/interfaces/georouter.interface';
|
import { IGeorouter } from '../domain/interfaces/georouter.interface';
|
||||||
import { ICreateGeorouter } from '../domain/interfaces/georouter-creator.interface';
|
import { ICreateGeorouter } from '../domain/interfaces/georouter-creator.interface';
|
||||||
|
import { IFindTimezone } from '../../geography/domain/interfaces/timezone-finder.interface';
|
||||||
|
|
||||||
export class MatchQuery {
|
export class MatchQuery {
|
||||||
private readonly _matchRequest: MatchRequest;
|
private readonly matchRequest: MatchRequest;
|
||||||
private readonly _defaultParams: IDefaultParams;
|
private readonly defaultParams: IDefaultParams;
|
||||||
private readonly _georouterCreator: ICreateGeorouter;
|
private readonly georouterCreator: ICreateGeorouter;
|
||||||
person: Person;
|
person: Person;
|
||||||
roles: Array<Role>;
|
roles: Array<Role>;
|
||||||
time: Time;
|
time: Time;
|
||||||
|
@ -21,83 +22,89 @@ export class MatchQuery {
|
||||||
requirement: Requirement;
|
requirement: Requirement;
|
||||||
algorithmSettings: AlgorithmSettings;
|
algorithmSettings: AlgorithmSettings;
|
||||||
georouter: IGeorouter;
|
georouter: IGeorouter;
|
||||||
|
timezoneFinder: IFindTimezone;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
matchRequest: MatchRequest,
|
matchRequest: MatchRequest,
|
||||||
defaultParams: IDefaultParams,
|
defaultParams: IDefaultParams,
|
||||||
georouterCreator: ICreateGeorouter,
|
georouterCreator: ICreateGeorouter,
|
||||||
|
timezoneFinder: IFindTimezone,
|
||||||
) {
|
) {
|
||||||
this._matchRequest = matchRequest;
|
this.matchRequest = matchRequest;
|
||||||
this._defaultParams = defaultParams;
|
this.defaultParams = defaultParams;
|
||||||
this._georouterCreator = georouterCreator;
|
this.georouterCreator = georouterCreator;
|
||||||
this._setPerson();
|
this.timezoneFinder = timezoneFinder;
|
||||||
this._setRoles();
|
this.setPerson();
|
||||||
this._setTime();
|
this.setRoles();
|
||||||
this._setGeography();
|
this.setTime();
|
||||||
this._setRequirement();
|
this.setGeography();
|
||||||
this._setAlgorithmSettings();
|
this.setRequirement();
|
||||||
this._setExclusions();
|
this.setAlgorithmSettings();
|
||||||
|
this.setExclusions();
|
||||||
}
|
}
|
||||||
|
|
||||||
createRoutes = (): void => {
|
createRoutes = (): void => {
|
||||||
this.geography.createRoutes(this.roles, this.algorithmSettings.georouter);
|
this.geography.createRoutes(this.roles, this.algorithmSettings.georouter);
|
||||||
};
|
};
|
||||||
|
|
||||||
_setPerson = (): void => {
|
private setPerson = (): void => {
|
||||||
this.person = new Person(
|
this.person = new Person(
|
||||||
this._matchRequest,
|
this.matchRequest,
|
||||||
this._defaultParams.DEFAULT_IDENTIFIER,
|
this.defaultParams.DEFAULT_IDENTIFIER,
|
||||||
this._defaultParams.MARGIN_DURATION,
|
this.defaultParams.MARGIN_DURATION,
|
||||||
);
|
);
|
||||||
this.person.init();
|
this.person.init();
|
||||||
};
|
};
|
||||||
|
|
||||||
_setRoles = (): void => {
|
private setRoles = (): void => {
|
||||||
this.roles = [];
|
this.roles = [];
|
||||||
if (this._matchRequest.driver) this.roles.push(Role.DRIVER);
|
if (this.matchRequest.driver) this.roles.push(Role.DRIVER);
|
||||||
if (this._matchRequest.passenger) this.roles.push(Role.PASSENGER);
|
if (this.matchRequest.passenger) this.roles.push(Role.PASSENGER);
|
||||||
if (this.roles.length == 0) this.roles.push(Role.PASSENGER);
|
if (this.roles.length == 0) this.roles.push(Role.PASSENGER);
|
||||||
};
|
};
|
||||||
|
|
||||||
_setTime = (): void => {
|
private setTime = (): void => {
|
||||||
this.time = new Time(
|
this.time = new Time(
|
||||||
this._matchRequest,
|
this.matchRequest,
|
||||||
this._defaultParams.MARGIN_DURATION,
|
this.defaultParams.MARGIN_DURATION,
|
||||||
this._defaultParams.VALIDITY_DURATION,
|
this.defaultParams.VALIDITY_DURATION,
|
||||||
);
|
);
|
||||||
this.time.init();
|
this.time.init();
|
||||||
};
|
};
|
||||||
|
|
||||||
_setGeography = (): void => {
|
private setGeography = (): void => {
|
||||||
this.geography = new Geography(
|
this.geography = new Geography(
|
||||||
this._matchRequest,
|
this.matchRequest,
|
||||||
this._defaultParams.DEFAULT_TIMEZONE,
|
{
|
||||||
|
timezone: this.defaultParams.DEFAULT_TIMEZONE,
|
||||||
|
finder: this.timezoneFinder,
|
||||||
|
},
|
||||||
this.person,
|
this.person,
|
||||||
);
|
);
|
||||||
this.geography.init();
|
this.geography.init();
|
||||||
};
|
};
|
||||||
|
|
||||||
_setRequirement = (): void => {
|
private setRequirement = (): void => {
|
||||||
this.requirement = new Requirement(
|
this.requirement = new Requirement(
|
||||||
this._matchRequest,
|
this.matchRequest,
|
||||||
this._defaultParams.DEFAULT_SEATS,
|
this.defaultParams.DEFAULT_SEATS,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
_setAlgorithmSettings = (): void => {
|
private setAlgorithmSettings = (): void => {
|
||||||
this.algorithmSettings = new AlgorithmSettings(
|
this.algorithmSettings = new AlgorithmSettings(
|
||||||
this._matchRequest,
|
this.matchRequest,
|
||||||
this._defaultParams.DEFAULT_ALGORITHM_SETTINGS,
|
this.defaultParams.DEFAULT_ALGORITHM_SETTINGS,
|
||||||
this.time.frequency,
|
this.time.frequency,
|
||||||
this._georouterCreator,
|
this.georouterCreator,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
_setExclusions = (): void => {
|
private setExclusions = (): void => {
|
||||||
this.exclusions = [];
|
this.exclusions = [];
|
||||||
if (this._matchRequest.identifier)
|
if (this.matchRequest.identifier)
|
||||||
this.exclusions.push(this._matchRequest.identifier);
|
this.exclusions.push(this.matchRequest.identifier);
|
||||||
if (this._matchRequest.exclusions)
|
if (this.matchRequest.exclusions)
|
||||||
this.exclusions.push(...this._matchRequest.exclusions);
|
this.exclusions.push(...this.matchRequest.exclusions);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
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('Geo TZ Finder', () => {
|
||||||
|
let timezoneFinder: TimezoneFinder;
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
imports: [],
|
||||||
|
providers: [
|
||||||
|
TimezoneFinder,
|
||||||
|
{
|
||||||
|
provide: GeoTimezoneFinder,
|
||||||
|
useValue: mockGeoTimezoneFinder,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}).compile();
|
||||||
|
|
||||||
|
timezoneFinder = module.get<TimezoneFinder>(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');
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,14 +1,38 @@
|
||||||
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
import { MatcherGeodesic } from '../../../../adapters/secondaries/geodesic';
|
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', () => {
|
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>(MatcherGeodesic);
|
||||||
|
});
|
||||||
|
|
||||||
it('should be defined', () => {
|
it('should be defined', () => {
|
||||||
const geodesic: MatcherGeodesic = new MatcherGeodesic();
|
expect(matcherGeodesic).toBeDefined();
|
||||||
expect(geodesic).toBeDefined();
|
|
||||||
});
|
});
|
||||||
it('should get inverse values', () => {
|
it('should get inverse values', () => {
|
||||||
const geodesic: MatcherGeodesic = new MatcherGeodesic();
|
const inv = matcherGeodesic.inverse(0, 0, 1, 1);
|
||||||
const inv = geodesic.inverse(0, 0, 1, 1);
|
|
||||||
expect(Math.round(inv.azimuth)).toBe(45);
|
expect(Math.round(inv.azimuth)).toBe(45);
|
||||||
expect(Math.round(inv.distance)).toBe(156900);
|
expect(Math.round(inv.distance)).toBe(50000);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -6,7 +6,7 @@ import {
|
||||||
import { Role } from '../../../../domain/types/role.enum';
|
import { Role } from '../../../../domain/types/role.enum';
|
||||||
import { NamedRoute } from '../../../../domain/entities/ecosystem/named-route';
|
import { NamedRoute } from '../../../../domain/entities/ecosystem/named-route';
|
||||||
import { Route } from '../../../../domain/entities/ecosystem/route';
|
import { Route } from '../../../../domain/entities/ecosystem/route';
|
||||||
import { IGeodesic } from '../../../../domain/interfaces/geodesic.interface';
|
import { IGeodesic } from '../../../../../geography/domain/interfaces/geodesic.interface';
|
||||||
import { PointType } from '../../../../domain/types/geography.enum';
|
import { PointType } from '../../../../domain/types/geography.enum';
|
||||||
|
|
||||||
const person: Person = new Person(
|
const person: Person = new Person(
|
||||||
|
@ -65,6 +65,10 @@ const mockGeorouter = {
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const mockTimezoneFinder = {
|
||||||
|
timezones: jest.fn().mockImplementation(),
|
||||||
|
};
|
||||||
|
|
||||||
describe('Geography entity', () => {
|
describe('Geography entity', () => {
|
||||||
it('should be defined', () => {
|
it('should be defined', () => {
|
||||||
const geography = new Geography(
|
const geography = new Geography(
|
||||||
|
@ -80,7 +84,10 @@ describe('Geography entity', () => {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
'Europe/Paris',
|
{
|
||||||
|
timezone: 'Europe/Paris',
|
||||||
|
finder: mockTimezoneFinder,
|
||||||
|
},
|
||||||
person,
|
person,
|
||||||
);
|
);
|
||||||
expect(geography).toBeDefined();
|
expect(geography).toBeDefined();
|
||||||
|
@ -103,7 +110,10 @@ describe('Geography entity', () => {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
'Europe/Paris',
|
{
|
||||||
|
timezone: 'Europe/Paris',
|
||||||
|
finder: mockTimezoneFinder,
|
||||||
|
},
|
||||||
person,
|
person,
|
||||||
);
|
);
|
||||||
geography.init();
|
geography.init();
|
||||||
|
@ -115,7 +125,10 @@ describe('Geography entity', () => {
|
||||||
{
|
{
|
||||||
waypoints: [],
|
waypoints: [],
|
||||||
},
|
},
|
||||||
'Europe/Paris',
|
{
|
||||||
|
timezone: 'Europe/Paris',
|
||||||
|
finder: mockTimezoneFinder,
|
||||||
|
},
|
||||||
person,
|
person,
|
||||||
);
|
);
|
||||||
expect(() => geography.init()).toThrow();
|
expect(() => geography.init()).toThrow();
|
||||||
|
@ -130,7 +143,10 @@ describe('Geography entity', () => {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
'Europe/Paris',
|
{
|
||||||
|
timezone: 'Europe/Paris',
|
||||||
|
finder: mockTimezoneFinder,
|
||||||
|
},
|
||||||
person,
|
person,
|
||||||
);
|
);
|
||||||
expect(() => geography.init()).toThrow();
|
expect(() => geography.init()).toThrow();
|
||||||
|
@ -149,7 +165,10 @@ describe('Geography entity', () => {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
'Europe/Paris',
|
{
|
||||||
|
timezone: 'Europe/Paris',
|
||||||
|
finder: mockTimezoneFinder,
|
||||||
|
},
|
||||||
person,
|
person,
|
||||||
);
|
);
|
||||||
expect(() => geography.init()).toThrow();
|
expect(() => geography.init()).toThrow();
|
||||||
|
@ -168,7 +187,10 @@ describe('Geography entity', () => {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
'Europe/Paris',
|
{
|
||||||
|
timezone: 'Europe/Paris',
|
||||||
|
finder: mockTimezoneFinder,
|
||||||
|
},
|
||||||
person,
|
person,
|
||||||
);
|
);
|
||||||
expect(() => geography.init()).toThrow();
|
expect(() => geography.init()).toThrow();
|
||||||
|
@ -190,7 +212,10 @@ describe('Geography entity', () => {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
'Europe/Paris',
|
{
|
||||||
|
timezone: 'Europe/Paris',
|
||||||
|
finder: mockTimezoneFinder,
|
||||||
|
},
|
||||||
person,
|
person,
|
||||||
);
|
);
|
||||||
geography.init();
|
geography.init();
|
||||||
|
@ -220,7 +245,10 @@ describe('Geography entity', () => {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
'Europe/Paris',
|
{
|
||||||
|
timezone: 'Europe/Paris',
|
||||||
|
finder: mockTimezoneFinder,
|
||||||
|
},
|
||||||
person,
|
person,
|
||||||
);
|
);
|
||||||
geography.init();
|
geography.init();
|
||||||
|
@ -246,7 +274,10 @@ describe('Geography entity', () => {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
'Europe/Paris',
|
{
|
||||||
|
timezone: 'Europe/Paris',
|
||||||
|
finder: mockTimezoneFinder,
|
||||||
|
},
|
||||||
person,
|
person,
|
||||||
);
|
);
|
||||||
geography.init();
|
geography.init();
|
||||||
|
@ -269,7 +300,10 @@ describe('Geography entity', () => {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
'Europe/Paris',
|
{
|
||||||
|
timezone: 'Europe/Paris',
|
||||||
|
finder: mockTimezoneFinder,
|
||||||
|
},
|
||||||
person,
|
person,
|
||||||
);
|
);
|
||||||
geography.init();
|
geography.init();
|
||||||
|
|
|
@ -9,6 +9,10 @@ const mockGeorouterCreator = {
|
||||||
create: jest.fn().mockImplementation(),
|
create: jest.fn().mockImplementation(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const mockTimezoneFinder = {
|
||||||
|
timezones: jest.fn().mockImplementation(),
|
||||||
|
};
|
||||||
|
|
||||||
const defaultParams: IDefaultParams = {
|
const defaultParams: IDefaultParams = {
|
||||||
DEFAULT_IDENTIFIER: 0,
|
DEFAULT_IDENTIFIER: 0,
|
||||||
MARGIN_DURATION: 900,
|
MARGIN_DURATION: 900,
|
||||||
|
@ -46,6 +50,7 @@ const matchQuery: MatchQuery = new MatchQuery(
|
||||||
matchRequest,
|
matchRequest,
|
||||||
defaultParams,
|
defaultParams,
|
||||||
mockGeorouterCreator,
|
mockGeorouterCreator,
|
||||||
|
mockTimezoneFinder,
|
||||||
);
|
);
|
||||||
|
|
||||||
describe('AlgorithmFactoryCreator', () => {
|
describe('AlgorithmFactoryCreator', () => {
|
||||||
|
|
|
@ -11,6 +11,10 @@ const mockGeorouterCreator = {
|
||||||
create: jest.fn().mockImplementation(),
|
create: jest.fn().mockImplementation(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const mockTimezoneFinder = {
|
||||||
|
timezones: jest.fn().mockImplementation(),
|
||||||
|
};
|
||||||
|
|
||||||
const defaultParams: IDefaultParams = {
|
const defaultParams: IDefaultParams = {
|
||||||
DEFAULT_IDENTIFIER: 0,
|
DEFAULT_IDENTIFIER: 0,
|
||||||
MARGIN_DURATION: 900,
|
MARGIN_DURATION: 900,
|
||||||
|
@ -48,6 +52,7 @@ const matchQuery: MatchQuery = new MatchQuery(
|
||||||
matchRequest,
|
matchRequest,
|
||||||
defaultParams,
|
defaultParams,
|
||||||
mockGeorouterCreator,
|
mockGeorouterCreator,
|
||||||
|
mockTimezoneFinder,
|
||||||
);
|
);
|
||||||
|
|
||||||
class FakeSelector extends Selector {
|
class FakeSelector extends Selector {
|
||||||
|
|
|
@ -9,6 +9,10 @@ const mockGeorouterCreator = {
|
||||||
create: jest.fn().mockImplementation(),
|
create: jest.fn().mockImplementation(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const mockTimezoneFinder = {
|
||||||
|
timezones: jest.fn().mockImplementation(),
|
||||||
|
};
|
||||||
|
|
||||||
const defaultParams: IDefaultParams = {
|
const defaultParams: IDefaultParams = {
|
||||||
DEFAULT_IDENTIFIER: 0,
|
DEFAULT_IDENTIFIER: 0,
|
||||||
MARGIN_DURATION: 900,
|
MARGIN_DURATION: 900,
|
||||||
|
@ -46,6 +50,7 @@ const matchQuery: MatchQuery = new MatchQuery(
|
||||||
matchRequest,
|
matchRequest,
|
||||||
defaultParams,
|
defaultParams,
|
||||||
mockGeorouterCreator,
|
mockGeorouterCreator,
|
||||||
|
mockTimezoneFinder,
|
||||||
);
|
);
|
||||||
|
|
||||||
describe('ClassicAlgorithmFactory', () => {
|
describe('ClassicAlgorithmFactory', () => {
|
||||||
|
|
|
@ -9,6 +9,10 @@ const mockGeorouterCreator = {
|
||||||
create: jest.fn().mockImplementation(),
|
create: jest.fn().mockImplementation(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const mockTimezoneFinder = {
|
||||||
|
timezones: jest.fn().mockImplementation(),
|
||||||
|
};
|
||||||
|
|
||||||
const defaultParams: IDefaultParams = {
|
const defaultParams: IDefaultParams = {
|
||||||
DEFAULT_IDENTIFIER: 0,
|
DEFAULT_IDENTIFIER: 0,
|
||||||
MARGIN_DURATION: 900,
|
MARGIN_DURATION: 900,
|
||||||
|
@ -46,6 +50,7 @@ const matchQuery: MatchQuery = new MatchQuery(
|
||||||
matchRequest,
|
matchRequest,
|
||||||
defaultParams,
|
defaultParams,
|
||||||
mockGeorouterCreator,
|
mockGeorouterCreator,
|
||||||
|
mockTimezoneFinder,
|
||||||
);
|
);
|
||||||
|
|
||||||
describe('ClassicGeoFilter', () => {
|
describe('ClassicGeoFilter', () => {
|
||||||
|
|
|
@ -9,6 +9,10 @@ const mockGeorouterCreator = {
|
||||||
create: jest.fn().mockImplementation(),
|
create: jest.fn().mockImplementation(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const mockTimezoneFinder = {
|
||||||
|
timezones: jest.fn().mockImplementation(),
|
||||||
|
};
|
||||||
|
|
||||||
const defaultParams: IDefaultParams = {
|
const defaultParams: IDefaultParams = {
|
||||||
DEFAULT_IDENTIFIER: 0,
|
DEFAULT_IDENTIFIER: 0,
|
||||||
MARGIN_DURATION: 900,
|
MARGIN_DURATION: 900,
|
||||||
|
@ -46,6 +50,7 @@ const matchQuery: MatchQuery = new MatchQuery(
|
||||||
matchRequest,
|
matchRequest,
|
||||||
defaultParams,
|
defaultParams,
|
||||||
mockGeorouterCreator,
|
mockGeorouterCreator,
|
||||||
|
mockTimezoneFinder,
|
||||||
);
|
);
|
||||||
|
|
||||||
describe('ClassicTimeFilter', () => {
|
describe('ClassicTimeFilter', () => {
|
||||||
|
|
|
@ -9,6 +9,10 @@ const mockGeorouterCreator = {
|
||||||
create: jest.fn().mockImplementation(),
|
create: jest.fn().mockImplementation(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const mockTimezoneFinder = {
|
||||||
|
timezones: jest.fn().mockImplementation(),
|
||||||
|
};
|
||||||
|
|
||||||
const defaultParams: IDefaultParams = {
|
const defaultParams: IDefaultParams = {
|
||||||
DEFAULT_IDENTIFIER: 0,
|
DEFAULT_IDENTIFIER: 0,
|
||||||
MARGIN_DURATION: 900,
|
MARGIN_DURATION: 900,
|
||||||
|
@ -46,6 +50,7 @@ const matchQuery: MatchQuery = new MatchQuery(
|
||||||
matchRequest,
|
matchRequest,
|
||||||
defaultParams,
|
defaultParams,
|
||||||
mockGeorouterCreator,
|
mockGeorouterCreator,
|
||||||
|
mockTimezoneFinder,
|
||||||
);
|
);
|
||||||
|
|
||||||
describe('ClassicWaypointCompleter', () => {
|
describe('ClassicWaypointCompleter', () => {
|
||||||
|
|
|
@ -9,6 +9,10 @@ const mockGeorouterCreator = {
|
||||||
create: jest.fn().mockImplementation(),
|
create: jest.fn().mockImplementation(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const mockTimezoneFinder = {
|
||||||
|
timezones: jest.fn().mockImplementation(),
|
||||||
|
};
|
||||||
|
|
||||||
const defaultParams: IDefaultParams = {
|
const defaultParams: IDefaultParams = {
|
||||||
DEFAULT_IDENTIFIER: 0,
|
DEFAULT_IDENTIFIER: 0,
|
||||||
MARGIN_DURATION: 900,
|
MARGIN_DURATION: 900,
|
||||||
|
@ -46,6 +50,7 @@ const matchQuery: MatchQuery = new MatchQuery(
|
||||||
matchRequest,
|
matchRequest,
|
||||||
defaultParams,
|
defaultParams,
|
||||||
mockGeorouterCreator,
|
mockGeorouterCreator,
|
||||||
|
mockTimezoneFinder,
|
||||||
);
|
);
|
||||||
|
|
||||||
describe('ClassicSelector', () => {
|
describe('ClassicSelector', () => {
|
||||||
|
|
|
@ -9,6 +9,10 @@ const mockGeorouterCreator = {
|
||||||
create: jest.fn().mockImplementation(),
|
create: jest.fn().mockImplementation(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const mockTimezoneFinder = {
|
||||||
|
timezones: jest.fn().mockImplementation(),
|
||||||
|
};
|
||||||
|
|
||||||
const defaultParams: IDefaultParams = {
|
const defaultParams: IDefaultParams = {
|
||||||
DEFAULT_IDENTIFIER: 0,
|
DEFAULT_IDENTIFIER: 0,
|
||||||
MARGIN_DURATION: 900,
|
MARGIN_DURATION: 900,
|
||||||
|
@ -46,6 +50,7 @@ const matchQuery: MatchQuery = new MatchQuery(
|
||||||
matchRequest,
|
matchRequest,
|
||||||
defaultParams,
|
defaultParams,
|
||||||
mockGeorouterCreator,
|
mockGeorouterCreator,
|
||||||
|
mockTimezoneFinder,
|
||||||
);
|
);
|
||||||
|
|
||||||
class FakeCompleter extends Completer {
|
class FakeCompleter extends Completer {
|
||||||
|
|
|
@ -9,6 +9,10 @@ const mockGeorouterCreator = {
|
||||||
create: jest.fn().mockImplementation(),
|
create: jest.fn().mockImplementation(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const mockTimezoneFinder = {
|
||||||
|
timezones: jest.fn().mockImplementation(),
|
||||||
|
};
|
||||||
|
|
||||||
const defaultParams: IDefaultParams = {
|
const defaultParams: IDefaultParams = {
|
||||||
DEFAULT_IDENTIFIER: 0,
|
DEFAULT_IDENTIFIER: 0,
|
||||||
MARGIN_DURATION: 900,
|
MARGIN_DURATION: 900,
|
||||||
|
@ -46,6 +50,7 @@ const matchQuery: MatchQuery = new MatchQuery(
|
||||||
matchRequest,
|
matchRequest,
|
||||||
defaultParams,
|
defaultParams,
|
||||||
mockGeorouterCreator,
|
mockGeorouterCreator,
|
||||||
|
mockTimezoneFinder,
|
||||||
);
|
);
|
||||||
|
|
||||||
class FakeFilter extends Filter {
|
class FakeFilter extends Filter {
|
||||||
|
|
|
@ -9,6 +9,10 @@ const mockGeorouterCreator = {
|
||||||
create: jest.fn().mockImplementation(),
|
create: jest.fn().mockImplementation(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const mockTimezoneFinder = {
|
||||||
|
timezones: jest.fn().mockImplementation(),
|
||||||
|
};
|
||||||
|
|
||||||
const defaultParams: IDefaultParams = {
|
const defaultParams: IDefaultParams = {
|
||||||
DEFAULT_IDENTIFIER: 0,
|
DEFAULT_IDENTIFIER: 0,
|
||||||
MARGIN_DURATION: 900,
|
MARGIN_DURATION: 900,
|
||||||
|
@ -46,6 +50,7 @@ const matchQuery: MatchQuery = new MatchQuery(
|
||||||
matchRequest,
|
matchRequest,
|
||||||
defaultParams,
|
defaultParams,
|
||||||
mockGeorouterCreator,
|
mockGeorouterCreator,
|
||||||
|
mockTimezoneFinder,
|
||||||
);
|
);
|
||||||
|
|
||||||
describe('JourneyCompleter', () => {
|
describe('JourneyCompleter', () => {
|
||||||
|
|
|
@ -21,6 +21,10 @@ const mockGeorouterCreator = {
|
||||||
create: jest.fn().mockImplementation(),
|
create: jest.fn().mockImplementation(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const mockTimezoneFinder = {
|
||||||
|
timezones: jest.fn().mockImplementation(),
|
||||||
|
};
|
||||||
|
|
||||||
const defaultParams: IDefaultParams = {
|
const defaultParams: IDefaultParams = {
|
||||||
DEFAULT_IDENTIFIER: 0,
|
DEFAULT_IDENTIFIER: 0,
|
||||||
MARGIN_DURATION: 900,
|
MARGIN_DURATION: 900,
|
||||||
|
@ -58,6 +62,7 @@ const matchQuery: MatchQuery = new MatchQuery(
|
||||||
matchRequest,
|
matchRequest,
|
||||||
defaultParams,
|
defaultParams,
|
||||||
mockGeorouterCreator,
|
mockGeorouterCreator,
|
||||||
|
mockTimezoneFinder,
|
||||||
);
|
);
|
||||||
|
|
||||||
describe('Matcher', () => {
|
describe('Matcher', () => {
|
||||||
|
|
|
@ -9,6 +9,10 @@ const mockGeorouterCreator = {
|
||||||
create: jest.fn().mockImplementation(),
|
create: jest.fn().mockImplementation(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const mockTimezoneFinder = {
|
||||||
|
timezones: jest.fn().mockImplementation(),
|
||||||
|
};
|
||||||
|
|
||||||
const defaultParams: IDefaultParams = {
|
const defaultParams: IDefaultParams = {
|
||||||
DEFAULT_IDENTIFIER: 0,
|
DEFAULT_IDENTIFIER: 0,
|
||||||
MARGIN_DURATION: 900,
|
MARGIN_DURATION: 900,
|
||||||
|
@ -46,6 +50,7 @@ const matchQuery: MatchQuery = new MatchQuery(
|
||||||
matchRequest,
|
matchRequest,
|
||||||
defaultParams,
|
defaultParams,
|
||||||
mockGeorouterCreator,
|
mockGeorouterCreator,
|
||||||
|
mockTimezoneFinder,
|
||||||
);
|
);
|
||||||
|
|
||||||
class FakeProcessor extends Processor {
|
class FakeProcessor extends Processor {
|
||||||
|
|
|
@ -9,6 +9,10 @@ const mockGeorouterCreator = {
|
||||||
create: jest.fn().mockImplementation(),
|
create: jest.fn().mockImplementation(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const mockTimezoneFinder = {
|
||||||
|
timezones: jest.fn().mockImplementation(),
|
||||||
|
};
|
||||||
|
|
||||||
const defaultParams: IDefaultParams = {
|
const defaultParams: IDefaultParams = {
|
||||||
DEFAULT_IDENTIFIER: 0,
|
DEFAULT_IDENTIFIER: 0,
|
||||||
MARGIN_DURATION: 900,
|
MARGIN_DURATION: 900,
|
||||||
|
@ -46,6 +50,7 @@ const matchQuery: MatchQuery = new MatchQuery(
|
||||||
matchRequest,
|
matchRequest,
|
||||||
defaultParams,
|
defaultParams,
|
||||||
mockGeorouterCreator,
|
mockGeorouterCreator,
|
||||||
|
mockTimezoneFinder,
|
||||||
);
|
);
|
||||||
|
|
||||||
describe('RouteCompleter', () => {
|
describe('RouteCompleter', () => {
|
||||||
|
|
|
@ -9,6 +9,10 @@ const mockGeorouterCreator = {
|
||||||
create: jest.fn().mockImplementation(),
|
create: jest.fn().mockImplementation(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const mockTimezoneFinder = {
|
||||||
|
timezones: jest.fn().mockImplementation(),
|
||||||
|
};
|
||||||
|
|
||||||
const defaultParams: IDefaultParams = {
|
const defaultParams: IDefaultParams = {
|
||||||
DEFAULT_IDENTIFIER: 0,
|
DEFAULT_IDENTIFIER: 0,
|
||||||
MARGIN_DURATION: 900,
|
MARGIN_DURATION: 900,
|
||||||
|
@ -46,6 +50,7 @@ const matchQuery: MatchQuery = new MatchQuery(
|
||||||
matchRequest,
|
matchRequest,
|
||||||
defaultParams,
|
defaultParams,
|
||||||
mockGeorouterCreator,
|
mockGeorouterCreator,
|
||||||
|
mockTimezoneFinder,
|
||||||
);
|
);
|
||||||
|
|
||||||
class FakeSelector extends Selector {
|
class FakeSelector extends Selector {
|
||||||
|
|
|
@ -34,6 +34,10 @@ const mockGeorouterCreator = {
|
||||||
create: jest.fn().mockImplementation(),
|
create: jest.fn().mockImplementation(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const mockTimezoneFinder = {
|
||||||
|
timezones: jest.fn().mockImplementation(),
|
||||||
|
};
|
||||||
|
|
||||||
const defaultParams: IDefaultParams = {
|
const defaultParams: IDefaultParams = {
|
||||||
DEFAULT_IDENTIFIER: 0,
|
DEFAULT_IDENTIFIER: 0,
|
||||||
MARGIN_DURATION: 900,
|
MARGIN_DURATION: 900,
|
||||||
|
@ -97,7 +101,12 @@ describe('MatchUseCase', () => {
|
||||||
describe('execute', () => {
|
describe('execute', () => {
|
||||||
it('should return matches', async () => {
|
it('should return matches', async () => {
|
||||||
const matches = await matchUseCase.execute(
|
const matches = await matchUseCase.execute(
|
||||||
new MatchQuery(matchRequest, defaultParams, mockGeorouterCreator),
|
new MatchQuery(
|
||||||
|
matchRequest,
|
||||||
|
defaultParams,
|
||||||
|
mockGeorouterCreator,
|
||||||
|
mockTimezoneFinder,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
expect(matches.total).toBe(3);
|
expect(matches.total).toBe(3);
|
||||||
});
|
});
|
||||||
|
@ -105,7 +114,12 @@ describe('MatchUseCase', () => {
|
||||||
it('should throw an exception when error occurs', async () => {
|
it('should throw an exception when error occurs', async () => {
|
||||||
await expect(
|
await expect(
|
||||||
matchUseCase.execute(
|
matchUseCase.execute(
|
||||||
new MatchQuery(matchRequest, defaultParams, mockGeorouterCreator),
|
new MatchQuery(
|
||||||
|
matchRequest,
|
||||||
|
defaultParams,
|
||||||
|
mockGeorouterCreator,
|
||||||
|
mockTimezoneFinder,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
).rejects.toBeInstanceOf(MatcherException);
|
).rejects.toBeInstanceOf(MatcherException);
|
||||||
});
|
});
|
||||||
|
|
|
@ -30,6 +30,10 @@ const mockGeorouterCreator = {
|
||||||
create: jest.fn().mockImplementation(),
|
create: jest.fn().mockImplementation(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const mockTimezoneFinder = {
|
||||||
|
timezones: jest.fn().mockImplementation(),
|
||||||
|
};
|
||||||
|
|
||||||
describe('Match query', () => {
|
describe('Match query', () => {
|
||||||
it('should be defined', () => {
|
it('should be defined', () => {
|
||||||
const matchRequest: MatchRequest = new MatchRequest();
|
const matchRequest: MatchRequest = new MatchRequest();
|
||||||
|
@ -48,6 +52,7 @@ describe('Match query', () => {
|
||||||
matchRequest,
|
matchRequest,
|
||||||
defaultParams,
|
defaultParams,
|
||||||
mockGeorouterCreator,
|
mockGeorouterCreator,
|
||||||
|
mockTimezoneFinder,
|
||||||
);
|
);
|
||||||
expect(matchQuery).toBeDefined();
|
expect(matchQuery).toBeDefined();
|
||||||
});
|
});
|
||||||
|
@ -71,6 +76,7 @@ describe('Match query', () => {
|
||||||
matchRequest,
|
matchRequest,
|
||||||
defaultParams,
|
defaultParams,
|
||||||
mockGeorouterCreator,
|
mockGeorouterCreator,
|
||||||
|
mockTimezoneFinder,
|
||||||
);
|
);
|
||||||
expect(matchQuery.exclusions.length).toBe(4);
|
expect(matchQuery.exclusions.length).toBe(4);
|
||||||
});
|
});
|
||||||
|
@ -93,6 +99,7 @@ describe('Match query', () => {
|
||||||
matchRequest,
|
matchRequest,
|
||||||
defaultParams,
|
defaultParams,
|
||||||
mockGeorouterCreator,
|
mockGeorouterCreator,
|
||||||
|
mockTimezoneFinder,
|
||||||
);
|
);
|
||||||
expect(matchQuery.roles).toEqual([Role.DRIVER]);
|
expect(matchQuery.roles).toEqual([Role.DRIVER]);
|
||||||
});
|
});
|
||||||
|
@ -115,6 +122,7 @@ describe('Match query', () => {
|
||||||
matchRequest,
|
matchRequest,
|
||||||
defaultParams,
|
defaultParams,
|
||||||
mockGeorouterCreator,
|
mockGeorouterCreator,
|
||||||
|
mockTimezoneFinder,
|
||||||
);
|
);
|
||||||
expect(matchQuery.roles).toEqual([Role.PASSENGER]);
|
expect(matchQuery.roles).toEqual([Role.PASSENGER]);
|
||||||
});
|
});
|
||||||
|
@ -138,6 +146,7 @@ describe('Match query', () => {
|
||||||
matchRequest,
|
matchRequest,
|
||||||
defaultParams,
|
defaultParams,
|
||||||
mockGeorouterCreator,
|
mockGeorouterCreator,
|
||||||
|
mockTimezoneFinder,
|
||||||
);
|
);
|
||||||
expect(matchQuery.roles.length).toBe(2);
|
expect(matchQuery.roles.length).toBe(2);
|
||||||
expect(matchQuery.roles).toContain(Role.PASSENGER);
|
expect(matchQuery.roles).toContain(Role.PASSENGER);
|
||||||
|
@ -163,6 +172,7 @@ describe('Match query', () => {
|
||||||
matchRequest,
|
matchRequest,
|
||||||
defaultParams,
|
defaultParams,
|
||||||
mockGeorouterCreator,
|
mockGeorouterCreator,
|
||||||
|
mockTimezoneFinder,
|
||||||
);
|
);
|
||||||
expect(matchQuery.requirement.seatsDriver).toBe(1);
|
expect(matchQuery.requirement.seatsDriver).toBe(1);
|
||||||
expect(matchQuery.requirement.seatsPassenger).toBe(2);
|
expect(matchQuery.requirement.seatsPassenger).toBe(2);
|
||||||
|
@ -194,6 +204,7 @@ describe('Match query', () => {
|
||||||
matchRequest,
|
matchRequest,
|
||||||
defaultParams,
|
defaultParams,
|
||||||
mockGeorouterCreator,
|
mockGeorouterCreator,
|
||||||
|
mockTimezoneFinder,
|
||||||
);
|
);
|
||||||
expect(matchQuery.algorithmSettings.algorithmType).toBe(
|
expect(matchQuery.algorithmSettings.algorithmType).toBe(
|
||||||
AlgorithmType.CLASSIC,
|
AlgorithmType.CLASSIC,
|
||||||
|
|
Loading…
Reference in New Issue