import { Inject, Injectable } from '@nestjs/common'; import { AdEntity } from './core/domain/ad.entity'; import { AdWriteModel, AdReadModel, ScheduleItemModel, AdWriteExtraModel, } from './infrastructure/ad.repository'; import { v4 } from 'uuid'; import { ScheduleItem, ScheduleItemProps, } from './core/domain/value-objects/schedule-item.value-object'; import { DirectionEncoderPort } from '@modules/geography/core/application/ports/direction-encoder.port'; import { AD_DIRECTION_ENCODER } from './ad.di-tokens'; import { ExtendedMapper } from '@mobicoop/ddd-library'; /** * Mapper constructs objects that are used in different layers: * Record is an object that is stored in a database, * Entity is an object that is used in application domain layer, * and a ResponseDTO is an object returned to a user (usually as json). */ @Injectable() export class AdMapper implements ExtendedMapper< AdEntity, AdReadModel, AdWriteModel, AdWriteExtraModel, undefined > { constructor( @Inject(AD_DIRECTION_ENCODER) private readonly directionEncoder: DirectionEncoderPort, ) {} toPersistence = (entity: AdEntity): AdWriteModel => { const copy = entity.getProps(); const now = new Date(); const record: AdWriteModel = { uuid: copy.id, driver: copy.driver, passenger: copy.passenger, 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, time: new Date( 1970, 0, 1, parseInt(scheduleItem.time.split(':')[0]), parseInt(scheduleItem.time.split(':')[1]), ), margin: scheduleItem.margin, createdAt: now, updatedAt: now, })), }, seatsProposed: copy.seatsProposed, seatsRequested: copy.seatsRequested, strict: copy.strict, driverDuration: copy.driverDuration, driverDistance: copy.driverDistance, passengerDuration: copy.passengerDuration, passengerDistance: copy.passengerDistance, fwdAzimuth: copy.fwdAzimuth, backAzimuth: copy.backAzimuth, createdAt: copy.createdAt, updatedAt: copy.updatedAt, }; return record; }; toDomain = (record: AdReadModel): AdEntity => new AdEntity({ id: record.uuid, createdAt: new Date(record.createdAt), updatedAt: new Date(record.updatedAt), props: { seatsProposed: record.seatsProposed, seatsRequested: record.seatsRequested, strict: record.strict, driverDuration: record.driverDuration, driverDistance: record.driverDistance, passengerDuration: record.passengerDuration, passengerDistance: record.passengerDistance, driver: record.driver, passenger: record.passenger, frequency: record.frequency, fromDate: record.fromDate.toISOString().split('T')[0], toDate: record.toDate.toISOString().split('T')[0], schedule: record.schedule.map( (scheduleItem: ScheduleItemModel) => new ScheduleItem({ day: scheduleItem.day, time: `${scheduleItem.time .getUTCHours() .toString() .padStart(2, '0')}:${scheduleItem.time .getUTCMinutes() .toString() .padStart(2, '0')}`, margin: scheduleItem.margin, }), ), waypoints: this.directionEncoder .decode(record.waypoints) .map((coordinates, index) => ({ position: index, ...coordinates, })), fwdAzimuth: record.fwdAzimuth, backAzimuth: record.backAzimuth, points: [], }, }); toPersistenceExtra = (entity: AdEntity): AdWriteExtraModel => ({ waypoints: this.directionEncoder.encode(entity.getProps().waypoints), direction: this.directionEncoder.encode(entity.getProps().points), }); }