Reputation: 384
Scenario
I'm trying to implement 3 level for APIs, controller -> Service -> DAO. As I don't want to create entity per module, and DAO will be dynamic.
Current Implementation
I want to have service/provider inside service which will dynamically instantiate based on which database model I pass.
e.g
I can have Module1, Module2 etc. Inside Module1
module1.controller.ts
import { Controller, Get } from '@nestjs/common';
import { AppService } from './module1.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
getHello(): Promise<any> {
return this.appService.getHello();
}
}
module1.service.ts
import { Inject, Injectable, Logger } from '@nestjs/common';
@Injectable()
export class AppService {
constructor(
@Inject('DB_CONNECTION') private db: any
) {}
async getHello(): Promise<any> {
const dao = this.daoService(this.db.h_users);
// execute methods of dao and return result
return ""
}
}
module1.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './module1.controller';
import { AppService } from './module1.service';
@Module({
imports: [],
controllers: [AppController],
providers: [AppService],
})
export class Module1Module {}
My DatabaseModule
database.provider.ts
init-models is from sequelie-auto
import { ConfigService } from '@nestjs/config';
import { Sequelize } from 'sequelize';
import { initModels } from '../models/init-models';
export const databaseProviders = [
{
inject: [ConfigService],
provide: 'DATABASE_CONNECTION',
useFactory: async (config: ConfigService): Promise<Object> => {
try {
const sequelize = new Sequelize(
config.get('DB_NAME') || '',
config.get('DB_USER') || '',
config.get('DB_PASS') || '',
{
dialect: config.get('DB_DIALECT') || 'mysql',
host: process.env.DB_HOST,
port: config.get('DB_PORT') || 3006,
define: {
timestamps: true,
},
pool: {
max: 5,
min: 0,
idle: 20000,
},
},
);
const db = initModels(sequelize);
return db;
} catch (error) {
throw error;
}
},
},
];
Now I've common DAO which have multiple method which is like wrapper on sequelize methods
dao.service.ts
import { Injectable } from '@nestjs/common';
/**
* Class reperesnt the Generic Data Acceess Object
*/
@Injectable()
export class DAOService {
/**
* @param {string} model - sequalize model
*/
declare model;
constructor(model: any) {
this.model = model;
}
/**
* Get a single record for specified model by unique idenntifier
*/
getRecordById = async (id: number) => {
try {
if (id) {
const record = await this.model.findOne({ where: { id: id } });
if (record !== null) {
return { success: true, data: record };
}
} else {
return { success: false };
}
return { success: false };
} catch (e) {
throw e;
}
};
}
database.module.ts
import { Global, Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { databaseProviders } from './database.provider';
import { databaseProvider2 } from './database.provider2';
@Global()
@Module({
imports: [ConfigModule],
providers: [...databaseProviders],
exports: [...databaseProviders],
})
export class DatabaseModule {}
Issue
I'm not able to figure out how to exactly move forward, I've tried to inject DAOService but it gives error.
If I do
database.module.ts
import { Global, Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { DAOService } from './dao.service';
import { databaseProviders } from './database.provider';
@Global()
@Module({
imports: [ConfigModule],
providers: [...databaseProviders, DAOService],
exports: [...databaseProviders, DAOService],
})
export class DatabaseModule {}
And try to inject and use inside Module1 service, I can't use it as I want to
import { Inject, Injectable, Logger } from '@nestjs/common';
import { DAOService } from '../database/dao.service';
@Injectable()
export class AppService {
// private daoService: DAO;
constructor(
@Inject('DB_CONNECTION') private db: any,
private daoService: DAOService,
) {}
async getHello(): Promise<any> {
const r = this.daoService(this.db.h_users);
// const r = await this.daoService.getAllRecords(1, 10, 1, 'DESC', '', {});
// Logger.log(JSON.stringify(r, null, 2));
return r;
}
}
Error
src/Module1/module1.service.ts:13:26 - error TS2349: This expression is not callable.
Type 'DAOService' has no call signatures.
Goal
My only goal is to have instantiate or have dynamic DAO based on which database model I pass and use it inside service and if possible I want to have DAOService extended if for some module I want to extend the functionality.
Upvotes: 1
Views: 179
Reputation: 61
I'm new to NestJS, but this is how I use a service inside another, maybe it can help
@Injectable()
export class Service1 {
constructor(
private DAOService: DAO
) {
this.DAOService.init();
}
async myMethod(data: any): Promise<any> {
await this.DAOService.myDAOFunction(/* param */);
}
}
/* DAO Service */
@Injectable({ scope: Scope.TRANSIENT })
export default class DAO {
private obj;
init() {
this.obj = new DAO();
}
async myDAOFunction(/* param */){
}
}
Upvotes: 1