diff --git a/README.md b/README.md index b576d6a..7db1891 100644 --- a/README.md +++ b/README.md @@ -20,9 +20,13 @@ First, import the EnvironmentConfigModule in your application's module and call import { Module } from '@nestjs/common'; import { EnvironmentConfigModule } from '@nodeflip/nest-env-config'; import { AppConfig } from './app-config'; +import { DBConfig } from './db-config'; @Module({ - imports: [EnvironmentConfigModule.forRoot(AppConfig)], + imports: [ + EnvironmentConfigModule.forRoot({configClass: AppConfig}), + EnvironmentConfigModule.forRoot({configClass: DBConfig, serviceName: 'DB_CONFIG_SERVICE'}) + ], }) export class AppModule {} ``` @@ -50,15 +54,20 @@ Inject the EnvironmentConfigService into your services to access the configurati import { Injectable } from '@nestjs/common'; import { EnvironmentConfigService } from '@nodeflip/nest-env-config'; import { AppConfig } from './app-config'; +import { DBConfig } from './db-config'; @Injectable() export class AppService { - constructor(private readonly configService: EnvironmentConfigService) { - console.log(this.configService.config); + constructor( + private readonly appConfigService: EnvironmentConfigService, + @Inject('DB_CONFIG_SERVICE') private readonly dbConfigService: EnvironmentConfigService + ) { + console.log(this.appConfigService.config); + console.log(this.dbConfigService.config); } getPort(): number { - return this.configService.config.port; + return this.dbConfigService.config.port; } } ``` @@ -102,7 +111,7 @@ describe('EnvironmentConfigService', () => { beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ - imports: [EnvironmentConfigModule.forRoot(DBConfig)], + imports: [EnvironmentConfigModule.forRoot({configClass: DBConfig})], }).compile(); service = module.get>(EnvironmentConfigService); diff --git a/src/environment-config/environment-config.module.ts b/src/environment-config/environment-config.module.ts index 147b96a..98141cd 100644 --- a/src/environment-config/environment-config.module.ts +++ b/src/environment-config/environment-config.module.ts @@ -4,25 +4,54 @@ import { ConfigModule, ConfigService } from "@nestjs/config"; import { EnvironmentConfigService } from "./environment-config.service"; import { PropClassType } from "./prop.decorator"; +export interface EnvironmentConfigModuleOptions { + serviceName?: string; + configClass: T; +} + @Module({}) export class EnvironmentConfigModule { - static forRoot(configClass: T): DynamicModule { - const environmentConfigServiceProvider: Provider = { - provide: EnvironmentConfigService, - useFactory: (configService: ConfigService) => { - return new EnvironmentConfigService( - configService, - configClass as PropClassType - ); - }, - inject: [ConfigService], - }; + static forRoot( + options: + | EnvironmentConfigModuleOptions + | EnvironmentConfigModuleOptions[] + ): DynamicModule { + const providers: Provider[] = []; + if (Array.isArray(options)) { + options.forEach((option) => { + providers.push({ + provide: option.serviceName + ? option.serviceName + : EnvironmentConfigService, + useFactory: (configService: ConfigService) => { + return new EnvironmentConfigService( + configService, + option.configClass as PropClassType + ); + }, + inject: [ConfigService], + }); + }); + } else { + providers.push({ + provide: options.serviceName + ? options.serviceName + : EnvironmentConfigService, + useFactory: (configService: ConfigService) => { + return new EnvironmentConfigService( + configService, + options.configClass as PropClassType + ); + }, + inject: [ConfigService], + }); + } return { module: EnvironmentConfigModule, imports: [ConfigModule.forRoot({ isGlobal: true })], - providers: [environmentConfigServiceProvider, ConfigService], - exports: [EnvironmentConfigService], + providers: [...providers, ConfigService], + exports: [...providers, ConfigService], }; } } diff --git a/src/environment-config/environment-config.service.ts b/src/environment-config/environment-config.service.ts index 73e1072..f1b7fde 100644 --- a/src/environment-config/environment-config.service.ts +++ b/src/environment-config/environment-config.service.ts @@ -3,39 +3,26 @@ import { ConfigService } from "@nestjs/config"; import { PropClassType } from "./prop.decorator"; -/** - * A service that provides configuration settings by extracting them from - * the environment variables and mapping them to a specified configuration class. - * - * @template T - The type of the configuration class. - */ @Injectable() export class EnvironmentConfigService { - /** - * The configuration object containing the mapped environment variables. - */ public readonly config: T; - - /** - * Creates an instance of EnvironmentConfigService. - * - * @param {ConfigService} configService - The ConfigService instance to access environment variables. - * @param {PropClassType} configClass - The configuration class type that defines the properties and their default values. - */ constructor( private readonly configService: ConfigService, - configClass: PropClassType + configClass: PropClassType | PropClassType[] ) { - this.config = this.getConfigObject(configClass); + if (Array.isArray(configClass)) { + this.config = configClass.reduce((acc, cls) => { + acc = { + ...acc, + ...this.getConfigObject(cls), + }; + return acc; + }, {} as T); + } else { + this.config = this.getConfigObject(configClass); + } } - /** - * Maps the environment variables to the configuration class properties. - * - * @private - * @param {T} configClass - The configuration class instance. - * @returns {T} The configuration object with properties populated from environment variables or their default values. - */ private getConfigObject(configClass: T): T { const configObject: any = {}; const cls = configClass as PropClassType; diff --git a/src/test/index.spec.ts b/src/test/index.spec.ts index 1f387d0..37b25c2 100644 --- a/src/test/index.spec.ts +++ b/src/test/index.spec.ts @@ -3,26 +3,40 @@ import { Test, TestingModule } from "@nestjs/testing"; import { EnvironmentConfigModule } from "../environment-config/environment-config.module"; import { EnvironmentConfigService } from "../environment-config/environment-config.service"; import { DBConfig } from "./db-config"; +import { RabitMqConfig } from "./mq.config"; describe("EnvironmentConfigService", () => { - let service: EnvironmentConfigService; + let dbservice: EnvironmentConfigService; + let mqservice: EnvironmentConfigService; beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ - imports: [EnvironmentConfigModule.forRoot(DBConfig)], + imports: [ + EnvironmentConfigModule.forRoot({ + configClass: DBConfig, + serviceName: "DBConfigService", + }), + EnvironmentConfigModule.forRoot({ configClass: RabitMqConfig }), + ], }).compile(); - service = module.get>( + dbservice = + module.get>("DBConfigService"); + mqservice = module.get>( EnvironmentConfigService ); }); - it("should be defined", () => { - expect(service).toBeDefined(); + it("dbservice should be defined", () => { + expect(dbservice).toBeDefined(); }); - it("should retrieve configuration properties", () => { - const config = service.config; + it("mqservice should be defined", () => { + expect(mqservice).toBeDefined(); + }); + + it("should retrieve configuration properties from dbservice", () => { + const config = dbservice.config; expect(config).toBeDefined(); expect(config.name).toBe("test_db"); expect(config.username).toBe("test_user"); @@ -31,4 +45,12 @@ describe("EnvironmentConfigService", () => { expect(config.port).toBe(5432); expect(config.logging).toBe(false); }); + + it("should retrieve configuration properties from mqservice", () => { + const config = mqservice.config; + expect(config).toBeDefined(); + expect(config.uri).toBe("amqp://test:test@localhost:5672"); + expect(config.exchangeName).toBe("test_exchange"); + expect(config.queueExchange).toBe("test_queue_exchange"); + }); }); diff --git a/src/test/mq.config.ts b/src/test/mq.config.ts new file mode 100644 index 0000000..0765504 --- /dev/null +++ b/src/test/mq.config.ts @@ -0,0 +1,18 @@ +import { Prop } from "../environment-config/prop.decorator"; + +export class RabitMqConfig { + @Prop("uri", "amqp://test:test@localhost:5672") + uri: string; + + @Prop("exchange", "test_exchange") + exchangeName: string; + + @Prop("queueExchangeName", "test_queue_exchange") + queueExchange?: string; + + @Prop("queueName", "test_queue") + queueName?: string; + + @Prop("queueRoutingKey", "test_routing_key") + queueRoutingKey?: string; +}