Search code examples
typescriptnestjsrepositorytypeorm

How to migrate from TypeOrm custom repository to Injectable NestJs providers


I've just upgraded typeorm to version 0.3.12 and @nestjs/typeorm at version 9.0.1

I read here that the recommended approach is this one: https://gist.github.com/anchan828/9e569f076e7bc18daf21c652f7c3d012?permalink_comment_id=4319458#gistcomment-4319458

So I transformed all my custom repositories accordingly.

But moving those dependencies into the providers metadata of the createTestingModule doesn't seem to be enough.

Maybe this line dailyTaskRepository = module.get<TypeOrmDailyTaskRepository>(TypeOrmDailyTaskRepository) is obsolete, but then I don't know how I am suppose to retrieve the provider from the module.

Here is the full code:

daily-task.typeorm.inte.ts

import { TypeOrmModule } from '@nestjs/typeorm'
import { config } from '../../../config'
import { Test } from '@nestjs/testing'
import { TypeOrmDailyTaskRepository } from './daily-task.typeorm.repository'
import { dailyTaskDataBuilder } from '../data-builders/daily-task.data-builder'
import { DailyTask } from '../entities/daily-task.entity'
import { TypeOrmExerciseRepository } from '../../exercise/repositories/type-orm-exercise.repository'
import { TypeOrmAthleteRepository } from '../../athlete/repositories/typeorm-athlete.repository'
import { TypeOrmProgramRepository } from '../../program/repositories/type-orm-program.repository'
import { TypeOrmBiometricsRepository } from '../../biometrics/repositories/typeorm-biometrics.repository'
import { TypeOrmExerciseTemplateRepository } from '../../exercise/repositories/type-orm-exercise-template.repository'
import { TypeOrmWorkoutRepository } from '../../workout/repositories/workout.typeorm.repository'
import { TypeOrmSessionRepository } from '../../session/repositories/session.typeorm.repository'
import { TypeOrmPerformanceRepository } from '../../performance/repositories/performance.typeorm.repository'
import { BaseEntity } from '../../__infrastructure__/typeorm/base.entity'

const dailyTasksFixtures = [dailyTaskDataBuilder(), dailyTaskDataBuilder()]

async function generateDailyTasksFixtures(
  dailyTaskRepository: TypeOrmDailyTaskRepository,
) {
  await dailyTaskRepository.save(dailyTasksFixtures)
}

describe('TypeOrm DailyTask Repository', () => {
  let dailyTaskRepository: TypeOrmDailyTaskRepository

  beforeAll(async () => {
    const module = await Test.createTestingModule({
      imports: [TypeOrmModule.forRoot(config.db)],
      providers: [
        TypeOrmAthleteRepository,
        TypeOrmBiometricsRepository,
        TypeOrmDailyTaskRepository,
        TypeOrmExerciseRepository,
        TypeOrmExerciseTemplateRepository,
        TypeOrmProgramRepository,
        TypeOrmWorkoutRepository,
        TypeOrmSessionRepository,
        TypeOrmPerformanceRepository,
        DailyTask,
        BaseEntity,
      ],
    }).compile()

    dailyTaskRepository = module.get<TypeOrmDailyTaskRepository>(
      TypeOrmDailyTaskRepository,
    )

    await dailyTaskRepository.query('SET FOREIGN_KEY_CHECKS=0')
    await dailyTaskRepository.query(`DELETE FROM daily_task;`)
    await generateDailyTasksFixtures(dailyTaskRepository)
  })

  afterAll(async () => {
    await dailyTaskRepository.query('SET FOREIGN_KEY_CHECKS=0')
    await dailyTaskRepository.query(`DELETE FROM daily_task;`)
  })

  it('should be defined', () => {
    expect(dailyTaskRepository).toBeDefined()
  })

  it('should get all daily tasks', async () => {
    const expectedDailyTasks = [
      new DailyTask(dailyTasksFixtures[0]),
      new DailyTask(dailyTasksFixtures[1]),
    ]

    const retrievedDailyTasks = await dailyTaskRepository.getAll()

    expect(retrievedDailyTasks).toStrictEqual(expectedDailyTasks)
  })
})

The console error:

yarn run v1.22.17
$ jest --testTimeout=10000 -c jest-inte.json --runInBand --forceExit src/daily-task/repositories/daily-task.typeorm.repository.inte.ts -t 'should be defined'
 FAIL  src/daily-task/repositories/daily-task.typeorm.repository.inte.ts (5.365 s)
  TypeOrm DailyTask Repository
    ✕ should be defined (2 ms)
    ○ skipped should get all daily tasks

  ● TypeOrm DailyTask Repository › should be defined

    Nest can't resolve dependencies of the DailyTask (?). Please make sure that the argument Object at index [0] is available in the RootTestModule context.

    Potential solutions:
    - If Object is a provider, is it part of the current RootTestModule?
    - If Object is exported from a separate @Module, is that module imported within RootTestModule?
      @Module({
        imports: [ /* the Module containing Object */ ]
      })

      at Injector.lookupComponentInParentModules (node_modules/@nestjs/core/injector/injector.js:188:19)
      at Injector.resolveComponentInstance (node_modules/@nestjs/core/injector/injector.js:144:33)
      at resolveParam (node_modules/@nestjs/core/injector/injector.js:98:38)
          at async Promise.all (index 0)
      at Injector.resolveConstructorParams (node_modules/@nestjs/core/injector/injector.js:113:27)
      at Injector.loadInstance (node_modules/@nestjs/core/injector/injector.js:46:9)
      at Injector.loadProvider (node_modules/@nestjs/core/injector/injector.js:68:9)
          at async Promise.all (index 12)
      at InstanceLoader.createInstancesOfProviders (node_modules/@nestjs/core/injector/instance-loader.js:43:9)
      at node_modules/@nestjs/core/injector/instance-loader.js:28:13

  ● TypeOrm DailyTask Repository › should be defined

    expect(received).toBeDefined()

    Received: undefined

      59 |
      60 |   it('should be defined', () => {
    > 61 |     expect(dailyTaskRepository).toBeDefined()
         |                                 ^
      62 |   })
      63 |
      64 |   it('should get all daily tasks', async () => {

      at Object.<anonymous> (src/daily-task/repositories/daily-task.typeorm.repository.inte.ts:61:33)

  ● TypeOrm DailyTask Repository › should get all daily tasks

    Nest can't resolve dependencies of the DailyTask (?). Please make sure that the argument Object at index [0] is available in the RootTestModule context.

    Potential solutions:
    - If Object is a provider, is it part of the current RootTestModule?
    - If Object is exported from a separate @Module, is that module imported within RootTestModule?
      @Module({
        imports: [ /* the Module containing Object */ ]
      })

      at Injector.lookupComponentInParentModules (node_modules/@nestjs/core/injector/injector.js:188:19)
      at Injector.resolveComponentInstance (node_modules/@nestjs/core/injector/injector.js:144:33)
      at resolveParam (node_modules/@nestjs/core/injector/injector.js:98:38)
          at async Promise.all (index 0)
      at Injector.resolveConstructorParams (node_modules/@nestjs/core/injector/injector.js:113:27)
      at Injector.loadInstance (node_modules/@nestjs/core/injector/injector.js:46:9)
      at Injector.loadProvider (node_modules/@nestjs/core/injector/injector.js:68:9)
          at async Promise.all (index 12)
      at InstanceLoader.createInstancesOfProviders (node_modules/@nestjs/core/injector/instance-loader.js:43:9)
      at node_modules/@nestjs/core/injector/instance-loader.js:28:13

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 skipped, 2 total
Snapshots:   0 total
Time:        5.42 s, estimated 9 s
Ran all test suites matching /src\/daily-task\/repositories\/daily-task.typeorm.repository.inte.ts/i with tests matching "should be defined".
Force exiting Jest: Have you considered using `--detectOpenHandles` to detect async operations that kept running after all tests finished?
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
➜  back git:(migrate/typeorm) ✗

Solution

  • I found it thanks to this thread: https://stackoverflow.com/a/74729950/11698446

    I needed to use TypeOrmModule.forFeatue() and pass it all the entities. Hence this code:

      beforeAll(async () => {
        const module = await Test.createTestingModule({
          imports: [
            TypeOrmModule.forRoot(config.db),
            TypeOrmModule.forFeature([
              DailyTask,
              Athlete,
              Biometrics,
              DailyTask,
              Exercise,
              ExerciseTemplate,
              Program,
              Workout,
              Session,
              Performance,
            ]),
          ],
          providers: [
            TypeOrmAthleteRepository,
            TypeOrmBiometricsRepository,
            TypeOrmDailyTaskRepository,
            TypeOrmExerciseRepository,
            TypeOrmExerciseTemplateRepository,
            TypeOrmProgramRepository,
            TypeOrmWorkoutRepository,
            TypeOrmSessionRepository,
            TypeOrmPerformanceRepository,
          ],
        }).compile()
    
        dailyTaskRepository = module.get<TypeOrmDailyTaskRepository>(
          TypeOrmDailyTaskRepository,
        )
    
        await dailyTaskRepository.query('SET FOREIGN_KEY_CHECKS=0')
        await dailyTaskRepository.query(`DELETE FROM daily_task;`)
        await generateDailyTasksFixtures(dailyTaskRepository)
      })