Sequelize Model 제네릭 타입 정의 Sequelize
의 Model
을 메서드의 매개변수등으로 전달 받거나 할때 특정한 하나의 Model
이 아닌 여러 Model
을 받아야 하는 경우가 있을 수 있습니다. 이 요구사항을 만족시키기 위해 Generic
타입을 지정하는 것은 보편적인 해결 방법입니다. 그렇다면 Sequelize Model
의 타입은 어떻게 Generic Type
으로 지정할 수 있는지 알아보겠습니다.
ModelCtor 타입 1 type ModelCtor <M extends Model = Model > = Repository <M>;
앞서 말한 케이스 같은 경우 ModelCtor
타입을 토대로 Generic
타입을 지정할 수 있습니다.ModelCtor
타입의 정의는 위와 같고 “sequelize-typescript”에 정의되어있습니다.
예시를 통한 사용방법 아래와 같은 요구사항이 있다고 가정하고 예시 코드를 살펴 보겠습니다.
요구사항
여러 Model과 Service에서 Pagination 기능을 포함하여야 한다.
결과 값과 조건에 해당하는 총 rows의 수를 반환한다.
해결 방법 메서드에서 <T extends Model>
제네릭 타입을 선언한 후, 매개변수의 model
의 타입을 ModelCtor<T>
로 정의합니다.
코드의 재사용성을 높이기 위해 BaseService
라는 Class
를 작성하였습니다. 어떤 모델이던 아래의 코드를 통해 API 호출시 filter
를 위한 쿼리 스트링을 sequelize where
객체로 변경하거나 페이지네이션을 위한 Offset
을 매번 계산할 필요가 없습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 import { Model , ModelCtor } from "sequelize-typescript" ;import QueryBuilder from "./common/query.builder" ;export class BaseService { public async findAllAndCountWithPage<T extends Model >( model : ModelCtor <T>, searchQuery : { query; sort; page; pageSize } ): Promise <{ rows : T[]; count : number }> { const { page, pageSize, sort, query } = searchQuery; const offset = this .getPaginationOffset (page, pageSize); return model.findAndCountAll ({ where : query, order : sort, offset : +offset, limit : +pageSize, }); } public buildSequelizeQuery (validKey, reqQuery ) { const query = QueryBuilder .buildFilterQuery (validKey, reqQuery); const sort = QueryBuilder .buildSortQuery (reqQuery.sort ); const page = reqQuery.page || 1 ; const pageSize = reqQuery.pageSize || 10 ; return { query, sort, page, pageSize }; } getPaginationOffset (page, pageSize ) { let offset = 0 ; if (page > 1 ) { offset = pageSize * (page - 1 ); } return offset; } }
요구사항을 만족하는 기능이 필요한 Service
에서 BaseService
를 상속받아 사용합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import { Injectable } from "@nestjs/common" ;import { BaseService } from "../common/service" ;import { InjectModel } from "@nestjs/sequelize" ;import { Book } from "./boook.model" ;@Injectable ()export class BooksService extends BaseService { constructor (@InjectModel (Book) private bookModel : typeof Book ) { super (); } async getBooks (reqQuery ) { const VALID_KEY = ["title" , "description" ]; const { query, sort, page, pageSize } = super .buildSequelizeQuery (VALID_KEY , reqQuery); return super .findAllAndCountWithPage (this .bookModel , { query, sort, page, pageSize }); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import { Controller , Get , Query } from "@nestjs/common" ;import { BooksService } from "./books.service" ;import { BaseController } from "../common/controller" ;@Controller ("books" )export class BooksController extends BaseController { constructor (private booksService : BooksService ) { super (); } @Get () async getUsers (@Query () query ) { return this .booksService .getBooks (query); } }