transform to output

This commit is contained in:
sbriat 2023-07-27 12:31:54 +02:00
parent 218595553d
commit df92245357
21 changed files with 533 additions and 91 deletions

View File

@ -2,5 +2,8 @@ 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 DATETIME_TRANSFORMER = Symbol('DATETIME_TRANSFORMER');
export const INPUT_DATETIME_TRANSFORMER = Symbol('INPUT_DATETIME_TRANSFORMER');
export const OUTPUT_DATETIME_TRANSFORMER = Symbol(
'OUTPUT_DATETIME_TRANSFORMER',
);
export const AD_REPOSITORY = Symbol('AD_REPOSITORY');

View File

@ -1,6 +1,6 @@
import { Mapper } from '@mobicoop/ddd-library';
import { AdResponseDto } from './interface/dtos/ad.response.dto';
import { Injectable } from '@nestjs/common';
import { Inject, Injectable } from '@nestjs/common';
import { AdEntity } from './core/domain/ad.entity';
import {
AdWriteModel,
@ -12,6 +12,8 @@ import { Frequency } from './core/domain/ad.types';
import { WaypointProps } from './core/domain/value-objects/waypoint.value-object';
import { v4 } from 'uuid';
import { ScheduleItemProps } from './core/domain/value-objects/schedule-item.value-object';
import { OUTPUT_DATETIME_TRANSFORMER } from './ad.di-tokens';
import { DateTimeTransformerPort } from './core/application/ports/datetime-transformer.port';
/**
* Mapper constructs objects that are used in different layers:
@ -24,6 +26,11 @@ import { ScheduleItemProps } from './core/domain/value-objects/schedule-item.val
export class AdMapper
implements Mapper<AdEntity, AdReadModel, AdWriteModel, AdResponseDto>
{
constructor(
@Inject(OUTPUT_DATETIME_TRANSFORMER)
private readonly outputDatetimeTransformer: DateTimeTransformerPort,
) {}
toPersistence = (entity: AdEntity): AdWriteModel => {
const copy = entity.getProps();
const now = new Date();
@ -129,12 +136,42 @@ export class AdMapper
response.driver = props.driver;
response.passenger = props.passenger;
response.frequency = props.frequency;
response.fromDate = props.fromDate;
response.toDate = props.toDate;
response.fromDate = this.outputDatetimeTransformer.fromDate(
{
date: props.fromDate,
time: props.schedule[0].time,
coordinates: props.waypoints[0].address.coordinates,
},
props.frequency,
);
response.toDate = this.outputDatetimeTransformer.toDate(
props.toDate,
{
date: props.fromDate,
time: props.schedule[0].time,
coordinates: props.waypoints[0].address.coordinates,
},
props.frequency,
);
response.schedule = props.schedule.map(
(scheduleItem: ScheduleItemProps) => ({
day: scheduleItem.day,
time: scheduleItem.time,
day: this.outputDatetimeTransformer.day(
scheduleItem.day,
{
date: props.fromDate,
time: scheduleItem.time,
coordinates: props.waypoints[0].address.coordinates,
},
props.frequency,
),
time: this.outputDatetimeTransformer.time(
{
date: props.fromDate,
time: scheduleItem.time,
coordinates: props.waypoints[0].address.coordinates,
},
props.frequency,
),
margin: scheduleItem.margin,
}),
);

View File

@ -4,7 +4,8 @@ import { CqrsModule } from '@nestjs/cqrs';
import {
AD_MESSAGE_PUBLISHER,
AD_REPOSITORY,
DATETIME_TRANSFORMER,
INPUT_DATETIME_TRANSFORMER,
OUTPUT_DATETIME_TRANSFORMER,
PARAMS_PROVIDER,
TIMEZONE_FINDER,
TIME_CONVERTER,
@ -20,7 +21,8 @@ import { FindAdByIdQueryHandler } from './core/application/queries/find-ad-by-id
import { PublishMessageWhenAdIsCreatedDomainEventHandler } from './core/application/event-handlers/publish-message-when-ad-is-created.domain-event-handler';
import { PrismaService } from './infrastructure/prisma.service';
import { MessageBrokerPublisher } from '@mobicoop/message-broker-module';
import { DateTimeTransformer } from './infrastructure/datetime-transformer';
import { InputDateTimeTransformer } from './infrastructure/input-datetime-transformer';
import { OutputDateTimeTransformer } from './infrastructure/output-datetime-transformer';
const grpcControllers = [CreateAdGrpcController, FindAdByIdGrpcController];
@ -63,8 +65,12 @@ const adapters: Provider[] = [
useClass: TimeConverter,
},
{
provide: DATETIME_TRANSFORMER,
useClass: DateTimeTransformer,
provide: INPUT_DATETIME_TRANSFORMER,
useClass: InputDateTimeTransformer,
},
{
provide: OUTPUT_DATETIME_TRANSFORMER,
useClass: OutputDateTimeTransformer,
},
];

View File

@ -3,7 +3,7 @@ import { CreateAdCommand } from './create-ad.command';
import { Inject } from '@nestjs/common';
import {
AD_REPOSITORY,
DATETIME_TRANSFORMER,
INPUT_DATETIME_TRANSFORMER,
PARAMS_PROVIDER,
} from '@modules/ad/ad.di-tokens';
import { AdEntity } from '@modules/ad/core/domain/ad.entity';
@ -25,7 +25,7 @@ export class CreateAdService implements ICommandHandler {
private readonly repository: AdRepositoryPort,
@Inject(PARAMS_PROVIDER)
private readonly defaultParamsProvider: DefaultParamsProviderPort,
@Inject(DATETIME_TRANSFORMER)
@Inject(INPUT_DATETIME_TRANSFORMER)
private readonly datetimeTransformer: DateTimeTransformerPort,
) {
this._defaultParams = defaultParamsProvider.getParams();

View File

@ -1,10 +1,18 @@
export interface TimeConverterPort {
localStringTimeToUtcStringTime(time: string, timezone: string): string;
utcStringTimeToLocalStringTime(time: string, timezone: string): string;
localStringDateTimeToUtcDate(
date: string,
time: string,
timezone: string,
dst?: boolean,
): Date;
utcStringDateTimeToLocalIsoString(
date: string,
time: string,
timezone: string,
dst?: boolean,
): string;
utcUnixEpochDayFromTime(time: string, timezone: string): number;
localUnixEpochDayFromTime(time: string, timezone: string): number;
}

View File

@ -12,6 +12,9 @@ export class FindAdByIdQueryHandler implements IQueryHandler {
private readonly repository: AdRepositoryPort,
) {}
async execute(query: FindAdByIdQuery): Promise<AdEntity> {
return await this.repository.findOneById(query.id, { waypoints: true });
return await this.repository.findOneById(query.id, {
waypoints: true,
schedule: true,
});
}
}

View File

@ -14,7 +14,7 @@ import { TimezoneFinderPort } from '../core/application/ports/timezone-finder.po
import { DefaultParamsProviderPort } from '../core/application/ports/default-params-provider.port';
@Injectable()
export class DateTimeTransformer implements DateTimeTransformerPort {
export class InputDateTimeTransformer implements DateTimeTransformerPort {
private readonly _defaultTimezone: string;
constructor(
@Inject(PARAMS_PROVIDER)

View File

@ -0,0 +1,116 @@
import { Inject, Injectable } from '@nestjs/common';
import {
DateTimeTransformerPort,
Frequency,
GeoDateTime,
} from '../core/application/ports/datetime-transformer.port';
import { TimeConverterPort } from '../core/application/ports/time-converter.port';
import { TIMEZONE_FINDER, TIME_CONVERTER } from '../ad.di-tokens';
import { TimezoneFinderPort } from '../core/application/ports/timezone-finder.port';
@Injectable()
export class OutputDateTimeTransformer implements DateTimeTransformerPort {
constructor(
@Inject(TIMEZONE_FINDER)
private readonly timezoneFinder: TimezoneFinderPort,
@Inject(TIME_CONVERTER) private readonly timeConverter: TimeConverterPort,
) {}
/**
* Compute the fromDate : if an ad is punctual, the departure date
* is converted from UTC to the local date with the time and timezone
*/
fromDate = (geoFromDate: GeoDateTime, frequency: Frequency): string => {
if (frequency === Frequency.RECURRENT) return geoFromDate.date;
return this.timeConverter
.utcStringDateTimeToLocalIsoString(
geoFromDate.date,
geoFromDate.time,
this.timezoneFinder.timezones(
geoFromDate.coordinates.lon,
geoFromDate.coordinates.lat,
)[0],
)
.split('T')[0];
};
/**
* Get the toDate depending on frequency, time and timezone :
* if the ad is punctual, the toDate is equal to the fromDate
*/
toDate = (
toDate: string,
geoFromDate: GeoDateTime,
frequency: Frequency,
): string => {
if (frequency === Frequency.RECURRENT) return toDate;
return this.fromDate(geoFromDate, frequency);
};
/**
* Get the day for a schedule item :
* - if the ad is punctual, the day is infered from fromDate
* - if the ad is recurrent, the day is computed by converting the time from utc to local time
*/
day = (
day: number,
geoFromDate: GeoDateTime,
frequency: Frequency,
): number => {
if (frequency === Frequency.RECURRENT)
return this.recurrentDay(
day,
geoFromDate.time,
this.timezoneFinder.timezones(
geoFromDate.coordinates.lon,
geoFromDate.coordinates.lat,
)[0],
);
return new Date(this.fromDate(geoFromDate, frequency)).getDay();
};
/**
* Get the utc time
*/
time = (geoFromDate: GeoDateTime, frequency: Frequency): string => {
if (frequency === Frequency.RECURRENT)
return this.timeConverter.utcStringTimeToLocalStringTime(
geoFromDate.time,
this.timezoneFinder.timezones(
geoFromDate.coordinates.lon,
geoFromDate.coordinates.lat,
)[0],
);
return this.timeConverter
.utcStringDateTimeToLocalIsoString(
geoFromDate.date,
geoFromDate.time,
this.timezoneFinder.timezones(
geoFromDate.coordinates.lon,
geoFromDate.coordinates.lat,
)[0],
)
.split('T')[1]
.split(':', 2)
.join(':');
};
/**
* Get the day for a schedule item for a recurrent ad
* The day may change when transforming from utc to local timezone
*/
private recurrentDay = (
day: number,
time: string,
timezone: string,
): number => {
const unixEpochDay = 4; // 1970-01-01 is a thursday !
const localBaseDay = this.timeConverter.localUnixEpochDayFromTime(
time,
timezone,
);
if (unixEpochDay == localBaseDay) return day;
if (unixEpochDay > localBaseDay) return day > 0 ? day - 1 : 6;
return day < 6 ? day + 1 : 0;
};
}

View File

@ -17,6 +17,17 @@ export class TimeConverter implements TimeConverterPort {
}
};
utcStringTimeToLocalStringTime = (time: string, timezone: string): string => {
try {
if (!time || !timezone) throw new Error();
return new DateTime(`${this.UNIX_EPOCH}T${time}`, TimeZone.zone('UTC'))
.convert(TimeZone.zone(timezone))
.format('HH:mm');
} catch (e) {
return undefined;
}
};
localStringDateTimeToUtcDate = (
date: string,
time: string,
@ -24,7 +35,7 @@ export class TimeConverter implements TimeConverterPort {
dst = true,
): Date => {
try {
if (!time || !timezone) throw new Error();
if (!date || !time || !timezone) throw new Error();
return new Date(
new DateTime(
`${date}T${time}`,
@ -36,6 +47,22 @@ export class TimeConverter implements TimeConverterPort {
}
};
utcStringDateTimeToLocalIsoString = (
date: string,
time: string,
timezone: string,
dst?: boolean,
): string => {
try {
if (!date || !time || !timezone) throw new Error();
return new DateTime(`${date}T${time}`, TimeZone.zone('UTC'))
.convert(TimeZone.zone(timezone, dst))
.toIsoString();
} catch (e) {
return undefined;
}
};
utcUnixEpochDayFromTime = (time: string, timezone: string): number => {
try {
if (!time || !timezone) throw new Error();
@ -52,4 +79,18 @@ export class TimeConverter implements TimeConverterPort {
return undefined;
}
};
localUnixEpochDayFromTime = (time: string, timezone: string): number => {
try {
if (!time || !timezone) throw new Error();
return new Date(
new DateTime(`${this.UNIX_EPOCH}T${time}`, TimeZone.zone('UTC'))
.convert(TimeZone.zone(timezone))
.toIsoString()
.split('T')[0],
).getDay();
} catch (e) {
return undefined;
}
};
}

View File

@ -37,8 +37,8 @@ message ScheduleItem {
message Waypoint {
int32 position = 1;
float lon = 2;
float lat = 3;
double lon = 2;
double lat = 3;
string name = 4;
string houseNumber = 5;
string street = 6;

View File

@ -1,17 +1,9 @@
import { Transform } from 'class-transformer';
import { IsLatitude, IsLongitude } from 'class-validator';
import { toPrecision } from './transformers/to-precision';
export class CoordinatesDto {
@Transform(({ value }) => toPrecision(value, 6), {
toClassOnly: true,
})
@IsLongitude()
lon: number;
@Transform(({ value }) => toPrecision(value, 6), {
toClassOnly: true,
})
@IsLatitude()
lat: number;
}

View File

@ -1,7 +0,0 @@
import { Frequency } from '@modules/ad/core/domain/ad.types';
export const intToFrequency = (frequencyAsInt: number): Frequency => {
if (frequencyAsInt == 1) return Frequency.PUNCTUAL;
if (frequencyAsInt == 2) return Frequency.RECURRENT;
throw new Error('Unknown frequency value');
};

View File

@ -1,4 +0,0 @@
export const toPrecision = (input: number, precision: number): number => {
const multiplier = 10 ** precision;
return Math.round((input + Number.EPSILON) * multiplier) / multiplier;
};

View File

@ -23,7 +23,7 @@ export class FindAdByIdGrpcController {
private readonly queryBus: QueryBus,
) {}
@GrpcMethod('AdsService', 'FindOneById')
@GrpcMethod('AdService', 'FindOneById')
async findOnebyId(data: FindAdByIdRequestDto): Promise<AdResponseDto> {
try {
const ad: AdEntity = await this.queryBus.execute(

View File

@ -1,4 +1,6 @@
import { OUTPUT_DATETIME_TRANSFORMER } from '@modules/ad/ad.di-tokens';
import { AdMapper } from '@modules/ad/ad.mapper';
import { DateTimeTransformerPort } from '@modules/ad/core/application/ports/datetime-transformer.port';
import { AdEntity } from '@modules/ad/core/domain/ad.entity';
import { Frequency } from '@modules/ad/core/domain/ad.types';
import {
@ -111,12 +113,25 @@ const adReadModel: AdReadModel = {
updatedAt: now,
};
const mockOutputDatetimeTransformer: DateTimeTransformerPort = {
fromDate: jest.fn(),
toDate: jest.fn(),
day: jest.fn(),
time: jest.fn(),
};
describe('Ad Mapper', () => {
let adMapper: AdMapper;
beforeAll(async () => {
const module = await Test.createTestingModule({
providers: [AdMapper],
providers: [
AdMapper,
{
provide: OUTPUT_DATETIME_TRANSFORMER,
useValue: mockOutputDatetimeTransformer,
},
],
}).compile();
adMapper = module.get<AdMapper>(AdMapper);
});

View File

@ -1,7 +1,7 @@
import { Test, TestingModule } from '@nestjs/testing';
import {
AD_REPOSITORY,
DATETIME_TRANSFORMER,
INPUT_DATETIME_TRANSFORMER,
PARAMS_PROVIDER,
} from '@modules/ad/ad.di-tokens';
import { WaypointDto } from '@modules/ad/interface/grpc-controllers/dtos/waypoint.dto';
@ -76,7 +76,7 @@ const mockDefaultParamsProvider: DefaultParamsProviderPort = {
},
};
const mockDateTimeTransformer: DateTimeTransformerPort = {
const mockInputDateTimeTransformer: DateTimeTransformerPort = {
fromDate: jest.fn(),
toDate: jest.fn(),
day: jest.fn(),
@ -98,8 +98,8 @@ describe('create-ad.service', () => {
useValue: mockDefaultParamsProvider,
},
{
provide: DATETIME_TRANSFORMER,
useValue: mockDateTimeTransformer,
provide: INPUT_DATETIME_TRANSFORMER,
useValue: mockInputDateTimeTransformer,
},
CreateAdService,
],

View File

@ -1,4 +1,6 @@
import { OUTPUT_DATETIME_TRANSFORMER } from '@modules/ad/ad.di-tokens';
import { AdMapper } from '@modules/ad/ad.mapper';
import { DateTimeTransformerPort } from '@modules/ad/core/application/ports/datetime-transformer.port';
import { AdRepository } from '@modules/ad/infrastructure/ad.repository';
import { PrismaService } from '@modules/ad/infrastructure/prisma.service';
import { EventEmitter2, EventEmitterModule } from '@nestjs/event-emitter';
@ -8,6 +10,13 @@ const mockMessagePublisher = {
publish: jest.fn().mockImplementation(),
};
const mockOutputDatetimeTransformer: DateTimeTransformerPort = {
fromDate: jest.fn(),
toDate: jest.fn(),
day: jest.fn(),
time: jest.fn(),
};
describe('Ad repository', () => {
let prismaService: PrismaService;
let adMapper: AdMapper;
@ -16,7 +25,14 @@ describe('Ad repository', () => {
beforeAll(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [EventEmitterModule.forRoot()],
providers: [PrismaService, AdMapper],
providers: [
PrismaService,
AdMapper,
{
provide: OUTPUT_DATETIME_TRANSFORMER,
useValue: mockOutputDatetimeTransformer,
},
],
}).compile();
prismaService = module.get<PrismaService>(PrismaService);

View File

@ -7,7 +7,7 @@ import { Frequency } from '@modules/ad/core/application/ports/datetime-transform
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 { DateTimeTransformer } from '@modules/ad/infrastructure/datetime-transformer';
import { InputDateTimeTransformer } from '@modules/ad/infrastructure/input-datetime-transformer';
import { Test, TestingModule } from '@nestjs/testing';
const mockDefaultParamsProvider: DefaultParamsProviderPort = {
@ -32,12 +32,14 @@ const mockTimeConverter: TimeConverterPort = {
localStringTimeToUtcStringTime: jest
.fn()
.mockImplementationOnce(() => '00:15'),
utcStringTimeToLocalStringTime: jest.fn(),
localStringDateTimeToUtcDate: jest
.fn()
.mockImplementationOnce(() => new Date('2023-07-30T06:15:00.000Z'))
.mockImplementationOnce(() => new Date('2023-07-20T08:15:00.000Z'))
.mockImplementationOnce(() => new Date('2023-07-19T23:15:00.000Z'))
.mockImplementationOnce(() => new Date('2023-07-19T23:15:00.000Z')),
utcStringDateTimeToLocalIsoString: jest.fn(),
utcUnixEpochDayFromTime: jest
.fn()
.mockImplementationOnce(() => 4)
@ -45,10 +47,11 @@ const mockTimeConverter: TimeConverterPort = {
.mockImplementationOnce(() => 3)
.mockImplementationOnce(() => 5)
.mockImplementationOnce(() => 5),
localUnixEpochDayFromTime: jest.fn(),
};
describe('Datetime Transformer', () => {
let datetimeTransformer: DateTimeTransformer;
describe('Input Datetime Transformer', () => {
let inputDatetimeTransformer: InputDateTimeTransformer;
beforeAll(async () => {
const module: TestingModule = await Test.createTestingModule({
@ -65,20 +68,22 @@ describe('Datetime Transformer', () => {
provide: TIME_CONVERTER,
useValue: mockTimeConverter,
},
DateTimeTransformer,
InputDateTimeTransformer,
],
}).compile();
datetimeTransformer = module.get<DateTimeTransformer>(DateTimeTransformer);
inputDatetimeTransformer = module.get<InputDateTimeTransformer>(
InputDateTimeTransformer,
);
});
it('should be defined', () => {
expect(datetimeTransformer).toBeDefined();
expect(inputDatetimeTransformer).toBeDefined();
});
describe('fromDate', () => {
it('should return fromDate as is if frequency is recurrent', () => {
const transformedFromDate: string = datetimeTransformer.fromDate(
const transformedFromDate: string = inputDatetimeTransformer.fromDate(
{
date: '2023-07-30',
time: '07:15',
@ -92,7 +97,7 @@ describe('Datetime Transformer', () => {
expect(transformedFromDate).toBe('2023-07-30');
});
it('should return transformed fromDate if frequency is punctual and coordinates are those of Nancy', () => {
const transformedFromDate: string = datetimeTransformer.fromDate(
const transformedFromDate: string = inputDatetimeTransformer.fromDate(
{
date: '2023-07-30',
time: '07:15',
@ -109,7 +114,7 @@ describe('Datetime Transformer', () => {
describe('toDate', () => {
it('should return toDate as is if frequency is recurrent', () => {
const transformedToDate: string = datetimeTransformer.toDate(
const transformedToDate: string = inputDatetimeTransformer.toDate(
'2024-07-29',
{
date: '2023-07-20',
@ -124,7 +129,7 @@ describe('Datetime Transformer', () => {
expect(transformedToDate).toBe('2024-07-29');
});
it('should return transformed fromDate if frequency is punctual', () => {
const transformedToDate: string = datetimeTransformer.toDate(
const transformedToDate: string = inputDatetimeTransformer.toDate(
'2024-07-30',
{
date: '2023-07-20',
@ -142,7 +147,7 @@ describe('Datetime Transformer', () => {
describe('day', () => {
it('should not change day if frequency is recurrent and converted UTC time is on the same day', () => {
const day: number = datetimeTransformer.day(
const day: number = inputDatetimeTransformer.day(
1,
{
date: '2023-07-24',
@ -157,7 +162,7 @@ describe('Datetime Transformer', () => {
expect(day).toBe(1);
});
it('should change day if frequency is recurrent and converted UTC time is on the previous day', () => {
const day: number = datetimeTransformer.day(
const day: number = inputDatetimeTransformer.day(
1,
{
date: '2023-07-24',
@ -172,7 +177,7 @@ describe('Datetime Transformer', () => {
expect(day).toBe(0);
});
it('should change day if frequency is recurrent and converted UTC time is on the previous day and given day is sunday', () => {
const day: number = datetimeTransformer.day(
const day: number = inputDatetimeTransformer.day(
0,
{
date: '2023-07-23',
@ -187,7 +192,7 @@ describe('Datetime Transformer', () => {
expect(day).toBe(6);
});
it('should change day if frequency is recurrent and converted UTC time is on the next day', () => {
const day: number = datetimeTransformer.day(
const day: number = inputDatetimeTransformer.day(
1,
{
date: '2023-07-24',
@ -202,7 +207,7 @@ describe('Datetime Transformer', () => {
expect(day).toBe(2);
});
it('should change day if frequency is recurrent and converted UTC time is on the next day and given day is saturday(6)', () => {
const day: number = datetimeTransformer.day(
const day: number = inputDatetimeTransformer.day(
6,
{
date: '2023-07-29',
@ -217,7 +222,7 @@ describe('Datetime Transformer', () => {
expect(day).toBe(0);
});
it('should return utc fromDate day if frequency is punctual', () => {
const day: number = datetimeTransformer.day(
const day: number = inputDatetimeTransformer.day(
1,
{
date: '2023-07-20',
@ -235,7 +240,7 @@ describe('Datetime Transformer', () => {
describe('time', () => {
it('should transform given time to utc time if frequency is recurrent', () => {
const time: string = datetimeTransformer.time(
const time: string = inputDatetimeTransformer.time(
{
date: '2023-07-24',
time: '01:15',
@ -249,7 +254,7 @@ describe('Datetime Transformer', () => {
expect(time).toBe('00:15');
});
it('should return given time to utc time if frequency is punctual', () => {
const time: string = datetimeTransformer.time(
const time: string = inputDatetimeTransformer.time(
{
date: '2023-07-24',
time: '01:15',

View File

@ -54,6 +54,54 @@ describe('Time Converter', () => {
});
});
describe('utcStringTimeToLocalStringTime', () => {
it('should convert a utc time to a paris time', () => {
const timeConverter: TimeConverter = new TimeConverter();
const utcTime = '07:00';
const parisTime = timeConverter.utcStringTimeToLocalStringTime(
utcTime,
'Europe/Paris',
);
expect(parisTime).toBe('08:00');
});
it('should return undefined if time is invalid', () => {
const timeConverter: TimeConverter = new TimeConverter();
const utcTime = '27:00';
const parisTime = timeConverter.utcStringTimeToLocalStringTime(
utcTime,
'Europe/Paris',
);
expect(parisTime).toBeUndefined();
});
it('should return undefined if time is undefined', () => {
const timeConverter: TimeConverter = new TimeConverter();
const utcTime = undefined;
const parisTime = timeConverter.utcStringTimeToLocalStringTime(
utcTime,
'Europe/Paris',
);
expect(parisTime).toBeUndefined();
});
it('should return undefined if timezone is invalid', () => {
const timeConverter: TimeConverter = new TimeConverter();
const utcTime = '07:00';
const parisTime = timeConverter.utcStringTimeToLocalStringTime(
utcTime,
'Foo/Bar',
);
expect(parisTime).toBeUndefined();
});
it('should return undefined if timezone is undefined', () => {
const timeConverter: TimeConverter = new TimeConverter();
const utcTime = '07:00';
const parisTime = timeConverter.utcStringTimeToLocalStringTime(
utcTime,
undefined,
);
expect(parisTime).toBeUndefined();
});
});
describe('localStringDateTimeToUtcDate', () => {
it('should convert a summer paris date and time to a utc date', () => {
const timeConverter: TimeConverter = new TimeConverter();
@ -111,6 +159,28 @@ describe('Time Converter', () => {
);
expect(utcDate.toISOString()).toBe('2023-02-03T01:00:00.000Z');
});
it('should return undefined if date is invalid', () => {
const timeConverter: TimeConverter = new TimeConverter();
const parisDate = '2023-06-32';
const parisTime = '08:00';
const utcDate = timeConverter.localStringDateTimeToUtcDate(
parisDate,
parisTime,
'Europe/Paris',
);
expect(utcDate).toBeUndefined();
});
it('should return undefined if date is undefined', () => {
const timeConverter: TimeConverter = new TimeConverter();
const parisDate = undefined;
const parisTime = '08:00';
const utcDate = timeConverter.localStringDateTimeToUtcDate(
parisDate,
parisTime,
'Europe/Paris',
);
expect(utcDate).toBeUndefined();
});
it('should return undefined if time is invalid', () => {
const timeConverter: TimeConverter = new TimeConverter();
const parisDate = '2023-06-22';
@ -157,7 +227,132 @@ describe('Time Converter', () => {
});
});
describe('utcBaseDayFromTime', () => {
describe('utcStringDateTimeToLocalIsoString', () => {
it('should convert a utc string date and time to a summer paris date isostring', () => {
const timeConverter: TimeConverter = new TimeConverter();
const utcDate = '2023-06-22';
const utcTime = '10:00';
const localIsoString = timeConverter.utcStringDateTimeToLocalIsoString(
utcDate,
utcTime,
'Europe/Paris',
);
expect(localIsoString).toBe('2023-06-22T12:00:00.000+02:00');
});
it('should convert a utc string date and time to a winter paris date isostring', () => {
const timeConverter: TimeConverter = new TimeConverter();
const utcDate = '2023-02-02';
const utcTime = '10:00';
const localIsoString = timeConverter.utcStringDateTimeToLocalIsoString(
utcDate,
utcTime,
'Europe/Paris',
);
expect(localIsoString).toBe('2023-02-02T11:00:00.000+01:00');
});
it('should convert a utc string date and time to a summer paris date isostring without dst', () => {
const timeConverter: TimeConverter = new TimeConverter();
const utcDate = '2023-06-22';
const utcTime = '10:00';
const localIsoString = timeConverter.utcStringDateTimeToLocalIsoString(
utcDate,
utcTime,
'Europe/Paris',
false,
);
expect(localIsoString).toBe('2023-06-22T11:00:00.000+01:00');
});
it('should convert a utc date to a tonga date isostring', () => {
const timeConverter: TimeConverter = new TimeConverter();
const utcDate = '2023-02-01';
const utcTime = '23:00';
const localIsoString = timeConverter.utcStringDateTimeToLocalIsoString(
utcDate,
utcTime,
'Pacific/Tongatapu',
);
expect(localIsoString).toBe('2023-02-02T12:00:00.000+13:00');
});
it('should convert a utc date to a papeete date isostring', () => {
const timeConverter: TimeConverter = new TimeConverter();
const utcDate = '2023-02-03';
const utcTime = '01:00';
const localIsoString = timeConverter.utcStringDateTimeToLocalIsoString(
utcDate,
utcTime,
'Pacific/Tahiti',
);
expect(localIsoString).toBe('2023-02-02T15:00:00.000-10:00');
});
it('should return undefined if date is invalid', () => {
const timeConverter: TimeConverter = new TimeConverter();
const utcDate = '2023-06-32';
const utcTime = '07:00';
const parisTime = timeConverter.utcStringDateTimeToLocalIsoString(
utcDate,
utcTime,
'Europe/Paris',
);
expect(parisTime).toBeUndefined();
});
it('should return undefined if date is undefined', () => {
const timeConverter: TimeConverter = new TimeConverter();
const utcDate = undefined;
const utcTime = '07:00';
const parisTime = timeConverter.utcStringDateTimeToLocalIsoString(
utcDate,
utcTime,
'Europe/Paris',
);
expect(parisTime).toBeUndefined();
});
it('should return undefined if time is invalid', () => {
const timeConverter: TimeConverter = new TimeConverter();
const utcDate = '2023-06-22';
const utcTime = '27:00';
const parisTime = timeConverter.utcStringDateTimeToLocalIsoString(
utcDate,
utcTime,
'Europe/Paris',
);
expect(parisTime).toBeUndefined();
});
it('should return undefined if time is undefined', () => {
const timeConverter: TimeConverter = new TimeConverter();
const utcDate = '2023-06-22';
const utcTime = undefined;
const parisTime = timeConverter.utcStringDateTimeToLocalIsoString(
utcDate,
utcTime,
'Europe/Paris',
);
expect(parisTime).toBeUndefined();
});
it('should return undefined if timezone is invalid', () => {
const timeConverter: TimeConverter = new TimeConverter();
const utcDate = '2023-06-22';
const utcTime = '07:00';
const parisTime = timeConverter.utcStringDateTimeToLocalIsoString(
utcDate,
utcTime,
'Foo/Bar',
);
expect(parisTime).toBeUndefined();
});
it('should return undefined if timezone is undefined', () => {
const timeConverter: TimeConverter = new TimeConverter();
const utcDate = '2023-06-22';
const utcTime = '07:00';
const parisTime = timeConverter.utcStringDateTimeToLocalIsoString(
utcDate,
utcTime,
undefined,
);
expect(parisTime).toBeUndefined();
});
});
describe('utcUnixEpochDayFromTime', () => {
it('should get the utc day of paris at 12:00', () => {
const timeConverter: TimeConverter = new TimeConverter();
expect(
@ -201,4 +396,49 @@ describe('Time Converter', () => {
).toBeUndefined();
});
});
describe('localUnixEpochDayFromTime', () => {
it('should get the day of paris at 12:00 utc', () => {
const timeConverter: TimeConverter = new TimeConverter();
expect(
timeConverter.localUnixEpochDayFromTime('12:00', 'Europe/Paris'),
).toBe(4);
});
it('should get the day of paris at 23:00 utc', () => {
const timeConverter: TimeConverter = new TimeConverter();
expect(
timeConverter.localUnixEpochDayFromTime('23:00', 'Europe/Paris'),
).toBe(5);
});
it('should get the day of papeete at 05:00 utc', () => {
const timeConverter: TimeConverter = new TimeConverter();
expect(
timeConverter.localUnixEpochDayFromTime('05:00', 'Pacific/Tahiti'),
).toBe(3);
});
it('should return undefined if time is invalid', () => {
const timeConverter: TimeConverter = new TimeConverter();
expect(
timeConverter.localUnixEpochDayFromTime('28:00', 'Europe/Paris'),
).toBeUndefined();
});
it('should return undefined if time is undefined', () => {
const timeConverter: TimeConverter = new TimeConverter();
expect(
timeConverter.localUnixEpochDayFromTime(undefined, 'Europe/Paris'),
).toBeUndefined();
});
it('should return undefined if timezone is invalid', () => {
const timeConverter: TimeConverter = new TimeConverter();
expect(
timeConverter.localUnixEpochDayFromTime('12:00', 'Foo/Bar'),
).toBeUndefined();
});
it('should return undefined if timezone is undefined', () => {
const timeConverter: TimeConverter = new TimeConverter();
expect(
timeConverter.localUnixEpochDayFromTime('12:00', undefined),
).toBeUndefined();
});
});
});

View File

@ -1,15 +0,0 @@
import { Frequency } from '@modules/ad/core/domain/ad.types';
import { intToFrequency } from '@modules/ad/interface/grpc-controllers/dtos/transformers/int-to-frequency';
describe('frequency mapping', () => {
it('should return punctual if frequency is 1', () => {
expect(intToFrequency(1)).toBe(Frequency.PUNCTUAL);
});
it('should return recurrent if frequency is 2', () => {
expect(intToFrequency(2)).toBe(Frequency.RECURRENT);
});
it('should throw an error if frequency is unknown', () => {
expect(() => intToFrequency(0)).toThrow();
expect(() => intToFrequency(3)).toThrow();
});
});

View File

@ -1,14 +0,0 @@
import { toPrecision } from '@modules/ad/interface/grpc-controllers/dtos/transformers/to-precision';
describe('precision handler', () => {
it('should return a 6 digits float number for a 10 digits float input number and 6 as precision', () => {
const precised = toPrecision(1.1234567891, 6);
const stringPrecised = precised.toString().split('.')[1];
expect(stringPrecised.length).toBe(6);
});
it('should return a 2 digits float number for a 2 digits float input number and 4 as precision', () => {
const precised = toPrecision(1.12, 4);
const stringPrecised = precised.toString().split('.')[1];
expect(stringPrecised.length).toBe(2);
});
});