Joel Ochoa
Joel Ochoa

Reputation: 31

how can i generate a migration using TypeOrmModule.forRootAsync as the DataSource?

Trying to integrate migrations in a nest.js project I ran the migration:create command from typeorm and there was no problem, but when I try to generate a migration with migration:generate like this: yarn run typeorm migration:generate ./src/migrations -d ./src/database/database.provider.ts being ./src/migrations the folder where I want the migrations to be and ./src/database/database.provider.ts where I have my Datasource as I will show you in a moment, the point is that I got the following error: `

Error: Given data source file must contain export of a DataSource instance
    at Function.loadDataSource (C:\Proyectos\AmazingDigisignBackend\documents-service-nest\node_modules\src\commands\CommandUtils.ts:49:19)
    at async Object.handler (C:\Proyectos\AmazingDigisignBackend\documents-service-nest\node_modules\src\commands\MigrationGenerateCommand.ts:73:26)
Done in 3.74s.

this is database.provider.ts:

import {DynamicModule} from "@nestjs/common";
import {ConfigService} from "@nestjs/config";
import {TypeOrmModule} from "@nestjs/typeorm";
import {DataSourceOptions} from "typeorm";

export const DatabaseProvider: DynamicModule = TypeOrmModule.forRootAsync({
  inject: [ConfigService],
  async useFactory(config: ConfigService) {
    return {
      type: 'postgres',
      host: config.get('DATABASE_HOST'),
      username: config.get('DATABASE_USERNAME'),
      password: config.get('DATABASE_PASSWORD'),
      port: config.get('DATABASE_PORT'),
      database: config.get('DATABASE_NAME'),
      autoLoadEntities: true,
      synchronize: false,
      migrations: [__dirname + '/../src/migrations/*{.ts,.js}'],
    } as DataSourceOptions;
  }
})

and this is my database module:

import {Module} from '@nestjs/common';
import {DatabaseProvider} from './database.provider';

@Module({
  imports: [DatabaseProvider],
  exports: [DatabaseProvider]
})
export class DatabaseModule {
};

I have tried to use the old typeorm commands like:yarn run typeorm migration:generate -n newMigration . I have checked the documentation like a hundred times and nowhere do they tell you how to generate a migration using the typeormmoduleconfig as datasource, I was thinking of creating an ormconfig.json but I don't like it, if nothing else works I guess I wouldn't have much choice.

Upvotes: 3

Views: 1768

Answers (2)

kaleb teshale
kaleb teshale

Reputation: 89

In times of this, we revert back to node ;-) Its much better to use dotenv. try this Make a database module Add this provider database.provider.ts

import { registerAs } from "@nestjs/config";
import { config as dotenvConfig } from 'dotenv';
import { DataSource, DataSourceOptions } from "typeorm";

dotenvConfig({ path: '.env.dev' });

const config = {
    type: 'postgres',
    host: `${process.env.POSTGRES_HOST}`,
    port: `${process.env.POSTGRES_PORT}`,
    username: `${process.env.POSTGRES_USER}`,
    password: `${process.env.POSTGRES_PASSWORD}`,
    database: `${process.env.POSTGRES_DB}`,
    entities: ["dist/**/*.entity{.ts,.js}"],
    migrations: ["dist/migrations/*{.ts,.js}"],
    autoLoadEntities: true,
    synchronize: false,
}

export default registerAs('typeorm', () => config)
export const connectionSource = new DataSource(config as DataSourceOptions);

And for your database module

import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm';
import typeorm from './database.provider';


@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true, load: [typeorm]
    }), // Make ConfigModule global
    TypeOrmModule.forRootAsync({
      inject: [ConfigService],
      useFactory: async (configService: ConfigService) => (configService.get('typeorm'))
    }),
  ],
})
export class DatabaseModule { }

Add this to package json

"typeorm": "ts-node ./node_modules/typeorm/cli",
"migration:run": "npm run typeorm migration:run -- -d ./src/database/database.provider.ts",
"migration:generate": "npm run typeorm -- -d ./src/config/database.provider.ts migration:generate ./src/migrations/$npm_config_name",
"migration:create": "npm run typeorm -- migration:create ./src/migrations/$npm_config_name",
"migration:revert": "npm run typeorm -- -d ./src/database/database.provider.ts migration:revert"

Upvotes: 0

Enalla
Enalla

Reputation: 318

The file database.provider.ts that you are providing to the command yarn run typeorm migration:generate exports a NestJS dynamic module, not a DataSource that can be used by the TypeORM CLI.

However, you could add a function that build the DataSource options in database.provider.ts, and then reuse this function in a separate file to build the CLI's required configuration.

In your database.provider.ts :

import {DynamicModule} from "@nestjs/common";
import {ConfigService} from "@nestjs/config";
import {TypeOrmModule} from "@nestjs/typeorm";
import {DataSourceOptions} from "typeorm";

export const DatabaseProvider: DynamicModule = TypeOrmModule.forRootAsync({
  inject: [ConfigService],
  useFactory: buildDataSourceOptions
})

export function buildDataSourceOptions(configService: ConfigService): DataSourceOptions {
    return {
      type: 'postgres',
      host: config.get('DATABASE_HOST'),
      username: config.get('DATABASE_USERNAME'),
      password: config.get('DATABASE_PASSWORD'),
      port: config.get('DATABASE_PORT'),
      database: config.get('DATABASE_NAME'),
      autoLoadEntities: true,
      synchronize: false,
      migrations: [__dirname + '/../src/migrations/*{.ts,.js}'],
    };
}

and the configuration file for TypeORM cli, in a separate file (database.config.ts for example)

import { ConfigModule, ConfigService } from '@nestjs/config';
import { DataSource } from 'typeorm';
import { buildDataSourceOptions } from './database.provider';

// This will load environment values.
ConfigModule.forRoot(/* Pass here the same options that you would pass when
calling this method from your root module */);

// This will be used by the cli
export default new DataSource(buildDataSourceOptions(new ConfigService()));

Therefore, you could call the CLI this way :

yarn run typeorm migration:generate ./src/migrations -d ./src/database/database.config.ts

Also, the option autoLoadEntities is not supported by the TypeORM CLI. You could replace this option by something like this entities: ['dist/**/*.entity{.ts,.js}']

Upvotes: 0

Related Questions