WIP ad creation mapping
This commit is contained in:
		
							parent
							
								
									954f26b2b3
								
							
						
					
					
						commit
						bee5fef9ff
					
				| 
						 | 
				
			
			@ -11,7 +11,6 @@ import { Ad } from '../../domain/entities/ad';
 | 
			
		|||
import { CreateAdRequest } from '../../domain/dtos/create-ad.request';
 | 
			
		||||
import { CreateAdCommand } from '../../commands/create-ad.command';
 | 
			
		||||
import { DatabaseException } from '../../../database/exceptions/database.exception';
 | 
			
		||||
import { AddressDTO } from '../../domain/dtos/create.address.dto';
 | 
			
		||||
 | 
			
		||||
@UsePipes(
 | 
			
		||||
  new RpcValidationPipe({
 | 
			
		||||
| 
						 | 
				
			
			@ -43,9 +42,6 @@ export class AdController {
 | 
			
		|||
  @GrpcMethod('AdsService', 'Create')
 | 
			
		||||
  async createAd(data: CreateAdRequest): Promise<AdPresenter> {
 | 
			
		||||
    try {
 | 
			
		||||
      console.log('controler--------------------------------');
 | 
			
		||||
      console.log(data);
 | 
			
		||||
      console.log('-----------------------------------------');
 | 
			
		||||
      const ad = await this._commandBus.execute(new CreateAdCommand(data));
 | 
			
		||||
      return this._mapper.map(ad, Ad, AdPresenter);
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,34 +1,7 @@
 | 
			
		|||
import { Injectable } from '@nestjs/common';
 | 
			
		||||
import { AdRepository } from '../../../database/domain/ad-repository';
 | 
			
		||||
import { Ad } from '../../domain/entities/ad';
 | 
			
		||||
import { DatabaseException } from '../../../database/exceptions/database.exception';
 | 
			
		||||
import { Prisma } from '@prisma/client';
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class AdsRepository extends AdRepository<Ad> {
 | 
			
		||||
  protected _model = 'ad';
 | 
			
		||||
 | 
			
		||||
  async create(entity: Partial<Ad> | any, include?: any): Promise<Ad> {
 | 
			
		||||
    console.log('custom ad repo ');
 | 
			
		||||
    console.log(entity);
 | 
			
		||||
    console.log('*****************************************');
 | 
			
		||||
    try {
 | 
			
		||||
      const res = await this._prisma[this._model].create({
 | 
			
		||||
        data: entity,
 | 
			
		||||
        include: include,
 | 
			
		||||
      });
 | 
			
		||||
      return res;
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      console.log('repo error ');
 | 
			
		||||
      console.log(e);
 | 
			
		||||
      if (e instanceof Prisma.PrismaClientKnownRequestError) {
 | 
			
		||||
        throw new DatabaseException(
 | 
			
		||||
          Prisma.PrismaClientKnownRequestError.name,
 | 
			
		||||
          e.code,
 | 
			
		||||
          e.message,
 | 
			
		||||
        );
 | 
			
		||||
      } else {
 | 
			
		||||
        throw new DatabaseException();
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,125 @@
 | 
			
		|||
import { AutoMap } from '@automapper/classes';
 | 
			
		||||
import {
 | 
			
		||||
  IsOptional,
 | 
			
		||||
  IsString,
 | 
			
		||||
  IsBoolean,
 | 
			
		||||
  IsDate,
 | 
			
		||||
  IsInt,
 | 
			
		||||
  IsEnum,
 | 
			
		||||
  ValidateNested,
 | 
			
		||||
  IsUUID,
 | 
			
		||||
} from 'class-validator';
 | 
			
		||||
import { Frequency } from '../types/frequency.enum';
 | 
			
		||||
import { AddressCreation } from './address.creation';
 | 
			
		||||
export class AdCreation {
 | 
			
		||||
  @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: AddressCreation[] };
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,32 @@
 | 
			
		|||
import { AutoMap } from '@automapper/classes';
 | 
			
		||||
import { IsInt } from 'class-validator';
 | 
			
		||||
 | 
			
		||||
export class AddressCreation {
 | 
			
		||||
  @IsInt()
 | 
			
		||||
  @AutoMap()
 | 
			
		||||
  position: number;
 | 
			
		||||
 | 
			
		||||
  @AutoMap()
 | 
			
		||||
  lon: number;
 | 
			
		||||
 | 
			
		||||
  @AutoMap()
 | 
			
		||||
  lat: number;
 | 
			
		||||
 | 
			
		||||
  @AutoMap()
 | 
			
		||||
  name?: string;
 | 
			
		||||
 | 
			
		||||
  @AutoMap()
 | 
			
		||||
  houseNumber?: string;
 | 
			
		||||
 | 
			
		||||
  @AutoMap()
 | 
			
		||||
  street?: string;
 | 
			
		||||
 | 
			
		||||
  @AutoMap()
 | 
			
		||||
  locality: string;
 | 
			
		||||
 | 
			
		||||
  @AutoMap()
 | 
			
		||||
  postalCode: string;
 | 
			
		||||
 | 
			
		||||
  @AutoMap()
 | 
			
		||||
  country: string;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -16,7 +16,7 @@ import { Transform, Type } from 'class-transformer';
 | 
			
		|||
import { mappingKeyToFrequency } from './utils/frequency.mapping';
 | 
			
		||||
import { MarginDTO } from './create.margin.dto';
 | 
			
		||||
import { ScheduleDTO } from './create.schedule.dto';
 | 
			
		||||
import { AddressDTO } from './create.address.dto';
 | 
			
		||||
import { AddressRequestDTO } from './create.address.request';
 | 
			
		||||
import { HasProperPassengerSeats } from './utils/has-passenger-seats.validator';
 | 
			
		||||
import { HasProperDriverSeats } from './utils/has-driver-seats.validator';
 | 
			
		||||
import { HasProperPositionIndexes } from './utils/address-position.validator';
 | 
			
		||||
| 
						 | 
				
			
			@ -27,7 +27,6 @@ export class CreateAdRequest {
 | 
			
		|||
  @AutoMap()
 | 
			
		||||
  uuid?: string;
 | 
			
		||||
 | 
			
		||||
  // TODO create validation rule to verify is user exists ??
 | 
			
		||||
  @IsUUID(4)
 | 
			
		||||
  @AutoMap()
 | 
			
		||||
  userUuid: string;
 | 
			
		||||
| 
						 | 
				
			
			@ -51,6 +50,7 @@ export class CreateAdRequest {
 | 
			
		|||
  @AutoMap()
 | 
			
		||||
  frequency: Frequency;
 | 
			
		||||
 | 
			
		||||
  // TODO create a proper validator
 | 
			
		||||
  @ValidateIf((ad) => ad.frequency === 'PUNCTUAL')
 | 
			
		||||
  @Type(() => Date)
 | 
			
		||||
  @IsDate()
 | 
			
		||||
| 
						 | 
				
			
			@ -98,9 +98,9 @@ export class CreateAdRequest {
 | 
			
		|||
  strict?: boolean;
 | 
			
		||||
 | 
			
		||||
  @ArrayMinSize(2)
 | 
			
		||||
  @Type(() => AddressDTO)
 | 
			
		||||
  @Type(() => AddressRequestDTO)
 | 
			
		||||
  @HasProperPositionIndexes()
 | 
			
		||||
  @ValidateNested({ each: true })
 | 
			
		||||
  @AutoMap()
 | 
			
		||||
  addresses: AddressDTO[];
 | 
			
		||||
  addresses: AddressRequestDTO[];
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,7 +8,7 @@ import {
 | 
			
		|||
  IsUUID,
 | 
			
		||||
} from 'class-validator';
 | 
			
		||||
 | 
			
		||||
export class AddressDTO {
 | 
			
		||||
export class AddressRequestDTO {
 | 
			
		||||
  @IsOptional()
 | 
			
		||||
  @IsUUID(4)
 | 
			
		||||
  @AutoMap()
 | 
			
		||||
| 
						 | 
				
			
			@ -1,7 +1,7 @@
 | 
			
		|||
import { ValidateBy, ValidationOptions, buildMessage } from 'class-validator';
 | 
			
		||||
import { AddressDTO } from '../create.address.dto';
 | 
			
		||||
import { AddressRequestDTO } from '../create.address.request';
 | 
			
		||||
 | 
			
		||||
export function hasProperPositionIndexes(value: AddressDTO[]) {
 | 
			
		||||
export function hasProperPositionIndexes(value: AddressRequestDTO[]) {
 | 
			
		||||
  if (value.every((address) => address.position === undefined)) return true;
 | 
			
		||||
  else if (value.every((address) => typeof address.position === 'number')) {
 | 
			
		||||
    value.sort((a, b) => a.position - b.position);
 | 
			
		||||
| 
						 | 
				
			
			@ -21,7 +21,7 @@ export function HasProperPositionIndexes(
 | 
			
		|||
      name: '',
 | 
			
		||||
      constraints: [],
 | 
			
		||||
      validator: {
 | 
			
		||||
        validate: (value: AddressDTO[]): boolean =>
 | 
			
		||||
        validate: (value: AddressRequestDTO[]): boolean =>
 | 
			
		||||
          hasProperPositionIndexes(value),
 | 
			
		||||
        defaultMessage: buildMessage(
 | 
			
		||||
          () =>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,15 +6,16 @@ import { Messager } from '../../adapters/secondaries/messager';
 | 
			
		|||
import { AdsRepository } from '../../adapters/secondaries/ads.repository';
 | 
			
		||||
import { CreateAdCommand } from '../../commands/create-ad.command';
 | 
			
		||||
import { CreateAdRequest } from '../dtos/create-ad.request';
 | 
			
		||||
import { Ad } from '../entities/ad';
 | 
			
		||||
 | 
			
		||||
import { IProvideParams } from '../interfaces/param-provider.interface';
 | 
			
		||||
import { DefaultParams } from '../types/default-params.type';
 | 
			
		||||
import { Address } from '../entities/address';
 | 
			
		||||
import { AdCreation } from '../dtos/ad.creation';
 | 
			
		||||
import { Ad } from '../entities/ad';
 | 
			
		||||
 | 
			
		||||
@CommandHandler(CreateAdCommand)
 | 
			
		||||
export class CreateAdUseCase {
 | 
			
		||||
  private readonly defaultParams: DefaultParams;
 | 
			
		||||
  private ad: Ad;
 | 
			
		||||
  private ad: AdCreation;
 | 
			
		||||
  constructor(
 | 
			
		||||
    private readonly _repository: AdsRepository,
 | 
			
		||||
    private readonly _messager: Messager,
 | 
			
		||||
| 
						 | 
				
			
			@ -26,50 +27,25 @@ export class CreateAdUseCase {
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  async execute(command: CreateAdCommand): Promise<Ad> {
 | 
			
		||||
    console.log('before mapping ');
 | 
			
		||||
    const entity: Ad = this._mapper.map(
 | 
			
		||||
    this.ad = this._mapper.map(
 | 
			
		||||
      command.createAdRequest,
 | 
			
		||||
      CreateAdRequest,
 | 
			
		||||
      Ad,
 | 
			
		||||
      AdCreation,
 | 
			
		||||
    );
 | 
			
		||||
    typeof entity.monMargin === 'number'
 | 
			
		||||
      ? entity.monMargin
 | 
			
		||||
      : (entity.monMargin = this.defaultParams.MON_MARGIN);
 | 
			
		||||
    typeof entity.tueMargin === 'number'
 | 
			
		||||
      ? entity.tueMargin
 | 
			
		||||
      : (entity.tueMargin = this.defaultParams.TUE_MARGIN);
 | 
			
		||||
    typeof entity.wedMargin === 'number'
 | 
			
		||||
      ? entity.wedMargin
 | 
			
		||||
      : (entity.wedMargin = this.defaultParams.WED_MARGIN);
 | 
			
		||||
    typeof entity.thuMargin === 'number'
 | 
			
		||||
      ? entity.thuMargin
 | 
			
		||||
      : (entity.thuMargin = this.defaultParams.THU_MARGIN);
 | 
			
		||||
    typeof entity.friMargin === 'number'
 | 
			
		||||
      ? entity.friMargin
 | 
			
		||||
      : (entity.friMargin = this.defaultParams.FRI_MARGIN);
 | 
			
		||||
    typeof entity.satMargin === 'number'
 | 
			
		||||
      ? entity.satMargin
 | 
			
		||||
      : (entity.satMargin = this.defaultParams.SAT_MARGIN);
 | 
			
		||||
    typeof entity.sunMargin === 'number'
 | 
			
		||||
      ? entity.sunMargin
 | 
			
		||||
      : (entity.sunMargin = this.defaultParams.SUN_MARGIN);
 | 
			
		||||
    typeof entity.strict === 'boolean'
 | 
			
		||||
      ? entity.strict
 | 
			
		||||
      : (entity.strict = this.defaultParams.STRICT);
 | 
			
		||||
    this.setDefaultSchedule();
 | 
			
		||||
    this.setDefaultAddressesPosition();
 | 
			
		||||
    this.setDefaultDriverAndPassengerParameters();
 | 
			
		||||
    this.setDefaultDistanceMargin();
 | 
			
		||||
 | 
			
		||||
    if (typeof entity.addresses[0].position === 'undefined') {
 | 
			
		||||
      for (let i = 0; i < entity.addresses.length; i++) {
 | 
			
		||||
        entity.addresses[i].position = i;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    try {
 | 
			
		||||
      console.log('before ***********************************');
 | 
			
		||||
      console.log(entity);
 | 
			
		||||
      console.log('******************************************');
 | 
			
		||||
      this.ad = await this._repository.create(entity);
 | 
			
		||||
      // this._messager.publish('ad.create', JSON.stringify(ad));
 | 
			
		||||
      // this._messager.publish('logging.ad.create.info', JSON.stringify(ad));
 | 
			
		||||
      return this.ad;
 | 
			
		||||
      console.log(this.ad);
 | 
			
		||||
      const adCreated: Ad = await this._repository.create(this.ad);
 | 
			
		||||
      this._messager.publish('ad.create', JSON.stringify(adCreated));
 | 
			
		||||
      this._messager.publish(
 | 
			
		||||
        'logging.ad.create.info',
 | 
			
		||||
        JSON.stringify(adCreated),
 | 
			
		||||
      );
 | 
			
		||||
      return adCreated;
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
      let key = 'logging.ad.create.crit';
 | 
			
		||||
      if (error.message.includes('Already exists')) {
 | 
			
		||||
| 
						 | 
				
			
			@ -85,107 +61,49 @@ export class CreateAdUseCase {
 | 
			
		|||
      throw error;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  setDefaultSchedule(): void {
 | 
			
		||||
    if (this.ad.monMargin === undefined)
 | 
			
		||||
      this.ad.monMargin = this.defaultParams.MON_MARGIN;
 | 
			
		||||
    if (this.ad.tueMargin === undefined)
 | 
			
		||||
      this.ad.tueMargin = this.defaultParams.TUE_MARGIN;
 | 
			
		||||
    if (this.ad.wedMargin === undefined)
 | 
			
		||||
      this.ad.wedMargin = this.defaultParams.WED_MARGIN;
 | 
			
		||||
    if (this.ad.thuMargin === undefined)
 | 
			
		||||
      this.ad.thuMargin = this.defaultParams.THU_MARGIN;
 | 
			
		||||
    if (this.ad.friMargin === undefined)
 | 
			
		||||
      this.ad.friMargin = this.defaultParams.FRI_MARGIN;
 | 
			
		||||
    if (this.ad.satMargin === undefined)
 | 
			
		||||
      this.ad.satMargin = this.defaultParams.SAT_MARGIN;
 | 
			
		||||
    if (this.ad.sunMargin === undefined)
 | 
			
		||||
      this.ad.sunMargin = this.defaultParams.SUN_MARGIN;
 | 
			
		||||
  }
 | 
			
		||||
/*
 | 
			
		||||
 repo error 
 | 
			
		||||
 PrismaClientValidationError: 
 | 
			
		||||
 Invalid `this._prisma[this._model].create()` invocation in
 | 
			
		||||
 /usr/src/app/src/modules/ad/adapters/secondaries/ads.repository.ts:15:51
 | 
			
		||||
 
 | 
			
		||||
   12 console.log(entity);
 | 
			
		||||
   13 console.log('*****************************************');
 | 
			
		||||
   14 try {
 | 
			
		||||
 → 15   const res = await this._prisma[this._model].create({
 | 
			
		||||
          data: {
 | 
			
		||||
            uuid: undefined,
 | 
			
		||||
            userUuid: '113e0000-0000-4000-a000-000000000000',
 | 
			
		||||
            driver: true,
 | 
			
		||||
            passenger: false,
 | 
			
		||||
            frequency: 'RECURRENT',
 | 
			
		||||
            fromDate: new Date('2023-01-15T00:00:00.000Z'),
 | 
			
		||||
            toDate: new Date('2023-08-01T00:00:00.000Z'),
 | 
			
		||||
            seatsDriver: 3,
 | 
			
		||||
            seatsPassenger: 0,
 | 
			
		||||
            strict: false,
 | 
			
		||||
            monMargin: 800,
 | 
			
		||||
            tueMargin: 900,
 | 
			
		||||
            wedMargin: 900,
 | 
			
		||||
            thuMargin: 900,
 | 
			
		||||
            friMargin: 900,
 | 
			
		||||
            satMargin: 900,
 | 
			
		||||
            sunMargin: 900,
 | 
			
		||||
            monTime: '04:40',
 | 
			
		||||
            tueTime: undefined,
 | 
			
		||||
            wedTime: undefined,
 | 
			
		||||
            thuTime: undefined,
 | 
			
		||||
            friTime: undefined,
 | 
			
		||||
            satTime: undefined,
 | 
			
		||||
            sunTime: undefined,
 | 
			
		||||
            addresses: [
 | 
			
		||||
              {
 | 
			
		||||
                lon: 48.68944549560547,
 | 
			
		||||
                lat: 6.176510334014893,
 | 
			
		||||
                houseNumber: '5',
 | 
			
		||||
                street: 'Avenue Foch',
 | 
			
		||||
                locality: 'Nancy',
 | 
			
		||||
                postalCode: '54000',
 | 
			
		||||
                country: 'France',
 | 
			
		||||
                position: 0
 | 
			
		||||
              },
 | 
			
		||||
              {
 | 
			
		||||
                lon: 48.85660171508789,
 | 
			
		||||
                lat: 2.3522000312805176,
 | 
			
		||||
                locality: 'Paris',
 | 
			
		||||
                postalCode: '75000',
 | 
			
		||||
                country: 'France',
 | 
			
		||||
                position: 1
 | 
			
		||||
  setDefaultDistanceMargin(): void {
 | 
			
		||||
    if (this.ad.strict === undefined)
 | 
			
		||||
      this.ad.strict = this.defaultParams.STRICT;
 | 
			
		||||
  }
 | 
			
		||||
            ]
 | 
			
		||||
            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
			
		||||
          },
 | 
			
		||||
          include: undefined
 | 
			
		||||
        })
 | 
			
		||||
 
 | 
			
		||||
 Argument addresses: Got invalid value 
 | 
			
		||||
 [
 | 
			
		||||
   {
 | 
			
		||||
     lon: 48.68944549560547,
 | 
			
		||||
     lat: 6.176510334014893,
 | 
			
		||||
     houseNumber: '5',
 | 
			
		||||
     street: 'Avenue Foch',
 | 
			
		||||
     locality: 'Nancy',
 | 
			
		||||
     postalCode: '54000',
 | 
			
		||||
     country: 'France',
 | 
			
		||||
     position: 0
 | 
			
		||||
   },
 | 
			
		||||
   {
 | 
			
		||||
     lon: 48.85660171508789,
 | 
			
		||||
     lat: 2.3522000312805176,
 | 
			
		||||
     locality: 'Paris',
 | 
			
		||||
     postalCode: '75000',
 | 
			
		||||
     country: 'France',
 | 
			
		||||
     position: 1
 | 
			
		||||
  setDefaultDriverAndPassengerParameters(): void {
 | 
			
		||||
    if (!this.ad.driver && !this.ad.passenger) {
 | 
			
		||||
      this.ad.driver = this.defaultParams.DRIVER;
 | 
			
		||||
      this.ad.seatsDriver = this.defaultParams.DRIVER_SEAT;
 | 
			
		||||
      this.ad.passenger = this.defaultParams.PASSENGER;
 | 
			
		||||
      this.ad.seatsPassenger = this.defaultParams.PASSENGER_SEATS;
 | 
			
		||||
    } else {
 | 
			
		||||
      if (!this.ad.driver) {
 | 
			
		||||
        this.ad.driver = false;
 | 
			
		||||
        this.ad.seatsDriver = 0;
 | 
			
		||||
      }
 | 
			
		||||
 ]
 | 
			
		||||
 on prisma.createOneAd. Provided List<Json>, expected AddressCreateNestedManyWithoutAdInput:
 | 
			
		||||
 type AddressCreateNestedManyWithoutAdInput {
 | 
			
		||||
   create?: AddressCreateWithoutAdInput | List<AddressCreateWithoutAdInput> | AddressUncheckedCreateWithoutAdInput | List<AddressUncheckedCreateWithoutAdInput>
 | 
			
		||||
   connectOrCreate?: AddressCreateOrConnectWithoutAdInput | List<AddressCreateOrConnectWithoutAdInput>
 | 
			
		||||
   createMany?: AddressCreateManyAdInputEnvelope
 | 
			
		||||
   connect?: AddressWhereUniqueInput | List<AddressWhereUniqueInput>
 | 
			
		||||
      if (!this.ad.passenger) {
 | 
			
		||||
        this.ad.passenger = false;
 | 
			
		||||
        this.ad.seatsPassenger = 0;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  setDefaultAddressesPosition(): void {
 | 
			
		||||
    if (this.ad.addresses.create[0].position === undefined) {
 | 
			
		||||
      for (let i = 0; i < this.ad.addresses.create.length; i++) {
 | 
			
		||||
        this.ad.addresses.create[i].position = i;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  TransformPunctualToReccurent(): void {}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
     at mi.validate (/usr/src/app/node_modules/@prisma/client/runtime/library.js:149:91)
 | 
			
		||||
     at tn.createMessage (/usr/src/app/node_modules/@prisma/client/runtime/library.js:166:1205)
 | 
			
		||||
     at /usr/src/app/node_modules/@prisma/client/runtime/library.js:179:10962
 | 
			
		||||
     at runInChildSpan (/usr/src/app/node_modules/@prisma/client/runtime/library.js:70:25817)
 | 
			
		||||
     at PrismaService._executeRequest (/usr/src/app/node_modules/@prisma/client/runtime/library.js:179:10951)
 | 
			
		||||
     at PrismaService._request (/usr/src/app/node_modules/@prisma/client/runtime/library.js:179:10484)
 | 
			
		||||
     at AdsRepository.create (/usr/src/app/src/modules/ad/adapters/secondaries/ads.repository.ts:15:19)
 | 
			
		||||
     at CreateAdUseCase.execute (/usr/src/app/src/modules/ad/domain/usecases/create-ad.usecase.ts:69:17)
 | 
			
		||||
     at AdController.createAd (/usr/src/app/src/modules/ad/adapters/primaries/ad.controller.ts:49:18)
 | 
			
		||||
     at /usr/src/app/node_modules/@nestjs/microservices/context/rpc-proxy.js:11:32
 | 
			
		||||
     at Object.Create (/usr/src/app/node_modules/@nestjs/microservices/server/server-grpc.js:148:40) {
 | 
			
		||||
   clientVersion: '4.13.0'
 | 
			
		||||
*/
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,11 +1,17 @@
 | 
			
		|||
import { createMap, forMember, mapFrom, Mapper } from '@automapper/core';
 | 
			
		||||
import {
 | 
			
		||||
  condition,
 | 
			
		||||
  createMap,
 | 
			
		||||
  forMember,
 | 
			
		||||
  mapFrom,
 | 
			
		||||
  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';
 | 
			
		||||
import { CreateAdRequest } from '../domain/dtos/create-ad.request';
 | 
			
		||||
import { Address } from '../domain/entities/address';
 | 
			
		||||
import { AddressDTO } from '../domain/dtos/create.address.dto';
 | 
			
		||||
import { AdCreation } from '../domain/dtos/ad.creation';
 | 
			
		||||
import { Frequency } from '@prisma/client';
 | 
			
		||||
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class AdProfile extends AutomapperProfile {
 | 
			
		||||
| 
						 | 
				
			
			@ -15,12 +21,11 @@ export class AdProfile extends AutomapperProfile {
 | 
			
		|||
 | 
			
		||||
  override get profile() {
 | 
			
		||||
    return (mapper) => {
 | 
			
		||||
      createMap(mapper, Address, AddressDTO);
 | 
			
		||||
      createMap(mapper, Ad, AdPresenter);
 | 
			
		||||
      createMap(
 | 
			
		||||
        mapper,
 | 
			
		||||
        CreateAdRequest,
 | 
			
		||||
        Ad,
 | 
			
		||||
        AdCreation,
 | 
			
		||||
        forMember(
 | 
			
		||||
          (destination) => destination.monMargin,
 | 
			
		||||
          mapFrom((source) => source.marginDurations.mon),
 | 
			
		||||
| 
						 | 
				
			
			@ -78,9 +83,17 @@ export class AdProfile extends AutomapperProfile {
 | 
			
		|||
          mapFrom((source) => source.schedule.sun),
 | 
			
		||||
        ),
 | 
			
		||||
        forMember(
 | 
			
		||||
          (destination) => destination.addresses,
 | 
			
		||||
          (destination) => destination.addresses.create,
 | 
			
		||||
          mapFrom((source) => source.addresses),
 | 
			
		||||
        ),
 | 
			
		||||
        //TODO use custom resolver
 | 
			
		||||
        // forMember(
 | 
			
		||||
        //   (destination) => destination.fromDate,
 | 
			
		||||
        //   condition(
 | 
			
		||||
        //     (source) => source.frequency == Frequency.PUNCTUAL,
 | 
			
		||||
        //     source.departure,
 | 
			
		||||
        //   ),
 | 
			
		||||
        // ),
 | 
			
		||||
      );
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,17 @@
 | 
			
		|||
import { Mapper, createMap } from '@automapper/core';
 | 
			
		||||
import { AutomapperProfile, InjectMapper } from '@automapper/nestjs';
 | 
			
		||||
import { Injectable } from '@nestjs/common';
 | 
			
		||||
import { AddressRequestDTO } from '../domain/dtos/create.address.request';
 | 
			
		||||
import { AddressCreation } from '../domain/dtos/address.creation';
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class AdProfile extends AutomapperProfile {
 | 
			
		||||
  constructor(@InjectMapper() mapper: Mapper) {
 | 
			
		||||
    super(mapper);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  override get profile() {
 | 
			
		||||
    return (mapper) => {
 | 
			
		||||
      createMap(mapper, AddressRequestDTO, AddressCreation);
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -9,9 +9,11 @@ import { classes } from '@automapper/classes';
 | 
			
		|||
import { Frequency } from '../../domain/types/frequency.enum';
 | 
			
		||||
import { Ad } from '../../domain/entities/ad';
 | 
			
		||||
import { AdProfile } from '../../mappers/ad.profile';
 | 
			
		||||
import { AddressDTO } from '../../domain/dtos/create.address.dto';
 | 
			
		||||
import { AddressRequestDTO } from '../../domain/dtos/create.address.request';
 | 
			
		||||
import { AdCreation } from '../../domain/dtos/ad.creation';
 | 
			
		||||
import { AddressCreation } from '../../domain/dtos/address.creation';
 | 
			
		||||
 | 
			
		||||
const mockAddress1: AddressDTO = {
 | 
			
		||||
const mockAddress1: AddressRequestDTO = {
 | 
			
		||||
  position: 0,
 | 
			
		||||
  lon: 48.68944505415954,
 | 
			
		||||
  lat: 6.176510296462267,
 | 
			
		||||
| 
						 | 
				
			
			@ -21,7 +23,7 @@ const mockAddress1: AddressDTO = {
 | 
			
		|||
  postalCode: '54000',
 | 
			
		||||
  country: 'France',
 | 
			
		||||
};
 | 
			
		||||
const mockAddress2: AddressDTO = {
 | 
			
		||||
const mockAddress2: AddressRequestDTO = {
 | 
			
		||||
  position: 1,
 | 
			
		||||
  lon: 48.8566,
 | 
			
		||||
  lat: 2.3522,
 | 
			
		||||
| 
						 | 
				
			
			@ -29,25 +31,29 @@ const mockAddress2: AddressDTO = {
 | 
			
		|||
  postalCode: '75000',
 | 
			
		||||
  country: 'France',
 | 
			
		||||
};
 | 
			
		||||
const mockAddressWithoutPos1: AddressRequestDTO = {
 | 
			
		||||
  lon: 43.2965,
 | 
			
		||||
  lat: 5.3698,
 | 
			
		||||
  locality: 'Marseille',
 | 
			
		||||
  postalCode: '13000',
 | 
			
		||||
  country: 'France',
 | 
			
		||||
};
 | 
			
		||||
const mockAddressWithoutPos2: AddressRequestDTO = {
 | 
			
		||||
  lon: 43.7102,
 | 
			
		||||
  lat: 7.262,
 | 
			
		||||
  locality: 'Marseille',
 | 
			
		||||
  postalCode: '06000',
 | 
			
		||||
  country: 'France',
 | 
			
		||||
};
 | 
			
		||||
const minimalReccurentAdREquest: CreateAdRequest = {
 | 
			
		||||
  userUuid: '224e0000-0000-4000-a000-000000000000',
 | 
			
		||||
  driver: undefined,
 | 
			
		||||
  passenger: undefined,
 | 
			
		||||
  frequency: Frequency.RECURRENT,
 | 
			
		||||
  fromDate: new Date('01-05-2023'),
 | 
			
		||||
  toDate: new Date('01-05-2024'),
 | 
			
		||||
  schedule: {
 | 
			
		||||
    mon: '08:00',
 | 
			
		||||
  },
 | 
			
		||||
  marginDurations: {
 | 
			
		||||
    mon: undefined,
 | 
			
		||||
    tue: undefined,
 | 
			
		||||
    wed: undefined,
 | 
			
		||||
    thu: undefined,
 | 
			
		||||
    fri: undefined,
 | 
			
		||||
    sat: undefined,
 | 
			
		||||
    sun: undefined,
 | 
			
		||||
  },
 | 
			
		||||
  marginDurations: {},
 | 
			
		||||
  addresses: [mockAddress1, mockAddress2],
 | 
			
		||||
};
 | 
			
		||||
const newAdRequest: CreateAdRequest = {
 | 
			
		||||
| 
						 | 
				
			
			@ -70,9 +76,26 @@ const newAdRequest: CreateAdRequest = {
 | 
			
		|||
    sat: undefined,
 | 
			
		||||
    sun: undefined,
 | 
			
		||||
  },
 | 
			
		||||
  seatsPassenger: 2,
 | 
			
		||||
  seatsDriver: 2,
 | 
			
		||||
  addresses: [mockAddress1, mockAddress2],
 | 
			
		||||
};
 | 
			
		||||
const newPunctualPassengerAdRequest: CreateAdRequest = {
 | 
			
		||||
  userUuid: '113e0000-0000-4000-a000-000000000000',
 | 
			
		||||
  passenger: true,
 | 
			
		||||
  frequency: Frequency.PUNCTUAL,
 | 
			
		||||
  departure: new Date('05-22-2023'),
 | 
			
		||||
  marginDurations: {
 | 
			
		||||
    mon: undefined,
 | 
			
		||||
    tue: undefined,
 | 
			
		||||
    wed: undefined,
 | 
			
		||||
    thu: undefined,
 | 
			
		||||
    fri: undefined,
 | 
			
		||||
    sat: undefined,
 | 
			
		||||
    sun: undefined,
 | 
			
		||||
  },
 | 
			
		||||
  seatsPassenger: 1,
 | 
			
		||||
  addresses: [mockAddressWithoutPos1, mockAddressWithoutPos2],
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const mockMessager = {
 | 
			
		||||
  publish: jest.fn().mockImplementation(),
 | 
			
		||||
| 
						 | 
				
			
			@ -109,7 +132,7 @@ let mockAdRepository = {
 | 
			
		|||
    .mockImplementationOnce(() => {
 | 
			
		||||
      throw new Error('Already exists');
 | 
			
		||||
    })
 | 
			
		||||
    .mockImplementation(),
 | 
			
		||||
    .mockImplementation((command?: CreateAdCommand) => {}),
 | 
			
		||||
};
 | 
			
		||||
describe('CreateAdUseCase', () => {
 | 
			
		||||
  let createAdUseCase: CreateAdUseCase;
 | 
			
		||||
| 
						 | 
				
			
			@ -154,17 +177,48 @@ describe('CreateAdUseCase', () => {
 | 
			
		|||
  });
 | 
			
		||||
 | 
			
		||||
  describe('Ad parameter default setting ', () => {
 | 
			
		||||
    const newAdCommand = new CreateAdCommand(minimalReccurentAdREquest);
 | 
			
		||||
    beforeEach(() => {
 | 
			
		||||
      mockAdRepository.create.mockClear();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('should define mimimal ad as 1 passager add', async () => {
 | 
			
		||||
      const newAd: Ad = await createAdUseCase.execute(newAdCommand);
 | 
			
		||||
      expect(mockAdRepository).toBeCalledWith({
 | 
			
		||||
        userUuid: '113e0000-0000-4000-a000-000000000000',
 | 
			
		||||
        driver: true,
 | 
			
		||||
        passenger: false,
 | 
			
		||||
        frequency: Frequency.RECURRENT,
 | 
			
		||||
        fromDate: new Date('01-05-2023'),
 | 
			
		||||
        toDate: new Date('20-08-2023'),
 | 
			
		||||
      });
 | 
			
		||||
      const newAdCommand = new CreateAdCommand(minimalReccurentAdREquest);
 | 
			
		||||
      await createAdUseCase.execute(newAdCommand);
 | 
			
		||||
      const expectedAdCreation = {
 | 
			
		||||
        userUuid: minimalReccurentAdREquest.userUuid,
 | 
			
		||||
        frequency: minimalReccurentAdREquest.frequency,
 | 
			
		||||
        fromDate: minimalReccurentAdREquest.fromDate,
 | 
			
		||||
        toDate: minimalReccurentAdREquest.toDate,
 | 
			
		||||
        monTime: minimalReccurentAdREquest.schedule.mon,
 | 
			
		||||
        tueTime: undefined,
 | 
			
		||||
        wedTime: undefined,
 | 
			
		||||
        thuTime: undefined,
 | 
			
		||||
        friTime: undefined,
 | 
			
		||||
        satTime: undefined,
 | 
			
		||||
        sunTime: undefined,
 | 
			
		||||
        monMargin: mockDefaultParamsProvider.getParams().MON_MARGIN,
 | 
			
		||||
        tueMargin: mockDefaultParamsProvider.getParams().TUE_MARGIN,
 | 
			
		||||
        wedMargin: mockDefaultParamsProvider.getParams().WED_MARGIN,
 | 
			
		||||
        thuMargin: mockDefaultParamsProvider.getParams().THU_MARGIN,
 | 
			
		||||
        friMargin: mockDefaultParamsProvider.getParams().FRI_MARGIN,
 | 
			
		||||
        satMargin: mockDefaultParamsProvider.getParams().SAT_MARGIN,
 | 
			
		||||
        sunMargin: mockDefaultParamsProvider.getParams().SUN_MARGIN,
 | 
			
		||||
        driver: mockDefaultParamsProvider.getParams().DRIVER,
 | 
			
		||||
        seatsDriver: mockDefaultParamsProvider.getParams().DRIVER_SEAT,
 | 
			
		||||
        passenger: mockDefaultParamsProvider.getParams().PASSENGER,
 | 
			
		||||
        seatsPassenger: mockDefaultParamsProvider.getParams().PASSENGER_SEATS,
 | 
			
		||||
        strict: mockDefaultParamsProvider.getParams().STRICT,
 | 
			
		||||
        addresses: {
 | 
			
		||||
          create: minimalReccurentAdREquest.addresses as AddressCreation[],
 | 
			
		||||
        },
 | 
			
		||||
        createdAt: undefined,
 | 
			
		||||
      } as AdCreation;
 | 
			
		||||
 | 
			
		||||
      expect(mockAdRepository.create).toBeCalledWith(expectedAdCreation);
 | 
			
		||||
    });
 | 
			
		||||
    it('should create an passengerAd with addresses without position ', async () => {
 | 
			
		||||
      const newAdCommand = new CreateAdCommand(newPunctualPassengerAdRequest);
 | 
			
		||||
      await createAdUseCase.execute(newAdCommand);
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,7 @@
 | 
			
		|||
import { AddressDTO } from '../../domain/dtos/create.address.dto';
 | 
			
		||||
import { AddressRequestDTO } from '../../domain/dtos/create.address.request';
 | 
			
		||||
import { hasProperPositionIndexes } from '../../domain/dtos/utils/address-position.validator';
 | 
			
		||||
describe('addresses position validators', () => {
 | 
			
		||||
  const mockAddress1: AddressDTO = {
 | 
			
		||||
  const mockAddress1: AddressRequestDTO = {
 | 
			
		||||
    lon: 48.68944505415954,
 | 
			
		||||
    lat: 6.176510296462267,
 | 
			
		||||
    houseNumber: '5',
 | 
			
		||||
| 
						 | 
				
			
			@ -10,7 +10,7 @@ describe('addresses position validators', () => {
 | 
			
		|||
    postalCode: '54000',
 | 
			
		||||
    country: 'France',
 | 
			
		||||
  };
 | 
			
		||||
  const mockAddress2: AddressDTO = {
 | 
			
		||||
  const mockAddress2: AddressRequestDTO = {
 | 
			
		||||
    lon: 48.8566,
 | 
			
		||||
    lat: 2.3522,
 | 
			
		||||
    locality: 'Paris',
 | 
			
		||||
| 
						 | 
				
			
			@ -18,7 +18,7 @@ describe('addresses position validators', () => {
 | 
			
		|||
    country: 'France',
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const mockAddress3: AddressDTO = {
 | 
			
		||||
  const mockAddress3: AddressRequestDTO = {
 | 
			
		||||
    lon: 49.2628,
 | 
			
		||||
    lat: 4.0347,
 | 
			
		||||
    locality: 'Reims',
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -80,20 +80,13 @@ export abstract class PrismaRepository<T> implements IRepository<T> {
 | 
			
		|||
  // TODO : using any is not good, but needed for nested entities
 | 
			
		||||
  // TODO : Refactor for good clean architecture ?
 | 
			
		||||
  async create(entity: Partial<T> | any, include?: any): Promise<T> {
 | 
			
		||||
    console.log('repo entity ');
 | 
			
		||||
    console.log(entity);
 | 
			
		||||
    console.log('-----------------------------------------');
 | 
			
		||||
    try {
 | 
			
		||||
      const res = await this._prisma[this._model].create({
 | 
			
		||||
        data: entity,
 | 
			
		||||
        include: include,
 | 
			
		||||
      });
 | 
			
		||||
      console.log('result');
 | 
			
		||||
      console.log(res);
 | 
			
		||||
      return res;
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      console.log('repo error ');
 | 
			
		||||
      console.log(e);
 | 
			
		||||
      if (e instanceof Prisma.PrismaClientKnownRequestError) {
 | 
			
		||||
        throw new DatabaseException(
 | 
			
		||||
          Prisma.PrismaClientKnownRequestError.name,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue