WIP create query
This commit is contained in:
parent
f3ca813dd6
commit
d6a12e4d0e
|
@ -2,17 +2,18 @@ import { Mapper } from '@automapper/core';
|
||||||
import { InjectMapper } from '@automapper/nestjs';
|
import { InjectMapper } from '@automapper/nestjs';
|
||||||
import { Controller, UsePipes } from '@nestjs/common';
|
import { Controller, UsePipes } from '@nestjs/common';
|
||||||
import { QueryBus } from '@nestjs/cqrs';
|
import { QueryBus } from '@nestjs/cqrs';
|
||||||
import { GrpcMethod } from '@nestjs/microservices';
|
import { GrpcMethod, RpcException } from '@nestjs/microservices';
|
||||||
import { RpcValidationPipe } from 'src/modules/utils/pipes/rpc.validation-pipe';
|
import { RpcValidationPipe } from 'src/modules/utils/pipes/rpc.validation-pipe';
|
||||||
import { MatchRequest } from '../../domain/dtos/match.request';
|
import { MatchRequest } from '../../domain/dtos/match.request';
|
||||||
import { ICollection } from 'src/modules/database/src/interfaces/collection.interface';
|
import { ICollection } from 'src/modules/database/src/interfaces/collection.interface';
|
||||||
import { Match } from '../../domain/entities/match';
|
import { Match } from '../../domain/entities/match';
|
||||||
import { MatchQuery } from '../../queries/match.query';
|
import { MatchQuery } from '../../queries/match.query';
|
||||||
import { MatchPresenter } from '../secondaries/match.presenter';
|
import { MatchPresenter } from '../secondaries/match.presenter';
|
||||||
|
import { ConfigService } from '@nestjs/config';
|
||||||
|
|
||||||
@UsePipes(
|
@UsePipes(
|
||||||
new RpcValidationPipe({
|
new RpcValidationPipe({
|
||||||
whitelist: true,
|
whitelist: false,
|
||||||
forbidUnknownValues: false,
|
forbidUnknownValues: false,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
@ -20,17 +21,27 @@ import { MatchPresenter } from '../secondaries/match.presenter';
|
||||||
export class MatcherController {
|
export class MatcherController {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly _queryBus: QueryBus,
|
private readonly _queryBus: QueryBus,
|
||||||
|
private readonly _configService: ConfigService,
|
||||||
@InjectMapper() private readonly _mapper: Mapper,
|
@InjectMapper() private readonly _mapper: Mapper,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@GrpcMethod('MatcherService', 'Match')
|
@GrpcMethod('MatcherService', 'Match')
|
||||||
async match(data: MatchRequest): Promise<ICollection<Match>> {
|
async match(data: MatchRequest): Promise<ICollection<Match>> {
|
||||||
const matchCollection = await this._queryBus.execute(new MatchQuery(data));
|
try {
|
||||||
|
const matchCollection = await this._queryBus.execute(
|
||||||
|
new MatchQuery(data, this._configService),
|
||||||
|
);
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
data: matchCollection.data.map((match: Match) =>
|
data: matchCollection.data.map((match: Match) =>
|
||||||
this._mapper.map(match, Match, MatchPresenter),
|
this._mapper.map(match, Match, MatchPresenter),
|
||||||
),
|
),
|
||||||
total: matchCollection.total,
|
total: matchCollection.total,
|
||||||
});
|
});
|
||||||
|
} catch (e) {
|
||||||
|
throw new RpcException({
|
||||||
|
code: e.code,
|
||||||
|
message: e.message,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,27 @@ service MatcherService {
|
||||||
|
|
||||||
message MatchRequest {
|
message MatchRequest {
|
||||||
repeated Point waypoints = 1;
|
repeated Point waypoints = 1;
|
||||||
|
string departure = 2;
|
||||||
|
string fromDate = 3;
|
||||||
|
Schedule schedule = 4;
|
||||||
|
bool driver = 5;
|
||||||
|
bool passenger = 6;
|
||||||
|
string toDate = 7;
|
||||||
|
int32 marginDuration = 8;
|
||||||
|
MarginDurations marginDurations = 9;
|
||||||
|
int32 seatsPassenger = 10;
|
||||||
|
int32 seatsDriver = 11;
|
||||||
|
bool strict = 12;
|
||||||
|
Algorithm algorithm = 13;
|
||||||
|
int32 remoteness = 14;
|
||||||
|
bool useProportion = 15;
|
||||||
|
int32 proportion = 16;
|
||||||
|
bool useAzimuth = 17;
|
||||||
|
int32 azimuthMargin = 18;
|
||||||
|
int32 maxDetourDistanceRatio = 19;
|
||||||
|
int32 maxDetourDurationRatio = 20;
|
||||||
|
repeated int32 exclusions = 21;
|
||||||
|
int32 identifier = 22;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Point {
|
message Point {
|
||||||
|
@ -15,6 +36,30 @@ message Point {
|
||||||
float lat = 2;
|
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 {
|
message Match {
|
||||||
string uuid = 1;
|
string uuid = 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
import {
|
import {
|
||||||
IsArray,
|
IsArray,
|
||||||
IsBoolean,
|
IsBoolean,
|
||||||
IsDate,
|
|
||||||
IsEnum,
|
IsEnum,
|
||||||
IsInt,
|
IsInt,
|
||||||
IsNumber,
|
IsNumber,
|
||||||
IsOptional,
|
IsOptional,
|
||||||
|
IsString,
|
||||||
Max,
|
Max,
|
||||||
Min,
|
Min,
|
||||||
} from 'class-validator';
|
} from 'class-validator';
|
||||||
import { AutoMap } from '@automapper/classes';
|
import { AutoMap } from '@automapper/classes';
|
||||||
import { Point } from '../entities/point.type';
|
import { Point } from '../entities/point.type';
|
||||||
import { Schedule } from '../entities/schedule.type';
|
import { Schedule } from './schedule.type';
|
||||||
import { MarginDurations } from '../entities/margin_durations.type';
|
import { MarginDurations } from './margin-durations.type';
|
||||||
import { Algorithm } from './algorithm.enum';
|
import { Algorithm } from './algorithm.enum';
|
||||||
|
|
||||||
export class MatchRequest {
|
export class MatchRequest {
|
||||||
|
@ -20,15 +20,15 @@ export class MatchRequest {
|
||||||
@AutoMap()
|
@AutoMap()
|
||||||
waypoints: Array<Point>;
|
waypoints: Array<Point>;
|
||||||
|
|
||||||
@IsDate()
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
@AutoMap()
|
@AutoMap()
|
||||||
departure: Date;
|
departure: number;
|
||||||
|
|
||||||
@IsDate()
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
|
@IsInt()
|
||||||
@AutoMap()
|
@AutoMap()
|
||||||
fromDate: Date;
|
fromDate: number;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@AutoMap()
|
@AutoMap()
|
||||||
|
@ -45,9 +45,9 @@ export class MatchRequest {
|
||||||
passenger: boolean;
|
passenger: boolean;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsDate()
|
@IsInt()
|
||||||
@AutoMap()
|
@AutoMap()
|
||||||
toDate: Date;
|
toDate: number;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsInt()
|
@IsInt()
|
||||||
|
@ -123,4 +123,9 @@ export class MatchRequest {
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsArray()
|
@IsArray()
|
||||||
exclusions: Array<number>;
|
exclusions: Array<number>;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsInt()
|
||||||
|
@AutoMap()
|
||||||
|
identifier: number;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
import { Point } from './point.type';
|
||||||
|
import { Route } from './route';
|
||||||
|
|
||||||
|
export class Geography {
|
||||||
|
waypoints: Array<Point>;
|
||||||
|
originType: number;
|
||||||
|
destinationType: number;
|
||||||
|
timezone: string;
|
||||||
|
driverRoute: Route;
|
||||||
|
passengerRoute: Route;
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
import { MatchRequest } from '../dtos/match.request';
|
||||||
|
|
||||||
|
export class Person {
|
||||||
|
_matchRequest: MatchRequest;
|
||||||
|
_defaultIdentifier: number;
|
||||||
|
_defaultMarginDuration: number;
|
||||||
|
identifier: number;
|
||||||
|
marginDurations: Array<number>;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
matchRequest: MatchRequest,
|
||||||
|
defaultIdentifier: number,
|
||||||
|
defaultMarginDuration: number,
|
||||||
|
) {
|
||||||
|
this._matchRequest = matchRequest;
|
||||||
|
this._defaultIdentifier = defaultIdentifier;
|
||||||
|
this._defaultMarginDuration = defaultMarginDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
this.setIdentifier(
|
||||||
|
this._matchRequest.identifier ?? this._defaultIdentifier,
|
||||||
|
);
|
||||||
|
this.setMarginDurations([
|
||||||
|
this._defaultMarginDuration,
|
||||||
|
this._defaultMarginDuration,
|
||||||
|
this._defaultMarginDuration,
|
||||||
|
this._defaultMarginDuration,
|
||||||
|
this._defaultMarginDuration,
|
||||||
|
this._defaultMarginDuration,
|
||||||
|
this._defaultMarginDuration,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
setIdentifier(identifier: number) {
|
||||||
|
this.identifier = identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
setMarginDurations(marginDurations: Array<number>) {
|
||||||
|
this.marginDurations = marginDurations;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
export class Requirement {
|
||||||
|
seatsDriver: number;
|
||||||
|
seatsPassenger: number;
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
export class Route {}
|
|
@ -0,0 +1,14 @@
|
||||||
|
import { Georouter } from '../interfaces/georouter.interface';
|
||||||
|
|
||||||
|
export class Settings {
|
||||||
|
algorithm: Algorithm;
|
||||||
|
restrict: boolean;
|
||||||
|
remoteness: number;
|
||||||
|
useProportion: boolean;
|
||||||
|
proportion: number;
|
||||||
|
useAzimuth: boolean;
|
||||||
|
azimuthMargin: number;
|
||||||
|
maxDetourDurationRatio: number;
|
||||||
|
maxDetourDistanceRatio: number;
|
||||||
|
georouter: Georouter;
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
import { MatcherException } from '../../exceptions/matcher.exception';
|
||||||
|
import { MatchRequest } from '../dtos/match.request';
|
||||||
|
import { TimingFrequency } from './timing';
|
||||||
|
|
||||||
|
export class Time {
|
||||||
|
_matchRequest: MatchRequest;
|
||||||
|
_defaultMarginDuration: number;
|
||||||
|
_defaultValidityDuration: number;
|
||||||
|
frequency: TimingFrequency;
|
||||||
|
fromDate: Date;
|
||||||
|
toDate: Date;
|
||||||
|
schedule: Array<Date>;
|
||||||
|
marginDurations: Array<number>;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
matchRequest: MatchRequest,
|
||||||
|
defaultMarginDuration: number,
|
||||||
|
defaultValidityDuration: number,
|
||||||
|
) {
|
||||||
|
this._matchRequest = matchRequest;
|
||||||
|
this._defaultMarginDuration = defaultMarginDuration;
|
||||||
|
this._defaultValidityDuration = defaultValidityDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
this._validatePunctualDate();
|
||||||
|
this._validateRecurrentDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
_validatePunctualDate() {
|
||||||
|
if (!this._matchRequest.departure && !this._matchRequest.fromDate) {
|
||||||
|
throw new MatcherException(3, 'departure or fromDate is Required');
|
||||||
|
}
|
||||||
|
if (this._matchRequest.departure) {
|
||||||
|
this.fromDate = new Date(this._matchRequest.departure);
|
||||||
|
if (!this._isDate(this.fromDate)) {
|
||||||
|
throw new MatcherException(3, 'Wrong departure date');
|
||||||
|
}
|
||||||
|
console.log(this.fromDate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_validateRecurrentDate() {
|
||||||
|
console.log('validate recurrent date');
|
||||||
|
}
|
||||||
|
|
||||||
|
_isDate(date: Date) {
|
||||||
|
return date instanceof Date && isFinite(+date);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
export enum TimingFrequency {
|
||||||
|
FREQUENCY_PUNCTUAL = 1,
|
||||||
|
FREQUENCY_RECURRENT = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum TimingDays {
|
||||||
|
'mon',
|
||||||
|
'tue',
|
||||||
|
'wed',
|
||||||
|
'thu',
|
||||||
|
'fri',
|
||||||
|
'sat',
|
||||||
|
'sun',
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
export interface Georouter {
|
||||||
|
type: string;
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,85 @@
|
||||||
|
import { ConfigService } from '@nestjs/config';
|
||||||
import { MatchRequest } from '../domain/dtos/match.request';
|
import { MatchRequest } from '../domain/dtos/match.request';
|
||||||
|
import { Geography } from '../domain/entities/geography';
|
||||||
|
import { Person } from '../domain/entities/person';
|
||||||
|
import { Requirement } from '../domain/entities/requirement';
|
||||||
|
import { Role } from '../domain/entities/role.enum';
|
||||||
|
import { Settings } from '../domain/entities/settings';
|
||||||
|
import { Time } from '../domain/entities/time';
|
||||||
|
import { MatcherException } from '../exceptions/matcher.exception';
|
||||||
|
|
||||||
export class MatchQuery {
|
export class MatchQuery {
|
||||||
matchRequest: MatchRequest;
|
private readonly _matchRequest: MatchRequest;
|
||||||
|
private readonly _configService: ConfigService;
|
||||||
|
person: Person;
|
||||||
|
exclusions: Array<number>;
|
||||||
|
time: Time;
|
||||||
|
geography: Geography;
|
||||||
|
roles: Array<Role>;
|
||||||
|
requirement: Requirement;
|
||||||
|
settings: Settings;
|
||||||
|
|
||||||
constructor(matchRequest?: MatchRequest) {
|
constructor(matchRequest: MatchRequest, configService: ConfigService) {
|
||||||
this.matchRequest = matchRequest;
|
this._matchRequest = matchRequest;
|
||||||
|
this._configService = configService;
|
||||||
|
this._validate();
|
||||||
|
this._initialize();
|
||||||
|
this._setPerson();
|
||||||
|
this._setExclusions();
|
||||||
|
this._setRoles();
|
||||||
|
this._setTime();
|
||||||
|
// console.log(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
_validate() {
|
||||||
|
if (!this._matchRequest.departure) {
|
||||||
|
if (!this._matchRequest.fromDate)
|
||||||
|
throw new MatcherException(3, 'departure or fromDate is Required');
|
||||||
|
if (!this._matchRequest.schedule)
|
||||||
|
throw new MatcherException(3, 'schedule is Required');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_initialize() {
|
||||||
|
if (
|
||||||
|
this._matchRequest.driver === undefined &&
|
||||||
|
this._matchRequest.passenger === undefined
|
||||||
|
)
|
||||||
|
this._matchRequest.passenger = true;
|
||||||
|
this.geography = new Geography();
|
||||||
|
this.requirement = new Requirement();
|
||||||
|
this.settings = new Settings();
|
||||||
|
}
|
||||||
|
|
||||||
|
_setPerson() {
|
||||||
|
this.person = new Person(
|
||||||
|
this._matchRequest,
|
||||||
|
this._configService.get<number>('DEFAULT_IDENTIFIER'),
|
||||||
|
this._configService.get<number>('MARGIN_DURATION'),
|
||||||
|
);
|
||||||
|
this.person.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
_setExclusions() {
|
||||||
|
this.exclusions = [];
|
||||||
|
if (this._matchRequest.identifier)
|
||||||
|
this.exclusions.push(this._matchRequest.identifier);
|
||||||
|
if (this._matchRequest.exclusions)
|
||||||
|
this.exclusions.push(...this._matchRequest.exclusions);
|
||||||
|
}
|
||||||
|
|
||||||
|
_setRoles() {
|
||||||
|
this.roles = [];
|
||||||
|
if (this._matchRequest.driver) this.roles.push(Role.DRIVER);
|
||||||
|
if (this._matchRequest.passenger) this.roles.push(Role.PASSENGER);
|
||||||
|
}
|
||||||
|
|
||||||
|
_setTime() {
|
||||||
|
this.time = new Time(
|
||||||
|
this._matchRequest,
|
||||||
|
this._configService.get<number>('MARGIN_DURATION'),
|
||||||
|
this._configService.get<number>('VALIDITY_DURATION'),
|
||||||
|
);
|
||||||
|
this.time.init();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue