use interfaces for requests

This commit is contained in:
sbriat 2023-04-11 10:13:15 +02:00
parent d6a12e4d0e
commit 8ab1ddbebc
16 changed files with 141 additions and 47 deletions

View File

@ -89,6 +89,7 @@
".controller.ts",
".module.ts",
".request.ts",
".presenter.ts",
"main.ts"
],
"rootDir": "src",

View File

@ -9,7 +9,7 @@ import { ICollection } from 'src/modules/database/src/interfaces/collection.inte
import { Match } from '../../domain/entities/match';
import { MatchQuery } from '../../queries/match.query';
import { MatchPresenter } from '../secondaries/match.presenter';
import { ConfigService } from '@nestjs/config';
import { DefaultParamsProvider } from '../secondaries/default-params.provider';
@UsePipes(
new RpcValidationPipe({
@ -21,7 +21,7 @@ import { ConfigService } from '@nestjs/config';
export class MatcherController {
constructor(
private readonly _queryBus: QueryBus,
private readonly _configService: ConfigService,
private readonly _defaultParamsProvider: DefaultParamsProvider,
@InjectMapper() private readonly _mapper: Mapper,
) {}
@ -29,7 +29,7 @@ export class MatcherController {
async match(data: MatchRequest): Promise<ICollection<Match>> {
try {
const matchCollection = await this._queryBus.execute(
new MatchQuery(data, this._configService),
new MatchQuery(data, this._defaultParamsProvider.getParams()),
);
return Promise.resolve({
data: matchCollection.data.map((match: Match) =>

View File

@ -0,0 +1,16 @@
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { IDefaultParams } from '../../domain/interfaces/default-params.interface';
@Injectable()
export class DefaultParamsProvider {
constructor(private readonly configService: ConfigService) {}
getParams(): IDefaultParams {
return {
DEFAULT_IDENTIFIER: this.configService.get<number>('DEFAULT_IDENTIFIER'),
MARGIN_DURATION: this.configService.get<number>('MARGIN_DURATION'),
VALIDITY_DURATION: this.configService.get<number>('VALIDITY_DURATION'),
};
}
}

View File

@ -1,7 +1,7 @@
import { Injectable } from '@nestjs/common';
@Injectable()
export abstract class IMessageBroker {
export abstract class MessageBroker {
exchange: string;
constructor(exchange: string) {

View File

@ -1,10 +1,10 @@
import { AmqpConnection } from '@golevelup/nestjs-rabbitmq';
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { IMessageBroker } from './message-broker';
import { MessageBroker } from './message-broker';
@Injectable()
export class Messager extends IMessageBroker {
export class Messager extends MessageBroker {
constructor(
private readonly _amqpConnection: AmqpConnection,
configService: ConfigService,

View File

@ -14,8 +14,13 @@ import { Point } from '../entities/point.type';
import { Schedule } from './schedule.type';
import { MarginDurations } from './margin-durations.type';
import { Algorithm } from './algorithm.enum';
import { IRequestTime } from '../interfaces/time-request.interface';
import { IRequestRole } from '../interfaces/role-request.interface';
import { IRequestPerson } from '../interfaces/person-request.interface';
export class MatchRequest {
export class MatchRequest
implements IRequestTime, IRequestRole, IRequestPerson
{
@IsArray()
@AutoMap()
waypoints: Array<Point>;
@ -23,12 +28,12 @@ export class MatchRequest {
@IsOptional()
@IsString()
@AutoMap()
departure: number;
departure: string;
@IsOptional()
@IsInt()
@IsString()
@AutoMap()
fromDate: number;
fromDate: string;
@IsOptional()
@AutoMap()

View File

@ -1,25 +1,25 @@
import { MatchRequest } from '../dtos/match.request';
import { IRequestPerson } from '../interfaces/person-request.interface';
export class Person {
_matchRequest: MatchRequest;
_personRequest: IRequestPerson;
_defaultIdentifier: number;
_defaultMarginDuration: number;
identifier: number;
marginDurations: Array<number>;
constructor(
matchRequest: MatchRequest,
personRequest: IRequestPerson,
defaultIdentifier: number,
defaultMarginDuration: number,
) {
this._matchRequest = matchRequest;
this._personRequest = personRequest;
this._defaultIdentifier = defaultIdentifier;
this._defaultMarginDuration = defaultMarginDuration;
}
init() {
this.setIdentifier(
this._matchRequest.identifier ?? this._defaultIdentifier,
this._personRequest.identifier ?? this._defaultIdentifier,
);
this.setMarginDurations([
this._defaultMarginDuration,

View File

@ -1,9 +1,9 @@
import { MatcherException } from '../../exceptions/matcher.exception';
import { MatchRequest } from '../dtos/match.request';
import { IRequestTime } from '../interfaces/time-request.interface';
import { TimingFrequency } from './timing';
export class Time {
_matchRequest: MatchRequest;
_timeRequest: IRequestTime;
_defaultMarginDuration: number;
_defaultValidityDuration: number;
frequency: TimingFrequency;
@ -13,35 +13,44 @@ export class Time {
marginDurations: Array<number>;
constructor(
matchRequest: MatchRequest,
timeRequest: IRequestTime,
defaultMarginDuration: number,
defaultValidityDuration: number,
) {
this._matchRequest = matchRequest;
this._timeRequest = timeRequest;
this._defaultMarginDuration = defaultMarginDuration;
this._defaultValidityDuration = defaultValidityDuration;
}
init() {
this._validateBaseDate();
this._validatePunctualDate();
this._validateRecurrentDate();
console.log(this.fromDate);
}
_validateBaseDate() {
if (!this._timeRequest.departure && !this._timeRequest.fromDate) {
throw new MatcherException(3, 'departure or fromDate is required');
}
}
_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._timeRequest.departure) {
this.fromDate = new Date(this._timeRequest.departure);
if (!this._isDate(this.fromDate)) {
throw new MatcherException(3, 'Wrong departure date');
}
console.log(this.fromDate);
}
}
_validateRecurrentDate() {
console.log('validate recurrent date');
if (this._timeRequest.fromDate) {
this.fromDate = new Date(this._timeRequest.fromDate);
if (!this._isDate(this.fromDate)) {
throw new MatcherException(3, 'Wrong fromDate');
}
}
}
_isDate(date: Date) {

View File

@ -0,0 +1,5 @@
export interface IDefaultParams {
DEFAULT_IDENTIFIER: number;
MARGIN_DURATION: number;
VALIDITY_DURATION: number;
}

View File

@ -0,0 +1,3 @@
export interface IRequestPerson {
identifier: number;
}

View File

@ -0,0 +1,4 @@
export interface IRequestRole {
driver: boolean;
passenger: boolean;
}

View File

@ -0,0 +1,7 @@
import { Schedule } from '../dtos/schedule.type';
export interface IRequestTime {
departure: string;
fromDate: string;
schedule: Schedule;
}

View File

@ -11,6 +11,7 @@ import { Messager } from './adapters/secondaries/messager';
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';
@Module({
imports: [
@ -44,7 +45,13 @@ import { redisStore } from 'cache-manager-ioredis-yet';
}),
],
controllers: [MatcherController],
providers: [MatchProfile, AdRepository, Messager, MatchUseCase],
providers: [
MatchProfile,
AdRepository,
Messager,
DefaultParamsProvider,
MatchUseCase,
],
exports: [],
})
export class MatcherModule {}

View File

@ -1,4 +1,3 @@
import { ConfigService } from '@nestjs/config';
import { MatchRequest } from '../domain/dtos/match.request';
import { Geography } from '../domain/entities/geography';
import { Person } from '../domain/entities/person';
@ -6,11 +5,11 @@ 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';
import { IDefaultParams } from '../domain/interfaces/default-params.interface';
export class MatchQuery {
private readonly _matchRequest: MatchRequest;
private readonly _configService: ConfigService;
private readonly _defaultParams: IDefaultParams;
person: Person;
exclusions: Array<number>;
time: Time;
@ -19,10 +18,9 @@ export class MatchQuery {
requirement: Requirement;
settings: Settings;
constructor(matchRequest: MatchRequest, configService: ConfigService) {
constructor(matchRequest: MatchRequest, defaultParams: IDefaultParams) {
this._matchRequest = matchRequest;
this._configService = configService;
this._validate();
this._defaultParams = defaultParams;
this._initialize();
this._setPerson();
this._setExclusions();
@ -31,15 +29,6 @@ export class MatchQuery {
// 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 &&
@ -54,8 +43,8 @@ export class MatchQuery {
_setPerson() {
this.person = new Person(
this._matchRequest,
this._configService.get<number>('DEFAULT_IDENTIFIER'),
this._configService.get<number>('MARGIN_DURATION'),
this._defaultParams.DEFAULT_IDENTIFIER,
this._defaultParams.MARGIN_DURATION,
);
this.person.init();
}
@ -77,8 +66,8 @@ export class MatchQuery {
_setTime() {
this.time = new Time(
this._matchRequest,
this._configService.get<number>('MARGIN_DURATION'),
this._configService.get<number>('VALIDITY_DURATION'),
this._defaultParams.MARGIN_DURATION,
this._defaultParams.VALIDITY_DURATION,
);
this.time.init();
}

View File

@ -0,0 +1,38 @@
import { ConfigService } from '@nestjs/config';
import { Test, TestingModule } from '@nestjs/testing';
import { DefaultParamsProvider } from '../../adapters/secondaries/default-params.provider';
import { IDefaultParams } from '../../domain/interfaces/default-params.interface';
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>(
DefaultParamsProvider,
);
});
it('should be defined', () => {
expect(defaultParamsProvider).toBeDefined();
});
it('should provide default params', async () => {
const params: IDefaultParams = defaultParamsProvider.getParams();
expect(params.DEFAULT_IDENTIFIER).toBe(99);
});
});

View File

@ -6,6 +6,7 @@ import { MatchQuery } from '../../queries/match.query';
import { AdRepository } from '../../adapters/secondaries/ad.repository';
import { AutomapperModule } from '@automapper/nestjs';
import { classes } from '@automapper/classes';
import { IDefaultParams } from '../../domain/interfaces/default-params.interface';
const mockAdRepository = {};
@ -13,6 +14,12 @@ const mockMessager = {
publish: jest.fn().mockImplementation(),
};
const defaultParams: IDefaultParams = {
DEFAULT_IDENTIFIER: 0,
MARGIN_DURATION: 900,
VALIDITY_DURATION: 365,
};
describe('MatchUseCase', () => {
let matchUseCase: MatchUseCase;
@ -52,7 +59,10 @@ describe('MatchUseCase', () => {
lon: 3.045432,
},
];
const matches = await matchUseCase.execute(new MatchQuery(matchRequest));
matchRequest.departure = '2023-04-01 12:23:00';
const matches = await matchUseCase.execute(
new MatchQuery(matchRequest, defaultParams),
);
expect(matches.total).toBe(1);
});
});