extract config files

This commit is contained in:
sbriat 2023-10-24 11:21:45 +02:00
parent 376260d903
commit f960299565
35 changed files with 313 additions and 113 deletions

View File

@ -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

20
package-lock.json generated
View File

@ -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",

View File

@ -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],

View File

@ -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,
}));

View File

@ -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,
}));

View File

@ -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',
}));

View File

@ -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,
}));

View File

@ -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,
}));

View File

@ -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;
};
}

View File

@ -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) {

View File

@ -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(

View File

@ -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,
});

View File

@ -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]: {},
};

View File

@ -18,9 +18,9 @@ export class ConfigurationEntity extends AggregateRoot<ConfigurationProps> {
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<ConfigurationProps> {
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<ConfigurationProps> {
this.addEvent(
new ConfigurationDeletedDomainEvent({
aggregateId: this.id,
domain: this.props.domain,
key: this.props.key,
identifier: this.props.identifier,
}),
);
}

View File

@ -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<string>;
}
>
>;

View File

@ -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<ConfigurationDeletedDomainEvent>) {
super(props);
this.domain = props.domain;
this.key = props.key;
this.identifier = props.identifier;
}
}

View File

@ -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<ConfigurationSetDomainEvent>) {
super(props);
this.domain = props.domain;
this.key = props.key;
this.identifier = props.identifier;
this.type = props.type;
this.value = props.value;
}
}

View File

@ -17,6 +17,7 @@ export type ConfigurationBaseModel = {
domain: string;
key: string;
value: string;
type: string;
};
export type ConfigurationReadModel = ConfigurationBaseModel & {

View File

@ -4,4 +4,5 @@ export class ConfigurationResponseDto extends ResponseBase {
domain: string;
key: string;
value: string;
type: string;
}

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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);

View File

@ -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,
};

View File

@ -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 = {

View File

@ -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',
};

View File

@ -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 =

View File

@ -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"}]',
);
});
});

View File

@ -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"}',
);
});
});

View File

@ -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"}',
);
});
});

View File

@ -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'),

View File

@ -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',
};

View File

@ -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) {

View File

@ -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',
};

View File

@ -16,12 +16,10 @@ const imports = [
useFactory: async (
configService: ConfigService,
): Promise<MessageBrokerModuleOptions> => ({
uri: configService.get<string>('MESSAGE_BROKER_URI') as string,
uri: configService.get<string>('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: configService.get<string>('broker.exchange') as string,
durable: configService.get<boolean>('broker.durability') as boolean,
},
name: SERVICE_NAME,
}),