nestjs / typeorm

TypeORM module for Nest framework (node.js) 🍇

Home Page:https://nestjs.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

InjectRepository not working for custom repositories in v8

fhervieux opened this issue · comments

I'm submitting a...


[x] Regression 
[ ] Bug report
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.

Current behavior

While trying to migrate an application from v7 to v8 I stumbled upon a change of behavior that looks like a regression. I have a custom repository that I want to inject in a service with @InjectRepository. Nest fails with an error "Nest can't resolve dependencies of the XxxService". The change of behavior seems to come from getRepositoryToken that used to return a string for a custom repository and now returns the object itself (here: https://github.com/nestjs/typeorm/blob/master/lib/common/typeorm.utils.ts#L39).

Expected behavior

I am not sure if returning something else that a string is valid as a token. It seemed to work fine in v7 with a string that is all I can say. Moreover removing the @InjectRepository works but it comes with another issue: when mocking in tests the best practice still seems to be using getRepositoryToken (https://docs.nestjs.com/techniques/database#testing) which in this case returns a string so it only works with the annotation.

Minimal reproduction of the problem with instructions

The issue can be reproduced with a simple entity repository

@EntityRepository(Cat)
export class CatRepository extends Repository<Cat> {}
@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: 'postgres',
      entities: [Cat],
    }),
    TypeOrmModule.forFeature([CatRepository]),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

Nest will fail to resolve the dependencies of this service:

@Injectable()
export class AppService {
  constructor(
    @InjectRepository(Cat)
    private readonly catRepository: CatRepository,
  ) {}
}

What is the motivation / use case for changing the behavior?

Environment


Nest version: 8.0.6
Nest/TypeOrm version : 8.0.2

 
For Tooling issues:
- Node version: v14.15.5  
- Platform:  Mac 

Others:

If you remove the @InjectRepository(Cat) (since you're using a custom repository, you don't need this) it will work?

Removing @InjectRepository(Cat) will work when starting the app. However then unit tests do no work anymore. I do something along those lines in my tests:

    const app: TestingModule = await Test.createTestingModule({
      controllers: [AppController],
      providers: [
        AppService,
        {
          provide: getRepositoryToken(Cat),
          useValue: {},
        },
      ],
    }).compile();

If I remove @InjectRepository(Cat) then this will fail with the same error: "Nest can't resolve dependencies of the AppService". It works if I keep the annotation.

what if you change getRepositoryToken(Cat) to getRepositoryToken(CatRepository)?

Indeed in v8 you can't use getRepositoryToken(Entity) if you don't annotate with @InjectRepository(Entity). But this is what the docs already states.

image

I'd say: remove all your @InjectRepository(Entity) if you're using custom repo and use getRepositoryToken(YourCustomRepo).

In v8, you should be able to replace this:

@Injectable()
export class AppService {
  constructor(
    @InjectRepository(Cat)
    private readonly catRepository: CatRepository,
  ) {}
}

with this:

@Injectable()
export class AppService {
  constructor(
    private readonly catRepository: CatRepository,
  ) {}
}

as for unit tests, change this:

{
  provide: getRepositoryToken(Cat),
  useValue: {},
},

to this:

{
  provide: CatRepository,
  useValue: {},
},