Dynamically changing TypeORM configuration in NestJS typically involves several steps, primarily using a custom service to dynamically establish database connections. Below, I will provide a detailed explanation of how to implement this functionality.
Step 1: Creating a Dynamic Database Configuration Service
First, we need to create a service that generates database configuration based on dynamic data (e.g., from API requests or environment variables).
typescriptimport { Injectable } from '@nestjs/common'; import { TypeOrmModuleOptions } from '@nestjs/typeorm'; @Injectable() export class DatabaseConfigService { createTypeOrmOptions(): TypeOrmModuleOptions { const options: TypeOrmModuleOptions = { type: 'postgres', // or other database types host: process.env.DATABASE_HOST, port: parseInt(process.env.DATABASE_PORT, 10) || 5432, username: process.env.DATABASE_USERNAME, password: process.env.DATABASE_PASSWORD, database: process.env.DATABASE_NAME, entities: [__dirname + '/../**/*.entity{.ts,.js}'], synchronize: true, // should be set to false in production }; return options; } }
Step 2: Dynamically Connecting to the Database
In AppModule, we typically use the TypeOrmModule.forRoot() static method to initialize the database connection. However, to implement dynamic configuration, we will use the forRootAsync() method and leverage the DatabaseConfigService created above.
typescriptimport { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; import { DatabaseConfigService } from './database-config.service'; @Module({ imports: [ TypeOrmModule.forRootAsync({ useClass: DatabaseConfigService, }), ], providers: [DatabaseConfigService], }) export class AppModule {}
Step 3: Testing Changes
Now, whenever the application starts or needs to reconnect to the database, DatabaseConfigService will generate new database configuration based on the current environment variables or other dynamic data sources. This makes it possible to adjust the database configuration at runtime as needed.
Example
Suppose we need to dynamically connect to different databases based on user selection. We can extend DatabaseConfigService to accept user input and generate configuration accordingly:
typescript@Injectable() export class DatabaseConfigService { constructor(private requestService: RequestService) {} createTypeOrmOptions(): TypeOrmModuleOptions { const userData = this.requestService.getUserData(); const options: TypeOrmModuleOptions = { type: 'postgres', host: userData.dbHost, port: userData.dbPort, username: userData.dbUsername, password: userData.dbPassword, database: userData.dbName, entities: [__dirname + '/../**/*.entity{.ts,.js}'], synchronize: true, }; return options; } }
In this example, RequestService is a hypothetical service used to retrieve user data from an API request. This approach allows each user to connect to a specific database instance based on their needs, which is particularly useful in multi-tenant applications.