Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does InjectRepository work internally in NestJS?

Tags:

In nestjs, I understand that

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

creates some kind of provider token so then I can inject the repository in my service (in same module) with this token.

What I don't understand is how @InjectRepository() works internally, for example:

constructor(
    @InjectRepository(TaskRepository)
    private taskRepository: TaskRepository,
  ) {}

How is InjectRepository custom decorator (which should have been created with createParamDecorator) able to inject a provider registered in a module? I researched and found out that createParamDecorator doesn't have ability to use DI. If createParamDecorator just creates a new TaskRepository instance and returns it, then why do I need to import TypeOrmModule.forFeature in module? Can someone explain how this works internally? Thanks!

like image 351
Mister M Avatar asked Jan 28 '21 13:01

Mister M


People also ask

What is @InjectRepository?

@InjectRepository() on the other hand is an extension of @Inject() that takes the currently passed entity/repository and uses some logic to create a new injection token. Generally, this logic is <EntityName>Repository sometimes with a connection added to it.

What is dependency injection in NestJS?

Dependency injection is an inversion of control (IoC) technique wherein you delegate instantiation of dependencies to the IoC container (in our case, the NestJS runtime system), instead of doing it in your own code imperatively.

What is TypeORM NestJS?

TypeORM Integration. For integrating with SQL and NoSQL databases, Nest provides the @nestjs/typeorm package. Nest uses TypeORM because it's the most mature Object Relational Mapper (ORM) available for TypeScript. Since it's written in TypeScript, it integrates well with the Nest framework.


1 Answers

You're on the right track, but @InjectRespoitory() and createParamDecorator() are generally two different decorator types. Yes they both work on parameters, but they generally have different use cases.

createParamDecorator works on controller, resolver, and gateway route handlers, so that Nest can know what part of the req, context, or payload object (or whatever other part of the ExecutionContext you want to get) should be put into the route handler's parameter position. The code behind that is a little complex, but I can point you to it if you get really curious.

@InjectRepository() on the other hand is an extension of @Inject() that takes the currently passed entity/repository and uses some logic to create a new injection token. Generally, this logic is <EntityName>Repository sometimes with a connection added to it. This token matches up with the created token from TypeormModule.forFeature() for the same entity. (Side note: if the entity passed is a repository, the token is just <EntityName> with the optional connection if it is not the default one).

You can try this out but getting rid of @InjectRepository() and instead using @Inject() just for testing purposes, but I wouldn't suggest that in a production server instance. Too many chances it will go wrong.

The really important thing to make note of here is that @InjectRepository() doesn't actually inject anything. It just sets up the metadata for Nest to read and match to a custom provider. TypeormModule.forFeature() is actually what's doing the heavy lifting here, creating a custom provider with a matching injection token and providing the right value for the provider.

By the way, @InjectRepository() and TypeormModule.forFeature() have to work together because Typescript cannot reflect generics properly. Normally with Nest we can use class names as injection tokens, but something like Repository<TaskEntity> just comes back as Repository so Nest wouldn't know which repository to inject. By using the @InjectRepository() decorator we are able to set the injection token metadata and override the reflected class value.

like image 58
Jay McDoniel Avatar answered Oct 12 '22 02:10

Jay McDoniel