I am running nestjs and I want to make an async provider. Here is my folder structure
.
├── dist
│ └── main.js
├── libs
│ └── dma
│ ├── src
│ │ ├── client
│ │ │ ├── client.module.ts
│ │ │ ├── client.service.spec.ts
│ │ │ └── client.service.ts
│ │ ├── cmts
│ │ │ ├── cmts.module.ts
│ │ │ ├── cmts.service.spec.ts
│ │ │ └── cmts.service.ts
│ │ ├── dma.module.ts
│ │ └── index.ts
│ └── tsconfig.lib.json
├── nest-cli.json
├── package.json
├── package-lock.json
├── README.md
├── src
│ ├── app.controller.spec.ts
│ ├── app.controller.ts
│ ├── app.module.ts
│ ├── app.service.ts
│ └── main.ts
├── test
│ ├── app.e2e-spec.ts
│ └── jest-e2e.json
├── tsconfig.build.json
└── tsconfig.json
I want to make the ClientService
an async provider.
- I want the Async operation of db connect to run first.
- after that any dependent provider can start calling the sendSql() method.
And here are my files:
~/src/app.module.ts
import { Module } from '@nestjs/common'
import { AppController } from './app.controller'
import { AppService } from './app.service'
import { DmaModule } from '@app/dma'
@Module({
imports: [DmaModule],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
~/src/app.service.ts
import { CmtsService } from '@app/dma/cmts/cmts.service'
import { Injectable } from '@nestjs/common'
@Injectable()
export class AppService {
constructor(private readonly cmtsService: CmtsService) {}
getHello(): string {
return 'Hello World!'
}
}
~/libs/dma/client/client.module.ts
import { Module } from '@nestjs/common'
import { ClientService } from './client.service'
@Module({
providers: [ClientService],
exports: [ClientService],
})
export class ClientModule {}
~/libs/dma/client/client.service.ts
import { Injectable } from '@nestjs/common'
@Injectable()
export class ClientService {
dbConnection: any;
async connectToDb(){
// connection logic...
this.dbConnection = theConnectionObject;
}
async sendSql(sql: string){
const result = await dbConnection.send(sql) // for example
return result
}
}
~/libs/dma/cmts/cmts.module.ts
import { Module } from '@nestjs/common'
import { CmtsService } from './cmts.service'
import { ClientModule } from '../client/client.module'
@Module({
imports: [ClientModule],
providers: [CmtsService],
exports: [CmtsService],
})
export class CmtsModule {}
~/libs/dma/cmts.service.ts
import { Injectable } from '@nestjs/common'
import { ClientService } from '../client/client.service'
@Injectable()
export class CmtsService {
constructor(private readonly clientService: ClientService) {}
}
On the nestjs documentation, here’s what’s written: here
It’s written that you can do this:
{
provide: 'ASYNC_CONNECTION',
useFactory: async () => {
const connection = await createConnection(options);
return connection;
},
}
But my question is.. isn’t it a bad practice to create an instance from the provider ourselves?
Because now I will have to do this:
{
provide: 'ASYNC_CONNECTION',
useFactory: async () => {
const clientService = new ClientService() // 👎 bad practice (?)
const connection = await clientService.connectDb();
return connection;
},
}
4
This is database.providers.ts where the connection is initiatied
export const databaseProviders = [
{
provide: 'DbConnectionToken',
useFactory: async (
environmentSettingsService: EnvironmentSettingsService
): Promise<typeof mongoose> => {
mongoose.set({ strict: false });
return await mongoose.connect(
process.env.isApiTestRunning
? testDatabaseUrl
: environmentSettingsService.config.get('usersdb')
);
},
inject: [EnvironmentSettingsService],
},
];
My schema token provider class – where i inject the schema with initiated connection. MyAppPRoviders.ts
export const MyAppProviders = [
{
provide: modelTokens.UsersToken,
useFactory: (connection: Connection) => connection.model(dbCollections.users, UsersSchema),
inject: ["DbConnectionToken"],
},
You will have to initiate these in your modules – i am assuming you already know this
How to use these schema provider token in services? I will inject below in one of my service class where i want to use the user model to perform DB operation on users collection
Injectable()
export class UserCrud {
private similaritySearch: any;
constructor(
@Inject(modelTokens.UsersToken)
private usersModel: Model<any>)
{}
// Your code
//using userModel
await this.usersModel.findOne({}).....
....
}