Search code examples
typescriptnestjsdatasourcetypeorm

How do I separate my Typeorm data source config into a separate variable?


I'm using NestJS 10 and TypeORM 0.3.17. I have this src/config/data-source.ts file ...

import * as dotenv from 'dotenv';
import * as dotenvExpand from 'dotenv-expand';
import { DataSource } from 'typeorm';

dotenvExpand.expand(dotenv.config());

export default new DataSource({
  type: 'postgres',
  host: process.env.DATABASE_HOST,
  port: Number(process.env.DATABASE_PORT) || 5432,
  database: process.env.DATABASE_NAME,
  username: process.env.DATABASE_USERNAME,
  password: process.env.DATABASE_PASSWORD,
  entities: ['dist/**/*.entity.js'],
  migrations: ['dist/database/migrations/*.js'],
  extra: {
    charset: 'utf8mb4_unicode_ci',
  },
 });

I would like to separate the argument as a variable so that I can export it for use in my src/config/typeorm.ts file, which has duplicate code ...

import { ConfigModule, ConfigService } from '@nestjs/config';
import {
  TypeOrmModuleAsyncOptions,
  TypeOrmModuleOptions,
} from '@nestjs/typeorm';

export const typeOrmAsyncConfig: TypeOrmModuleAsyncOptions = {
  imports: [ConfigModule],
  inject: [ConfigService],
  useFactory: async (): Promise<TypeOrmModuleOptions> => {
    return {
      type: 'postgres',
      host: process.env.DATABASE_HOST,
      port: Number(process.env.DATABASE_PORT) || 5432,
      database: process.env.DATABASE_NAME,
      username: process.env.DATABASE_USERNAME,
      password: process.env.DATABASE_PASSWORD,
      synchronize: false,
      logging: true,
    };
  },
};

export const typeOrmConfig: TypeOrmModuleOptions = {
    type: 'postgres',
    host: process.env.DB_HOST,
    port: parseInt(process.env.DB_PORT, 10),
    username: process.env.DB_USERNAME,
    database: process.env.DB_NAME,
    password: process.env.DB_PASSWORD,
    entities: ['dist/**/*.entity.js'],
    migrations: ['dist/migrations/**/*.js'],
    extra: {
      charset: 'utf8mb4_unicode_ci',
    },
    logging: true,
};

but when I attempt to refactor my src/config/data-source.ts file like so

export const dsConfig = {
    type: 'postgres',
    host: process.env.DATABASE_HOST,
    port: Number(process.env.DATABASE_PORT) || 5432,
    database: process.env.DATABASE_NAME,
    username: process.env.DATABASE_USERNAME,
    password: process.env.DATABASE_PASSWORD,
    entities: ['dist/**/*.entity.js'],
    migrations: ['dist/database/migrations/*.js'],
    extra: {
      charset: 'utf8mb4_unicode_ci',
    },
   };

export default new DataSource(dsConfig);

I get the error

    Argument of type '{ type: string; host: string; port: number; database: string; username: string; password: string; entities: string[]; migrations: string[]; extra: { charset: string; }; }' is not assignable to parameter of type 'DataSourceOptions'.
  Type '{ type: string; host: string; port: number; database: string; username: string; password: string; entities: string[]; migrations: string[]; extra: { charset: string; }; }' is missing the following properties from type 'AuroraMysqlConnectionOptions': region, secretArn, resourceArn

on the line "export default new DataSource(dsConfig);". How do I properly refactor my data source configuration file?


Solution

  • you can see around my repo to separate config data source file in app.module.ts file:

        TypeOrmModule.forRootAsync(typeOrmAsyncConfig),
    
    

    your config file:

    const config: ConfigService = new ConfigService();
    const dbConfig = {
    type: 'postgres' as const,
      host: config.get<string>('DATABASE_HOST'),
      port: config.get<number>('DATABASE_PORT'),
      database: config.get<string>('DATABASE_NAME'),
      username: config.get<string>('DATABASE_USER'),
      password: config.get<string>('DATABASE_PASS'),
      entities: ['dist/**/*.entity.{ts,js}'],
      migrations: ['dist/migrations/*.{ts,js}'],
      migrationsRun: true,
      migrationsTableName: 'typeorm_migrations',
      synchronize: false,
      ssl: config.get('SSL_MODE', false),
      cli: {
        migrationsDir: 'src/migrations',
      },
      logging: true,
    }
    
    export const typeOrmAsyncConfig: TypeOrmModuleAsyncOptions = {
      useFactory: async (): Promise<TypeOrmModuleOptions> => {
        return dbConfig;
      },
    };
    export default new DataSource(dbConfig);
    

    your package.json file:

        "typeorm": "ts-node ./node_modules/typeorm/cli.js -d src/utils/config/database/config.service.ts",
        "migration:generate": "npm run build && npm run typeorm -- migration:generate ./src/migrations/$npm_config_name",
        "migration:run": "npm run typeorm -- migration:run",
        "migration:create": "ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli migration:create ./src/migrations/$npm_config_name",
        "migration:revert": "npm run typeorm -- migration:revert"
    

    and your command will be like this below:

    npm run migration:generate --name=<your_migration_name> //auto generate migration with entities
    npm run migration:create --name=<your_migration_name> //create empty migration file
    npm run migration:revert    //revert your last migration
    npm run migration:run // in case you set `migrationsRun: false` in your config and run it manually