Search code examples
modulerepositorynestjsentitytypeorm

What arguments of TypeOrmModule.forFeature() in TS should be?


I am trying to add repositories to my TypeOrmModule.forFeature(), which from what I understood, defines which repositories have been created.

Following the documentation, I saw that we could simply add the entity name, like : imports: [TypeOrmModule.forFeature([User])],

In another tutorial, I saw someone putting direcly the repository name into forFeature, such as follow :

imports: [TypeOrmModule.forFeature([UserRepository])],

In my current code, I am declaring few entities and repositories. Repositories are created using DataSource, for example :

export const WheelRepository = (src: DataSource) => src.getRepository(Wheel);

However, the only way I could make my code works is this way, which is a mix of two solutions above - while all my entities declarations are strictly similar as the one mentionned above : (here is a car.module.ts)

@Module({
    imports: [TypeOrmModule.forFeature([Car, Wheel, OptionRepository])], /* define repositories */
    controllers: [CarController, WheelController, OptionController],
    providers: [CarService, WheelService, OptionService],
})
export class CarModule {}

... so by explicitely naming "Repository" for my entity.

While this does not work :

@Module({
    imports: [TypeOrmModule.forFeature([Car, Wheel, Option])], /* define repositories */
    controllers: [CarController, WheelController, OptionController],
    providers: [CarService, WheelService, OptionService],
})
export class CarModule {}

Complete output :

[Nest] 18832  - 2022-06-22 16:34:13   ERROR [ExceptionHandler] Nest can't resolve dependencies of the OptionService (?). Please make sure that the argument OptionRepositoryRepository at index [0] is available in the CarModule context.

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

Error: Nest can't resolve dependencies of the OptionService (?). Please make sure that the argument OptionRepositoryRepository at index [0] is available in the CarModule context.

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

    at Injector.lookupComponentInParentModules (/Users/me/Documents/project_test/node_modules/@nestjs/core/injector/injector.js:231:19)
    at process._tickCallback (internal/process/next_tick.js:68:7)
    at Function.Module.runMain (internal/modules/cjs/loader.js:757:11)
    at startup (internal/bootstrap/node.js:283:19)
    at bootstrapNodeJSCore (internal/bootstrap/node.js:622:3)
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] start: `nest start`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the [email protected] start script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:

I have the same error when I try to change "Wheel" by "WheelRepository" in my list of imports.

I can not understand in which case I should be able to use one or another method, and why in this case I have to mix both.

[ EDIT ]

I found why by comparing files : in my OptionService constructor, I was injecting @InjectRepository(OptionRepository) instead of @InjectRepository(Option). I am still curious of knowing why this error happens because I do not understand the link between car module, which is like "above", and the injection in the service.


Solution

  • From what I understand from https://docs.nestjs.com/recipes/sql-typeorm and the source of @nestjs/typeorm

    TypeOrmModule.forFeature([...Entities]) imports TypeormModule providers coming from TypeormModule.forRoot() and make it available inside service using its provider token string.

    import { DataSource } from 'typeorm';
    import { Photo } from './photo.entity';
    
    export const photoProviders = [
      {
        provide: 'PHOTO_REPOSITORY', // provider token string
        useFactory: (dataSource: DataSource) => dataSource.getRepository(Photo),
        inject: ['DATA_SOURCE'],
      },
    ];
    

    and @InjectRepository(Photo) gives the provider token string and use it like any injectable provider.

    export class PhotoService {
      constructor(
        @Inject('PHOTO_REPOSITORY') //@InjectRepository(Photo)
        private photoRepository: Repository<Photo>,
      ) {}
    }
    

    when you put @InjectRepository(OptionRepository) in the constructor. @nestjs/typeorm couldn't resolve its provider token string because OptionRepository wasn't the thing you give to

    imports: [TypeOrmModule.forFeature([Car, Wheel, Option])]