mangei
mangei

Reputation: 817

NestJS - inject service into typeorm migration

I would like to inject a service into a typeorm migration, so that I can perform data migration based on some logic within a service:

import { MigrationInterface, QueryRunner, Repository } from 'typeorm';
import { MyService } from '../../services/MyService.service';
import { MyEntity } from '../../entities/MyEntity.entity';

export class MyEntityMigration12345678
  implements MigrationInterface
{
  name = 'MyEntityMigration12345678';

  constructor(
    private readonly myService: MyService,
  ) {}

  public async up(queryRunner: QueryRunner): Promise<void> {
    const myEntityRepository: Repository<MyEntity> =
      queryRunner.connection.getRepository<MyEntity>(MyEntity);

    const entities = await myEntityRepository.findBy({
      myColumn: '',
    });

    for (const entity of entities) {
      const columnValue = this.myService.getColumnValue(myEntity.id);
      await myEntityRepository.save({
        ...entity,
        myColumn: columnValue,
      });
    }
  }

  // ...
}

Nevertheless

How can I do a migration based on business logic?

Thanks!

Upvotes: 1

Views: 2272

Answers (1)

Jay McDoniel
Jay McDoniel

Reputation: 70600

One option would be to write whatever query myService.getColumn value does inside your migration. If you're hell bent on using Nest's DI inside your migration then you could do something like this:

import { NestFactory } from '@nestjs/core';
import { MigrationInterface, QueryRunner, Repository } from 'typeorm';
import { AppModule } from '../../app.module'; // assumed path
import { MyService } from '../../services/MyService.service';
import { MyEntity } from '../../entities/MyEntity.entity';

export class MyEntityMigration12345678
  implements MigrationInterface
{
  name = 'MyEntityMigration12345678';

  public async up(queryRunner: QueryRunner): Promise<void> {
    const myEntityRepository: Repository<MyEntity> =
      queryRunner.connection.getRepository<MyEntity>(MyEntity);

    const entities = await myEntityRepository.findBy({
      myColumn: '',
    });
    const appCtx = await NestFactory.createApplicationContext(AppModule);
    const myService = app.get(MyService, { strict: false });
    for (const entity of entities) {
      const columnValue = myService.getColumnValue(myEntity.id);
      await myEntityRepository.save({
        ...entity,
        myColumn: columnValue,
      });
    }
    await app.close();
  }

  // ...
}

You can't use injection inside the migration because the class itself is managed by TypeORM. You can, as shown above, create a NestApplicationContext instance and get the MyService instance from that. This only works, by the way, if MyService is REQUEST scoped

Upvotes: 4

Related Questions