我需要为 Nestjs 和 typeorm 中的控制器和服务创建一个可重用的类

i need to create a reusable classes for the controllers and services in Nestjs & typeorm

提问人:kassem moghraby 提问时间:11/6/2023 更新时间:11/6/2023 访问量:30

问:

我为 BaseController 和 BaseService 创建了抽象类,并将动态权限传递给每个方法,我的问题是 DTo,我如何将动态 Dto 传递给每个方法?

你认为在构造函数级别传递它们好吗??

`

import { BaseEntity, DeepPartial } from "typeorm";
import { BaseService } from "./base.service";
import { Body, Delete, Get, Patch, Post } from "@nestjs/common";
import { ID } from "@/decorators/common.decorator";
import { ResourceTypes } from "@/types/permission.types";
import { PermissionAccess } from "@/decorators/roles.decorator";
import { ControllerInterface } from "./controller.interface";

export abstract class BaseController<T extends BaseEntity,DtoAdd,DtoEdit> implements ControllerInterface<BaseEntity>{

  protected constructor(private readonly baseService: BaseService<T>,
                        private readonly resource: ResourceTypes) {

  }

  @PermissionAccess({ resource: this.resource, action: "all", possession: "any" })
  @Get("all")
  async findAllElements(): Promise<T[]> {
    return this.baseService.findAll();
  }

  @PermissionAccess({ resource: this.resource, action: "read", possession: "any" })
  @Get(":id")
  async findElement(@ID() id: number): Promise<T> {
    return this.baseService.findOneById(id);
  }

  @PermissionAccess({ resource: this.resource, action: "create", possession: "any" })
  @Post()
  async createElement(@Body() payload: DtoAdd): Promise<T> {
    return await this.baseService.createOne(payload);
  }

  @PermissionAccess({ resource: this.resource, action: "edit", possession: "any" })
  @Patch(":id")
  async updateElementById(@ID() id: number,@Body() payload: DtoEdit): Promise<T> {
    return this.baseService.updateOneById(id, payload);
  }

  @PermissionAccess({ resource: this.resource, action: "remove", possession: "any" })
  @Delete(":id")
  async deleteElement(@ID() id: number): Promise<void> {
    await this.baseService.deleteOne(id);
  }
}

对应于以下 intrepjected 的 BaseService:

import { BasicEntity } from "@/entities/basic.entity";
import { DeepPartial, Repository } from "typeorm";
import { HttpException, HttpStatus } from "@nestjs/common";
import { ListPaginatedService } from "./list-paginated.service";
import { BaseServiceInterface } from "./base-service.interface";

export abstract class BaseService<T extends BasicEntity> extends ListPaginatedService <T> implements BaseServiceInterface<T>{
  protected constructor(private readonly repository: Repository<T>) {
    super(repository);}

  async findAll(): Promise<T[]> {
    return this.repository.find();
  }

  async findOneById(id: number): Promise<T> {
    return this.repository.findOneBy(id);
  }

  async createOne(_payload: DeepPartial<T>): Promise<T> {
    const entity = this.repository.create(_payload);
    return await this.repository.save(entity);
  }

  async updateOneById(id: number, _payload: DeepPartial<T>): Promise<T> {
    const _elementObject:T = await this.getOneByField('id', _payload)
    Object.assign(_elementObject,_payload)
    // await this.repository.update(id, _elementObject); // Number of affected rows
    // not used because i need to return the new state for obj to user
    await this.repository.save(_elementObject)
  }

  async deleteOne(id: number): Promise<void> {
    await this.repository.delete(id);
  }

  async getOneByField(_byField:keyof T,_payload:DeepPartial<T>):Promise<T>{
    try {
      const _existenceDb:T = await this.repository.findOneBy(
        {[_byField]:_payload[_byField]}
      )
      if(!_existenceDb){
        throw new HttpException('the element not found in database to make the changes !', HttpStatus.NOT_FOUND)
      }
      return _existenceDb
    }catch (error){
      throw new HttpException('internal error happened !,' + error.toString(), HttpStatus.INTERNAL_SERVER_ERROR)
    }
  }
  async isValueNotInUse(_byField:keyof T,_payload:DeepPartial<T>):Promise<void>{
    try {
      const _existenceDb:T = await this.repository.findOneBy(
        {[_byField]:_payload[_byField]}
      )
      if(_existenceDb){
        throw new HttpException(`the${_payload} with value ${_payload[_byField]} already taken !`, HttpStatus.NOT_FOUND)
      }
    }catch (error){
    throw new HttpException('internal error happened !,' + error.toString(), HttpStatus.INTERNAL_SERVER_ERROR)
  }

  }
  abstract excludeResponseField(_element:T):DeepPartial<T>

  buildResponse(_element:T){  // its better to replace it with interceptor
    return {
      data:_element,
      success:true
    }
  }



}

使用的接口:

export interface BaseServiceInterface<T extends BasicEntity> {
  findAll(): Promise<T[]>;
  findOneById(id: number): Promise<T>;
  createOne(_payload: DeepPartial<T>): Promise<T>;
  updateOneById(id: number, _payload: DeepPartial<T>): Promise<T>;
  deleteOne(id: number): Promise<void>;
}


export interface ControllerInterface<T>{
  findAllElements(): Promise<T[]>
  findElement(@ID() id: number): Promise<T>
  createElement(data: DeepPartial<T>): Promise<T>
  updateElementById(@ID() id: number, _payload: DeepPartial<T>): Promise<T>
  deleteElement(@ID() id: number): Promise<void>
}

model-view-controller 依赖注入 抽象类 typescript-generics nestjs-typeorm

评论

0赞 kassem moghraby 11/6/2023
在 BaseService 中,我们有 createOne 和 payload : DeepPartial<T>,它必须是 DtoCreate = 类型,应该是动态的,并且在 BaseController 中,_payload props 必须是动态 Dto 的。有没有合适的方法可以做到这一点???
0赞 kassem moghraby 11/6/2023
你认为这个抽象的控制器是不方便的,不一定是这样做的吗?

答: 暂无答案