Merge branch 'refactor' into 'main'

refactor and fixes

See merge request v3/service/ad!6
This commit is contained in:
Sylvain Briat 2023-06-06 09:13:25 +00:00
commit 2754c36132
11 changed files with 51 additions and 99 deletions

View File

@ -4,5 +4,5 @@ import { Ad } from '../../domain/entities/ad';
//TODO : properly implement mutate operation to prisma
@Injectable()
export class AdsRepository extends AdRepository<Ad> {
protected _model = 'ad';
protected model = 'ad';
}

View File

@ -6,20 +6,18 @@ import { IProvideParams } from '../../domain/interfaces/param-provider.interface
@Injectable()
export class DefaultParamsProvider implements IProvideParams {
constructor(private readonly configService: ConfigService) {}
getParams = (): DefaultParams => {
return {
MON_MARGIN: parseInt(this.configService.get('DEPARTURE_MARGIN')),
TUE_MARGIN: parseInt(this.configService.get('DEPARTURE_MARGIN')),
WED_MARGIN: parseInt(this.configService.get('DEPARTURE_MARGIN')),
THU_MARGIN: parseInt(this.configService.get('DEPARTURE_MARGIN')),
FRI_MARGIN: parseInt(this.configService.get('DEPARTURE_MARGIN')),
SAT_MARGIN: parseInt(this.configService.get('DEPARTURE_MARGIN')),
SUN_MARGIN: parseInt(this.configService.get('DEPARTURE_MARGIN')),
DRIVER: this.configService.get('ROLE') == 'driver' ? true : false,
SEATS_PROVIDED: parseInt(this.configService.get('SEATS_PROVIDED')),
PASSENGER: this.configService.get('ROLE') == 'passenger' ? true : false,
SEATS_REQUESTED: parseInt(this.configService.get('SEATS_REQUESTED')),
STRICT: false,
};
};
getParams = (): DefaultParams => ({
MON_MARGIN: parseInt(this.configService.get('DEPARTURE_MARGIN')),
TUE_MARGIN: parseInt(this.configService.get('DEPARTURE_MARGIN')),
WED_MARGIN: parseInt(this.configService.get('DEPARTURE_MARGIN')),
THU_MARGIN: parseInt(this.configService.get('DEPARTURE_MARGIN')),
FRI_MARGIN: parseInt(this.configService.get('DEPARTURE_MARGIN')),
SAT_MARGIN: parseInt(this.configService.get('DEPARTURE_MARGIN')),
SUN_MARGIN: parseInt(this.configService.get('DEPARTURE_MARGIN')),
DRIVER: this.configService.get('ROLE') == 'driver',
SEATS_PROVIDED: parseInt(this.configService.get('SEATS_PROVIDED')),
PASSENGER: this.configService.get('ROLE') == 'passenger',
SEATS_REQUESTED: parseInt(this.configService.get('SEATS_REQUESTED')),
STRICT: this.configService.get('STRICT_FREQUENCY') == 'true',
});
}

View File

@ -1,130 +1,86 @@
import { AutoMap } from '@automapper/classes';
import {
IsOptional,
IsString,
IsBoolean,
IsDate,
IsInt,
IsEnum,
ValidateNested,
IsUUID,
} from 'class-validator';
import { Frequency } from '../types/frequency.enum';
import { Address } from '../entities/address';
export class AdCreation {
@IsUUID(4)
@AutoMap()
uuid: string;
@IsUUID(4)
@AutoMap()
userUuid: string;
@IsBoolean()
@AutoMap()
driver: boolean;
@IsBoolean()
@AutoMap()
passenger: boolean;
@IsEnum(Frequency)
@AutoMap()
frequency: Frequency;
@IsDate()
@AutoMap()
fromDate: Date;
@IsDate()
@AutoMap()
toDate: Date;
@IsOptional()
@IsDate()
@AutoMap()
monTime?: string;
@IsOptional()
@IsString()
@AutoMap()
tueTime?: string;
@IsOptional()
@IsString()
@AutoMap()
wedTime?: string;
@IsOptional()
@IsString()
@AutoMap()
thuTime?: string;
@IsOptional()
@IsString()
@AutoMap()
friTime?: string;
@IsOptional()
@IsString()
@AutoMap()
satTime?: string;
@IsOptional()
@IsString()
@AutoMap()
sunTime?: string;
@IsInt()
@AutoMap()
monMargin: number;
@IsInt()
@AutoMap()
tueMargin: number;
@IsInt()
@AutoMap()
wedMargin: number;
@IsInt()
@AutoMap()
thuMargin: number;
@IsInt()
@AutoMap()
friMargin: number;
@IsInt()
@AutoMap()
satMargin: number;
@IsInt()
@AutoMap()
sunMargin: number;
@IsInt()
@AutoMap()
seatsDriver: number;
@IsInt()
@AutoMap()
seatsPassenger: number;
@IsBoolean()
@AutoMap()
strict: boolean;
@IsDate()
@AutoMap()
createdAt: Date;
@IsDate()
@AutoMap()
updatedAt?: Date;
@ValidateNested({ each: true })
@AutoMap()
addresses: { create: Address[] };
}

View File

@ -68,6 +68,7 @@ export class CreateAdRequest {
@AutoMap()
toDate?: Date;
@IsOptional()
@Type(() => ScheduleDTO)
@IsPunctualOrRecurrent()
@ValidateNested({ each: true })

View File

@ -18,7 +18,7 @@ export const IsPunctualOrRecurrent = (
isPunctualOrRecurrent(args),
defaultMessage: buildMessage(
() =>
`the departure, from date, to date and schedule must be properly set on reccurent or punctual ad`,
`the departure, from date, to date and schedule must be properly set on recurrent or punctual ad`,
validationOptions,
),
},

View File

@ -31,7 +31,7 @@ export class CreateAdUseCase {
CreateAdRequest,
AdCreation,
);
this.setDefaultSchedule();
this.setDefaultMarginDurations();
this.setDefaultAddressesPosition();
this.setDefaultDriverAndPassengerParameters();
this.setDefaultStrict();
@ -60,7 +60,7 @@ export class CreateAdUseCase {
}
}
private setDefaultSchedule = (): void => {
private setDefaultMarginDurations = (): void => {
if (this.ad.monMargin === undefined)
this.ad.monMargin = this.defaultParams.MON_MARGIN;
if (this.ad.tueMargin === undefined)
@ -83,21 +83,19 @@ export class CreateAdUseCase {
};
private setDefaultDriverAndPassengerParameters = (): void => {
this.ad.driver = !!this.ad.driver;
this.ad.passenger = !!this.ad.passenger;
if (!this.ad.driver && !this.ad.passenger) {
this.ad.driver = this.defaultParams.DRIVER;
this.ad.seatsDriver = this.defaultParams.SEATS_PROVIDED;
this.ad.passenger = this.defaultParams.PASSENGER;
this.ad.seatsPassenger = this.defaultParams.SEATS_REQUESTED;
} else {
if (!this.ad.driver) {
this.ad.driver = false;
this.ad.seatsDriver = 0;
}
if (!this.ad.passenger) {
this.ad.passenger = false;
this.ad.seatsPassenger = 0;
}
return;
}
if (!this.ad.seatsDriver || this.ad.seatsDriver <= 0)
this.ad.seatsDriver = this.defaultParams.SEATS_PROVIDED;
if (!this.ad.seatsPassenger || this.ad.seatsPassenger <= 0)
this.ad.seatsPassenger = this.defaultParams.SEATS_REQUESTED;
};
private setDefaultAddressesPosition = (): void => {

View File

@ -21,34 +21,33 @@ export class AdProfile extends AutomapperProfile {
mapper,
CreateAdRequest,
AdCreation,
forMember(
(destination) => destination.monMargin,
mapFrom((source) => source.marginDurations.mon),
mapFrom((source) => source.marginDurations?.mon),
),
forMember(
(destination) => destination.tueMargin,
mapFrom((source) => source.marginDurations.tue),
mapFrom((source) => source.marginDurations?.tue),
),
forMember(
(destination) => destination.wedMargin,
mapFrom((source) => source.marginDurations.wed),
mapFrom((source) => source.marginDurations?.wed),
),
forMember(
(destination) => destination.thuMargin,
mapFrom((source) => source.marginDurations.thu),
mapFrom((source) => source.marginDurations?.thu),
),
forMember(
(destination) => destination.friMargin,
mapFrom((source) => source.marginDurations.fri),
mapFrom((source) => source.marginDurations?.fri),
),
forMember(
(destination) => destination.satMargin,
mapFrom((source) => source.marginDurations.sat),
mapFrom((source) => source.marginDurations?.sat),
),
forMember(
(destination) => destination.sunMargin,
mapFrom((source) => source.marginDurations.sun),
mapFrom((source) => source.marginDurations?.sun),
),
forMember(
(destination) => destination.monTime,

View File

@ -5,7 +5,7 @@ describe('frequency mapping function ', () => {
it('should return punctual', () => {
expect(intToFrequency(1)).toBe(Frequency.PUNCTUAL);
});
it('should return recurent', () => {
it('should return recurrent', () => {
expect(intToFrequency(2)).toBe(Frequency.RECURRENT);
});
it('should return undefined', () => {

View File

@ -1,7 +1,7 @@
import { isPunctualOrRecurrent } from '../../../domain/dtos/validators/is-punctual-or-recurrent';
import { Frequency } from '../../../domain/types/frequency.enum';
describe('punctual or reccurent validators', () => {
describe('punctual or recurrent validators', () => {
describe('punctual case ', () => {
describe('valid cases', () => {
it('should validate with valid departure and empty schedule ', () => {
@ -55,7 +55,7 @@ describe('punctual or reccurent validators', () => {
});
});
});
describe('reccurent case ', () => {
describe('recurrent case ', () => {
describe('valid cases', () => {
it('should validate with valid from date, to date and non empty schedule ', () => {
expect(

View File

@ -6,11 +6,11 @@ import { IRepository } from '../../interfaces/repository.interface';
import { PrismaService } from './prisma-service';
/**
* Child classes MUST redefined _model property with appropriate model name
* Child classes MUST redefined model property with appropriate model name
*/
@Injectable()
export abstract class PrismaRepository<T> implements IRepository<T> {
protected _model: string;
protected model: string;
constructor(protected readonly _prisma: PrismaService) {}
@ -21,13 +21,13 @@ export abstract class PrismaRepository<T> implements IRepository<T> {
include?: any,
): Promise<ICollection<T>> {
const [data, total] = await this._prisma.$transaction([
this._prisma[this._model].findMany({
this._prisma[this.model].findMany({
where,
include,
skip: (page - 1) * perPage,
take: perPage,
}),
this._prisma[this._model].count({
this._prisma[this.model].count({
where,
}),
]);
@ -39,7 +39,7 @@ export abstract class PrismaRepository<T> implements IRepository<T> {
async findOneByUuid(uuid: string): Promise<T> {
try {
const entity = await this._prisma[this._model].findUnique({
const entity = await this._prisma[this.model].findUnique({
where: { uuid },
});
@ -59,7 +59,7 @@ export abstract class PrismaRepository<T> implements IRepository<T> {
async findOne(where: any, include?: any): Promise<T> {
try {
const entity = await this._prisma[this._model].findFirst({
const entity = await this._prisma[this.model].findFirst({
where: where,
include: include,
});
@ -81,7 +81,7 @@ export abstract class PrismaRepository<T> implements IRepository<T> {
// TODO : Refactor for good clean architecture ?
async create(entity: Partial<T> | any, include?: any): Promise<T> {
try {
const res = await this._prisma[this._model].create({
const res = await this._prisma[this.model].create({
data: entity,
include: include,
});
@ -101,7 +101,7 @@ export abstract class PrismaRepository<T> implements IRepository<T> {
async update(uuid: string, entity: Partial<T>): Promise<T> {
try {
const updatedEntity = await this._prisma[this._model].update({
const updatedEntity = await this._prisma[this.model].update({
where: { uuid },
data: entity,
});
@ -125,7 +125,7 @@ export abstract class PrismaRepository<T> implements IRepository<T> {
include?: any,
): Promise<T> {
try {
const updatedEntity = await this._prisma[this._model].update({
const updatedEntity = await this._prisma[this.model].update({
where: where,
data: entity,
include: include,
@ -147,7 +147,7 @@ export abstract class PrismaRepository<T> implements IRepository<T> {
async delete(uuid: string): Promise<T> {
try {
const entity = await this._prisma[this._model].delete({
const entity = await this._prisma[this.model].delete({
where: { uuid },
});
@ -167,7 +167,7 @@ export abstract class PrismaRepository<T> implements IRepository<T> {
async deleteMany(where: any): Promise<void> {
try {
const entity = await this._prisma[this._model].deleteMany({
const entity = await this._prisma[this.model].deleteMany({
where: where,
});
@ -190,7 +190,7 @@ export abstract class PrismaRepository<T> implements IRepository<T> {
where: string[],
): Promise<ICollection<T>> {
const query = `SELECT ${include.join(',')} FROM ${
this._model
this.model
} WHERE ${where.join(' AND ')}`;
const data: T[] = await this._prisma.$queryRawUnsafe(query);
return Promise.resolve({
@ -201,7 +201,7 @@ export abstract class PrismaRepository<T> implements IRepository<T> {
async createWithFields(fields: object): Promise<number> {
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(',')})`;
return await this._prisma.$executeRawUnsafe(command);
@ -222,7 +222,7 @@ export abstract class PrismaRepository<T> implements IRepository<T> {
entity['"updatedAt"'] = `to_timestamp(${Date.now()} / 1000.0)`;
const values = Object.keys(entity).map((key) => `${key} = ${entity[key]}`);
try {
const command = `UPDATE ${this._model} SET ${values.join(
const command = `UPDATE ${this.model} SET ${values.join(
', ',
)} WHERE uuid = '${uuid}'`;
return await this._prisma.$executeRawUnsafe(command);

View File

@ -41,7 +41,7 @@ Array.from({ length: 10 }).forEach(() => {
@Injectable()
class FakePrismaRepository extends PrismaRepository<FakeEntity> {
protected _model = 'fake';
protected model = 'fake';
}
class FakePrismaService extends PrismaService {