From ee541466156ac735d54d8c0356c2495c22456f87 Mon Sep 17 00:00:00 2001 From: Supan Adit Pratama Date: Fri, 1 Nov 2024 17:16:36 +0700 Subject: [PATCH] fix: pagination not a number format by dto --- .../src/processes/pagination.process.ts | 6 +-- libs/skeleton/src/decoratos/index.ts | 1 + .../skeleton-controller.decorator.ts | 5 +++ libs/skeleton/src/dto/index.ts | 1 + libs/skeleton/src/dto/pagination.dto.ts | 15 +++++++ .../src/executors/pagination.executor.ts | 8 ++-- libs/skeleton/src/index.ts | 11 +++-- .../skeleton-crud.controller.interface.ts | 4 +- .../interfaces/pagination-param.interface.ts | 4 ++ .../src/processes/pagination.process.ts | 3 +- libs/skeleton/src/skeleton-crud.controller.ts | 13 +++--- package-lock.json | 44 ++++++++++++++++++- package.json | 4 +- src/example/simple/simple.controller.ts | 3 +- 14 files changed, 99 insertions(+), 23 deletions(-) create mode 100644 libs/skeleton/src/decoratos/index.ts create mode 100644 libs/skeleton/src/decoratos/skeleton-controller.decorator.ts create mode 100644 libs/skeleton/src/dto/index.ts create mode 100644 libs/skeleton/src/dto/pagination.dto.ts create mode 100644 libs/skeleton/src/interfaces/pagination-param.interface.ts diff --git a/libs/prisma/src/processes/pagination.process.ts b/libs/prisma/src/processes/pagination.process.ts index 137947a..8c0c32d 100644 --- a/libs/prisma/src/processes/pagination.process.ts +++ b/libs/prisma/src/processes/pagination.process.ts @@ -1,11 +1,12 @@ import { PaginationProcess } from '@aditama-labs/nest-autocrud/skeleton'; import { PrismaProcess } from './prisma.process'; +import { IPaginationParam } from '@aditama-labs/nest-autocrud/skeleton/src/interfaces/pagination-param.interface'; export class PrismaPaginationProcess extends PrismaProcess implements PaginationProcess { - public params: { page: number; limit: number }; + params: IPaginationParam; async process(): Promise { const { page, limit } = this.params; @@ -13,8 +14,7 @@ export class PrismaPaginationProcess this.result = await this.getDelegate().findMany({ skip, - // @TODO: I don't know why this actually string even the type is number, without parseInt it will throw error - take: parseInt(limit.toString(), 10), + take: limit, }); } } diff --git a/libs/skeleton/src/decoratos/index.ts b/libs/skeleton/src/decoratos/index.ts new file mode 100644 index 0000000..4e327db --- /dev/null +++ b/libs/skeleton/src/decoratos/index.ts @@ -0,0 +1 @@ +export * from './skeleton-controller.decorator'; diff --git a/libs/skeleton/src/decoratos/skeleton-controller.decorator.ts b/libs/skeleton/src/decoratos/skeleton-controller.decorator.ts new file mode 100644 index 0000000..8a5e32d --- /dev/null +++ b/libs/skeleton/src/decoratos/skeleton-controller.decorator.ts @@ -0,0 +1,5 @@ +export function SkeletonController(): ClassDecorator { + return (target: object) => { + console.log('STARTED', target); + }; +} diff --git a/libs/skeleton/src/dto/index.ts b/libs/skeleton/src/dto/index.ts new file mode 100644 index 0000000..5f10edb --- /dev/null +++ b/libs/skeleton/src/dto/index.ts @@ -0,0 +1 @@ +export * from './pagination.dto'; diff --git a/libs/skeleton/src/dto/pagination.dto.ts b/libs/skeleton/src/dto/pagination.dto.ts new file mode 100644 index 0000000..cc3e1d9 --- /dev/null +++ b/libs/skeleton/src/dto/pagination.dto.ts @@ -0,0 +1,15 @@ +import { Transform } from 'class-transformer'; +import { IsNotEmpty, IsNumber, IsNumberString } from 'class-validator'; +import { IPaginationParam } from '../interfaces/pagination-param.interface'; + +export class PaginationParamDTO implements IPaginationParam { + @IsNotEmpty() + @IsNumber() + @Transform((data) => parseInt(data.value)) + page: number; + + @IsNotEmpty() + @IsNumber() + @Transform((data) => parseInt(data.value)) + limit: number; +} diff --git a/libs/skeleton/src/executors/pagination.executor.ts b/libs/skeleton/src/executors/pagination.executor.ts index 54fd728..fbde373 100644 --- a/libs/skeleton/src/executors/pagination.executor.ts +++ b/libs/skeleton/src/executors/pagination.executor.ts @@ -1,11 +1,9 @@ import { DefaultExecutor } from '.'; +import { PaginationParamDTO } from '../dto'; import { PaginationProcess } from '../processes'; export class PaginationExecutor extends DefaultExecutor { - constructor( - process: PaginationProcess, - params: { page: number; limit: number }, - ) { + constructor(process: PaginationProcess, params: PaginationParamDTO) { super(process); // Set params to process process.params = params; @@ -13,7 +11,7 @@ export class PaginationExecutor extends DefaultExecutor { static async bootstrap( process: PaginationProcess, - params: { page: number; limit: number }, + params: PaginationParamDTO, ): Promise { const executor = new PaginationExecutor(process, params); await executor.execute(); diff --git a/libs/skeleton/src/index.ts b/libs/skeleton/src/index.ts index a7f0b35..4d7bb0b 100644 --- a/libs/skeleton/src/index.ts +++ b/libs/skeleton/src/index.ts @@ -1,6 +1,9 @@ export * from './constants'; -export * from './processes'; -export * from './interfaces'; -export * from './executors'; -export * from './skeleton-crud.controller'; +export * from './decoratos'; +export * from './dto'; export * from './entities'; +export * from './executors'; +export * from './interfaces'; +export * from './processes'; +export * from './skeleton-crud.controller'; + diff --git a/libs/skeleton/src/interfaces/controller/skeleton-crud.controller.interface.ts b/libs/skeleton/src/interfaces/controller/skeleton-crud.controller.interface.ts index 06795d5..0e448a8 100644 --- a/libs/skeleton/src/interfaces/controller/skeleton-crud.controller.interface.ts +++ b/libs/skeleton/src/interfaces/controller/skeleton-crud.controller.interface.ts @@ -1,8 +1,10 @@ +import { IPaginationParam } from '../pagination-param.interface'; + export interface ISkeletonCRUDController { create(body); delete(id); list(); - pagination(params: { page?: number; limit?: number }); + pagination(params: IPaginationParam); read(id); update(id, body); } diff --git a/libs/skeleton/src/interfaces/pagination-param.interface.ts b/libs/skeleton/src/interfaces/pagination-param.interface.ts new file mode 100644 index 0000000..7916a90 --- /dev/null +++ b/libs/skeleton/src/interfaces/pagination-param.interface.ts @@ -0,0 +1,4 @@ +export interface IPaginationParam { + page: number; + limit: number; +} diff --git a/libs/skeleton/src/processes/pagination.process.ts b/libs/skeleton/src/processes/pagination.process.ts index 19dc821..4341b1b 100644 --- a/libs/skeleton/src/processes/pagination.process.ts +++ b/libs/skeleton/src/processes/pagination.process.ts @@ -1,5 +1,6 @@ +import { IPaginationParam } from '../interfaces/pagination-param.interface'; import { DefaultProcess } from './default.process'; export class PaginationProcess extends DefaultProcess { - params: { page: number; limit: number }; + params: IPaginationParam; } diff --git a/libs/skeleton/src/skeleton-crud.controller.ts b/libs/skeleton/src/skeleton-crud.controller.ts index 77e6772..cdcbbe2 100644 --- a/libs/skeleton/src/skeleton-crud.controller.ts +++ b/libs/skeleton/src/skeleton-crud.controller.ts @@ -1,5 +1,6 @@ import { Body, + ClassSerializerInterceptor, Delete, Get, Inject, @@ -7,6 +8,9 @@ import { Patch, Post, Query, + UseInterceptors, + UsePipes, + ValidationPipe, } from '@nestjs/common'; import { CREATE_PROCESS, @@ -16,14 +20,14 @@ import { READ_PROCESS, UPDATE_PROCESS, } from './constants'; +import { PaginationParamDTO } from './dto'; +import { PaginationExecutor } from './executors'; import { CreateExcutor } from './executors/create.executor'; -import { DefaultExecutor } from './executors/default.executor'; import { DeleteExecutor } from './executors/delete.executor'; import { ListExecutor } from './executors/list.executor'; import { ReadExecutor } from './executors/read.executor'; import { UpdateExecutor } from './executors/update.executor'; import { ISkeletonCRUDController } from './interfaces/controller/skeleton-crud.controller.interface'; -import { PaginationExecutor } from './executors'; export class SkeletonCRUDController implements ISkeletonCRUDController { constructor( @@ -57,9 +61,8 @@ export class SkeletonCRUDController implements ISkeletonCRUDController { } @Get() - async pagination( - @Query() params: { page: number; limit: number } = { page: 1, limit: 10 }, - ) { + @UsePipes(new ValidationPipe({ transform: true })) + async pagination(@Query() params: PaginationParamDTO) { return await PaginationExecutor.bootstrap(this.paginationProcess, params); } diff --git a/package-lock.json b/package-lock.json index 1b07c09..5722913 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,18 +1,20 @@ { "name": "@aditama-labs/nest-autocrud", - "version": "0.0.13", + "version": "0.1.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@aditama-labs/nest-autocrud", - "version": "0.0.13", + "version": "0.1.4", "license": "MIT", "dependencies": { "@nestjs/common": "^10.0.0", "@nestjs/core": "^10.0.0", "@nestjs/platform-express": "^10.0.0", "@prisma/client": "^5.21.1", + "class-transformer": "^0.5.1", + "class-validator": "^0.14.1", "esm": "^3.2.25", "reflect-metadata": "^0.2.0", "rxjs": "^7.8.1" @@ -2671,6 +2673,12 @@ "@types/superagent": "^8.1.0" } }, + "node_modules/@types/validator": { + "version": "13.12.2", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.12.2.tgz", + "integrity": "sha512-6SlHBzUW8Jhf3liqrGGXyTJSIFe4nqlJ5A5KaMZ2l/vbM3Wh3KSybots/wfWVzNLK4D1NZluDlSQIbIEPx6oyA==", + "license": "MIT" + }, "node_modules/@types/yargs": { "version": "17.0.33", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", @@ -4029,6 +4037,23 @@ "dev": true, "license": "MIT" }, + "node_modules/class-transformer": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz", + "integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==", + "license": "MIT" + }, + "node_modules/class-validator": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.1.tgz", + "integrity": "sha512-2VEG9JICxIqTpoK1eMzZqaV+u/EiwEJkMGzTrZf6sU/fwsnOITVgYJ8yojSy6CaXtO9V0Cc6ZQZ8h8m4UBuLwQ==", + "license": "MIT", + "dependencies": { + "@types/validator": "^13.11.8", + "libphonenumber-js": "^1.10.53", + "validator": "^13.9.0" + } + }, "node_modules/cli-boxes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", @@ -7648,6 +7673,12 @@ "node": ">= 0.8.0" } }, + "node_modules/libphonenumber-js": { + "version": "1.11.12", + "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.11.12.tgz", + "integrity": "sha512-QkJn9/D7zZ1ucvT++TQSvZuSA2xAWeUytU+DiEQwbPKLyrDpvbul2AFs1CGbRAPpSCCk47aRAb5DX5mmcayp4g==", + "license": "MIT" + }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -11136,6 +11167,15 @@ "node": ">=10.12.0" } }, + "node_modules/validator": { + "version": "13.12.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.12.0.tgz", + "integrity": "sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", diff --git a/package.json b/package.json index a4e883e..25e423d 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,8 @@ "@nestjs/core": "^10.0.0", "@nestjs/platform-express": "^10.0.0", "@prisma/client": "^5.21.1", + "class-transformer": "^0.5.1", + "class-validator": "^0.14.1", "esm": "^3.2.25", "reflect-metadata": "^0.2.0", "rxjs": "^7.8.1" @@ -90,4 +92,4 @@ "^@aditama-labs/nest-autocrud/prisma(|/.*)$": "/libs/prisma/$1" } } -} \ No newline at end of file +} diff --git a/src/example/simple/simple.controller.ts b/src/example/simple/simple.controller.ts index 1da6add..739f593 100644 --- a/src/example/simple/simple.controller.ts +++ b/src/example/simple/simple.controller.ts @@ -1,5 +1,6 @@ import { Controller } from '@nestjs/common'; -import { SkeletonCRUDController } from 'libs'; +import { SkeletonController, SkeletonCRUDController } from 'libs'; @Controller('example/simple') +@SkeletonController() export class SimpleController extends SkeletonCRUDController {}