test find-by-id query
This commit is contained in:
parent
0409670eec
commit
b7bb656f10
59
README.md
59
README.md
|
@ -48,30 +48,34 @@ npm run migrate
|
|||
|
||||
The app exposes the following [gRPC](https://grpc.io/) services :
|
||||
|
||||
- **FindByUuid** : find an ad by its uuid
|
||||
- **FindById** : find an ad by its id
|
||||
|
||||
```json
|
||||
{
|
||||
"uuid": "80126a61-d128-4f96-afdb-92e33c75a3e1"
|
||||
"id": "80126a61-d128-4f96-afdb-92e33c75a3e1"
|
||||
}
|
||||
```
|
||||
|
||||
- **Create** : create an ad (note that uuid is optional, a uuid will be automatically attributed if it is not provided)
|
||||
- **Create** : create an ad (note that id is optional, an id (as a uuid) will be automatically attributed if it is not provided)
|
||||
|
||||
Punctual driver ad :
|
||||
|
||||
```json
|
||||
{
|
||||
"userUuid": "80c9bb02-0931-4a1d-bea6-22d358992245",
|
||||
"userId": "80c9bb02-0931-4a1d-bea6-22d358992245",
|
||||
"driver": true,
|
||||
"seatsDriver": 3,
|
||||
"seatsProposed": 3,
|
||||
"frequency": "PUNCTUAL",
|
||||
"departure": "2023-01-15 09:00",
|
||||
"addresses": [
|
||||
"fromDate": "2023-01-15",
|
||||
"toDate": "2023-01-15",
|
||||
"schedule": {
|
||||
"thu": "09:00"
|
||||
},
|
||||
"waypoints": [
|
||||
{
|
||||
"position": 0,
|
||||
"lon": 48.68944505415954,
|
||||
"lat": 6.176510296462267,
|
||||
"lon": 48.689445,
|
||||
"lat": 6.17651,
|
||||
"houseNumber": "5",
|
||||
"street": "Avenue Foch",
|
||||
"locality": "Nancy",
|
||||
|
@ -94,14 +98,18 @@ The app exposes the following [gRPC](https://grpc.io/) services :
|
|||
|
||||
```json
|
||||
{
|
||||
"userUuid": "80c9bb02-0931-4a1d-bea6-22d358992245",
|
||||
"userId": "80c9bb02-0931-4a1d-bea6-22d358992245",
|
||||
"driver": true,
|
||||
"pasenger": true,
|
||||
"seatsDriver": 3,
|
||||
"seatsPassenger": 1,
|
||||
"seatsProposed": 3,
|
||||
"seatsRequested": 1,
|
||||
"frequency": "PUNCTUAL",
|
||||
"departure": "2023-01-15 09:00",
|
||||
"addresses": [
|
||||
"fromDate": "2023-01-15",
|
||||
"toDate": "2023-01-15",
|
||||
"schedule": {
|
||||
"thu": "09:00"
|
||||
},
|
||||
"waypoints": [
|
||||
{
|
||||
"position": 0,
|
||||
"lon": 48.68944505415954,
|
||||
|
@ -139,11 +147,11 @@ The app exposes the following [gRPC](https://grpc.io/) services :
|
|||
"tue": "07:05",
|
||||
"fri": "07:10"
|
||||
},
|
||||
"addresses": [
|
||||
"waypoints": [
|
||||
{
|
||||
"position": 0,
|
||||
"lon": 48.68944505415954,
|
||||
"lat": 6.176510296462267,
|
||||
"lon": 48.689445,
|
||||
"lat": 6.17651,
|
||||
"houseNumber": "5",
|
||||
"street": "Avenue Foch",
|
||||
"locality": "Nancy",
|
||||
|
@ -164,15 +172,14 @@ The app exposes the following [gRPC](https://grpc.io/) services :
|
|||
|
||||
The list of possible options when creating an ad :
|
||||
|
||||
- uuid (optional): the uuid of the ad
|
||||
- userUuid: the user uuid
|
||||
- id (optional): the id of the ad (as a uuid)
|
||||
- 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
|
||||
- frequency: `PUNCTUAL` or `RECURRENT`
|
||||
- departure (required if punctual): departure date and hour/minute for a punctual ad
|
||||
- fromDate (required if recurrent): start date for recurrent ad
|
||||
- toDate (required if recurrent): end date for recurrent ad
|
||||
- schedule (required if recurrent): an object with the departure time for each carpooled day in the week
|
||||
- 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 object with the departure time for each carpooled day in the week
|
||||
- marginDurations (optional): an object with the margin duration (in seconds) for each carpooled day in the week, eg:
|
||||
|
||||
{
|
||||
|
@ -181,10 +188,10 @@ The app exposes the following [gRPC](https://grpc.io/) services :
|
|||
"fri": 950
|
||||
}
|
||||
|
||||
- seatsDriver (optional): number of seats proposed as driver;
|
||||
- seatsPassenger (optional): number of seats requested as passenger;
|
||||
- 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
|
||||
- addresses: an array of adresses that represent the waypoints of the journey (only first and last waypoints are used for passenger 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 **must** be consecutives
|
||||
|
||||
Default values must be set in `.env` file.
|
||||
|
||||
|
|
|
@ -2,8 +2,6 @@ import { Module } from '@nestjs/common';
|
|||
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||
// import { HealthModule } from './modules/health/health.module';
|
||||
import { AdModule } from './modules/ad/ad.module';
|
||||
import { AutomapperModule } from '@automapper/nestjs';
|
||||
import { classes } from '@automapper/classes';
|
||||
import {
|
||||
MessageBrokerModule,
|
||||
MessageBrokerModuleOptions,
|
||||
|
@ -21,7 +19,6 @@ import { HealthModule } from '@modules/health/health.module';
|
|||
ConfigModule.forRoot({ isGlobal: true }),
|
||||
EventEmitterModule.forRoot(),
|
||||
RequestContextModule,
|
||||
AutomapperModule.forRoot({ strategyInitializer: classes() }),
|
||||
MessageBrokerModule.forRootAsync({
|
||||
imports: [ConfigModule],
|
||||
inject: [ConfigService],
|
||||
|
|
|
@ -1,33 +1,26 @@
|
|||
import { AutoMap } from '@automapper/classes';
|
||||
import { IsOptional, IsString } from 'class-validator';
|
||||
import { CoordinatesDto as CoordinatesDto } from './coordinates.dto';
|
||||
|
||||
export class AddressDto extends CoordinatesDto {
|
||||
@IsOptional()
|
||||
@AutoMap()
|
||||
name?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@AutoMap()
|
||||
houseNumber?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@AutoMap()
|
||||
street?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@AutoMap()
|
||||
locality?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@AutoMap()
|
||||
postalCode?: string;
|
||||
|
||||
@IsString()
|
||||
@AutoMap()
|
||||
country: string;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { AutoMap } from '@automapper/classes';
|
||||
import { Transform } from 'class-transformer';
|
||||
import { IsLatitude, IsLongitude } from 'class-validator';
|
||||
import { toPrecision } from './transformers/to-precision';
|
||||
|
@ -8,13 +7,11 @@ export class CoordinatesDto {
|
|||
toClassOnly: true,
|
||||
})
|
||||
@IsLongitude()
|
||||
@AutoMap()
|
||||
lon: number;
|
||||
|
||||
@Transform(({ value }) => toPrecision(value, 6), {
|
||||
toClassOnly: true,
|
||||
})
|
||||
@IsLatitude()
|
||||
@AutoMap()
|
||||
lat: number;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { AutoMap } from '@automapper/classes';
|
||||
import {
|
||||
IsOptional,
|
||||
IsBoolean,
|
||||
|
@ -21,65 +20,54 @@ import { Frequency } from '@modules/ad/core/ad.types';
|
|||
|
||||
export class CreateAdRequestDto {
|
||||
@IsUUID(4)
|
||||
@AutoMap()
|
||||
userId: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
@AutoMap()
|
||||
driver?: boolean;
|
||||
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
@AutoMap()
|
||||
passenger?: boolean;
|
||||
|
||||
@Transform(({ value }) => intToFrequency(value), {
|
||||
toClassOnly: true,
|
||||
})
|
||||
@IsEnum(Frequency)
|
||||
@AutoMap()
|
||||
frequency: Frequency;
|
||||
|
||||
@IsISO8601({
|
||||
strict: true,
|
||||
strictSeparator: true,
|
||||
})
|
||||
@AutoMap()
|
||||
fromDate: string;
|
||||
|
||||
@IsISO8601({
|
||||
strict: true,
|
||||
strictSeparator: true,
|
||||
})
|
||||
@AutoMap()
|
||||
toDate: string;
|
||||
|
||||
@Type(() => ScheduleDto)
|
||||
@IsSchedule()
|
||||
@ValidateNested({ each: true })
|
||||
@AutoMap()
|
||||
schedule: ScheduleDto;
|
||||
|
||||
@IsOptional()
|
||||
@Type(() => MarginDurationsDto)
|
||||
@ValidateNested({ each: true })
|
||||
@AutoMap()
|
||||
marginDurations?: MarginDurationsDto;
|
||||
|
||||
@IsOptional()
|
||||
@IsInt()
|
||||
@AutoMap()
|
||||
seatsProposed?: number;
|
||||
|
||||
@IsOptional()
|
||||
@IsInt()
|
||||
@AutoMap()
|
||||
seatsRequested?: number;
|
||||
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
@AutoMap()
|
||||
strict?: boolean;
|
||||
|
||||
@Type(() => WaypointDto)
|
||||
|
@ -87,6 +75,5 @@ export class CreateAdRequestDto {
|
|||
@ArrayMinSize(2)
|
||||
@HasValidPositionIndexes()
|
||||
@ValidateNested({ each: true })
|
||||
@AutoMap()
|
||||
waypoints: WaypointDto[];
|
||||
}
|
||||
|
|
|
@ -1,39 +1,31 @@
|
|||
import { AutoMap } from '@automapper/classes';
|
||||
import { IsInt, IsOptional } from 'class-validator';
|
||||
|
||||
export class MarginDurationsDto {
|
||||
@IsOptional()
|
||||
@IsInt()
|
||||
@AutoMap()
|
||||
mon?: number;
|
||||
|
||||
@IsOptional()
|
||||
@IsInt()
|
||||
@AutoMap()
|
||||
tue?: number;
|
||||
|
||||
@IsOptional()
|
||||
@IsInt()
|
||||
@AutoMap()
|
||||
wed?: number;
|
||||
|
||||
@IsOptional()
|
||||
@IsInt()
|
||||
@AutoMap()
|
||||
thu?: number;
|
||||
|
||||
@IsOptional()
|
||||
@IsInt()
|
||||
@AutoMap()
|
||||
fri?: number;
|
||||
|
||||
@IsOptional()
|
||||
@IsInt()
|
||||
@AutoMap()
|
||||
sat?: number;
|
||||
|
||||
@IsOptional()
|
||||
@IsInt()
|
||||
@AutoMap()
|
||||
sun?: number;
|
||||
}
|
||||
|
|
|
@ -1,39 +1,31 @@
|
|||
import { AutoMap } from '@automapper/classes';
|
||||
import { IsOptional, IsMilitaryTime } from 'class-validator';
|
||||
|
||||
export class ScheduleDto {
|
||||
@IsOptional()
|
||||
@IsMilitaryTime()
|
||||
@AutoMap()
|
||||
mon?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsMilitaryTime()
|
||||
@AutoMap()
|
||||
tue?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsMilitaryTime()
|
||||
@AutoMap()
|
||||
wed?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsMilitaryTime()
|
||||
@AutoMap()
|
||||
thu?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsMilitaryTime()
|
||||
@AutoMap()
|
||||
fri?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsMilitaryTime()
|
||||
@AutoMap()
|
||||
sat?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsMilitaryTime()
|
||||
@AutoMap()
|
||||
sun?: string;
|
||||
}
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
import { AutoMap } from '@automapper/classes';
|
||||
import { IsInt, IsOptional } from 'class-validator';
|
||||
import { AddressDto } from './address.dto';
|
||||
|
||||
export class WaypointDto extends AddressDto {
|
||||
@IsOptional()
|
||||
@IsInt()
|
||||
@AutoMap()
|
||||
position?: number;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
import { AD_REPOSITORY } from '@modules/ad/ad.di-tokens';
|
||||
import { AdEntity } from '@modules/ad/core/ad.entity';
|
||||
import {
|
||||
CreateAdProps,
|
||||
DefaultAdProps,
|
||||
Frequency,
|
||||
} from '@modules/ad/core/ad.types';
|
||||
import { FindAdByIdQuery } from '@modules/ad/core/queries/find-ad-by-id/find-ad-by-id.query';
|
||||
import { FindAdByIdQueryHandler } from '@modules/ad/core/queries/find-ad-by-id/find-ad-by-id.query-handler';
|
||||
import { MarginDurationsProps } from '@modules/ad/core/value-objects/margin-durations.value-object';
|
||||
import { WaypointProps } from '@modules/ad/core/value-objects/waypoint.value-object';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
|
||||
const originWaypointProps: WaypointProps = {
|
||||
position: 0,
|
||||
address: {
|
||||
houseNumber: '5',
|
||||
street: 'Avenue Foch',
|
||||
locality: 'Nancy',
|
||||
postalCode: '54000',
|
||||
country: 'France',
|
||||
coordinates: {
|
||||
lon: 48.68944505415954,
|
||||
lat: 6.176510296462267,
|
||||
},
|
||||
},
|
||||
};
|
||||
const destinationWaypointProps: WaypointProps = {
|
||||
position: 1,
|
||||
address: {
|
||||
locality: 'Paris',
|
||||
postalCode: '75000',
|
||||
country: 'France',
|
||||
coordinates: {
|
||||
lon: 48.8566,
|
||||
lat: 2.3522,
|
||||
},
|
||||
},
|
||||
};
|
||||
const marginDurationsProps: MarginDurationsProps = {
|
||||
mon: 600,
|
||||
tue: 600,
|
||||
wed: 600,
|
||||
thu: 600,
|
||||
fri: 600,
|
||||
sat: 600,
|
||||
sun: 600,
|
||||
};
|
||||
const baseCreateAdProps = {
|
||||
userId: 'e8fe64b1-4c33-49e1-9f69-4db48b21df36',
|
||||
seatsProposed: 3,
|
||||
seatsRequested: 1,
|
||||
strict: false,
|
||||
waypoints: [originWaypointProps, destinationWaypointProps],
|
||||
};
|
||||
const punctualCreateAdProps = {
|
||||
fromDate: '2023-06-22',
|
||||
toDate: '2023-06-22',
|
||||
schedule: {
|
||||
wed: '08:30',
|
||||
},
|
||||
frequency: Frequency.PUNCTUAL,
|
||||
};
|
||||
const punctualPassengerCreateAdProps: CreateAdProps = {
|
||||
...baseCreateAdProps,
|
||||
...punctualCreateAdProps,
|
||||
marginDurations: marginDurationsProps,
|
||||
driver: false,
|
||||
passenger: true,
|
||||
};
|
||||
|
||||
const defaultAdProps: DefaultAdProps = {
|
||||
driver: false,
|
||||
passenger: true,
|
||||
marginDurations: {
|
||||
mon: 900,
|
||||
tue: 900,
|
||||
wed: 900,
|
||||
thu: 900,
|
||||
fri: 900,
|
||||
sat: 900,
|
||||
sun: 900,
|
||||
},
|
||||
seatsProposed: 3,
|
||||
seatsRequested: 1,
|
||||
strict: false,
|
||||
};
|
||||
|
||||
const ad: AdEntity = AdEntity.create(
|
||||
punctualPassengerCreateAdProps,
|
||||
defaultAdProps,
|
||||
);
|
||||
|
||||
const mockAdRepository = {
|
||||
findOneById: jest.fn().mockImplementation(() => ad),
|
||||
};
|
||||
|
||||
describe('find-ad-by-id.query-handler', () => {
|
||||
let findAdByIdQueryHandler: FindAdByIdQueryHandler;
|
||||
|
||||
beforeAll(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [
|
||||
{
|
||||
provide: AD_REPOSITORY,
|
||||
useValue: mockAdRepository,
|
||||
},
|
||||
FindAdByIdQueryHandler,
|
||||
],
|
||||
}).compile();
|
||||
|
||||
findAdByIdQueryHandler = module.get<FindAdByIdQueryHandler>(
|
||||
FindAdByIdQueryHandler,
|
||||
);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(findAdByIdQueryHandler).toBeDefined();
|
||||
});
|
||||
|
||||
describe('execution', () => {
|
||||
it('should return an ad', async () => {
|
||||
const findAdbyIdQuery = new FindAdByIdQuery(
|
||||
'dd264806-13b4-4226-9b18-87adf0ad5dd1',
|
||||
);
|
||||
const ad: AdEntity = await findAdByIdQueryHandler.execute(
|
||||
findAdbyIdQuery,
|
||||
);
|
||||
expect(ad.getProps().fromDate).toBe('2023-06-22');
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue