'Why does Repository regenerate In NestJS
Import the module if you want the service to be used by another service. Why do you regenerate the repository instead of exporting it from the module?
Solution 1:[1]
It is about different topologies and ways to use DI in NestJS.
You may have some different architectures to work on it and all of them needs it's own way.
Example:
Assume that you have microservices and your models in your project defined as npm package
You are want to use Repository
pattern to keep your code clean and easy to use.
However, you need to set up your DI in project to make it work. Here is what happened next. You have some services that provides you an object of the Repository, where BaseRepository have all CRUD-operations and maybe something more.
some.service.ts
@Injectable()
export class StaticDataService {
constructor (
@Inject(TEMPLATE_RESPONSES) private readonly responsesRepository: BaseRepository<TemplateResponses>,
) {}
async getAllResponses() {
return await this.responsesRepository.find({ type: 'TUTORIAL_LINK' }, {})
}
async getLinks() {
const data = await this.responsesRepository.find({ type: 'SOCIAL_LINK' }, {})
return {
twitter: data[0].link,
instagram: data[1].link
}
}
}
For this service you may have such controller
:
@Controller()
export class StaticDataController {
constructor (
private readonly staticDataService: StaticDataService
) {}
@Get('/api/static')
async staticData () {
return await this.staticDataService.getAllResponses()
}
@Get('/api/links')
async getLinks () {
return await this.staticDataService.getLinks()
}
}
So the DI module will be something like this:
module.ts
@Module({
imports: [
return MongooseModule.forFeature([{name: TemplateResponse.name, schema: TemplateResponsesSchema}])
],
providers: [
{
provide: TEMPLATE_RESPONSES, // just string
useFactory: async (
instance: Model<typeof TemplateResponses> // type of the model for DB
) => {
return new BaseRepository(instance)
},
inject: [getModelToken(TemplateResponses)]
},
StaticDataService
],
controllers: [StaticDataController]
})
export class StaticDataModule {}
The thing you have to look at, is the line with return MongooseModule.forFeature([{name: TemplateResponse.name, schema: TemplateResponsesSchema}])
.
It provides an access to the collection.
However answering the question is, Nest have such philosophy to write it's own service for accessing to the database. But here is my workaround to import everything as a module and not to write a lot of Repositories here is an example with some helper functions:
providerAggregation.ts
<-- helper
export function providerAggregation<T = any> (REPOSITORY_TOKEN, MODEL_TOKEN) {
return {
provide: REPOSITORY_TOKEN,
useFactory: (model) => new BaseRepository(model),
inject: [MODEL_TOKEN]
}
}
dbAggregation.ts
<-- helper
export function dbAggregation<T = any> (MODEL, factory, databaseConnection) {
return {
provide: MODEL,
useFactory: factory,
inject: [databaseConnection]
}
}
repository.providers.ts
export const repositoryProviders = [
providerAggregation(MODEL_1_REPOSITORY, MODEL_1),
providerAggregation(MODEL_2_REPOSITORY, MODEL_2),
providerAggregation(MODEL_3_REPOSITORY, MODEL_3)
]
model.providers.ts
export const modelProviders = [
dbAggregation(MODEL_1, connectModel_1, DB_CONNECTION),
dbAggregation(MODEL_2, connectModel_2, DB_CONNECTION),
dbAggregation(MODEL_3, connectModel_3, DB_CONNECTION)
]
All of this now, you are exporting as 1 single module,DbModule
.
db.module.ts
import { Module } from '@nestjs/common'
import { databaseProviders } from './db.providers'
import { modelProviders } from './model.providers'
import { repositoryProviders } from './repository.providers'
@Module({
providers: [...databaseProviders, ...modelProviders, ...repositoryProviders],
exports: [...databaseProviders, ...modelProviders, ...repositoryProviders]
})
export class DbModule {}
Straight after that you will be available to use your repositories as a Module. Whenever you wanna to add controllers and services to your project, just provide specific aggregation that I showed above.
Example of updating:
model.providers.ts
export const modelProviders = [
dbAggregation(MODEL_1, connectModel_1, DB_CONNECTION),
dbAggregation(MODEL_2, connectModel_2, DB_CONNECTION),
dbAggregation(MODEL_3, connectModel_3, DB_CONNECTION),
dbAggregation(MODEL_4, connectModel_4, DB_CONNECTION), // <-- adding new instance as functions that helps you to not write spaghetti
]
repository.providers.ts
export const repositoryProviders = [
providerAggregation(MODEL_1_REPOSITORY, MODEL_1),
providerAggregation(MODEL_2_REPOSITORY, MODEL_2),
providerAggregation(MODEL_3_REPOSITORY, MODEL_3),
providerAggregation(MODEL_3_REPOSITORY, MODEL_3) // same as in code above
]
And now you have moved from this:
some.module.ts
@Module({
imports: [
return MongooseModule.forFeature([{name: TemplateResponse.name, schema: TemplateResponsesSchema}])
],
providers: [
{
provide: TEMPLATE_RESPONSES, // just string
useFactory: async (
instance: Model<typeof TemplateResponses> // type of the model for DB
) => {
return new BaseRepository(instance)
},
inject: [getModelToken(TemplateResponses)]
},
StaticDataService
],
controllers: [StaticDataController]
})
export class StaticDataModule {}
To this:
some.module.ts
@Module({
imports: [DbModule],
providers: [StaticDataService],
controllers: [StaticDataController]
})
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Daniil Sinelnik |