简体   繁体   中英

NestJS - Dynamic Data Access Object service/provider

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.

eg

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.

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 */){ } }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM