diff --git a/.env.dist b/.env.dist index 8894555..3063ff5 100644 --- a/.env.dist +++ b/.env.dist @@ -10,3 +10,21 @@ DATABASE_URL="postgresql://mobicoop:mobicoop@v3-db:5432/mobicoop?schema=configur MESSAGE_BROKER_URI=amqp://v3-broker:5672 MESSAGE_BROKER_EXCHANGE=mobicoop MESSAGE_BROKER_EXCHANGE_DURABILITY=true + + +# DEFAULT CONFIGURATION + +# CARPOOL +# 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 + +# PAGINATION +# number of results per page +PER_PAGE=10 diff --git a/package-lock.json b/package-lock.json index 9bcdb52..a4e755d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2687,6 +2687,12 @@ "pretty-format": "^29.0.0" } }, + "node_modules/@types/js-yaml": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.8.tgz", + "integrity": "sha512-m6jnPk1VhlYRiLFm3f8X9Uep761f+CK8mHyS65LutH2OhmBF0BeMEjHgg05usH8PLZMWWc/BUR9RPmkvpWnyRA==", + "dev": true + }, "node_modules/@types/json-schema": { "version": "7.0.14", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.14.tgz", @@ -5559,20 +5565,6 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", diff --git a/src/app.module.ts b/src/app.module.ts index a729c4b..8c0e669 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -16,10 +16,24 @@ import { MESSAGE_PUBLISHER } from '@modules/messager/messager.di-tokens'; import { CONFIGURATION_REPOSITORY } from '@modules/configuration/configuration.di-tokens'; import { ConfigurationModule } from '@modules/configuration/configuration.module'; import { EventEmitterModule } from '@nestjs/event-emitter'; +import brokerConfig from './config/broker.config'; +import carpoolConfig from './config/carpool.config'; +import databaseConfig from './config/database.config'; +import paginationConfig from './config/pagination.config'; +import serviceConfig from './config/service.config'; @Module({ imports: [ - ConfigModule.forRoot({ isGlobal: true }), + ConfigModule.forRoot({ + isGlobal: true, + load: [ + brokerConfig, + carpoolConfig, + databaseConfig, + paginationConfig, + serviceConfig, + ], + }), EventEmitterModule.forRoot(), HealthModule.forRootAsync({ imports: [ConfigurationModule, MessagerModule], diff --git a/src/config/broker.config.ts b/src/config/broker.config.ts new file mode 100644 index 0000000..941a54e --- /dev/null +++ b/src/config/broker.config.ts @@ -0,0 +1,11 @@ +import { registerAs } from '@nestjs/config'; + +export default registerAs('broker', () => ({ + uri: process.env.MESSAGE_BROKER_URI ?? 'amqp://v3-broker:5672', + exchange: process.env.MESSAGE_BROKER_EXCHANGE ?? 'mobicoop', + durability: process.env.MESSAGE_BROKER_EXCHANGE_DURABILITY + ? process.env.MESSAGE_BROKER_EXCHANGE_DURABILITY === 'false' + ? false + : true + : true, +})); diff --git a/src/config/carpool.config.ts b/src/config/carpool.config.ts new file mode 100644 index 0000000..51f54bb --- /dev/null +++ b/src/config/carpool.config.ts @@ -0,0 +1,19 @@ +import { registerAs } from '@nestjs/config'; + +export default registerAs('carpool', () => ({ + departureTimeMargin: process.env.DEPARTURE_TIME_MARGIN + ? parseInt(process.env.DEPARTURE_TIME_MARGIN, 10) + : 900, + role: process.env.ROLE ?? 'passenger', + seatsProposed: process.env.SEATS_PROPOSED + ? parseInt(process.env.SEATS_PROPOSED, 10) + : 3, + seatsRequested: process.env.SEATS_REQUESTED + ? parseInt(process.env.SEATS_REQUESTED, 10) + : 1, + strictFrequency: process.env.STRICT_FREQUENCY + ? process.env.STRICT_FREQUENCY === 'false' + ? false + : true + : false, +})); diff --git a/src/config/database.config.ts b/src/config/database.config.ts new file mode 100644 index 0000000..116843a --- /dev/null +++ b/src/config/database.config.ts @@ -0,0 +1,7 @@ +import { registerAs } from '@nestjs/config'; + +export default registerAs('database', () => ({ + url: + process.env.DATABASE_URL ?? + 'postgresql://mobicoop:mobicoop@v3-db:5432/mobicoop?schema=configuration', +})); diff --git a/src/config/pagination.config.ts b/src/config/pagination.config.ts new file mode 100644 index 0000000..e7b9ded --- /dev/null +++ b/src/config/pagination.config.ts @@ -0,0 +1,5 @@ +import { registerAs } from '@nestjs/config'; + +export default registerAs('pagination', () => ({ + perPage: process.env.PER_PAGE ? parseInt(process.env.PER_PAGE, 10) : 10, +})); diff --git a/src/config/service.config.ts b/src/config/service.config.ts new file mode 100644 index 0000000..b562850 --- /dev/null +++ b/src/config/service.config.ts @@ -0,0 +1,8 @@ +import { registerAs } from '@nestjs/config'; + +export default registerAs('service', () => ({ + url: process.env.SERVICE_URL ?? '0.0.0.0', + port: process.env.SERVICE_PORT + ? parseInt(process.env.SERVICE_PORT, 10) + : 5003, +})); diff --git a/src/modules/configuration/configuration.mapper.ts b/src/modules/configuration/configuration.mapper.ts index 745f8f9..86767c0 100644 --- a/src/modules/configuration/configuration.mapper.ts +++ b/src/modules/configuration/configuration.mapper.ts @@ -6,6 +6,10 @@ import { ConfigurationWriteModel, } from './infrastructure/configuration.repository'; import { ConfigurationResponseDto } from './interface/dtos/configuration.response.dto'; +import { + ConfigurationDomain, + ConfigurationType, +} from './core/domain/configuration.types'; /** * Mapper constructs objects that are used in different layers: @@ -28,9 +32,10 @@ export class ConfigurationMapper const copy = entity.getProps(); const record: ConfigurationWriteModel = { uuid: entity.id, - domain: copy.domain, - key: copy.key, + domain: copy.identifier.domain, + key: copy.identifier.key, value: copy.value, + type: copy.type, }; return record; }; @@ -41,9 +46,12 @@ export class ConfigurationMapper createdAt: new Date(record.createdAt), updatedAt: new Date(record.updatedAt), props: { - domain: record.domain, - key: record.key, + identifier: { + domain: record.domain as ConfigurationDomain, + key: record.key, + }, value: record.value, + type: record.type as ConfigurationType, }, }); return entity; @@ -52,9 +60,10 @@ export class ConfigurationMapper toResponse = (entity: ConfigurationEntity): ConfigurationResponseDto => { const props = entity.getProps(); const response = new ConfigurationResponseDto(entity); - response.domain = props.domain; - response.key = props.key; + response.domain = props.identifier.domain; + response.key = props.identifier.key; response.value = props.value; + response.type = props.type; return response; }; } diff --git a/src/modules/configuration/core/application/commands/set-configuration/set-configuration.service.ts b/src/modules/configuration/core/application/commands/set-configuration/set-configuration.service.ts index 6fd351d..f1faa3d 100644 --- a/src/modules/configuration/core/application/commands/set-configuration/set-configuration.service.ts +++ b/src/modules/configuration/core/application/commands/set-configuration/set-configuration.service.ts @@ -5,6 +5,10 @@ import { SetConfigurationCommand } from './set-configuration.command'; import { CONFIGURATION_REPOSITORY } from '@modules/configuration/configuration.di-tokens'; import { ConfigurationRepositoryPort } from '../../ports/configuration.repository.port'; import { ConfigurationEntity } from '@modules/configuration/core/domain/configuration.entity'; +import { + ConfigurationDomain, + ConfigurationType, +} from '@modules/configuration/core/domain/configuration.types'; @CommandHandler(SetConfigurationCommand) export class SetConfigurationService implements ICommandHandler { @@ -29,7 +33,14 @@ export class SetConfigurationService implements ICommandHandler { } catch (error: any) { if (error instanceof NotFoundException) { try { - const newConfiguration = ConfigurationEntity.create(command); + const newConfiguration = ConfigurationEntity.create({ + identifier: { + domain: command.domain as ConfigurationDomain, + key: command.key, + }, + value: command.value, + type: ConfigurationType.STRING, + }); await this.repository.insert(newConfiguration); return newConfiguration.id; } catch (error: any) { diff --git a/src/modules/configuration/core/application/event-handlers/publish-message-when-configuration-is-deleted.domain-event-handler.ts b/src/modules/configuration/core/application/event-handlers/publish-message-when-configuration-is-deleted.domain-event-handler.ts index 6f01343..b7c0f65 100644 --- a/src/modules/configuration/core/application/event-handlers/publish-message-when-configuration-is-deleted.domain-event-handler.ts +++ b/src/modules/configuration/core/application/event-handlers/publish-message-when-configuration-is-deleted.domain-event-handler.ts @@ -21,8 +21,8 @@ export class PublishMessageWhenConfigurationIsDeletedDomainEventHandler { const configurationDeletedIntegrationEvent = new ConfigurationDeletedIntegrationEvent({ id: event.aggregateId, - domain: event.domain, - key: event.key, + domain: event.identifier.domain, + key: event.identifier.key, metadata: event.metadata, }); this.messagePublisher.publish( diff --git a/src/modules/configuration/core/application/event-handlers/publish-message-when-configuration-is-set.domain-event-handler.ts b/src/modules/configuration/core/application/event-handlers/publish-message-when-configuration-is-set.domain-event-handler.ts index 0e100ce..4a8672a 100644 --- a/src/modules/configuration/core/application/event-handlers/publish-message-when-configuration-is-set.domain-event-handler.ts +++ b/src/modules/configuration/core/application/event-handlers/publish-message-when-configuration-is-set.domain-event-handler.ts @@ -18,8 +18,8 @@ export class PublishMessageWhenConfigurationIsSetDomainEventHandler { const configurationSetIntegrationEvent = new ConfigurationSetIntegrationEvent({ id: event.aggregateId, - domain: event.domain, - key: event.key, + domain: event.identifier.domain, + key: event.identifier.key, value: event.value, metadata: event.metadata, }); diff --git a/src/modules/configuration/core/domain/configuration.default.ts b/src/modules/configuration/core/domain/configuration.default.ts new file mode 100644 index 0000000..e933302 --- /dev/null +++ b/src/modules/configuration/core/domain/configuration.default.ts @@ -0,0 +1,32 @@ +import { + ConfigurationDomain, + ConfigurationType, + ConfigurationItems, +} from './configuration.types'; + +export const configurationItems: ConfigurationItems = { + [ConfigurationDomain.CARPOOL]: { + seatsProposed: { + value: '3', + type: ConfigurationType.NUMBER, + }, + seatsRequested: { + value: '1', + type: ConfigurationType.NUMBER, + }, + strictFrequency: { + value: 'false', + type: ConfigurationType.BOOLEAN, + }, + departureTimeMargin: { + value: '900', + type: ConfigurationType.NUMBER, + }, + role: { + value: 'passenger', + type: ConfigurationType.STRING, + enum: ['driver', 'passenger'], + }, + }, + [ConfigurationDomain.USER]: {}, +}; diff --git a/src/modules/configuration/core/domain/configuration.entity.ts b/src/modules/configuration/core/domain/configuration.entity.ts index d739c0c..3167e78 100644 --- a/src/modules/configuration/core/domain/configuration.entity.ts +++ b/src/modules/configuration/core/domain/configuration.entity.ts @@ -18,9 +18,9 @@ export class ConfigurationEntity extends AggregateRoot { configuration.addEvent( new ConfigurationSetDomainEvent({ aggregateId: id, - domain: props.domain, - key: props.key, + identifier: props.identifier, value: props.value, + type: props.type, }), ); return configuration; @@ -31,9 +31,9 @@ export class ConfigurationEntity extends AggregateRoot { this.addEvent( new ConfigurationSetDomainEvent({ aggregateId: this._id, - domain: this.props.domain, - key: this.props.key, + identifier: this.props.identifier, value: props.value, + type: this.props.type, }), ); } @@ -42,8 +42,7 @@ export class ConfigurationEntity extends AggregateRoot { this.addEvent( new ConfigurationDeletedDomainEvent({ aggregateId: this.id, - domain: this.props.domain, - key: this.props.key, + identifier: this.props.identifier, }), ); } diff --git a/src/modules/configuration/core/domain/configuration.types.ts b/src/modules/configuration/core/domain/configuration.types.ts index 9f4872a..28b2f42 100644 --- a/src/modules/configuration/core/domain/configuration.types.ts +++ b/src/modules/configuration/core/domain/configuration.types.ts @@ -1,23 +1,48 @@ // All properties that a Configuration has export interface ConfigurationProps { - domain: string; - key: string; - value: string; + identifier: ConfigurationIdentifier; + value: ConfigurationValue; + type: ConfigurationType; } // Properties that are needed for a Configuration creation export interface CreateConfigurationProps { - domain: string; - key: string; - value: string; + identifier: ConfigurationIdentifier; + value: ConfigurationValue; + type: ConfigurationType; } export interface UpdateConfigurationProps { - value: string; + value: ConfigurationValue; } -export enum Domain { - AD = 'AD', - MATCHER = 'MATCHER', +export enum ConfigurationDomain { + CARPOOL = 'CARPOOL', USER = 'USER', } + +export enum ConfigurationType { + BOOLEAN = 'BOOLEAN', + NUMBER = 'NUMBER', + STRING = 'STRING', +} + +export type ConfigurationIdentifier = { + domain: ConfigurationDomain; + key: ConfigurationKey; +}; + +export type ConfigurationKey = string; +export type ConfigurationValue = string; + +export type ConfigurationItems = Record< + ConfigurationDomain, + Record< + ConfigurationKey, + { + value: ConfigurationValue; + type: ConfigurationType; + enum?: Array; + } + > +>; diff --git a/src/modules/configuration/core/domain/events/configuration-deleted.domain-event.ts b/src/modules/configuration/core/domain/events/configuration-deleted.domain-event.ts index 6baab37..658e079 100644 --- a/src/modules/configuration/core/domain/events/configuration-deleted.domain-event.ts +++ b/src/modules/configuration/core/domain/events/configuration-deleted.domain-event.ts @@ -1,12 +1,11 @@ import { DomainEvent, DomainEventProps } from '@mobicoop/ddd-library'; +import { ConfigurationIdentifier } from '../configuration.types'; export class ConfigurationDeletedDomainEvent extends DomainEvent { - readonly domain: string; - readonly key: string; + readonly identifier: ConfigurationIdentifier; constructor(props: DomainEventProps) { super(props); - this.domain = props.domain; - this.key = props.key; + this.identifier = props.identifier; } } diff --git a/src/modules/configuration/core/domain/events/configuration-set.domain-event.ts b/src/modules/configuration/core/domain/events/configuration-set.domain-event.ts index d9564f4..c9b651e 100644 --- a/src/modules/configuration/core/domain/events/configuration-set.domain-event.ts +++ b/src/modules/configuration/core/domain/events/configuration-set.domain-event.ts @@ -1,14 +1,19 @@ import { DomainEvent, DomainEventProps } from '@mobicoop/ddd-library'; +import { + ConfigurationIdentifier, + ConfigurationType, + ConfigurationValue, +} from '../configuration.types'; export class ConfigurationSetDomainEvent extends DomainEvent { - readonly domain: string; - readonly key: string; - readonly value: string; + readonly identifier: ConfigurationIdentifier; + readonly value: ConfigurationValue; + readonly type: ConfigurationType; constructor(props: DomainEventProps) { super(props); - this.domain = props.domain; - this.key = props.key; + this.identifier = props.identifier; + this.type = props.type; this.value = props.value; } } diff --git a/src/modules/configuration/infrastructure/configuration.repository.ts b/src/modules/configuration/infrastructure/configuration.repository.ts index b77c992..7284f81 100644 --- a/src/modules/configuration/infrastructure/configuration.repository.ts +++ b/src/modules/configuration/infrastructure/configuration.repository.ts @@ -17,6 +17,7 @@ export type ConfigurationBaseModel = { domain: string; key: string; value: string; + type: string; }; export type ConfigurationReadModel = ConfigurationBaseModel & { diff --git a/src/modules/configuration/interface/dtos/configuration.response.dto.ts b/src/modules/configuration/interface/dtos/configuration.response.dto.ts index 8b7a7b2..f935c37 100644 --- a/src/modules/configuration/interface/dtos/configuration.response.dto.ts +++ b/src/modules/configuration/interface/dtos/configuration.response.dto.ts @@ -4,4 +4,5 @@ export class ConfigurationResponseDto extends ResponseBase { domain: string; key: string; value: string; + type: string; } diff --git a/src/modules/configuration/interface/grpc-controllers/dtos/delete-configuration.request.dto.ts b/src/modules/configuration/interface/grpc-controllers/dtos/delete-configuration.request.dto.ts index 223d8b9..4930d76 100644 --- a/src/modules/configuration/interface/grpc-controllers/dtos/delete-configuration.request.dto.ts +++ b/src/modules/configuration/interface/grpc-controllers/dtos/delete-configuration.request.dto.ts @@ -1,10 +1,10 @@ -import { Domain } from '@modules/configuration/core/domain/configuration.types'; +import { ConfigurationDomain } from '@modules/configuration/core/domain/configuration.types'; import { IsEnum, IsNotEmpty, IsString } from 'class-validator'; export class DeleteConfigurationRequestDto { - @IsEnum(Domain) + @IsEnum(ConfigurationDomain) @IsNotEmpty() - domain: Domain; + domain: ConfigurationDomain; @IsString() @IsNotEmpty() diff --git a/src/modules/configuration/interface/grpc-controllers/dtos/get-configuration.request.dto.ts b/src/modules/configuration/interface/grpc-controllers/dtos/get-configuration.request.dto.ts index 9ae99e8..65aefd6 100644 --- a/src/modules/configuration/interface/grpc-controllers/dtos/get-configuration.request.dto.ts +++ b/src/modules/configuration/interface/grpc-controllers/dtos/get-configuration.request.dto.ts @@ -1,10 +1,10 @@ -import { Domain } from '@modules/configuration/core/domain/configuration.types'; +import { ConfigurationDomain } from '@modules/configuration/core/domain/configuration.types'; import { IsEnum, IsNotEmpty, IsString } from 'class-validator'; export class GetConfigurationRequestDto { - @IsEnum(Domain) + @IsEnum(ConfigurationDomain) @IsNotEmpty() - domain: Domain; + domain: ConfigurationDomain; @IsString() @IsNotEmpty() diff --git a/src/modules/configuration/interface/grpc-controllers/dtos/set-configuration.request.dto.ts b/src/modules/configuration/interface/grpc-controllers/dtos/set-configuration.request.dto.ts index d9cd272..c6a0b80 100644 --- a/src/modules/configuration/interface/grpc-controllers/dtos/set-configuration.request.dto.ts +++ b/src/modules/configuration/interface/grpc-controllers/dtos/set-configuration.request.dto.ts @@ -1,10 +1,10 @@ -import { Domain } from '@modules/configuration/core/domain/configuration.types'; +import { ConfigurationDomain } from '@modules/configuration/core/domain/configuration.types'; import { IsEnum, IsNotEmpty, IsString } from 'class-validator'; export class SetConfigurationRequestDto { - @IsEnum(Domain) + @IsEnum(ConfigurationDomain) @IsNotEmpty() - domain: Domain; + domain: ConfigurationDomain; @IsString() @IsNotEmpty() diff --git a/src/modules/configuration/tests/integration/configuration.repository.spec.ts b/src/modules/configuration/tests/integration/configuration.repository.spec.ts index 832e87a..059b064 100644 --- a/src/modules/configuration/tests/integration/configuration.repository.spec.ts +++ b/src/modules/configuration/tests/integration/configuration.repository.spec.ts @@ -6,7 +6,7 @@ import { ConfigurationMapper } from '@modules/configuration/configuration.mapper import { ConfigurationEntity } from '@modules/configuration/core/domain/configuration.entity'; import { CreateConfigurationProps, - Domain, + ConfigurationDomain, } from '@modules/configuration/core/domain/configuration.types'; import { ConfigurationRepository } from '@modules/configuration/infrastructure/configuration.repository'; import { PrismaService } from '@modules/configuration/infrastructure/prisma.service'; @@ -36,7 +36,7 @@ describe('Configuration Repository', () => { for (let i = 0; i < nbToCreate; i++) { const configurationToCreate = { uuid: getSeed(i, baseUuid.uuid), - domain: Domain.AD, + domain: ConfigurationDomain.AD, key: `key${i}`, value: `value${i}`, createdAt: '2023-07-24 13:07:05.000', @@ -98,7 +98,7 @@ describe('Configuration Repository', () => { it('should return a configuration', async () => { await createConfigurations(1); const result = await configurationRepository.findOne({ - domain: Domain.AD, + domain: ConfigurationDomain.AD, key: 'key0', }); expect(result.getProps().value).toBe('value0'); @@ -119,7 +119,7 @@ describe('Configuration Repository', () => { const beforeCount = await prismaService.configuration.count(); const createConfigurationProps: CreateConfigurationProps = { - domain: Domain.AD, + domain: ConfigurationDomain.AD, key: 'seatsProposed', value: '3', }; @@ -139,7 +139,7 @@ describe('Configuration Repository', () => { await createConfigurations(1); const configurationToUpdate: ConfigurationEntity = await configurationRepository.findOne({ - domain: Domain.AD, + domain: ConfigurationDomain.AD, key: 'key0', }); configurationToUpdate.update({ value: 'newValue' }); @@ -149,7 +149,7 @@ describe('Configuration Repository', () => { ); const result: ConfigurationEntity = await configurationRepository.findOne( { - domain: Domain.AD, + domain: ConfigurationDomain.AD, key: 'key0', }, ); @@ -163,7 +163,7 @@ describe('Configuration Repository', () => { const beforeCount = await prismaService.configuration.count(); const configurationToDelete: ConfigurationEntity = await configurationRepository.findOne({ - domain: Domain.AD, + domain: ConfigurationDomain.AD, key: 'key4', }); await configurationRepository.delete(configurationToDelete); diff --git a/src/modules/configuration/tests/unit/configuration.mapper.spec.ts b/src/modules/configuration/tests/unit/configuration.mapper.spec.ts index 83fbb1e..2686aaa 100644 --- a/src/modules/configuration/tests/unit/configuration.mapper.spec.ts +++ b/src/modules/configuration/tests/unit/configuration.mapper.spec.ts @@ -1,6 +1,9 @@ import { ConfigurationMapper } from '@modules/configuration/configuration.mapper'; import { ConfigurationEntity } from '@modules/configuration/core/domain/configuration.entity'; -import { Domain } from '@modules/configuration/core/domain/configuration.types'; +import { + ConfigurationDomain, + ConfigurationType, +} from '@modules/configuration/core/domain/configuration.types'; import { ConfigurationReadModel, ConfigurationWriteModel, @@ -12,9 +15,12 @@ const now = new Date('2023-06-21 06:00:00'); const configurationEntity: ConfigurationEntity = new ConfigurationEntity({ id: 'c160cf8c-f057-4962-841f-3ad68346df44', props: { - domain: Domain.AD, - key: 'seatsProposed', + identifier: { + domain: ConfigurationDomain.CARPOOL, + key: 'seatsProposed', + }, value: '3', + type: ConfigurationType.NUMBER, }, createdAt: now, updatedAt: now, @@ -24,6 +30,7 @@ const configurationReadModel: ConfigurationReadModel = { domain: 'AD', key: 'seatsProposed', value: '4', + type: 'NUMBER', createdAt: now, updatedAt: now, }; diff --git a/src/modules/configuration/tests/unit/core/configuration.entity.spec.ts b/src/modules/configuration/tests/unit/core/configuration.entity.spec.ts index 6723472..0647071 100644 --- a/src/modules/configuration/tests/unit/core/configuration.entity.spec.ts +++ b/src/modules/configuration/tests/unit/core/configuration.entity.spec.ts @@ -1,16 +1,20 @@ import { ConfigurationEntity } from '@modules/configuration/core/domain/configuration.entity'; import { CreateConfigurationProps, - Domain, + ConfigurationDomain, UpdateConfigurationProps, + ConfigurationType, } from '@modules/configuration/core/domain/configuration.types'; import { ConfigurationDeletedDomainEvent } from '@modules/configuration/core/domain/events/configuration-deleted.domain-event'; import { ConfigurationSetDomainEvent } from '@modules/configuration/core/domain/events/configuration-set.domain-event'; const createConfigurationProps: CreateConfigurationProps = { - domain: Domain.AD, - key: 'seatsProposed', + identifier: { + domain: ConfigurationDomain.CARPOOL, + key: 'seatsProposed', + }, value: '3', + type: ConfigurationType.NUMBER, }; const updateConfigurationProps: UpdateConfigurationProps = { diff --git a/src/modules/configuration/tests/unit/core/delete-configuration.service.spec.ts b/src/modules/configuration/tests/unit/core/delete-configuration.service.spec.ts index 179786b..4236ba2 100644 --- a/src/modules/configuration/tests/unit/core/delete-configuration.service.spec.ts +++ b/src/modules/configuration/tests/unit/core/delete-configuration.service.spec.ts @@ -1,12 +1,12 @@ import { CONFIGURATION_REPOSITORY } from '@modules/configuration/configuration.di-tokens'; import { DeleteConfigurationCommand } from '@modules/configuration/core/application/commands/delete-configuration/delete-configuration.command'; import { DeleteConfigurationService } from '@modules/configuration/core/application/commands/delete-configuration/delete-configuration.service'; -import { Domain } from '@modules/configuration/core/domain/configuration.types'; +import { ConfigurationDomain } from '@modules/configuration/core/domain/configuration.types'; import { DeleteConfigurationRequestDto } from '@modules/configuration/interface/grpc-controllers/dtos/delete-configuration.request.dto'; import { Test, TestingModule } from '@nestjs/testing'; const deleteConfigurationRequest: DeleteConfigurationRequestDto = { - domain: Domain.AD, + domain: ConfigurationDomain.CARPOOL, key: 'seatsProposed', }; diff --git a/src/modules/configuration/tests/unit/core/get-configuration.query-handler.spec.ts b/src/modules/configuration/tests/unit/core/get-configuration.query-handler.spec.ts index 3af9582..dd2384f 100644 --- a/src/modules/configuration/tests/unit/core/get-configuration.query-handler.spec.ts +++ b/src/modules/configuration/tests/unit/core/get-configuration.query-handler.spec.ts @@ -1,6 +1,9 @@ import { Test, TestingModule } from '@nestjs/testing'; import { ConfigurationEntity } from '@modules/configuration/core/domain/configuration.entity'; -import { Domain } from '@modules/configuration/core/domain/configuration.types'; +import { + ConfigurationDomain, + ConfigurationType, +} from '@modules/configuration/core/domain/configuration.types'; import { GetConfigurationQueryHandler } from '@modules/configuration/core/application/queries/get-configuration/get-configuration.query-handler'; import { CONFIGURATION_REPOSITORY } from '@modules/configuration/configuration.di-tokens'; import { GetConfigurationQuery } from '@modules/configuration/core/application/queries/get-configuration/get-configuration.query'; @@ -9,9 +12,12 @@ const now = new Date('2023-06-21 06:00:00'); const configuration: ConfigurationEntity = new ConfigurationEntity({ id: 'c160cf8c-f057-4962-841f-3ad68346df44', props: { - domain: Domain.AD, - key: 'seatsProposed', + identifier: { + domain: ConfigurationDomain.CARPOOL, + key: 'seatsProposed', + }, value: '3', + type: ConfigurationType.NUMBER, }, createdAt: now, updatedAt: now, @@ -47,7 +53,7 @@ describe('Get Configuration Query Handler', () => { describe('execution', () => { it('should return a configuration item', async () => { const getConfigurationQuery = new GetConfigurationQuery( - Domain.AD, + ConfigurationDomain.CARPOOL, 'seatsProposed', ); const configuration: ConfigurationEntity = diff --git a/src/modules/configuration/tests/unit/core/propagate-configurations.service.spec.ts b/src/modules/configuration/tests/unit/core/propagate-configurations.service.spec.ts index 000e6a3..16d1442 100644 --- a/src/modules/configuration/tests/unit/core/propagate-configurations.service.spec.ts +++ b/src/modules/configuration/tests/unit/core/propagate-configurations.service.spec.ts @@ -1,5 +1,8 @@ import { Test, TestingModule } from '@nestjs/testing'; -import { Domain } from '@modules/configuration/core/domain/configuration.types'; +import { + ConfigurationDomain, + ConfigurationType, +} from '@modules/configuration/core/domain/configuration.types'; import { CONFIGURATION_MESSAGE_PUBLISHER, CONFIGURATION_REPOSITORY, @@ -17,9 +20,12 @@ const configurationEntities = [ new ConfigurationEntity({ id: '047a6ecf-23d4-4d3e-877c-3225d560a8da', props: { - domain: Domain.AD, - key: 'seatsProposed', + identifier: { + domain: ConfigurationDomain.CARPOOL, + key: 'seatsProposed', + }, value: '3', + type: ConfigurationType.NUMBER, }, createdAt: new Date('2023-10-23T07:00:00Z'), updatedAt: new Date('2023-10-23T07:00:00Z'), @@ -27,9 +33,12 @@ const configurationEntities = [ new ConfigurationEntity({ id: '047a6ecf-23d4-4d3e-877c-3225d560a8db', props: { - domain: Domain.AD, - key: 'seatsRequested', + identifier: { + domain: ConfigurationDomain.CARPOOL, + key: 'seatsRequested', + }, value: '1', + type: ConfigurationType.NUMBER, }, createdAt: new Date('2023-10-23T07:00:00Z'), updatedAt: new Date('2023-10-23T07:00:00Z'), @@ -40,14 +49,16 @@ const mockConfigurationMapper = { toResponse: jest .fn() .mockImplementationOnce(() => ({ - domain: Domain.AD, + domain: ConfigurationDomain.CARPOOL, key: 'seatsProposed', value: '3', + type: ConfigurationType.NUMBER, })) .mockImplementationOnce(() => ({ - domain: Domain.AD, + domain: ConfigurationDomain.CARPOOL, key: 'seatsRequested', value: '1', + type: ConfigurationType.NUMBER, })), }; @@ -93,7 +104,7 @@ describe('Propagate Configurations Service', () => { expect(mockMessagePublisher.publish).toHaveBeenCalledTimes(1); expect(mockMessagePublisher.publish).toHaveBeenCalledWith( CONFIGURATION_PROPAGATED_ROUTING_KEY, - '[{"domain":"AD","key":"seatsProposed","value":"3"},{"domain":"AD","key":"seatsRequested","value":"1"}]', + '[{"domain":"CARPOOL","key":"seatsProposed","value":"3","type":"NUMBER"},{"domain":"CARPOOL","key":"seatsRequested","value":"1","type":"NUMBER"}]', ); }); }); diff --git a/src/modules/configuration/tests/unit/core/publish-message-when-configuration-is-deleted.domain-event-handler.spec.ts b/src/modules/configuration/tests/unit/core/publish-message-when-configuration-is-deleted.domain-event-handler.spec.ts index 377cd82..46f350c 100644 --- a/src/modules/configuration/tests/unit/core/publish-message-when-configuration-is-deleted.domain-event-handler.spec.ts +++ b/src/modules/configuration/tests/unit/core/publish-message-when-configuration-is-deleted.domain-event-handler.spec.ts @@ -1,6 +1,6 @@ import { CONFIGURATION_MESSAGE_PUBLISHER } from '@modules/configuration/configuration.di-tokens'; import { PublishMessageWhenConfigurationIsDeletedDomainEventHandler } from '@modules/configuration/core/application/event-handlers/publish-message-when-configuration-is-deleted.domain-event-handler'; -import { Domain } from '@modules/configuration/core/domain/configuration.types'; +import { ConfigurationDomain } from '@modules/configuration/core/domain/configuration.types'; import { ConfigurationDeletedDomainEvent } from '@modules/configuration/core/domain/events/configuration-deleted.domain-event'; import { Test, TestingModule } from '@nestjs/testing'; import { CONFIGURATION_DELETED_ROUTING_KEY } from '@src/app.constants'; @@ -33,8 +33,10 @@ describe('Publish message when configuration is deleted domain event handler', ( jest.spyOn(mockMessagePublisher, 'publish'); const configurationDeletedDomainEvent: ConfigurationDeletedDomainEvent = { id: 'some-domain-event-id', - domain: Domain.AD, - key: 'seatsProposed', + identifier: { + domain: ConfigurationDomain.CARPOOL, + key: 'seatsProposed', + }, aggregateId: 'some-aggregate-id', metadata: { timestamp: new Date('2023-06-28T05:00:00Z').getTime(), @@ -50,7 +52,7 @@ describe('Publish message when configuration is deleted domain event handler', ( expect(mockMessagePublisher.publish).toHaveBeenCalledTimes(1); expect(mockMessagePublisher.publish).toHaveBeenCalledWith( CONFIGURATION_DELETED_ROUTING_KEY, - '{"id":"some-aggregate-id","metadata":{"correlationId":"some-correlation-id","timestamp":1687928400000},"domain":"AD","key":"seatsProposed"}', + '{"id":"some-aggregate-id","metadata":{"correlationId":"some-correlation-id","timestamp":1687928400000},"domain":"CARPOOL","key":"seatsProposed"}', ); }); }); diff --git a/src/modules/configuration/tests/unit/core/publish-message-when-configuration-is-set.domain-event-handler.spec.ts b/src/modules/configuration/tests/unit/core/publish-message-when-configuration-is-set.domain-event-handler.spec.ts index fe41262..e6cb4c2 100644 --- a/src/modules/configuration/tests/unit/core/publish-message-when-configuration-is-set.domain-event-handler.spec.ts +++ b/src/modules/configuration/tests/unit/core/publish-message-when-configuration-is-set.domain-event-handler.spec.ts @@ -1,6 +1,9 @@ import { CONFIGURATION_MESSAGE_PUBLISHER } from '@modules/configuration/configuration.di-tokens'; import { PublishMessageWhenConfigurationIsSetDomainEventHandler } from '@modules/configuration/core/application/event-handlers/publish-message-when-configuration-is-set.domain-event-handler'; -import { Domain } from '@modules/configuration/core/domain/configuration.types'; +import { + ConfigurationDomain, + ConfigurationType, +} from '@modules/configuration/core/domain/configuration.types'; import { ConfigurationSetDomainEvent } from '@modules/configuration/core/domain/events/configuration-set.domain-event'; import { Test, TestingModule } from '@nestjs/testing'; import { CONFIGURATION_SET_ROUTING_KEY } from '@src/app.constants'; @@ -34,8 +37,11 @@ describe('Publish message when configuration is set domain event handler', () => const configurationSetDomainEvent: ConfigurationSetDomainEvent = { id: 'some-domain-event-id', aggregateId: 'some-aggregate-id', - domain: Domain.AD, - key: 'seatsProposed', + identifier: { + domain: ConfigurationDomain.CARPOOL, + key: 'seatsProposed', + }, + type: ConfigurationType.NUMBER, value: '3', metadata: { timestamp: new Date('2023-06-28T05:00:00Z').getTime(), @@ -51,7 +57,7 @@ describe('Publish message when configuration is set domain event handler', () => expect(mockMessagePublisher.publish).toHaveBeenCalledTimes(1); expect(mockMessagePublisher.publish).toHaveBeenCalledWith( CONFIGURATION_SET_ROUTING_KEY, - '{"id":"some-aggregate-id","metadata":{"correlationId":"some-correlation-id","timestamp":1687928400000},"domain":"AD","key":"seatsProposed","value":"3"}', + '{"id":"some-aggregate-id","metadata":{"correlationId":"some-correlation-id","timestamp":1687928400000},"domain":"CARPOOL","key":"seatsProposed","value":"3"}', ); }); }); diff --git a/src/modules/configuration/tests/unit/core/set-configuration.service.spec.ts b/src/modules/configuration/tests/unit/core/set-configuration.service.spec.ts index 72ab2c7..d4b4f38 100644 --- a/src/modules/configuration/tests/unit/core/set-configuration.service.spec.ts +++ b/src/modules/configuration/tests/unit/core/set-configuration.service.spec.ts @@ -1,14 +1,17 @@ import { Test, TestingModule } from '@nestjs/testing'; import { AggregateID, NotFoundException } from '@mobicoop/ddd-library'; import { SetConfigurationRequestDto } from '@modules/configuration/interface/grpc-controllers/dtos/set-configuration.request.dto'; -import { Domain } from '@modules/configuration/core/domain/configuration.types'; +import { + ConfigurationDomain, + ConfigurationType, +} from '@modules/configuration/core/domain/configuration.types'; import { SetConfigurationService } from '@modules/configuration/core/application/commands/set-configuration/set-configuration.service'; import { CONFIGURATION_REPOSITORY } from '@modules/configuration/configuration.di-tokens'; import { SetConfigurationCommand } from '@modules/configuration/core/application/commands/set-configuration/set-configuration.command'; import { ConfigurationEntity } from '@modules/configuration/core/domain/configuration.entity'; const setConfigurationRequest: SetConfigurationRequestDto = { - domain: Domain.AD, + domain: ConfigurationDomain.CARPOOL, key: 'seatsProposed', value: '3', }; @@ -16,8 +19,11 @@ const setConfigurationRequest: SetConfigurationRequestDto = { const existingConfigurationEntity = new ConfigurationEntity({ id: '047a6ecf-23d4-4d3e-877c-3225d560a8da', props: { - domain: Domain.AD, - key: 'seatsProposed', + identifier: { + domain: ConfigurationDomain.CARPOOL, + key: 'seatsProposed', + }, + type: ConfigurationType.NUMBER, value: '2', }, createdAt: new Date('2023-10-23T07:00:00Z'), diff --git a/src/modules/configuration/tests/unit/interface/delete-configuration.grpc.controller.spec.ts b/src/modules/configuration/tests/unit/interface/delete-configuration.grpc.controller.spec.ts index 1cab8a8..980a267 100644 --- a/src/modules/configuration/tests/unit/interface/delete-configuration.grpc.controller.spec.ts +++ b/src/modules/configuration/tests/unit/interface/delete-configuration.grpc.controller.spec.ts @@ -3,7 +3,7 @@ import { NotFoundException, } from '@mobicoop/ddd-library'; import { RpcExceptionCode } from '@mobicoop/ddd-library'; -import { Domain } from '@modules/configuration/core/domain/configuration.types'; +import { ConfigurationDomain } from '@modules/configuration/core/domain/configuration.types'; import { DeleteConfigurationGrpcController } from '@modules/configuration/interface/grpc-controllers/delete-configuration.grpc.controller'; import { DeleteConfigurationRequestDto } from '@modules/configuration/interface/grpc-controllers/dtos/delete-configuration.request.dto'; import { CommandBus } from '@nestjs/cqrs'; @@ -11,7 +11,7 @@ import { RpcException } from '@nestjs/microservices'; import { Test, TestingModule } from '@nestjs/testing'; const deleteConfigurationRequest: DeleteConfigurationRequestDto = { - domain: Domain.AD, + domain: ConfigurationDomain.CARPOOL, key: 'seatsProposed', }; diff --git a/src/modules/configuration/tests/unit/interface/get-configuration.grpc.controller.spec.ts b/src/modules/configuration/tests/unit/interface/get-configuration.grpc.controller.spec.ts index 0687baf..604005f 100644 --- a/src/modules/configuration/tests/unit/interface/get-configuration.grpc.controller.spec.ts +++ b/src/modules/configuration/tests/unit/interface/get-configuration.grpc.controller.spec.ts @@ -1,7 +1,10 @@ import { NotFoundException } from '@mobicoop/ddd-library'; import { RpcExceptionCode } from '@mobicoop/ddd-library'; import { ConfigurationMapper } from '@modules/configuration/configuration.mapper'; -import { Domain } from '@modules/configuration/core/domain/configuration.types'; +import { + ConfigurationDomain, + ConfigurationType, +} from '@modules/configuration/core/domain/configuration.types'; import { GetConfigurationGrpcController } from '@modules/configuration/interface/grpc-controllers/get-configuration.grpc.controller'; import { QueryBus } from '@nestjs/cqrs'; import { RpcException } from '@nestjs/microservices'; @@ -21,9 +24,10 @@ const mockQueryBus = { const mockConfigurationMapper = { toResponse: jest.fn().mockImplementationOnce(() => ({ - domain: Domain.AD, + domain: ConfigurationDomain.CARPOOL, key: 'seatsProposed', value: '3', + type: ConfigurationType.NUMBER, })), }; @@ -62,7 +66,7 @@ describe('Get Configuration Grpc Controller', () => { jest.spyOn(mockQueryBus, 'execute'); jest.spyOn(mockConfigurationMapper, 'toResponse'); const response = await getConfigurationGrpcController.get({ - domain: Domain.AD, + domain: ConfigurationDomain.CARPOOL, key: 'seatsProposed', }); expect(response.value).toBe('3'); @@ -76,7 +80,7 @@ describe('Get Configuration Grpc Controller', () => { expect.assertions(4); try { await getConfigurationGrpcController.get({ - domain: Domain.AD, + domain: ConfigurationDomain.CARPOOL, key: 'price', }); } catch (e: any) { @@ -93,7 +97,7 @@ describe('Get Configuration Grpc Controller', () => { expect.assertions(4); try { await getConfigurationGrpcController.get({ - domain: Domain.AD, + domain: ConfigurationDomain.CARPOOL, key: 'someValue', }); } catch (e: any) { diff --git a/src/modules/configuration/tests/unit/interface/set-configuration.grpc.controller.spec.ts b/src/modules/configuration/tests/unit/interface/set-configuration.grpc.controller.spec.ts index 9a1d032..8a9d5f4 100644 --- a/src/modules/configuration/tests/unit/interface/set-configuration.grpc.controller.spec.ts +++ b/src/modules/configuration/tests/unit/interface/set-configuration.grpc.controller.spec.ts @@ -1,6 +1,6 @@ import { IdResponse } from '@mobicoop/ddd-library'; import { RpcExceptionCode } from '@mobicoop/ddd-library'; -import { Domain } from '@modules/configuration/core/domain/configuration.types'; +import { ConfigurationDomain } from '@modules/configuration/core/domain/configuration.types'; import { SetConfigurationRequestDto } from '@modules/configuration/interface/grpc-controllers/dtos/set-configuration.request.dto'; import { SetConfigurationGrpcController } from '@modules/configuration/interface/grpc-controllers/set-configuration.grpc.controller'; import { CommandBus } from '@nestjs/cqrs'; @@ -8,7 +8,7 @@ import { RpcException } from '@nestjs/microservices'; import { Test, TestingModule } from '@nestjs/testing'; const setConfigurationRequest: SetConfigurationRequestDto = { - domain: Domain.AD, + domain: ConfigurationDomain.CARPOOL, key: 'seatsProposed', value: '3', }; diff --git a/src/modules/messager/messager.module.ts b/src/modules/messager/messager.module.ts index d234c61..f14c322 100644 --- a/src/modules/messager/messager.module.ts +++ b/src/modules/messager/messager.module.ts @@ -16,12 +16,10 @@ const imports = [ useFactory: async ( configService: ConfigService, ): Promise => ({ - uri: configService.get('MESSAGE_BROKER_URI') as string, + uri: configService.get('broker.uri') as string, exchange: { - name: configService.get('MESSAGE_BROKER_EXCHANGE') as string, - durable: configService.get( - 'MESSAGE_BROKER_EXCHANGE_DURABILITY', - ) as boolean, + name: configService.get('broker.exchange') as string, + durable: configService.get('broker.durability') as boolean, }, name: SERVICE_NAME, }),