Merge branch 'updatePackages' into 'main'
Update packages See merge request v3/service/ad!23
This commit is contained in:
		
						commit
						a5fb44f9e4
					
				
							
								
								
									
										17
									
								
								.env.dist
								
								
								
								
							
							
						
						
									
										17
									
								
								.env.dist
								
								
								
								
							| 
						 | 
				
			
			@ -10,24 +10,9 @@ DATABASE_URL="postgresql://mobicoop:mobicoop@v3-db:5432/mobicoop?schema=ad"
 | 
			
		|||
# MESSAGE BROKER
 | 
			
		||||
MESSAGE_BROKER_URI=amqp://v3-broker:5672
 | 
			
		||||
MESSAGE_BROKER_EXCHANGE=mobicoop
 | 
			
		||||
MESSAGE_BROKER_EXCHANGE_DURABILITY=true
 | 
			
		||||
 | 
			
		||||
# REDIS
 | 
			
		||||
REDIS_HOST=v3-redis
 | 
			
		||||
REDIS_PASSWORD=redis
 | 
			
		||||
REDIS_PORT=6379
 | 
			
		||||
 | 
			
		||||
# DEFAULT CARPOOL DEPARTURE TIME MARGIN (in seconds)
 | 
			
		||||
DEPARTURE_TIME_MARGIN=900
 | 
			
		||||
 | 
			
		||||
# DEFAULT ROLE
 | 
			
		||||
ROLE=passenger
 | 
			
		||||
 | 
			
		||||
# SEATS PROPOSED AS DRIVER / REQUESTED AS PASSENGER
 | 
			
		||||
SEATS_PROPOSED=3
 | 
			
		||||
SEATS_REQUESTED=1
 | 
			
		||||
 | 
			
		||||
# ACCEPT ONLY SAME FREQUENCY REQUESTS
 | 
			
		||||
STRICT_FREQUENCY=false
 | 
			
		||||
 | 
			
		||||
# default timezone
 | 
			
		||||
TIMEZONE=Europe/Paris
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										34
									
								
								README.md
								
								
								
								
							
							
						
						
									
										34
									
								
								README.md
								
								
								
								
							| 
						 | 
				
			
			@ -64,12 +64,14 @@ The app exposes the following [gRPC](https://grpc.io/) services :
 | 
			
		|||
    {
 | 
			
		||||
        "userId": "80c9bb02-0931-4a1d-bea6-22d358992245",
 | 
			
		||||
        "driver": true,
 | 
			
		||||
        "passenger": false,
 | 
			
		||||
        "seatsProposed": 3,
 | 
			
		||||
        "frequency": "PUNCTUAL",
 | 
			
		||||
        "fromDate": "2023-01-15",
 | 
			
		||||
        "toDate": "2023-01-15",
 | 
			
		||||
        "schedule": [
 | 
			
		||||
            {
 | 
			
		||||
                "day": 0,
 | 
			
		||||
                "time": "09:00",
 | 
			
		||||
                "margin": 900
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -103,7 +105,7 @@ The app exposes the following [gRPC](https://grpc.io/) services :
 | 
			
		|||
    {
 | 
			
		||||
        "userId": "80c9bb02-0931-4a1d-bea6-22d358992245",
 | 
			
		||||
        "driver": true,
 | 
			
		||||
        "pasenger": true,
 | 
			
		||||
        "passenger": true,
 | 
			
		||||
        "seatsProposed": 3,
 | 
			
		||||
        "seatsRequested": 1,
 | 
			
		||||
        "frequency": "PUNCTUAL",
 | 
			
		||||
| 
						 | 
				
			
			@ -111,6 +113,7 @@ The app exposes the following [gRPC](https://grpc.io/) services :
 | 
			
		|||
        "toDate": "2023-01-15",
 | 
			
		||||
        "schedule": [
 | 
			
		||||
            {
 | 
			
		||||
                "day": 0,
 | 
			
		||||
                "time": "09:00",
 | 
			
		||||
                "margin": 900
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -144,22 +147,25 @@ The app exposes the following [gRPC](https://grpc.io/) services :
 | 
			
		|||
    {
 | 
			
		||||
        "userId": "80c9bb02-0931-4a1d-bea6-22d358992245",
 | 
			
		||||
        "passenger": true,
 | 
			
		||||
        "seatsPassenger": 1,
 | 
			
		||||
        "seatsRequested": 1,
 | 
			
		||||
        "frequency": "RECURRRENT",
 | 
			
		||||
        "fromDate": "2023-01-15",
 | 
			
		||||
        "toDate": "2023-12-31",
 | 
			
		||||
        "schedule": [
 | 
			
		||||
            {
 | 
			
		||||
                "day": 1,
 | 
			
		||||
                "time": "07:00"
 | 
			
		||||
                "time": "07:00",
 | 
			
		||||
                "margin": 600
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "day": 2,
 | 
			
		||||
                "time": "07:05"
 | 
			
		||||
                "time": "07:05",
 | 
			
		||||
                "margin": 600
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "day": 5,
 | 
			
		||||
                "time": "07:10"
 | 
			
		||||
                "time": "07:10",
 | 
			
		||||
                "margin": 600
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "waypoints": [
 | 
			
		||||
| 
						 | 
				
			
			@ -188,22 +194,20 @@ The app exposes the following [gRPC](https://grpc.io/) services :
 | 
			
		|||
    The list of possible options when creating an ad :
 | 
			
		||||
 | 
			
		||||
    -   userId: the user id (as a uuid)
 | 
			
		||||
    -   driver (boolean, optional): if the ad is a driver ad
 | 
			
		||||
    -   passenger (boolean, optional): if the ad is a passenger ad
 | 
			
		||||
    -   driver (boolean): if the ad is a driver ad. Note that at least a role must be set to true (driver and/or passenger).
 | 
			
		||||
    -   passenger (boolean): if the ad is a passenger ad. Note that at least a role must be set to true (driver and/or passenger).
 | 
			
		||||
    -   frequency: `PUNCTUAL` or `RECURRENT`
 | 
			
		||||
    -   fromDate: start date for recurrent ad, carpool date for punctual ad
 | 
			
		||||
    -   toDate: end date for recurrent ad, same as fromDate for punctual ad
 | 
			
		||||
    -   schedule: an array of schedule items, as schedule item containing :
 | 
			
		||||
        -   the week day as a number, from 0 (sunday) to 6 (saturday) if the ad is recurrent
 | 
			
		||||
    -   schedule: an array of schedule items, a schedule item containing :
 | 
			
		||||
        -   the week day as a number, from 0 (sunday) to 6 (saturday)
 | 
			
		||||
        -   the departure time (as HH:MM)
 | 
			
		||||
        -   the margin around the departure time in seconds (optional)
 | 
			
		||||
    -   seatsProposed (optional): number of seats proposed as driver
 | 
			
		||||
    -   seatsRequested (optional): number of seats requested as passenger
 | 
			
		||||
    -   strict (boolean, optional): if set to true, allow matching only with similar frequency ads
 | 
			
		||||
        -   the margin around the departure time in seconds
 | 
			
		||||
    -   seatsProposed: number of seats proposed as driver (required if `driver` is true)
 | 
			
		||||
    -   seatsRequested: number of seats requested as passenger (required if `passenger` is true)
 | 
			
		||||
    -   strict (boolean): if set to true, allow matching only with similar frequency ads
 | 
			
		||||
    -   waypoints: an array of addresses that represent the waypoints of the journey (only first and last waypoints are used for passenger ads). Note that positions are **required** and **must** be consecutives
 | 
			
		||||
 | 
			
		||||
    Default values must be set in `.env` file.
 | 
			
		||||
 | 
			
		||||
## Messages
 | 
			
		||||
 | 
			
		||||
As mentionned earlier, RabbitMQ messages are sent after these events :
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										86
									
								
								package.json
								
								
								
								
							
							
						
						
									
										86
									
								
								package.json
								
								
								
								
							| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
{
 | 
			
		||||
  "name": "@mobicoop/ad",
 | 
			
		||||
  "version": "2.1.1",
 | 
			
		||||
  "version": "2.2.0",
 | 
			
		||||
  "description": "Mobicoop V3 Ad",
 | 
			
		||||
  "author": "sbriat",
 | 
			
		||||
  "private": true,
 | 
			
		||||
| 
						 | 
				
			
			@ -30,56 +30,56 @@
 | 
			
		|||
    "migrate:deploy": "npx prisma migrate deploy"
 | 
			
		||||
  },
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "@grpc/grpc-js": "^1.8.14",
 | 
			
		||||
    "@grpc/proto-loader": "^0.7.6",
 | 
			
		||||
    "@liaoliaots/nestjs-redis": "^9.0.5",
 | 
			
		||||
    "@mobicoop/configuration-module": "^1.2.0",
 | 
			
		||||
    "@mobicoop/ddd-library": "^1.0.0",
 | 
			
		||||
    "@mobicoop/health-module": "^2.0.0",
 | 
			
		||||
    "@mobicoop/message-broker-module": "^1.2.0",
 | 
			
		||||
    "@nestjs/common": "^9.0.0",
 | 
			
		||||
    "@nestjs/config": "^2.3.1",
 | 
			
		||||
    "@nestjs/core": "^9.0.0",
 | 
			
		||||
    "@nestjs/cqrs": "^9.0.3",
 | 
			
		||||
    "@nestjs/event-emitter": "^1.4.2",
 | 
			
		||||
    "@nestjs/microservices": "^9.4.0",
 | 
			
		||||
    "@nestjs/platform-express": "^9.0.0",
 | 
			
		||||
    "@nestjs/terminus": "^9.2.2",
 | 
			
		||||
    "@prisma/client": "^4.13.0",
 | 
			
		||||
    "@grpc/grpc-js": "^1.9.5",
 | 
			
		||||
    "@grpc/proto-loader": "^0.7.10",
 | 
			
		||||
    "@songkeys/nestjs-redis": "^10.0.0",
 | 
			
		||||
    "@mobicoop/configuration-module": "^2.0.0",
 | 
			
		||||
    "@mobicoop/ddd-library": "^2.0.0",
 | 
			
		||||
    "@mobicoop/health-module": "^2.3.1",
 | 
			
		||||
    "@mobicoop/message-broker-module": "^2.1.1",
 | 
			
		||||
    "@nestjs/common": "^10.2.7",
 | 
			
		||||
    "@nestjs/config": "^3.1.1",
 | 
			
		||||
    "@nestjs/core": "^10.2.7",
 | 
			
		||||
    "@nestjs/cqrs": "^10.2.6",
 | 
			
		||||
    "@nestjs/event-emitter": "^2.0.2",
 | 
			
		||||
    "@nestjs/microservices": "^10.2.7",
 | 
			
		||||
    "@nestjs/platform-express": "^10.2.7",
 | 
			
		||||
    "@nestjs/terminus": "^10.1.1",
 | 
			
		||||
    "@prisma/client": "^5.4.2",
 | 
			
		||||
    "class-transformer": "^0.5.1",
 | 
			
		||||
    "class-validator": "^0.14.0",
 | 
			
		||||
    "geo-tz": "^7.0.7",
 | 
			
		||||
    "ioredis": "^5.3.2",
 | 
			
		||||
    "nestjs-request-context": "^2.1.0",
 | 
			
		||||
    "nestjs-request-context": "^3.0.0",
 | 
			
		||||
    "reflect-metadata": "^0.1.13",
 | 
			
		||||
    "rxjs": "^7.2.0",
 | 
			
		||||
    "rxjs": "^7.8.1",
 | 
			
		||||
    "timezonecomplete": "^5.12.4"
 | 
			
		||||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "@nestjs/cli": "^9.0.0",
 | 
			
		||||
    "@nestjs/schematics": "^9.0.0",
 | 
			
		||||
    "@nestjs/testing": "^9.0.0",
 | 
			
		||||
    "@types/express": "^4.17.13",
 | 
			
		||||
    "@types/jest": "29.5.0",
 | 
			
		||||
    "@types/node": "18.15.11",
 | 
			
		||||
    "@types/supertest": "^2.0.11",
 | 
			
		||||
    "@types/uuid": "^9.0.2",
 | 
			
		||||
    "@typescript-eslint/eslint-plugin": "^5.0.0",
 | 
			
		||||
    "@typescript-eslint/parser": "^5.0.0",
 | 
			
		||||
    "dotenv-cli": "^7.2.1",
 | 
			
		||||
    "eslint": "^8.0.1",
 | 
			
		||||
    "eslint-config-prettier": "^8.3.0",
 | 
			
		||||
    "eslint-plugin-prettier": "^4.0.0",
 | 
			
		||||
    "jest": "29.5.0",
 | 
			
		||||
    "prettier": "^2.3.2",
 | 
			
		||||
    "prisma": "^4.13.0",
 | 
			
		||||
    "source-map-support": "^0.5.20",
 | 
			
		||||
    "supertest": "^6.1.3",
 | 
			
		||||
    "ts-jest": "29.0.5",
 | 
			
		||||
    "ts-loader": "^9.2.3",
 | 
			
		||||
    "ts-node": "^10.0.0",
 | 
			
		||||
    "@nestjs/cli": "^10.1.18",
 | 
			
		||||
    "@nestjs/schematics": "^10.0.2",
 | 
			
		||||
    "@nestjs/testing": "^10.2.7",
 | 
			
		||||
    "@types/express": "^4.17.19",
 | 
			
		||||
    "@types/jest": "29.5.5",
 | 
			
		||||
    "@types/node": "20.8.6",
 | 
			
		||||
    "@types/supertest": "^2.0.14",
 | 
			
		||||
    "@types/uuid": "^9.0.5",
 | 
			
		||||
    "@typescript-eslint/eslint-plugin": "^6.7.5",
 | 
			
		||||
    "@typescript-eslint/parser": "^6.7.5",
 | 
			
		||||
    "dotenv-cli": "^7.3.0",
 | 
			
		||||
    "eslint": "^8.51.0",
 | 
			
		||||
    "eslint-config-prettier": "^9.0.0",
 | 
			
		||||
    "eslint-plugin-prettier": "^5.0.1",
 | 
			
		||||
    "jest": "29.7.0",
 | 
			
		||||
    "prettier": "^3.0.3",
 | 
			
		||||
    "prisma": "^5.4.2",
 | 
			
		||||
    "source-map-support": "^0.5.21",
 | 
			
		||||
    "supertest": "^6.3.3",
 | 
			
		||||
    "ts-jest": "29.1.1",
 | 
			
		||||
    "ts-loader": "^9.5.0",
 | 
			
		||||
    "ts-node": "^10.9.1",
 | 
			
		||||
    "tsconfig-paths": "4.2.0",
 | 
			
		||||
    "typescript": "^4.7.4"
 | 
			
		||||
    "typescript": "^5.2.2"
 | 
			
		||||
  },
 | 
			
		||||
  "jest": {
 | 
			
		||||
    "moduleFileExtensions": [
 | 
			
		||||
| 
						 | 
				
			
			@ -88,6 +88,7 @@
 | 
			
		|||
      "ts"
 | 
			
		||||
    ],
 | 
			
		||||
    "modulePathIgnorePatterns": [
 | 
			
		||||
      ".constants.ts",
 | 
			
		||||
      ".module.ts",
 | 
			
		||||
      ".dto.ts",
 | 
			
		||||
      ".di-tokens.ts",
 | 
			
		||||
| 
						 | 
				
			
			@ -105,6 +106,7 @@
 | 
			
		|||
      "**/*.(t|j)s"
 | 
			
		||||
    ],
 | 
			
		||||
    "coveragePathIgnorePatterns": [
 | 
			
		||||
      ".constants.ts",
 | 
			
		||||
      ".module.ts",
 | 
			
		||||
      ".dto.ts",
 | 
			
		||||
      ".di-tokens.ts",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,15 +26,19 @@ import { HEALTH_CRITICAL_LOGGING_KEY, SERVICE_NAME } from './app.constants';
 | 
			
		|||
      useFactory: async (
 | 
			
		||||
        configService: ConfigService,
 | 
			
		||||
      ): Promise<ConfigurationModuleOptions> => ({
 | 
			
		||||
        domain: configService.get<string>('SERVICE_CONFIGURATION_DOMAIN'),
 | 
			
		||||
        domain: configService.get<string>(
 | 
			
		||||
          'SERVICE_CONFIGURATION_DOMAIN',
 | 
			
		||||
        ) as string,
 | 
			
		||||
        messageBroker: {
 | 
			
		||||
          uri: configService.get<string>('MESSAGE_BROKER_URI'),
 | 
			
		||||
          exchange: configService.get<string>('MESSAGE_BROKER_EXCHANGE'),
 | 
			
		||||
          uri: configService.get<string>('MESSAGE_BROKER_URI') as string,
 | 
			
		||||
          exchange: configService.get<string>(
 | 
			
		||||
            'MESSAGE_BROKER_EXCHANGE',
 | 
			
		||||
          ) as string,
 | 
			
		||||
        },
 | 
			
		||||
        redis: {
 | 
			
		||||
          host: configService.get<string>('REDIS_HOST'),
 | 
			
		||||
          host: configService.get<string>('REDIS_HOST') as string,
 | 
			
		||||
          password: configService.get<string>('REDIS_PASSWORD'),
 | 
			
		||||
          port: configService.get<number>('REDIS_PORT'),
 | 
			
		||||
          port: configService.get<number>('REDIS_PORT') as number,
 | 
			
		||||
        },
 | 
			
		||||
        setConfigurationBrokerQueue: 'ad-configuration-create-update',
 | 
			
		||||
        deleteConfigurationQueue: 'ad-configuration-delete',
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,6 +22,6 @@ async function bootstrap() {
 | 
			
		|||
  });
 | 
			
		||||
 | 
			
		||||
  await app.startAllMicroservices();
 | 
			
		||||
  await app.listen(process.env.HEALTH_SERVICE_PORT);
 | 
			
		||||
  await app.listen(process.env.HEALTH_SERVICE_PORT as unknown as number);
 | 
			
		||||
}
 | 
			
		||||
bootstrap();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,4 @@
 | 
			
		|||
export const AD_MESSAGE_PUBLISHER = Symbol('AD_MESSAGE_PUBLISHER');
 | 
			
		||||
export const PARAMS_PROVIDER = Symbol('PARAMS_PROVIDER');
 | 
			
		||||
export const TIMEZONE_FINDER = Symbol('TIMEZONE_FINDER');
 | 
			
		||||
export const TIME_CONVERTER = Symbol('TIME_CONVERTER');
 | 
			
		||||
export const INPUT_DATETIME_TRANSFORMER = Symbol('INPUT_DATETIME_TRANSFORMER');
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -37,15 +37,15 @@ export class AdMapper
 | 
			
		|||
    const record: AdWriteModel = {
 | 
			
		||||
      uuid: copy.id,
 | 
			
		||||
      userUuid: copy.userId,
 | 
			
		||||
      driver: copy.driver,
 | 
			
		||||
      passenger: copy.passenger,
 | 
			
		||||
      driver: copy.driver as boolean,
 | 
			
		||||
      passenger: copy.passenger as boolean,
 | 
			
		||||
      frequency: copy.frequency,
 | 
			
		||||
      fromDate: new Date(copy.fromDate),
 | 
			
		||||
      toDate: new Date(copy.toDate),
 | 
			
		||||
      schedule: {
 | 
			
		||||
        create: copy.schedule.map((scheduleItem: ScheduleItemProps) => ({
 | 
			
		||||
          uuid: v4(),
 | 
			
		||||
          day: scheduleItem.day,
 | 
			
		||||
          day: scheduleItem.day as number,
 | 
			
		||||
          time: new Date(
 | 
			
		||||
            1970,
 | 
			
		||||
            0,
 | 
			
		||||
| 
						 | 
				
			
			@ -53,14 +53,14 @@ export class AdMapper
 | 
			
		|||
            parseInt(scheduleItem.time.split(':')[0]),
 | 
			
		||||
            parseInt(scheduleItem.time.split(':')[1]),
 | 
			
		||||
          ),
 | 
			
		||||
          margin: scheduleItem.margin,
 | 
			
		||||
          margin: scheduleItem.margin as number,
 | 
			
		||||
          createdAt: now,
 | 
			
		||||
          updatedAt: now,
 | 
			
		||||
        })),
 | 
			
		||||
      },
 | 
			
		||||
      seatsProposed: copy.seatsProposed,
 | 
			
		||||
      seatsRequested: copy.seatsRequested,
 | 
			
		||||
      strict: copy.strict,
 | 
			
		||||
      seatsProposed: copy.seatsProposed as number,
 | 
			
		||||
      seatsRequested: copy.seatsRequested as number,
 | 
			
		||||
      strict: copy.strict as boolean,
 | 
			
		||||
      waypoints: {
 | 
			
		||||
        create: copy.waypoints.map((waypoint: WaypointProps) => ({
 | 
			
		||||
          uuid: v4(),
 | 
			
		||||
| 
						 | 
				
			
			@ -92,7 +92,7 @@ export class AdMapper
 | 
			
		|||
        userId: record.userUuid,
 | 
			
		||||
        driver: record.driver,
 | 
			
		||||
        passenger: record.passenger,
 | 
			
		||||
        frequency: Frequency[record.frequency],
 | 
			
		||||
        frequency: record.frequency as Frequency,
 | 
			
		||||
        fromDate: record.fromDate.toISOString().split('T')[0],
 | 
			
		||||
        toDate: record.toDate.toISOString().split('T')[0],
 | 
			
		||||
        schedule: record.schedule.map((scheduleItem: ScheduleItemModel) => ({
 | 
			
		||||
| 
						 | 
				
			
			@ -133,8 +133,8 @@ export class AdMapper
 | 
			
		|||
    const props = entity.getProps();
 | 
			
		||||
    const response = new AdResponseDto(entity);
 | 
			
		||||
    response.userId = props.userId;
 | 
			
		||||
    response.driver = props.driver;
 | 
			
		||||
    response.passenger = props.passenger;
 | 
			
		||||
    response.driver = props.driver as boolean;
 | 
			
		||||
    response.passenger = props.passenger as boolean;
 | 
			
		||||
    response.frequency = props.frequency;
 | 
			
		||||
    response.fromDate = this.outputDatetimeTransformer.fromDate(
 | 
			
		||||
      {
 | 
			
		||||
| 
						 | 
				
			
			@ -156,7 +156,7 @@ export class AdMapper
 | 
			
		|||
    response.schedule = props.schedule.map(
 | 
			
		||||
      (scheduleItem: ScheduleItemProps) => ({
 | 
			
		||||
        day: this.outputDatetimeTransformer.day(
 | 
			
		||||
          scheduleItem.day,
 | 
			
		||||
          scheduleItem.day as number,
 | 
			
		||||
          {
 | 
			
		||||
            date: props.fromDate,
 | 
			
		||||
            time: scheduleItem.time,
 | 
			
		||||
| 
						 | 
				
			
			@ -172,11 +172,11 @@ export class AdMapper
 | 
			
		|||
          },
 | 
			
		||||
          props.frequency,
 | 
			
		||||
        ),
 | 
			
		||||
        margin: scheduleItem.margin,
 | 
			
		||||
        margin: scheduleItem.margin as number,
 | 
			
		||||
      }),
 | 
			
		||||
    );
 | 
			
		||||
    response.seatsProposed = props.seatsProposed;
 | 
			
		||||
    response.seatsRequested = props.seatsRequested;
 | 
			
		||||
    response.seatsProposed = props.seatsProposed as number;
 | 
			
		||||
    response.seatsRequested = props.seatsRequested as number;
 | 
			
		||||
    response.waypoints = props.waypoints.map((waypoint: WaypointProps) => ({
 | 
			
		||||
      position: waypoint.position,
 | 
			
		||||
      name: waypoint.address.name,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,12 +6,10 @@ import {
 | 
			
		|||
  AD_REPOSITORY,
 | 
			
		||||
  INPUT_DATETIME_TRANSFORMER,
 | 
			
		||||
  OUTPUT_DATETIME_TRANSFORMER,
 | 
			
		||||
  PARAMS_PROVIDER,
 | 
			
		||||
  TIMEZONE_FINDER,
 | 
			
		||||
  TIME_CONVERTER,
 | 
			
		||||
} from './ad.di-tokens';
 | 
			
		||||
import { AdRepository } from './infrastructure/ad.repository';
 | 
			
		||||
import { DefaultParamsProvider } from './infrastructure/default-params-provider';
 | 
			
		||||
import { AdMapper } from './ad.mapper';
 | 
			
		||||
import { CreateAdService } from './core/application/commands/create-ad/create-ad.service';
 | 
			
		||||
import { TimezoneFinder } from './infrastructure/timezone-finder';
 | 
			
		||||
| 
						 | 
				
			
			@ -52,10 +50,6 @@ const messagePublishers: Provider[] = [
 | 
			
		|||
const orms: Provider[] = [PrismaService];
 | 
			
		||||
 | 
			
		||||
const adapters: Provider[] = [
 | 
			
		||||
  {
 | 
			
		||||
    provide: PARAMS_PROVIDER,
 | 
			
		||||
    useClass: DefaultParamsProvider,
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    provide: TIMEZONE_FINDER,
 | 
			
		||||
    useClass: TimezoneFinder,
 | 
			
		||||
| 
						 | 
				
			
			@ -87,12 +81,6 @@ const adapters: Provider[] = [
 | 
			
		|||
    ...orms,
 | 
			
		||||
    ...adapters,
 | 
			
		||||
  ],
 | 
			
		||||
  exports: [
 | 
			
		||||
    PrismaService,
 | 
			
		||||
    AdMapper,
 | 
			
		||||
    AD_REPOSITORY,
 | 
			
		||||
    PARAMS_PROVIDER,
 | 
			
		||||
    TIMEZONE_FINDER,
 | 
			
		||||
  ],
 | 
			
		||||
  exports: [PrismaService, AdMapper, AD_REPOSITORY, TIMEZONE_FINDER],
 | 
			
		||||
})
 | 
			
		||||
export class AdModule {}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,15 +5,15 @@ import { Command, CommandProps } from '@mobicoop/ddd-library';
 | 
			
		|||
 | 
			
		||||
export class CreateAdCommand extends Command {
 | 
			
		||||
  readonly userId: string;
 | 
			
		||||
  readonly driver?: boolean;
 | 
			
		||||
  readonly passenger?: boolean;
 | 
			
		||||
  readonly frequency?: Frequency;
 | 
			
		||||
  readonly driver: boolean;
 | 
			
		||||
  readonly passenger: boolean;
 | 
			
		||||
  readonly frequency: Frequency;
 | 
			
		||||
  readonly fromDate: string;
 | 
			
		||||
  readonly toDate: string;
 | 
			
		||||
  readonly schedule: ScheduleItem[];
 | 
			
		||||
  readonly seatsProposed?: number;
 | 
			
		||||
  readonly seatsRequested?: number;
 | 
			
		||||
  readonly strict?: boolean;
 | 
			
		||||
  readonly strict: boolean;
 | 
			
		||||
  readonly waypoints: Waypoint[];
 | 
			
		||||
 | 
			
		||||
  constructor(props: CommandProps<CreateAdCommand>) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,13 +4,10 @@ import { Inject } from '@nestjs/common';
 | 
			
		|||
import {
 | 
			
		||||
  AD_REPOSITORY,
 | 
			
		||||
  INPUT_DATETIME_TRANSFORMER,
 | 
			
		||||
  PARAMS_PROVIDER,
 | 
			
		||||
} from '@modules/ad/ad.di-tokens';
 | 
			
		||||
import { AdEntity } from '@modules/ad/core/domain/ad.entity';
 | 
			
		||||
import { Waypoint } from '../../types/waypoint';
 | 
			
		||||
import { DefaultParams } from '../../ports/default-params.type';
 | 
			
		||||
import { AdRepositoryPort } from '../../ports/ad.repository.port';
 | 
			
		||||
import { DefaultParamsProviderPort } from '../../ports/default-params-provider.port';
 | 
			
		||||
import { AdAlreadyExistsException } from '@modules/ad/core/domain/ad.errors';
 | 
			
		||||
import { AggregateID, ConflictException } from '@mobicoop/ddd-library';
 | 
			
		||||
import { ScheduleItem } from '../../types/schedule-item';
 | 
			
		||||
| 
						 | 
				
			
			@ -18,30 +15,48 @@ import { DateTimeTransformerPort } from '../../ports/datetime-transformer.port';
 | 
			
		|||
 | 
			
		||||
@CommandHandler(CreateAdCommand)
 | 
			
		||||
export class CreateAdService implements ICommandHandler {
 | 
			
		||||
  private readonly _defaultParams: DefaultParams;
 | 
			
		||||
 | 
			
		||||
  constructor(
 | 
			
		||||
    @Inject(AD_REPOSITORY)
 | 
			
		||||
    private readonly repository: AdRepositoryPort,
 | 
			
		||||
    @Inject(PARAMS_PROVIDER)
 | 
			
		||||
    private readonly defaultParamsProvider: DefaultParamsProviderPort,
 | 
			
		||||
    @Inject(INPUT_DATETIME_TRANSFORMER)
 | 
			
		||||
    private readonly datetimeTransformer: DateTimeTransformerPort,
 | 
			
		||||
  ) {
 | 
			
		||||
    this._defaultParams = defaultParamsProvider.getParams();
 | 
			
		||||
  }
 | 
			
		||||
  ) {}
 | 
			
		||||
 | 
			
		||||
  async execute(command: CreateAdCommand): Promise<AggregateID> {
 | 
			
		||||
    const ad = AdEntity.create(
 | 
			
		||||
      {
 | 
			
		||||
        userId: command.userId,
 | 
			
		||||
        driver: command.driver,
 | 
			
		||||
        passenger: command.passenger,
 | 
			
		||||
        frequency: command.frequency,
 | 
			
		||||
        fromDate: this.datetimeTransformer.fromDate(
 | 
			
		||||
    const ad = AdEntity.create({
 | 
			
		||||
      userId: command.userId,
 | 
			
		||||
      driver: command.driver,
 | 
			
		||||
      passenger: command.passenger,
 | 
			
		||||
      frequency: command.frequency,
 | 
			
		||||
      fromDate: this.datetimeTransformer.fromDate(
 | 
			
		||||
        {
 | 
			
		||||
          date: command.fromDate,
 | 
			
		||||
          time: command.schedule[0].time,
 | 
			
		||||
          coordinates: {
 | 
			
		||||
            lon: command.waypoints[0].lon,
 | 
			
		||||
            lat: command.waypoints[0].lat,
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        command.frequency,
 | 
			
		||||
      ),
 | 
			
		||||
      toDate: this.datetimeTransformer.toDate(
 | 
			
		||||
        command.toDate,
 | 
			
		||||
        {
 | 
			
		||||
          date: command.fromDate,
 | 
			
		||||
          time: command.schedule[0].time,
 | 
			
		||||
          coordinates: {
 | 
			
		||||
            lon: command.waypoints[0].lon,
 | 
			
		||||
            lat: command.waypoints[0].lat,
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        command.frequency,
 | 
			
		||||
      ),
 | 
			
		||||
      schedule: command.schedule.map((scheduleItem: ScheduleItem) => ({
 | 
			
		||||
        day: this.datetimeTransformer.day(
 | 
			
		||||
          scheduleItem.day,
 | 
			
		||||
          {
 | 
			
		||||
            date: command.fromDate,
 | 
			
		||||
            time: command.schedule[0].time,
 | 
			
		||||
            time: scheduleItem.time,
 | 
			
		||||
            coordinates: {
 | 
			
		||||
              lon: command.waypoints[0].lon,
 | 
			
		||||
              lat: command.waypoints[0].lat,
 | 
			
		||||
| 
						 | 
				
			
			@ -49,11 +64,10 @@ export class CreateAdService implements ICommandHandler {
 | 
			
		|||
          },
 | 
			
		||||
          command.frequency,
 | 
			
		||||
        ),
 | 
			
		||||
        toDate: this.datetimeTransformer.toDate(
 | 
			
		||||
          command.toDate,
 | 
			
		||||
        time: this.datetimeTransformer.time(
 | 
			
		||||
          {
 | 
			
		||||
            date: command.fromDate,
 | 
			
		||||
            time: command.schedule[0].time,
 | 
			
		||||
            time: scheduleItem.time,
 | 
			
		||||
            coordinates: {
 | 
			
		||||
              lon: command.waypoints[0].lon,
 | 
			
		||||
              lat: command.waypoints[0].lat,
 | 
			
		||||
| 
						 | 
				
			
			@ -61,60 +75,27 @@ export class CreateAdService implements ICommandHandler {
 | 
			
		|||
          },
 | 
			
		||||
          command.frequency,
 | 
			
		||||
        ),
 | 
			
		||||
        schedule: command.schedule.map((scheduleItem: ScheduleItem) => ({
 | 
			
		||||
          day: this.datetimeTransformer.day(
 | 
			
		||||
            scheduleItem.day,
 | 
			
		||||
            {
 | 
			
		||||
              date: command.fromDate,
 | 
			
		||||
              time: scheduleItem.time,
 | 
			
		||||
              coordinates: {
 | 
			
		||||
                lon: command.waypoints[0].lon,
 | 
			
		||||
                lat: command.waypoints[0].lat,
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
            command.frequency,
 | 
			
		||||
          ),
 | 
			
		||||
          time: this.datetimeTransformer.time(
 | 
			
		||||
            {
 | 
			
		||||
              date: command.fromDate,
 | 
			
		||||
              time: scheduleItem.time,
 | 
			
		||||
              coordinates: {
 | 
			
		||||
                lon: command.waypoints[0].lon,
 | 
			
		||||
                lat: command.waypoints[0].lat,
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
            command.frequency,
 | 
			
		||||
          ),
 | 
			
		||||
          margin: scheduleItem.margin,
 | 
			
		||||
        })),
 | 
			
		||||
        seatsProposed: command.seatsProposed,
 | 
			
		||||
        seatsRequested: command.seatsRequested,
 | 
			
		||||
        strict: command.strict,
 | 
			
		||||
        waypoints: command.waypoints.map((waypoint: Waypoint) => ({
 | 
			
		||||
          position: waypoint.position,
 | 
			
		||||
          address: {
 | 
			
		||||
            name: waypoint.name,
 | 
			
		||||
            houseNumber: waypoint.houseNumber,
 | 
			
		||||
            street: waypoint.street,
 | 
			
		||||
            postalCode: waypoint.postalCode,
 | 
			
		||||
            locality: waypoint.locality,
 | 
			
		||||
            country: waypoint.country,
 | 
			
		||||
            coordinates: {
 | 
			
		||||
              lon: waypoint.lon,
 | 
			
		||||
              lat: waypoint.lat,
 | 
			
		||||
            },
 | 
			
		||||
        margin: scheduleItem.margin,
 | 
			
		||||
      })),
 | 
			
		||||
      seatsProposed: command.seatsProposed ?? 0,
 | 
			
		||||
      seatsRequested: command.seatsRequested ?? 0,
 | 
			
		||||
      strict: command.strict,
 | 
			
		||||
      waypoints: command.waypoints.map((waypoint: Waypoint) => ({
 | 
			
		||||
        position: waypoint.position,
 | 
			
		||||
        address: {
 | 
			
		||||
          name: waypoint.name,
 | 
			
		||||
          houseNumber: waypoint.houseNumber,
 | 
			
		||||
          street: waypoint.street,
 | 
			
		||||
          postalCode: waypoint.postalCode,
 | 
			
		||||
          locality: waypoint.locality,
 | 
			
		||||
          country: waypoint.country,
 | 
			
		||||
          coordinates: {
 | 
			
		||||
            lon: waypoint.lon,
 | 
			
		||||
            lat: waypoint.lat,
 | 
			
		||||
          },
 | 
			
		||||
        })),
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        driver: this._defaultParams.DRIVER,
 | 
			
		||||
        passenger: this._defaultParams.PASSENGER,
 | 
			
		||||
        marginDuration: this._defaultParams.DEPARTURE_TIME_MARGIN,
 | 
			
		||||
        strict: this._defaultParams.STRICT,
 | 
			
		||||
        seatsProposed: this._defaultParams.SEATS_PROPOSED,
 | 
			
		||||
        seatsRequested: this._defaultParams.SEATS_REQUESTED,
 | 
			
		||||
      },
 | 
			
		||||
    );
 | 
			
		||||
        },
 | 
			
		||||
      })),
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      await this.repository.insert(ad);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +0,0 @@
 | 
			
		|||
import { DefaultParams } from './default-params.type';
 | 
			
		||||
 | 
			
		||||
export interface DefaultParamsProviderPort {
 | 
			
		||||
  getParams(): DefaultParams;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,9 +0,0 @@
 | 
			
		|||
export type DefaultParams = {
 | 
			
		||||
  DRIVER: boolean;
 | 
			
		||||
  PASSENGER: boolean;
 | 
			
		||||
  SEATS_PROPOSED: number;
 | 
			
		||||
  SEATS_REQUESTED: number;
 | 
			
		||||
  DEPARTURE_TIME_MARGIN: number;
 | 
			
		||||
  STRICT: boolean;
 | 
			
		||||
  TIMEZONE: string;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -1,3 +1,3 @@
 | 
			
		|||
export interface TimezoneFinderPort {
 | 
			
		||||
  timezones(lon: number, lat: number, defaultTimezone?: string): string[];
 | 
			
		||||
  timezones(lon: number, lat: number): string[];
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
export type ScheduleItem = {
 | 
			
		||||
  day?: number;
 | 
			
		||||
  day: number;
 | 
			
		||||
  time: string;
 | 
			
		||||
  margin?: number;
 | 
			
		||||
  margin: number;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
import { Address } from './address';
 | 
			
		||||
 | 
			
		||||
export type Waypoint = {
 | 
			
		||||
  position?: number;
 | 
			
		||||
  position: number;
 | 
			
		||||
} & Address;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,29 +1,17 @@
 | 
			
		|||
import { AggregateRoot, AggregateID } from '@mobicoop/ddd-library';
 | 
			
		||||
import { v4 } from 'uuid';
 | 
			
		||||
import { AdCreatedDomainEvent } from './events/ad-created.domain-events';
 | 
			
		||||
import { AdProps, CreateAdProps, DefaultAdProps } from './ad.types';
 | 
			
		||||
import { AdProps, CreateAdProps } from './ad.types';
 | 
			
		||||
import { ScheduleItemProps } from './value-objects/schedule-item.value-object';
 | 
			
		||||
import { WaypointProps } from './value-objects/waypoint.value-object';
 | 
			
		||||
 | 
			
		||||
export class AdEntity extends AggregateRoot<AdProps> {
 | 
			
		||||
  protected readonly _id: AggregateID;
 | 
			
		||||
 | 
			
		||||
  static create = (
 | 
			
		||||
    create: CreateAdProps,
 | 
			
		||||
    defaultAdProps: DefaultAdProps,
 | 
			
		||||
  ): AdEntity => {
 | 
			
		||||
  static create = (create: CreateAdProps): AdEntity => {
 | 
			
		||||
    const id = v4();
 | 
			
		||||
    const props: AdProps = { ...create };
 | 
			
		||||
    const ad = new AdEntity({ id, props })
 | 
			
		||||
      .setMissingMarginDurations(defaultAdProps.marginDuration)
 | 
			
		||||
      .setMissingStrict(defaultAdProps.strict)
 | 
			
		||||
      .setDefaultDriverAndPassengerParameters({
 | 
			
		||||
        driver: defaultAdProps.driver,
 | 
			
		||||
        passenger: defaultAdProps.passenger,
 | 
			
		||||
        seatsProposed: defaultAdProps.seatsProposed,
 | 
			
		||||
        seatsRequested: defaultAdProps.seatsRequested,
 | 
			
		||||
      })
 | 
			
		||||
      .setMissingWaypointsPosition();
 | 
			
		||||
    const ad = new AdEntity({ id, props });
 | 
			
		||||
    ad.addEvent(
 | 
			
		||||
      new AdCreatedDomainEvent({
 | 
			
		||||
        aggregateId: id,
 | 
			
		||||
| 
						 | 
				
			
			@ -34,9 +22,9 @@ export class AdEntity extends AggregateRoot<AdProps> {
 | 
			
		|||
        fromDate: props.fromDate,
 | 
			
		||||
        toDate: props.toDate,
 | 
			
		||||
        schedule: props.schedule.map((day: ScheduleItemProps) => ({
 | 
			
		||||
          day: day.day,
 | 
			
		||||
          day: day.day as number,
 | 
			
		||||
          time: day.time,
 | 
			
		||||
          margin: day.margin,
 | 
			
		||||
          margin: day.margin as number,
 | 
			
		||||
        })),
 | 
			
		||||
        seatsProposed: props.seatsProposed,
 | 
			
		||||
        seatsRequested: props.seatsRequested,
 | 
			
		||||
| 
						 | 
				
			
			@ -48,7 +36,7 @@ export class AdEntity extends AggregateRoot<AdProps> {
 | 
			
		|||
          street: waypoint.address.street,
 | 
			
		||||
          postalCode: waypoint.address.postalCode,
 | 
			
		||||
          locality: waypoint.address.locality,
 | 
			
		||||
          country: waypoint.address.postalCode,
 | 
			
		||||
          country: waypoint.address.country,
 | 
			
		||||
          lon: waypoint.address.coordinates.lon,
 | 
			
		||||
          lat: waypoint.address.coordinates.lat,
 | 
			
		||||
        })),
 | 
			
		||||
| 
						 | 
				
			
			@ -57,60 +45,7 @@ export class AdEntity extends AggregateRoot<AdProps> {
 | 
			
		|||
    return ad;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  private setMissingMarginDurations = (
 | 
			
		||||
    defaultMarginDuration: number,
 | 
			
		||||
  ): AdEntity => {
 | 
			
		||||
    this.props.schedule.forEach((day: ScheduleItemProps) => {
 | 
			
		||||
      if (day.margin === undefined) day.margin = defaultMarginDuration;
 | 
			
		||||
    });
 | 
			
		||||
    return this;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  private setMissingStrict = (strict: boolean): AdEntity => {
 | 
			
		||||
    if (this.props.strict === undefined) this.props.strict = strict;
 | 
			
		||||
    return this;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  private setDefaultDriverAndPassengerParameters = (
 | 
			
		||||
    defaultDriverAndPassengerParameters: DefaultDriverAndPassengerParameters,
 | 
			
		||||
  ): AdEntity => {
 | 
			
		||||
    this.props.driver = !!this.props.driver;
 | 
			
		||||
    this.props.passenger = !!this.props.passenger;
 | 
			
		||||
    if (!this.props.driver && !this.props.passenger) {
 | 
			
		||||
      this.props.driver = defaultDriverAndPassengerParameters.driver;
 | 
			
		||||
      this.props.seatsProposed =
 | 
			
		||||
        defaultDriverAndPassengerParameters.seatsProposed;
 | 
			
		||||
      this.props.passenger = defaultDriverAndPassengerParameters.passenger;
 | 
			
		||||
      this.props.seatsRequested =
 | 
			
		||||
        defaultDriverAndPassengerParameters.seatsRequested;
 | 
			
		||||
      return this;
 | 
			
		||||
    }
 | 
			
		||||
    if (!this.props.seatsProposed || this.props.seatsProposed <= 0)
 | 
			
		||||
      this.props.seatsProposed =
 | 
			
		||||
        defaultDriverAndPassengerParameters.seatsProposed;
 | 
			
		||||
    if (!this.props.seatsRequested || this.props.seatsRequested <= 0)
 | 
			
		||||
      this.props.seatsRequested =
 | 
			
		||||
        defaultDriverAndPassengerParameters.seatsRequested;
 | 
			
		||||
    return this;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  private setMissingWaypointsPosition = (): AdEntity => {
 | 
			
		||||
    if (this.props.waypoints[0].position === undefined) {
 | 
			
		||||
      for (let i = 0; i < this.props.waypoints.length; i++) {
 | 
			
		||||
        this.props.waypoints[i].position = i;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return this;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  validate(): void {
 | 
			
		||||
    // entity business rules validation to protect it's invariant before saving entity to a database
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface DefaultDriverAndPassengerParameters {
 | 
			
		||||
  driver: boolean;
 | 
			
		||||
  passenger: boolean;
 | 
			
		||||
  seatsProposed: number;
 | 
			
		||||
  seatsRequested: number;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -31,15 +31,6 @@ export interface CreateAdProps {
 | 
			
		|||
  waypoints: WaypointProps[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface DefaultAdProps {
 | 
			
		||||
  driver: boolean;
 | 
			
		||||
  passenger: boolean;
 | 
			
		||||
  marginDuration: number;
 | 
			
		||||
  strict: boolean;
 | 
			
		||||
  seatsProposed: number;
 | 
			
		||||
  seatsRequested: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export enum Frequency {
 | 
			
		||||
  PUNCTUAL = 'PUNCTUAL',
 | 
			
		||||
  RECURRENT = 'RECURRENT',
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,23 +17,23 @@ export interface AddressProps {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
export class Address extends ValueObject<AddressProps> {
 | 
			
		||||
  get name(): string {
 | 
			
		||||
  get name(): string | undefined {
 | 
			
		||||
    return this.props.name;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  get houseNumber(): string {
 | 
			
		||||
  get houseNumber(): string | undefined {
 | 
			
		||||
    return this.props.houseNumber;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  get street(): string {
 | 
			
		||||
  get street(): string | undefined {
 | 
			
		||||
    return this.props.street;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  get locality(): string {
 | 
			
		||||
  get locality(): string | undefined {
 | 
			
		||||
    return this.props.locality;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  get postalCode(): string {
 | 
			
		||||
  get postalCode(): string | undefined {
 | 
			
		||||
    return this.props.postalCode;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,20 +0,0 @@
 | 
			
		|||
import { Injectable } from '@nestjs/common';
 | 
			
		||||
import { ConfigService } from '@nestjs/config';
 | 
			
		||||
import { DefaultParamsProviderPort } from '../core/application/ports/default-params-provider.port';
 | 
			
		||||
import { DefaultParams } from '../core/application/ports/default-params.type';
 | 
			
		||||
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class DefaultParamsProvider implements DefaultParamsProviderPort {
 | 
			
		||||
  constructor(private readonly _configService: ConfigService) {}
 | 
			
		||||
  getParams = (): DefaultParams => ({
 | 
			
		||||
    DRIVER: this._configService.get('ROLE') == 'driver',
 | 
			
		||||
    SEATS_PROPOSED: parseInt(this._configService.get('SEATS_PROPOSED')),
 | 
			
		||||
    PASSENGER: this._configService.get('ROLE') == 'passenger',
 | 
			
		||||
    SEATS_REQUESTED: parseInt(this._configService.get('SEATS_REQUESTED')),
 | 
			
		||||
    DEPARTURE_TIME_MARGIN: parseInt(
 | 
			
		||||
      this._configService.get('DEPARTURE_TIME_MARGIN'),
 | 
			
		||||
    ),
 | 
			
		||||
    STRICT: this._configService.get('STRICT_FREQUENCY') == 'true',
 | 
			
		||||
    TIMEZONE: this._configService.get('DEFAULT_TIMEZONE'),
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -5,26 +5,16 @@ import {
 | 
			
		|||
  GeoDateTime,
 | 
			
		||||
} from '../core/application/ports/datetime-transformer.port';
 | 
			
		||||
import { TimeConverterPort } from '../core/application/ports/time-converter.port';
 | 
			
		||||
import {
 | 
			
		||||
  PARAMS_PROVIDER,
 | 
			
		||||
  TIMEZONE_FINDER,
 | 
			
		||||
  TIME_CONVERTER,
 | 
			
		||||
} from '../ad.di-tokens';
 | 
			
		||||
import { TIMEZONE_FINDER, TIME_CONVERTER } from '../ad.di-tokens';
 | 
			
		||||
import { TimezoneFinderPort } from '../core/application/ports/timezone-finder.port';
 | 
			
		||||
import { DefaultParamsProviderPort } from '../core/application/ports/default-params-provider.port';
 | 
			
		||||
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class InputDateTimeTransformer implements DateTimeTransformerPort {
 | 
			
		||||
  private readonly _defaultTimezone: string;
 | 
			
		||||
  constructor(
 | 
			
		||||
    @Inject(PARAMS_PROVIDER)
 | 
			
		||||
    private readonly defaultParamsProvider: DefaultParamsProviderPort,
 | 
			
		||||
    @Inject(TIMEZONE_FINDER)
 | 
			
		||||
    private readonly timezoneFinder: TimezoneFinderPort,
 | 
			
		||||
    @Inject(TIME_CONVERTER) private readonly timeConverter: TimeConverterPort,
 | 
			
		||||
  ) {
 | 
			
		||||
    this._defaultTimezone = defaultParamsProvider.getParams().TIMEZONE;
 | 
			
		||||
  }
 | 
			
		||||
  ) {}
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Compute the fromDate : if an ad is punctual, the departure date
 | 
			
		||||
| 
						 | 
				
			
			@ -39,7 +29,6 @@ export class InputDateTimeTransformer implements DateTimeTransformerPort {
 | 
			
		|||
        this.timezoneFinder.timezones(
 | 
			
		||||
          geoFromDate.coordinates.lon,
 | 
			
		||||
          geoFromDate.coordinates.lat,
 | 
			
		||||
          this._defaultTimezone,
 | 
			
		||||
        )[0],
 | 
			
		||||
      )
 | 
			
		||||
      .toISOString()
 | 
			
		||||
| 
						 | 
				
			
			@ -76,7 +65,6 @@ export class InputDateTimeTransformer implements DateTimeTransformerPort {
 | 
			
		|||
        this.timezoneFinder.timezones(
 | 
			
		||||
          geoFromDate.coordinates.lon,
 | 
			
		||||
          geoFromDate.coordinates.lat,
 | 
			
		||||
          this._defaultTimezone,
 | 
			
		||||
        )[0],
 | 
			
		||||
      );
 | 
			
		||||
    return new Date(this.fromDate(geoFromDate, frequency)).getUTCDay();
 | 
			
		||||
| 
						 | 
				
			
			@ -92,7 +80,6 @@ export class InputDateTimeTransformer implements DateTimeTransformerPort {
 | 
			
		|||
        this.timezoneFinder.timezones(
 | 
			
		||||
          geoFromDate.coordinates.lon,
 | 
			
		||||
          geoFromDate.coordinates.lat,
 | 
			
		||||
          this._defaultTimezone,
 | 
			
		||||
        )[0],
 | 
			
		||||
      );
 | 
			
		||||
    return this.timeConverter
 | 
			
		||||
| 
						 | 
				
			
			@ -102,7 +89,6 @@ export class InputDateTimeTransformer implements DateTimeTransformerPort {
 | 
			
		|||
        this.timezoneFinder.timezones(
 | 
			
		||||
          geoFromDate.coordinates.lon,
 | 
			
		||||
          geoFromDate.coordinates.lat,
 | 
			
		||||
          this._defaultTimezone,
 | 
			
		||||
        )[0],
 | 
			
		||||
      )
 | 
			
		||||
      .toISOString()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
import { INestApplication, Injectable, OnModuleInit } from '@nestjs/common';
 | 
			
		||||
import { Injectable, OnModuleInit } from '@nestjs/common';
 | 
			
		||||
import { PrismaClient } from '@prisma/client';
 | 
			
		||||
 | 
			
		||||
@Injectable()
 | 
			
		||||
| 
						 | 
				
			
			@ -6,10 +6,4 @@ export class PrismaService extends PrismaClient implements OnModuleInit {
 | 
			
		|||
  async onModuleInit() {
 | 
			
		||||
    await this.$connect();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async enableShutdownHooks(app: INestApplication) {
 | 
			
		||||
    this.$on('beforeExit', async () => {
 | 
			
		||||
      await app.close();
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,13 +4,5 @@ import { TimezoneFinderPort } from '../core/application/ports/timezone-finder.po
 | 
			
		|||
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class TimezoneFinder implements TimezoneFinderPort {
 | 
			
		||||
  timezones = (
 | 
			
		||||
    lon: number,
 | 
			
		||||
    lat: number,
 | 
			
		||||
    defaultTimezone?: string,
 | 
			
		||||
  ): string[] => {
 | 
			
		||||
    const foundTimezones = find(lat, lon);
 | 
			
		||||
    if (defaultTimezone && foundTimezones.length == 0) return [defaultTimezone];
 | 
			
		||||
    return foundTimezones;
 | 
			
		||||
  };
 | 
			
		||||
  timezones = (lon: number, lat: number): string[] => find(lat, lon);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,24 +15,29 @@ import { WaypointDto } from './waypoint.dto';
 | 
			
		|||
import { HasValidPositionIndexes } from './validators/decorators/has-valid-position-indexes.decorator';
 | 
			
		||||
import { Frequency } from '@modules/ad/core/domain/ad.types';
 | 
			
		||||
import { IsAfterOrEqual } from './validators/decorators/is-after-or-equal.decorator';
 | 
			
		||||
import { HasDay } from './validators/decorators/has-day.decorator';
 | 
			
		||||
import { HasRole } from './validators/decorators/has-role.decorator';
 | 
			
		||||
import { HasSeats } from './validators/decorators/has-seats.decorator';
 | 
			
		||||
 | 
			
		||||
export class CreateAdRequestDto {
 | 
			
		||||
  @IsUUID(4)
 | 
			
		||||
  userId: string;
 | 
			
		||||
 | 
			
		||||
  @IsOptional()
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  driver?: boolean;
 | 
			
		||||
  @HasRole('passenger', {
 | 
			
		||||
    message: 'At least one of driver or passenger property needs to be truthy',
 | 
			
		||||
  })
 | 
			
		||||
  @HasSeats('seatsProposed', {
 | 
			
		||||
    message: 'Number of seats proposed as a driver is required',
 | 
			
		||||
  })
 | 
			
		||||
  driver: boolean;
 | 
			
		||||
 | 
			
		||||
  @IsOptional()
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  passenger?: boolean;
 | 
			
		||||
  @HasSeats('seatsRequested', {
 | 
			
		||||
    message: 'Number of seats requested as a passenger is required',
 | 
			
		||||
  })
 | 
			
		||||
  passenger: boolean;
 | 
			
		||||
 | 
			
		||||
  @IsEnum(Frequency)
 | 
			
		||||
  @HasDay('schedule', {
 | 
			
		||||
    message: 'At least a day is required for a recurrent ad',
 | 
			
		||||
  })
 | 
			
		||||
  frequency: Frequency;
 | 
			
		||||
 | 
			
		||||
  @IsISO8601({
 | 
			
		||||
| 
						 | 
				
			
			@ -56,17 +61,16 @@ export class CreateAdRequestDto {
 | 
			
		|||
  @ValidateNested({ each: true })
 | 
			
		||||
  schedule: ScheduleItemDto[];
 | 
			
		||||
 | 
			
		||||
  @IsOptional()
 | 
			
		||||
  @IsInt()
 | 
			
		||||
  @IsOptional()
 | 
			
		||||
  seatsProposed?: number;
 | 
			
		||||
 | 
			
		||||
  @IsOptional()
 | 
			
		||||
  @IsInt()
 | 
			
		||||
  @IsOptional()
 | 
			
		||||
  seatsRequested?: number;
 | 
			
		||||
 | 
			
		||||
  @IsOptional()
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  strict?: boolean;
 | 
			
		||||
  strict: boolean;
 | 
			
		||||
 | 
			
		||||
  @Type(() => WaypointDto)
 | 
			
		||||
  @IsArray()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,16 +1,14 @@
 | 
			
		|||
import { IsOptional, IsMilitaryTime, IsInt, Min, Max } from 'class-validator';
 | 
			
		||||
import { IsMilitaryTime, IsInt, Min, Max } from 'class-validator';
 | 
			
		||||
 | 
			
		||||
export class ScheduleItemDto {
 | 
			
		||||
  @IsOptional()
 | 
			
		||||
  @IsInt()
 | 
			
		||||
  @Min(0)
 | 
			
		||||
  @Max(6)
 | 
			
		||||
  day?: number;
 | 
			
		||||
  day: number;
 | 
			
		||||
 | 
			
		||||
  @IsMilitaryTime()
 | 
			
		||||
  time: string;
 | 
			
		||||
 | 
			
		||||
  @IsOptional()
 | 
			
		||||
  @IsInt()
 | 
			
		||||
  margin?: number;
 | 
			
		||||
  margin: number;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,17 +1,16 @@
 | 
			
		|||
import { Frequency } from '@modules/ad/core/domain/ad.types';
 | 
			
		||||
import {
 | 
			
		||||
  registerDecorator,
 | 
			
		||||
  ValidationOptions,
 | 
			
		||||
  ValidationArguments,
 | 
			
		||||
} from 'class-validator';
 | 
			
		||||
 | 
			
		||||
export function HasDay(
 | 
			
		||||
export function HasRole(
 | 
			
		||||
  property: string,
 | 
			
		||||
  validationOptions?: ValidationOptions,
 | 
			
		||||
) {
 | 
			
		||||
  return function (object: object, propertyName: string) {
 | 
			
		||||
    registerDecorator({
 | 
			
		||||
      name: 'hasDay',
 | 
			
		||||
      name: 'hasRole',
 | 
			
		||||
      target: object.constructor,
 | 
			
		||||
      propertyName: propertyName,
 | 
			
		||||
      constraints: [property],
 | 
			
		||||
| 
						 | 
				
			
			@ -20,13 +19,7 @@ export function HasDay(
 | 
			
		|||
        validate(value: any, args: ValidationArguments) {
 | 
			
		||||
          const [relatedPropertyName] = args.constraints;
 | 
			
		||||
          const relatedValue = (args.object as any)[relatedPropertyName];
 | 
			
		||||
          return (
 | 
			
		||||
            value == Frequency.PUNCTUAL ||
 | 
			
		||||
            (Array.isArray(relatedValue) &&
 | 
			
		||||
              relatedValue.some((scheduleItem) =>
 | 
			
		||||
                scheduleItem.hasOwnProperty('day'),
 | 
			
		||||
              ))
 | 
			
		||||
          );
 | 
			
		||||
          return value || relatedValue;
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
    });
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,27 @@
 | 
			
		|||
import {
 | 
			
		||||
  registerDecorator,
 | 
			
		||||
  ValidationOptions,
 | 
			
		||||
  ValidationArguments,
 | 
			
		||||
} from 'class-validator';
 | 
			
		||||
 | 
			
		||||
export function HasSeats(
 | 
			
		||||
  property: string,
 | 
			
		||||
  validationOptions?: ValidationOptions,
 | 
			
		||||
) {
 | 
			
		||||
  return function (object: object, propertyName: string) {
 | 
			
		||||
    registerDecorator({
 | 
			
		||||
      name: 'hasSeats',
 | 
			
		||||
      target: object.constructor,
 | 
			
		||||
      propertyName: propertyName,
 | 
			
		||||
      constraints: [property],
 | 
			
		||||
      options: validationOptions,
 | 
			
		||||
      validator: {
 | 
			
		||||
        validate(value: any, args: ValidationArguments) {
 | 
			
		||||
          const [relatedPropertyName] = args.constraints;
 | 
			
		||||
          const relatedValue = (args.object as any)[relatedPropertyName];
 | 
			
		||||
          return (value && relatedValue > 0) || !value;
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
    });
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,17 +1,10 @@
 | 
			
		|||
import { WaypointDto } from '../waypoint.dto';
 | 
			
		||||
 | 
			
		||||
export const hasValidPositionIndexes = (waypoints: WaypointDto[]): boolean => {
 | 
			
		||||
  if (!waypoints) return false;
 | 
			
		||||
  if (waypoints.length == 0) return false;
 | 
			
		||||
  if (waypoints.every((waypoint) => waypoint.position === undefined))
 | 
			
		||||
    return false;
 | 
			
		||||
  if (waypoints.every((waypoint) => typeof waypoint.position === 'number')) {
 | 
			
		||||
    const positions = Array.from(waypoints, (waypoint) => waypoint.position);
 | 
			
		||||
    positions.sort();
 | 
			
		||||
    for (let i = 1; i < positions.length; i++)
 | 
			
		||||
      if (positions[i] != positions[i - 1] + 1) return false;
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
  return false;
 | 
			
		||||
  const positions = Array.from(waypoints, (waypoint) => waypoint.position);
 | 
			
		||||
  positions.sort();
 | 
			
		||||
  for (let i = 1; i < positions.length; i++)
 | 
			
		||||
    if (positions[i] != positions[i - 1] + 1) return false;
 | 
			
		||||
  return true;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,8 +1,7 @@
 | 
			
		|||
import { IsInt, IsOptional } from 'class-validator';
 | 
			
		||||
import { IsInt } from 'class-validator';
 | 
			
		||||
import { AddressDto } from './address.dto';
 | 
			
		||||
 | 
			
		||||
export class WaypointDto extends AddressDto {
 | 
			
		||||
  @IsOptional()
 | 
			
		||||
  @IsInt()
 | 
			
		||||
  position?: number;
 | 
			
		||||
  position: number;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,11 +7,7 @@ import {
 | 
			
		|||
} from '@modules/ad/ad.di-tokens';
 | 
			
		||||
import { AdMapper } from '@modules/ad/ad.mapper';
 | 
			
		||||
import { AdEntity } from '@modules/ad/core/domain/ad.entity';
 | 
			
		||||
import {
 | 
			
		||||
  CreateAdProps,
 | 
			
		||||
  DefaultAdProps,
 | 
			
		||||
  Frequency,
 | 
			
		||||
} from '@modules/ad/core/domain/ad.types';
 | 
			
		||||
import { CreateAdProps, Frequency } from '@modules/ad/core/domain/ad.types';
 | 
			
		||||
import { AdRepository } from '@modules/ad/infrastructure/ad.repository';
 | 
			
		||||
import { OutputDateTimeTransformer } from '@modules/ad/infrastructure/output-datetime-transformer';
 | 
			
		||||
import { PrismaService } from '@modules/ad/infrastructure/prisma.service';
 | 
			
		||||
| 
						 | 
				
			
			@ -55,7 +51,7 @@ describe('Ad Repository', () => {
 | 
			
		|||
    driver: 'true',
 | 
			
		||||
    passenger: 'false',
 | 
			
		||||
    seatsProposed: 3,
 | 
			
		||||
    seatsRequested: 0,
 | 
			
		||||
    seatsRequested: 1,
 | 
			
		||||
    strict: 'false',
 | 
			
		||||
  };
 | 
			
		||||
  const punctualAd = {
 | 
			
		||||
| 
						 | 
				
			
			@ -231,19 +227,7 @@ describe('Ad Repository', () => {
 | 
			
		|||
        ],
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      const defaultAdProps: DefaultAdProps = {
 | 
			
		||||
        driver: false,
 | 
			
		||||
        passenger: true,
 | 
			
		||||
        marginDuration: 900,
 | 
			
		||||
        seatsProposed: 3,
 | 
			
		||||
        seatsRequested: 1,
 | 
			
		||||
        strict: false,
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      const adToCreate: AdEntity = AdEntity.create(
 | 
			
		||||
        createAdProps,
 | 
			
		||||
        defaultAdProps,
 | 
			
		||||
      );
 | 
			
		||||
      const adToCreate: AdEntity = AdEntity.create(createAdProps);
 | 
			
		||||
      await adRepository.insert(adToCreate);
 | 
			
		||||
 | 
			
		||||
      const afterCount = await prismaService.ad.count();
 | 
			
		||||
| 
						 | 
				
			
			@ -319,19 +303,7 @@ describe('Ad Repository', () => {
 | 
			
		|||
        ],
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      const defaultAdProps: DefaultAdProps = {
 | 
			
		||||
        driver: false,
 | 
			
		||||
        passenger: true,
 | 
			
		||||
        marginDuration: 900,
 | 
			
		||||
        seatsProposed: 3,
 | 
			
		||||
        seatsRequested: 1,
 | 
			
		||||
        strict: false,
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      const adToCreate: AdEntity = AdEntity.create(
 | 
			
		||||
        createAdProps,
 | 
			
		||||
        defaultAdProps,
 | 
			
		||||
      );
 | 
			
		||||
      const adToCreate: AdEntity = AdEntity.create(createAdProps);
 | 
			
		||||
      await adRepository.insert(adToCreate);
 | 
			
		||||
 | 
			
		||||
      const afterCount = await prismaService.ad.count();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,9 +1,5 @@
 | 
			
		|||
import { AdEntity } from '@modules/ad/core/domain/ad.entity';
 | 
			
		||||
import {
 | 
			
		||||
  CreateAdProps,
 | 
			
		||||
  DefaultAdProps,
 | 
			
		||||
  Frequency,
 | 
			
		||||
} from '@modules/ad/core/domain/ad.types';
 | 
			
		||||
import { CreateAdProps, Frequency } from '@modules/ad/core/domain/ad.types';
 | 
			
		||||
import { WaypointProps } from '@modules/ad/core/domain/value-objects/waypoint.value-object';
 | 
			
		||||
 | 
			
		||||
const originWaypointProps: WaypointProps = {
 | 
			
		||||
| 
						 | 
				
			
			@ -47,6 +43,7 @@ const punctualCreateAdProps = {
 | 
			
		|||
    {
 | 
			
		||||
      day: 3,
 | 
			
		||||
      time: '08:30',
 | 
			
		||||
      margin: 600,
 | 
			
		||||
    },
 | 
			
		||||
  ],
 | 
			
		||||
  frequency: Frequency.PUNCTUAL,
 | 
			
		||||
| 
						 | 
				
			
			@ -119,21 +116,12 @@ const recurrentDriverPassengerCreateAdProps: CreateAdProps = {
 | 
			
		|||
  driver: true,
 | 
			
		||||
  passenger: true,
 | 
			
		||||
};
 | 
			
		||||
const defaultAdProps: DefaultAdProps = {
 | 
			
		||||
  driver: false,
 | 
			
		||||
  passenger: true,
 | 
			
		||||
  marginDuration: 900,
 | 
			
		||||
  seatsProposed: 3,
 | 
			
		||||
  seatsRequested: 1,
 | 
			
		||||
  strict: false,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
describe('Ad entity create', () => {
 | 
			
		||||
  describe('With complete props', () => {
 | 
			
		||||
    it('should create a new punctual passenger ad entity', async () => {
 | 
			
		||||
      const punctualPassengerAd: AdEntity = AdEntity.create(
 | 
			
		||||
        punctualPassengerCreateAdProps,
 | 
			
		||||
        defaultAdProps,
 | 
			
		||||
      );
 | 
			
		||||
      expect(punctualPassengerAd.id.length).toBe(36);
 | 
			
		||||
      expect(punctualPassengerAd.getProps().schedule.length).toBe(1);
 | 
			
		||||
| 
						 | 
				
			
			@ -145,7 +133,6 @@ describe('Ad entity create', () => {
 | 
			
		|||
    it('should create a new punctual driver ad entity', async () => {
 | 
			
		||||
      const punctualDriverAd: AdEntity = AdEntity.create(
 | 
			
		||||
        punctualDriverCreateAdProps,
 | 
			
		||||
        defaultAdProps,
 | 
			
		||||
      );
 | 
			
		||||
      expect(punctualDriverAd.id.length).toBe(36);
 | 
			
		||||
      expect(punctualDriverAd.getProps().schedule.length).toBe(1);
 | 
			
		||||
| 
						 | 
				
			
			@ -157,7 +144,6 @@ describe('Ad entity create', () => {
 | 
			
		|||
    it('should create a new punctual driver and passenger ad entity', async () => {
 | 
			
		||||
      const punctualDriverPassengerAd: AdEntity = AdEntity.create(
 | 
			
		||||
        punctualDriverPassengerCreateAdProps,
 | 
			
		||||
        defaultAdProps,
 | 
			
		||||
      );
 | 
			
		||||
      expect(punctualDriverPassengerAd.id.length).toBe(36);
 | 
			
		||||
      expect(punctualDriverPassengerAd.getProps().schedule.length).toBe(1);
 | 
			
		||||
| 
						 | 
				
			
			@ -171,7 +157,6 @@ describe('Ad entity create', () => {
 | 
			
		|||
    it('should create a new recurrent passenger ad entity', async () => {
 | 
			
		||||
      const recurrentPassengerAd: AdEntity = AdEntity.create(
 | 
			
		||||
        recurrentPassengerCreateAdProps,
 | 
			
		||||
        defaultAdProps,
 | 
			
		||||
      );
 | 
			
		||||
      expect(recurrentPassengerAd.id.length).toBe(36);
 | 
			
		||||
      expect(recurrentPassengerAd.getProps().schedule.length).toBe(5);
 | 
			
		||||
| 
						 | 
				
			
			@ -183,7 +168,6 @@ describe('Ad entity create', () => {
 | 
			
		|||
    it('should create a new recurrent driver ad entity', async () => {
 | 
			
		||||
      const recurrentDriverAd: AdEntity = AdEntity.create(
 | 
			
		||||
        recurrentDriverCreateAdProps,
 | 
			
		||||
        defaultAdProps,
 | 
			
		||||
      );
 | 
			
		||||
      expect(recurrentDriverAd.id.length).toBe(36);
 | 
			
		||||
      expect(recurrentDriverAd.getProps().schedule.length).toBe(5);
 | 
			
		||||
| 
						 | 
				
			
			@ -195,7 +179,6 @@ describe('Ad entity create', () => {
 | 
			
		|||
    it('should create a new recurrent driver and passenger ad entity', async () => {
 | 
			
		||||
      const recurrentDriverPassengerAd: AdEntity = AdEntity.create(
 | 
			
		||||
        recurrentDriverPassengerCreateAdProps,
 | 
			
		||||
        defaultAdProps,
 | 
			
		||||
      );
 | 
			
		||||
      expect(recurrentDriverPassengerAd.id.length).toBe(36);
 | 
			
		||||
      expect(recurrentDriverPassengerAd.getProps().schedule.length).toBe(5);
 | 
			
		||||
| 
						 | 
				
			
			@ -207,177 +190,4 @@ describe('Ad entity create', () => {
 | 
			
		|||
      expect(recurrentDriverPassengerAd.getProps().passenger).toBeTruthy();
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('With incomplete props', () => {
 | 
			
		||||
    it('should create a new punctual passenger ad entity if no role is given', async () => {
 | 
			
		||||
      const punctualWithoutRoleCreateAdProps: CreateAdProps = {
 | 
			
		||||
        ...baseCreateAdProps,
 | 
			
		||||
        ...punctualCreateAdProps,
 | 
			
		||||
        driver: false,
 | 
			
		||||
        passenger: false,
 | 
			
		||||
      };
 | 
			
		||||
      const punctualWithoutRoleAd: AdEntity = AdEntity.create(
 | 
			
		||||
        punctualWithoutRoleCreateAdProps,
 | 
			
		||||
        defaultAdProps,
 | 
			
		||||
      );
 | 
			
		||||
      expect(punctualWithoutRoleAd.id.length).toBe(36);
 | 
			
		||||
      expect(punctualWithoutRoleAd.getProps().schedule.length).toBe(1);
 | 
			
		||||
      expect(punctualWithoutRoleAd.getProps().schedule[0].time).toBe('08:30');
 | 
			
		||||
      expect(punctualWithoutRoleAd.getProps().driver).toBeFalsy();
 | 
			
		||||
      expect(punctualWithoutRoleAd.getProps().passenger).toBeTruthy();
 | 
			
		||||
    });
 | 
			
		||||
    it('should create a new strict punctual passenger ad entity if no strict param is given', async () => {
 | 
			
		||||
      const punctualWithoutStrictCreateAdProps: CreateAdProps = {
 | 
			
		||||
        userId: 'e8fe64b1-4c33-49e1-9f69-4db48b21df36',
 | 
			
		||||
        seatsProposed: 3,
 | 
			
		||||
        seatsRequested: 1,
 | 
			
		||||
        strict: undefined,
 | 
			
		||||
        waypoints: [originWaypointProps, destinationWaypointProps],
 | 
			
		||||
        ...punctualCreateAdProps,
 | 
			
		||||
        driver: false,
 | 
			
		||||
        passenger: true,
 | 
			
		||||
      };
 | 
			
		||||
      const punctualWithoutStrictAd: AdEntity = AdEntity.create(
 | 
			
		||||
        punctualWithoutStrictCreateAdProps,
 | 
			
		||||
        defaultAdProps,
 | 
			
		||||
      );
 | 
			
		||||
      expect(punctualWithoutStrictAd.id.length).toBe(36);
 | 
			
		||||
      expect(punctualWithoutStrictAd.getProps().schedule.length).toBe(1);
 | 
			
		||||
      expect(punctualWithoutStrictAd.getProps().schedule[0].time).toBe('08:30');
 | 
			
		||||
      expect(punctualWithoutStrictAd.getProps().driver).toBeFalsy();
 | 
			
		||||
      expect(punctualWithoutStrictAd.getProps().passenger).toBeTruthy();
 | 
			
		||||
      expect(punctualWithoutStrictAd.getProps().strict).toBeFalsy();
 | 
			
		||||
    });
 | 
			
		||||
    it('should create a new punctual passenger ad entity with seats requested if no seats requested param is given', async () => {
 | 
			
		||||
      const punctualWithoutSeatsRequestedCreateAdProps: CreateAdProps = {
 | 
			
		||||
        userId: 'e8fe64b1-4c33-49e1-9f69-4db48b21df36',
 | 
			
		||||
        seatsProposed: 3,
 | 
			
		||||
        seatsRequested: undefined,
 | 
			
		||||
        strict: false,
 | 
			
		||||
        waypoints: [originWaypointProps, destinationWaypointProps],
 | 
			
		||||
        ...punctualCreateAdProps,
 | 
			
		||||
        driver: false,
 | 
			
		||||
        passenger: true,
 | 
			
		||||
      };
 | 
			
		||||
      const punctualWithoutSeatsRequestedAd: AdEntity = AdEntity.create(
 | 
			
		||||
        punctualWithoutSeatsRequestedCreateAdProps,
 | 
			
		||||
        defaultAdProps,
 | 
			
		||||
      );
 | 
			
		||||
      expect(punctualWithoutSeatsRequestedAd.id.length).toBe(36);
 | 
			
		||||
      expect(punctualWithoutSeatsRequestedAd.getProps().schedule.length).toBe(
 | 
			
		||||
        1,
 | 
			
		||||
      );
 | 
			
		||||
      expect(punctualWithoutSeatsRequestedAd.getProps().schedule[0].time).toBe(
 | 
			
		||||
        '08:30',
 | 
			
		||||
      );
 | 
			
		||||
      expect(punctualWithoutSeatsRequestedAd.getProps().driver).toBeFalsy();
 | 
			
		||||
      expect(punctualWithoutSeatsRequestedAd.getProps().passenger).toBeTruthy();
 | 
			
		||||
      expect(punctualWithoutSeatsRequestedAd.getProps().seatsRequested).toBe(1);
 | 
			
		||||
    });
 | 
			
		||||
    it('should create a new punctual driver ad entity with seats proposed if no seats proposed param is given', async () => {
 | 
			
		||||
      const punctualWithoutSeatsProposedCreateAdProps: CreateAdProps = {
 | 
			
		||||
        userId: 'e8fe64b1-4c33-49e1-9f69-4db48b21df36',
 | 
			
		||||
        seatsProposed: undefined,
 | 
			
		||||
        seatsRequested: 1,
 | 
			
		||||
        strict: false,
 | 
			
		||||
        waypoints: [originWaypointProps, destinationWaypointProps],
 | 
			
		||||
        ...punctualCreateAdProps,
 | 
			
		||||
        driver: true,
 | 
			
		||||
        passenger: false,
 | 
			
		||||
      };
 | 
			
		||||
      const punctualWithoutSeatsProposedAd: AdEntity = AdEntity.create(
 | 
			
		||||
        punctualWithoutSeatsProposedCreateAdProps,
 | 
			
		||||
        defaultAdProps,
 | 
			
		||||
      );
 | 
			
		||||
      expect(punctualWithoutSeatsProposedAd.id.length).toBe(36);
 | 
			
		||||
      expect(punctualWithoutSeatsProposedAd.getProps().schedule.length).toBe(1);
 | 
			
		||||
      expect(punctualWithoutSeatsProposedAd.getProps().schedule[0].time).toBe(
 | 
			
		||||
        '08:30',
 | 
			
		||||
      );
 | 
			
		||||
      expect(punctualWithoutSeatsProposedAd.getProps().driver).toBeTruthy();
 | 
			
		||||
      expect(punctualWithoutSeatsProposedAd.getProps().passenger).toBeFalsy();
 | 
			
		||||
      expect(punctualWithoutSeatsProposedAd.getProps().seatsProposed).toBe(3);
 | 
			
		||||
    });
 | 
			
		||||
    it('should create a new punctual driver ad entity with margin durations if margin durations are empty', async () => {
 | 
			
		||||
      const punctualWithoutMarginDurationCreateAdProps: CreateAdProps = {
 | 
			
		||||
        ...baseCreateAdProps,
 | 
			
		||||
        waypoints: [originWaypointProps, destinationWaypointProps],
 | 
			
		||||
        ...punctualCreateAdProps,
 | 
			
		||||
        driver: true,
 | 
			
		||||
        passenger: false,
 | 
			
		||||
      };
 | 
			
		||||
      const punctualWithoutMarginDurationAd: AdEntity = AdEntity.create(
 | 
			
		||||
        punctualWithoutMarginDurationCreateAdProps,
 | 
			
		||||
        defaultAdProps,
 | 
			
		||||
      );
 | 
			
		||||
      expect(punctualWithoutMarginDurationAd.id.length).toBe(36);
 | 
			
		||||
      expect(punctualWithoutMarginDurationAd.getProps().schedule.length).toBe(
 | 
			
		||||
        1,
 | 
			
		||||
      );
 | 
			
		||||
      expect(punctualWithoutMarginDurationAd.getProps().schedule[0].time).toBe(
 | 
			
		||||
        '08:30',
 | 
			
		||||
      );
 | 
			
		||||
      expect(
 | 
			
		||||
        punctualWithoutMarginDurationAd.getProps().schedule[0].margin,
 | 
			
		||||
      ).toBe(900);
 | 
			
		||||
      expect(punctualWithoutMarginDurationAd.getProps().driver).toBeTruthy();
 | 
			
		||||
      expect(punctualWithoutMarginDurationAd.getProps().passenger).toBeFalsy();
 | 
			
		||||
    });
 | 
			
		||||
    it('should create a new punctual passenger ad entity with valid positions if positions are missing', async () => {
 | 
			
		||||
      const punctualWithoutPositionsCreateAdProps: CreateAdProps = {
 | 
			
		||||
        userId: 'e8fe64b1-4c33-49e1-9f69-4db48b21df36',
 | 
			
		||||
        seatsProposed: 3,
 | 
			
		||||
        seatsRequested: 1,
 | 
			
		||||
        strict: undefined,
 | 
			
		||||
        waypoints: [
 | 
			
		||||
          {
 | 
			
		||||
            position: undefined,
 | 
			
		||||
            address: {
 | 
			
		||||
              houseNumber: '5',
 | 
			
		||||
              street: 'Avenue Foch',
 | 
			
		||||
              locality: 'Nancy',
 | 
			
		||||
              postalCode: '54000',
 | 
			
		||||
              country: 'France',
 | 
			
		||||
              coordinates: {
 | 
			
		||||
                lat: 48.689445,
 | 
			
		||||
                lon: 6.17651,
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            position: undefined,
 | 
			
		||||
            address: {
 | 
			
		||||
              locality: 'Paris',
 | 
			
		||||
              postalCode: '75000',
 | 
			
		||||
              country: 'France',
 | 
			
		||||
              coordinates: {
 | 
			
		||||
                lat: 48.8566,
 | 
			
		||||
                lon: 2.3522,
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        ],
 | 
			
		||||
        ...punctualCreateAdProps,
 | 
			
		||||
        driver: false,
 | 
			
		||||
        passenger: false,
 | 
			
		||||
      };
 | 
			
		||||
      const punctualWithoutPositionsAd: AdEntity = AdEntity.create(
 | 
			
		||||
        punctualWithoutPositionsCreateAdProps,
 | 
			
		||||
        defaultAdProps,
 | 
			
		||||
      );
 | 
			
		||||
      expect(punctualWithoutPositionsAd.id.length).toBe(36);
 | 
			
		||||
      expect(punctualWithoutPositionsAd.getProps().schedule.length).toBe(1);
 | 
			
		||||
      expect(punctualWithoutPositionsAd.getProps().schedule[0].time).toBe(
 | 
			
		||||
        '08:30',
 | 
			
		||||
      );
 | 
			
		||||
      expect(punctualWithoutPositionsAd.getProps().driver).toBeFalsy();
 | 
			
		||||
      expect(punctualWithoutPositionsAd.getProps().passenger).toBeTruthy();
 | 
			
		||||
      expect(punctualWithoutPositionsAd.getProps().waypoints[0].position).toBe(
 | 
			
		||||
        0,
 | 
			
		||||
      );
 | 
			
		||||
      expect(punctualWithoutPositionsAd.getProps().waypoints[1].position).toBe(
 | 
			
		||||
        1,
 | 
			
		||||
      );
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,6 @@ import { Test, TestingModule } from '@nestjs/testing';
 | 
			
		|||
import {
 | 
			
		||||
  AD_REPOSITORY,
 | 
			
		||||
  INPUT_DATETIME_TRANSFORMER,
 | 
			
		||||
  PARAMS_PROVIDER,
 | 
			
		||||
} from '@modules/ad/ad.di-tokens';
 | 
			
		||||
import { WaypointDto } from '@modules/ad/interface/grpc-controllers/dtos/waypoint.dto';
 | 
			
		||||
import { CreateAdRequestDto } from '@modules/ad/interface/grpc-controllers/dtos/create-ad.request.dto';
 | 
			
		||||
| 
						 | 
				
			
			@ -10,7 +9,6 @@ import { AggregateID } from '@mobicoop/ddd-library';
 | 
			
		|||
import { AdEntity } from '@modules/ad/core/domain/ad.entity';
 | 
			
		||||
import { ConflictException } from '@mobicoop/ddd-library';
 | 
			
		||||
import { Frequency } from '@modules/ad/core/domain/ad.types';
 | 
			
		||||
import { DefaultParamsProviderPort } from '@modules/ad/core/application/ports/default-params-provider.port';
 | 
			
		||||
import { CreateAdService } from '@modules/ad/core/application/commands/create-ad/create-ad.service';
 | 
			
		||||
import { CreateAdCommand } from '@modules/ad/core/application/commands/create-ad/create-ad.command';
 | 
			
		||||
import { AdAlreadyExistsException } from '@modules/ad/core/domain/ad.errors';
 | 
			
		||||
| 
						 | 
				
			
			@ -41,11 +39,15 @@ const punctualCreateAdRequest: CreateAdRequestDto = {
 | 
			
		|||
  schedule: [
 | 
			
		||||
    {
 | 
			
		||||
      time: '08:15',
 | 
			
		||||
      margin: 900,
 | 
			
		||||
      day: 4,
 | 
			
		||||
    },
 | 
			
		||||
  ],
 | 
			
		||||
  driver: true,
 | 
			
		||||
  passenger: true,
 | 
			
		||||
  seatsRequested: 1,
 | 
			
		||||
  seatsProposed: 3,
 | 
			
		||||
  strict: false,
 | 
			
		||||
  frequency: Frequency.PUNCTUAL,
 | 
			
		||||
  waypoints: [originWaypoint, destinationWaypoint],
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -62,20 +64,6 @@ const mockAdRepository = {
 | 
			
		|||
    }),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const mockDefaultParamsProvider: DefaultParamsProviderPort = {
 | 
			
		||||
  getParams: () => {
 | 
			
		||||
    return {
 | 
			
		||||
      DEPARTURE_TIME_MARGIN: 900,
 | 
			
		||||
      DRIVER: false,
 | 
			
		||||
      SEATS_PROPOSED: 3,
 | 
			
		||||
      PASSENGER: true,
 | 
			
		||||
      SEATS_REQUESTED: 1,
 | 
			
		||||
      STRICT: false,
 | 
			
		||||
      TIMEZONE: 'Europe/Paris',
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const mockInputDateTimeTransformer: DateTimeTransformerPort = {
 | 
			
		||||
  fromDate: jest.fn(),
 | 
			
		||||
  toDate: jest.fn(),
 | 
			
		||||
| 
						 | 
				
			
			@ -93,10 +81,6 @@ describe('create-ad.service', () => {
 | 
			
		|||
          provide: AD_REPOSITORY,
 | 
			
		||||
          useValue: mockAdRepository,
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          provide: PARAMS_PROVIDER,
 | 
			
		||||
          useValue: mockDefaultParamsProvider,
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          provide: INPUT_DATETIME_TRANSFORMER,
 | 
			
		||||
          useValue: mockInputDateTimeTransformer,
 | 
			
		||||
| 
						 | 
				
			
			@ -118,9 +102,8 @@ describe('create-ad.service', () => {
 | 
			
		|||
      AdEntity.create = jest.fn().mockReturnValue({
 | 
			
		||||
        id: '047a6ecf-23d4-4d3e-877c-3225d560a8da',
 | 
			
		||||
      });
 | 
			
		||||
      const result: AggregateID = await createAdService.execute(
 | 
			
		||||
        createAdCommand,
 | 
			
		||||
      );
 | 
			
		||||
      const result: AggregateID =
 | 
			
		||||
        await createAdService.execute(createAdCommand);
 | 
			
		||||
      expect(result).toBe('047a6ecf-23d4-4d3e-877c-3225d560a8da');
 | 
			
		||||
    });
 | 
			
		||||
    it('should throw an error if something bad happens', async () => {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,10 +1,6 @@
 | 
			
		|||
import { AD_REPOSITORY } from '@modules/ad/ad.di-tokens';
 | 
			
		||||
import { AdEntity } from '@modules/ad/core/domain/ad.entity';
 | 
			
		||||
import {
 | 
			
		||||
  CreateAdProps,
 | 
			
		||||
  DefaultAdProps,
 | 
			
		||||
  Frequency,
 | 
			
		||||
} from '@modules/ad/core/domain/ad.types';
 | 
			
		||||
import { CreateAdProps, Frequency } from '@modules/ad/core/domain/ad.types';
 | 
			
		||||
import { FindAdByIdQuery } from '@modules/ad/core/application/queries/find-ad-by-id/find-ad-by-id.query';
 | 
			
		||||
import { FindAdByIdQueryHandler } from '@modules/ad/core/application/queries/find-ad-by-id/find-ad-by-id.query-handler';
 | 
			
		||||
import { WaypointProps } from '@modules/ad/core/domain/value-objects/waypoint.value-object';
 | 
			
		||||
| 
						 | 
				
			
			@ -60,19 +56,7 @@ const punctualPassengerCreateAdProps: CreateAdProps = {
 | 
			
		|||
  passenger: true,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const defaultAdProps: DefaultAdProps = {
 | 
			
		||||
  marginDuration: 900,
 | 
			
		||||
  driver: false,
 | 
			
		||||
  passenger: true,
 | 
			
		||||
  seatsProposed: 3,
 | 
			
		||||
  seatsRequested: 1,
 | 
			
		||||
  strict: false,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const ad: AdEntity = AdEntity.create(
 | 
			
		||||
  punctualPassengerCreateAdProps,
 | 
			
		||||
  defaultAdProps,
 | 
			
		||||
);
 | 
			
		||||
const ad: AdEntity = AdEntity.create(punctualPassengerCreateAdProps);
 | 
			
		||||
 | 
			
		||||
const mockAdRepository = {
 | 
			
		||||
  findOneById: jest.fn().mockImplementation(() => ad),
 | 
			
		||||
| 
						 | 
				
			
			@ -106,9 +90,8 @@ describe('find-ad-by-id.query-handler', () => {
 | 
			
		|||
      const findAdbyIdQuery = new FindAdByIdQuery(
 | 
			
		||||
        'dd264806-13b4-4226-9b18-87adf0ad5dd1',
 | 
			
		||||
      );
 | 
			
		||||
      const ad: AdEntity = await findAdByIdQueryHandler.execute(
 | 
			
		||||
        findAdbyIdQuery,
 | 
			
		||||
      );
 | 
			
		||||
      const ad: AdEntity =
 | 
			
		||||
        await findAdByIdQueryHandler.execute(findAdbyIdQuery);
 | 
			
		||||
      expect(ad.getProps().fromDate).toBe('2023-06-22');
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,58 +0,0 @@
 | 
			
		|||
import { DefaultParams } from '@modules/ad/core/application/ports/default-params.type';
 | 
			
		||||
import { DefaultParamsProvider } from '@modules/ad/infrastructure/default-params-provider';
 | 
			
		||||
import { ConfigService } from '@nestjs/config';
 | 
			
		||||
import { Test, TestingModule } from '@nestjs/testing';
 | 
			
		||||
 | 
			
		||||
const mockConfigService = {
 | 
			
		||||
  get: jest.fn().mockImplementation((value: string) => {
 | 
			
		||||
    switch (value) {
 | 
			
		||||
      case 'DEPARTURE_TIME_MARGIN':
 | 
			
		||||
        return 900;
 | 
			
		||||
      case 'ROLE':
 | 
			
		||||
        return 'passenger';
 | 
			
		||||
      case 'SEATS_PROPOSED':
 | 
			
		||||
        return 3;
 | 
			
		||||
      case 'SEATS_REQUESTED':
 | 
			
		||||
        return 1;
 | 
			
		||||
      case 'STRICT_FREQUENCY':
 | 
			
		||||
        return 'false';
 | 
			
		||||
      case 'DEFAULT_TIMEZONE':
 | 
			
		||||
        return 'Europe/Paris';
 | 
			
		||||
      default:
 | 
			
		||||
        return 'some_default_value';
 | 
			
		||||
    }
 | 
			
		||||
  }),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
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: DefaultParams = defaultParamsProvider.getParams();
 | 
			
		||||
    expect(params.DEPARTURE_TIME_MARGIN).toBe(900);
 | 
			
		||||
    expect(params.PASSENGER).toBeTruthy();
 | 
			
		||||
    expect(params.DRIVER).toBeFalsy();
 | 
			
		||||
    expect(params.TIMEZONE).toBe('Europe/Paris');
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -1,29 +1,10 @@
 | 
			
		|||
import {
 | 
			
		||||
  PARAMS_PROVIDER,
 | 
			
		||||
  TIMEZONE_FINDER,
 | 
			
		||||
  TIME_CONVERTER,
 | 
			
		||||
} from '@modules/ad/ad.di-tokens';
 | 
			
		||||
import { TIMEZONE_FINDER, TIME_CONVERTER } from '@modules/ad/ad.di-tokens';
 | 
			
		||||
import { Frequency } from '@modules/ad/core/application/ports/datetime-transformer.port';
 | 
			
		||||
import { DefaultParamsProviderPort } from '@modules/ad/core/application/ports/default-params-provider.port';
 | 
			
		||||
import { TimeConverterPort } from '@modules/ad/core/application/ports/time-converter.port';
 | 
			
		||||
import { TimezoneFinderPort } from '@modules/ad/core/application/ports/timezone-finder.port';
 | 
			
		||||
import { InputDateTimeTransformer } from '@modules/ad/infrastructure/input-datetime-transformer';
 | 
			
		||||
import { Test, TestingModule } from '@nestjs/testing';
 | 
			
		||||
 | 
			
		||||
const mockDefaultParamsProvider: DefaultParamsProviderPort = {
 | 
			
		||||
  getParams: () => {
 | 
			
		||||
    return {
 | 
			
		||||
      DEPARTURE_TIME_MARGIN: 900,
 | 
			
		||||
      DRIVER: false,
 | 
			
		||||
      SEATS_PROPOSED: 3,
 | 
			
		||||
      PASSENGER: true,
 | 
			
		||||
      SEATS_REQUESTED: 1,
 | 
			
		||||
      STRICT: false,
 | 
			
		||||
      TIMEZONE: 'Europe/Paris',
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const mockTimezoneFinder: TimezoneFinderPort = {
 | 
			
		||||
  timezones: jest.fn().mockImplementation(() => ['Europe/Paris']),
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -56,10 +37,6 @@ describe('Input Datetime Transformer', () => {
 | 
			
		|||
  beforeAll(async () => {
 | 
			
		||||
    const module: TestingModule = await Test.createTestingModule({
 | 
			
		||||
      providers: [
 | 
			
		||||
        {
 | 
			
		||||
          provide: PARAMS_PROVIDER,
 | 
			
		||||
          useValue: mockDefaultParamsProvider,
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          provide: TIMEZONE_FINDER,
 | 
			
		||||
          useValue: mockTimezoneFinder,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,29 +1,10 @@
 | 
			
		|||
import {
 | 
			
		||||
  PARAMS_PROVIDER,
 | 
			
		||||
  TIMEZONE_FINDER,
 | 
			
		||||
  TIME_CONVERTER,
 | 
			
		||||
} from '@modules/ad/ad.di-tokens';
 | 
			
		||||
import { TIMEZONE_FINDER, TIME_CONVERTER } from '@modules/ad/ad.di-tokens';
 | 
			
		||||
import { Frequency } from '@modules/ad/core/application/ports/datetime-transformer.port';
 | 
			
		||||
import { DefaultParamsProviderPort } from '@modules/ad/core/application/ports/default-params-provider.port';
 | 
			
		||||
import { TimeConverterPort } from '@modules/ad/core/application/ports/time-converter.port';
 | 
			
		||||
import { TimezoneFinderPort } from '@modules/ad/core/application/ports/timezone-finder.port';
 | 
			
		||||
import { OutputDateTimeTransformer } from '@modules/ad/infrastructure/output-datetime-transformer';
 | 
			
		||||
import { Test, TestingModule } from '@nestjs/testing';
 | 
			
		||||
 | 
			
		||||
const mockDefaultParamsProvider: DefaultParamsProviderPort = {
 | 
			
		||||
  getParams: () => {
 | 
			
		||||
    return {
 | 
			
		||||
      DEPARTURE_TIME_MARGIN: 900,
 | 
			
		||||
      DRIVER: false,
 | 
			
		||||
      SEATS_PROPOSED: 3,
 | 
			
		||||
      PASSENGER: true,
 | 
			
		||||
      SEATS_REQUESTED: 1,
 | 
			
		||||
      STRICT: false,
 | 
			
		||||
      TIMEZONE: 'Europe/Paris',
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const mockTimezoneFinder: TimezoneFinderPort = {
 | 
			
		||||
  timezones: jest.fn().mockImplementation(() => ['Europe/Paris']),
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -56,10 +37,6 @@ describe('Output Datetime Transformer', () => {
 | 
			
		|||
  beforeAll(async () => {
 | 
			
		||||
    const module: TestingModule = await Test.createTestingModule({
 | 
			
		||||
      providers: [
 | 
			
		||||
        {
 | 
			
		||||
          provide: PARAMS_PROVIDER,
 | 
			
		||||
          useValue: mockDefaultParamsProvider,
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          provide: TIMEZONE_FINDER,
 | 
			
		||||
          useValue: mockTimezoneFinder,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,11 +34,15 @@ const punctualCreateAdRequest: CreateAdRequestDto = {
 | 
			
		|||
  schedule: [
 | 
			
		||||
    {
 | 
			
		||||
      time: '08:15',
 | 
			
		||||
      day: 4,
 | 
			
		||||
      margin: 600,
 | 
			
		||||
    },
 | 
			
		||||
  ],
 | 
			
		||||
  driver: false,
 | 
			
		||||
  passenger: true,
 | 
			
		||||
  seatsRequested: 1,
 | 
			
		||||
  seatsProposed: 3,
 | 
			
		||||
  strict: false,
 | 
			
		||||
  frequency: Frequency.PUNCTUAL,
 | 
			
		||||
  waypoints: [originWaypoint, destinationWaypoint],
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,60 +0,0 @@
 | 
			
		|||
import { Frequency } from '@modules/ad/core/domain/ad.types';
 | 
			
		||||
import { ScheduleItemDto } from '@modules/ad/interface/grpc-controllers/dtos/schedule-item.dto';
 | 
			
		||||
import { HasDay } from '@modules/ad/interface/grpc-controllers/dtos/validators/decorators/has-day.decorator';
 | 
			
		||||
import { Validator } from 'class-validator';
 | 
			
		||||
 | 
			
		||||
describe('Has day decorator', () => {
 | 
			
		||||
  class MyClass {
 | 
			
		||||
    @HasDay('schedule', {
 | 
			
		||||
      message: 'At least a day is required for a recurrent ad',
 | 
			
		||||
    })
 | 
			
		||||
    frequency: Frequency;
 | 
			
		||||
 | 
			
		||||
    schedule: ScheduleItemDto[];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  it('should return a property decorator has a function', () => {
 | 
			
		||||
    const hasDay = HasDay('someProperty');
 | 
			
		||||
    expect(typeof hasDay).toBe('function');
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should validate a punctual frequency associated with a valid schedule', async () => {
 | 
			
		||||
    const myClassInstance = new MyClass();
 | 
			
		||||
    myClassInstance.frequency = Frequency.PUNCTUAL;
 | 
			
		||||
    myClassInstance.schedule = [
 | 
			
		||||
      {
 | 
			
		||||
        time: '07:15',
 | 
			
		||||
      },
 | 
			
		||||
    ];
 | 
			
		||||
    const validator = new Validator();
 | 
			
		||||
    const validation = await validator.validate(myClassInstance);
 | 
			
		||||
    expect(validation.length).toBe(0);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should validate a recurrent frequency associated with a valid schedule', async () => {
 | 
			
		||||
    const myClassInstance = new MyClass();
 | 
			
		||||
    myClassInstance.frequency = Frequency.RECURRENT;
 | 
			
		||||
    myClassInstance.schedule = [
 | 
			
		||||
      {
 | 
			
		||||
        time: '07:15',
 | 
			
		||||
        day: 1,
 | 
			
		||||
      },
 | 
			
		||||
    ];
 | 
			
		||||
    const validator = new Validator();
 | 
			
		||||
    const validation = await validator.validate(myClassInstance);
 | 
			
		||||
    expect(validation.length).toBe(0);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should not validate a recurrent frequency associated with an invalid schedule', async () => {
 | 
			
		||||
    const myClassInstance = new MyClass();
 | 
			
		||||
    myClassInstance.frequency = Frequency.RECURRENT;
 | 
			
		||||
    myClassInstance.schedule = [
 | 
			
		||||
      {
 | 
			
		||||
        time: '07:15',
 | 
			
		||||
      },
 | 
			
		||||
    ];
 | 
			
		||||
    const validator = new Validator();
 | 
			
		||||
    const validation = await validator.validate(myClassInstance);
 | 
			
		||||
    expect(validation.length).toBe(1);
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,47 @@
 | 
			
		|||
import { HasRole } from '@modules/ad/interface/grpc-controllers/dtos/validators/decorators/has-role.decorator';
 | 
			
		||||
import { Validator } from 'class-validator';
 | 
			
		||||
 | 
			
		||||
describe('has role decorator', () => {
 | 
			
		||||
  class MyClass {
 | 
			
		||||
    @HasRole('passenger')
 | 
			
		||||
    driver: boolean;
 | 
			
		||||
 | 
			
		||||
    passenger: boolean;
 | 
			
		||||
  }
 | 
			
		||||
  it('should return a property decorator has a function', () => {
 | 
			
		||||
    const hasRole = HasRole('property');
 | 
			
		||||
    expect(typeof hasRole).toBe('function');
 | 
			
		||||
  });
 | 
			
		||||
  it('should validate an instance with driver only set to true', async () => {
 | 
			
		||||
    const myClassInstance = new MyClass();
 | 
			
		||||
    myClassInstance.driver = true;
 | 
			
		||||
    myClassInstance.passenger = false;
 | 
			
		||||
    const validator = new Validator();
 | 
			
		||||
    const validation = await validator.validate(myClassInstance);
 | 
			
		||||
    expect(validation.length).toBe(0);
 | 
			
		||||
  });
 | 
			
		||||
  it('should validate an instance with passenger only set to true', async () => {
 | 
			
		||||
    const myClassInstance = new MyClass();
 | 
			
		||||
    myClassInstance.driver = false;
 | 
			
		||||
    myClassInstance.passenger = true;
 | 
			
		||||
    const validator = new Validator();
 | 
			
		||||
    const validation = await validator.validate(myClassInstance);
 | 
			
		||||
    expect(validation.length).toBe(0);
 | 
			
		||||
  });
 | 
			
		||||
  it('should validate an instance with driver and passenger set to true', async () => {
 | 
			
		||||
    const myClassInstance = new MyClass();
 | 
			
		||||
    myClassInstance.driver = true;
 | 
			
		||||
    myClassInstance.passenger = true;
 | 
			
		||||
    const validator = new Validator();
 | 
			
		||||
    const validation = await validator.validate(myClassInstance);
 | 
			
		||||
    expect(validation.length).toBe(0);
 | 
			
		||||
  });
 | 
			
		||||
  it('should not validate an instance without driver and passenger set to true', async () => {
 | 
			
		||||
    const myClassInstance = new MyClass();
 | 
			
		||||
    myClassInstance.driver = false;
 | 
			
		||||
    myClassInstance.passenger = false;
 | 
			
		||||
    const validator = new Validator();
 | 
			
		||||
    const validation = await validator.validate(myClassInstance);
 | 
			
		||||
    expect(validation.length).toBe(1);
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,59 @@
 | 
			
		|||
import { HasSeats } from '@modules/ad/interface/grpc-controllers/dtos/validators/decorators/has-seats.decorator';
 | 
			
		||||
import { Validator } from 'class-validator';
 | 
			
		||||
 | 
			
		||||
describe('has seats decorator', () => {
 | 
			
		||||
  class MyClass {
 | 
			
		||||
    @HasSeats('seatsProposed')
 | 
			
		||||
    driver: boolean;
 | 
			
		||||
    @HasSeats('seatsRequested')
 | 
			
		||||
    passenger: boolean;
 | 
			
		||||
 | 
			
		||||
    seatsProposed?: number;
 | 
			
		||||
    seatsRequested?: number;
 | 
			
		||||
  }
 | 
			
		||||
  it('should return a property decorator has a function', () => {
 | 
			
		||||
    const hasSeats = HasSeats('property');
 | 
			
		||||
    expect(typeof hasSeats).toBe('function');
 | 
			
		||||
  });
 | 
			
		||||
  it('should validate an instance with seats proposed as driver', async () => {
 | 
			
		||||
    const myClassInstance = new MyClass();
 | 
			
		||||
    myClassInstance.driver = true;
 | 
			
		||||
    myClassInstance.seatsProposed = 3;
 | 
			
		||||
    const validator = new Validator();
 | 
			
		||||
    const validation = await validator.validate(myClassInstance);
 | 
			
		||||
    expect(validation.length).toBe(0);
 | 
			
		||||
  });
 | 
			
		||||
  it('should validate an instance with seats requested as passenger', async () => {
 | 
			
		||||
    const myClassInstance = new MyClass();
 | 
			
		||||
    myClassInstance.passenger = true;
 | 
			
		||||
    myClassInstance.seatsRequested = 1;
 | 
			
		||||
    const validator = new Validator();
 | 
			
		||||
    const validation = await validator.validate(myClassInstance);
 | 
			
		||||
    expect(validation.length).toBe(0);
 | 
			
		||||
  });
 | 
			
		||||
  it('should validate an instance with seats proposed as driver and passenger', async () => {
 | 
			
		||||
    const myClassInstance = new MyClass();
 | 
			
		||||
    myClassInstance.driver = true;
 | 
			
		||||
    myClassInstance.seatsProposed = 3;
 | 
			
		||||
    myClassInstance.passenger = true;
 | 
			
		||||
    myClassInstance.seatsRequested = 1;
 | 
			
		||||
    const validator = new Validator();
 | 
			
		||||
    const validation = await validator.validate(myClassInstance);
 | 
			
		||||
    expect(validation.length).toBe(0);
 | 
			
		||||
  });
 | 
			
		||||
  it('should not validate an instance without seats proposed as driver', async () => {
 | 
			
		||||
    const myClassInstance = new MyClass();
 | 
			
		||||
    myClassInstance.driver = true;
 | 
			
		||||
    myClassInstance.seatsProposed = 0;
 | 
			
		||||
    const validator = new Validator();
 | 
			
		||||
    const validation = await validator.validate(myClassInstance);
 | 
			
		||||
    expect(validation.length).toBe(1);
 | 
			
		||||
  });
 | 
			
		||||
  it('should not validate an instance without seats requested as passenger', async () => {
 | 
			
		||||
    const myClassInstance = new MyClass();
 | 
			
		||||
    myClassInstance.passenger = true;
 | 
			
		||||
    const validator = new Validator();
 | 
			
		||||
    const validation = await validator.validate(myClassInstance);
 | 
			
		||||
    expect(validation.length).toBe(1);
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -2,7 +2,8 @@ import { hasValidPositionIndexes } from '@modules/ad/interface/grpc-controllers/
 | 
			
		|||
import { WaypointDto } from '@modules/ad/interface/grpc-controllers/dtos/waypoint.dto';
 | 
			
		||||
 | 
			
		||||
describe('addresses position validator', () => {
 | 
			
		||||
  const mockAddress1: WaypointDto = {
 | 
			
		||||
  const waypoint1: WaypointDto = {
 | 
			
		||||
    position: 0,
 | 
			
		||||
    lat: 48.689445,
 | 
			
		||||
    lon: 6.17651,
 | 
			
		||||
    houseNumber: '5',
 | 
			
		||||
| 
						 | 
				
			
			@ -11,14 +12,16 @@ describe('addresses position validator', () => {
 | 
			
		|||
    postalCode: '54000',
 | 
			
		||||
    country: 'France',
 | 
			
		||||
  };
 | 
			
		||||
  const mockAddress2: WaypointDto = {
 | 
			
		||||
  const waypoint2: WaypointDto = {
 | 
			
		||||
    position: 1,
 | 
			
		||||
    lat: 48.8566,
 | 
			
		||||
    lon: 2.3522,
 | 
			
		||||
    locality: 'Paris',
 | 
			
		||||
    postalCode: '75000',
 | 
			
		||||
    country: 'France',
 | 
			
		||||
  };
 | 
			
		||||
  const mockAddress3: WaypointDto = {
 | 
			
		||||
  const waypoint3: WaypointDto = {
 | 
			
		||||
    position: 2,
 | 
			
		||||
    lon: 49.2628,
 | 
			
		||||
    lat: 4.0347,
 | 
			
		||||
    locality: 'Reims',
 | 
			
		||||
| 
						 | 
				
			
			@ -26,50 +29,26 @@ describe('addresses position validator', () => {
 | 
			
		|||
    country: 'France',
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  it('should not validate if no position is defined', () => {
 | 
			
		||||
    expect(
 | 
			
		||||
      hasValidPositionIndexes([mockAddress1, mockAddress2, mockAddress3]),
 | 
			
		||||
    ).toBeFalsy();
 | 
			
		||||
  });
 | 
			
		||||
  it('should not validate if only one position is defined', () => {
 | 
			
		||||
    mockAddress1.position = 0;
 | 
			
		||||
    expect(
 | 
			
		||||
      hasValidPositionIndexes([mockAddress1, mockAddress2, mockAddress3]),
 | 
			
		||||
    ).toBeFalsy();
 | 
			
		||||
  });
 | 
			
		||||
  it('should not validate if positions are partially defined', () => {
 | 
			
		||||
    mockAddress1.position = 0;
 | 
			
		||||
    mockAddress2.position = null;
 | 
			
		||||
    mockAddress3.position = undefined;
 | 
			
		||||
    expect(
 | 
			
		||||
      hasValidPositionIndexes([mockAddress1, mockAddress2, mockAddress3]),
 | 
			
		||||
    ).toBeFalsy();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should not validate if multiple positions have same value', () => {
 | 
			
		||||
    mockAddress1.position = 0;
 | 
			
		||||
    mockAddress2.position = 1;
 | 
			
		||||
    mockAddress3.position = 1;
 | 
			
		||||
    expect(
 | 
			
		||||
      hasValidPositionIndexes([mockAddress1, mockAddress2, mockAddress3]),
 | 
			
		||||
      hasValidPositionIndexes([waypoint1, waypoint1, waypoint2]),
 | 
			
		||||
    ).toBeFalsy();
 | 
			
		||||
  });
 | 
			
		||||
  it('should validate if all positions are ordered', () => {
 | 
			
		||||
    mockAddress1.position = 0;
 | 
			
		||||
    mockAddress2.position = 1;
 | 
			
		||||
    mockAddress3.position = 2;
 | 
			
		||||
    expect(
 | 
			
		||||
      hasValidPositionIndexes([mockAddress1, mockAddress2, mockAddress3]),
 | 
			
		||||
    ).toBeTruthy();
 | 
			
		||||
    mockAddress1.position = 1;
 | 
			
		||||
    mockAddress2.position = 2;
 | 
			
		||||
    mockAddress3.position = 3;
 | 
			
		||||
    expect(
 | 
			
		||||
      hasValidPositionIndexes([mockAddress1, mockAddress2, mockAddress3]),
 | 
			
		||||
    ).toBeTruthy();
 | 
			
		||||
  it('should not validate if positions are not consecutives', () => {
 | 
			
		||||
    expect(hasValidPositionIndexes([waypoint1, waypoint3])).toBeFalsy();
 | 
			
		||||
  });
 | 
			
		||||
  it('should not validate if no waypoints are defined', () => {
 | 
			
		||||
    expect(hasValidPositionIndexes(undefined)).toBeFalsy();
 | 
			
		||||
  it('should not validate if waypoints are empty', () => {
 | 
			
		||||
    expect(hasValidPositionIndexes([])).toBeFalsy();
 | 
			
		||||
  });
 | 
			
		||||
  it('should validate if all positions are ordered', () => {
 | 
			
		||||
    expect(
 | 
			
		||||
      hasValidPositionIndexes([waypoint1, waypoint2, waypoint3]),
 | 
			
		||||
    ).toBeTruthy();
 | 
			
		||||
    waypoint1.position = 1;
 | 
			
		||||
    waypoint2.position = 2;
 | 
			
		||||
    waypoint3.position = 3;
 | 
			
		||||
    expect(
 | 
			
		||||
      hasValidPositionIndexes([waypoint1, waypoint2, waypoint3]),
 | 
			
		||||
    ).toBeTruthy();
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,12 +1,13 @@
 | 
			
		|||
import { Module, Provider } from '@nestjs/common';
 | 
			
		||||
import { MESSAGE_PUBLISHER } from './messager.di-tokens';
 | 
			
		||||
 | 
			
		||||
import { ConfigModule, ConfigService } from '@nestjs/config';
 | 
			
		||||
import { SERVICE_NAME } from '@src/app.constants';
 | 
			
		||||
import {
 | 
			
		||||
  MessageBrokerModule,
 | 
			
		||||
  MessageBrokerModuleOptions,
 | 
			
		||||
  MessageBrokerPublisher,
 | 
			
		||||
} from '@mobicoop/message-broker-module';
 | 
			
		||||
import { ConfigModule, ConfigService } from '@nestjs/config';
 | 
			
		||||
import { SERVICE_NAME } from '@src/app.constants';
 | 
			
		||||
 | 
			
		||||
const imports = [
 | 
			
		||||
  MessageBrokerModule.forRootAsync({
 | 
			
		||||
| 
						 | 
				
			
			@ -15,8 +16,13 @@ const imports = [
 | 
			
		|||
    useFactory: async (
 | 
			
		||||
      configService: ConfigService,
 | 
			
		||||
    ): Promise<MessageBrokerModuleOptions> => ({
 | 
			
		||||
      uri: configService.get<string>('MESSAGE_BROKER_URI'),
 | 
			
		||||
      exchange: configService.get<string>('MESSAGE_BROKER_EXCHANGE'),
 | 
			
		||||
      uri: configService.get<string>('MESSAGE_BROKER_URI') as string,
 | 
			
		||||
      exchange: {
 | 
			
		||||
        name: configService.get<string>('MESSAGE_BROKER_EXCHANGE') as string,
 | 
			
		||||
        durable: configService.get<boolean>(
 | 
			
		||||
          'MESSAGE_BROKER_EXCHANGE_DURABILITY',
 | 
			
		||||
        ) as boolean,
 | 
			
		||||
      },
 | 
			
		||||
      name: SERVICE_NAME,
 | 
			
		||||
    }),
 | 
			
		||||
  }),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,10 +12,10 @@
 | 
			
		|||
    "baseUrl": "./",
 | 
			
		||||
    "incremental": true,
 | 
			
		||||
    "skipLibCheck": true,
 | 
			
		||||
    "strictNullChecks": false,
 | 
			
		||||
    "noImplicitAny": false,
 | 
			
		||||
    "strictNullChecks": true,
 | 
			
		||||
    "noImplicitAny": true,
 | 
			
		||||
    "strictBindCallApply": false,
 | 
			
		||||
    "forceConsistentCasingInFileNames": false,
 | 
			
		||||
    "forceConsistentCasingInFileNames": true,
 | 
			
		||||
    "noFallthroughCasesInSwitch": false,
 | 
			
		||||
    "paths": {
 | 
			
		||||
      "@libs/*": ["src/libs/*"],
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue