From c7ae346c07164af4cff2a3b4dfa767bfd9293f4e Mon Sep 17 00:00:00 2001 From: Supan Adit Pratama Date: Sat, 2 Nov 2024 00:48:19 +0700 Subject: [PATCH] feat: custom unique identifier --- libs/skeleton/src/decoratos/index.ts | 1 - .../skeleton-controller.decorator.ts | 7 -- .../decoratos/unique-override.decorator.ts | 19 ---- libs/skeleton/src/index.ts | 1 - libs/skeleton/src/skeleton-crud.controller.ts | 106 +++++++++++++----- src/example/custom/custom.controller.ts | 6 +- src/example/simple/simple.controller.ts | 17 +-- 7 files changed, 83 insertions(+), 74 deletions(-) delete mode 100644 libs/skeleton/src/decoratos/index.ts delete mode 100644 libs/skeleton/src/decoratos/skeleton-controller.decorator.ts delete mode 100644 libs/skeleton/src/decoratos/unique-override.decorator.ts diff --git a/libs/skeleton/src/decoratos/index.ts b/libs/skeleton/src/decoratos/index.ts deleted file mode 100644 index 4e327db..0000000 --- a/libs/skeleton/src/decoratos/index.ts +++ /dev/null @@ -1 +0,0 @@ -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 deleted file mode 100644 index 1060dd6..0000000 --- a/libs/skeleton/src/decoratos/skeleton-controller.decorator.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { UNIQUE_IDENTIFIER } from '../constants'; - -export function SkeletonController(): ClassDecorator { - return (target: object) => { - Reflect.defineMetadata(UNIQUE_IDENTIFIER, 'haha', target); - }; -} diff --git a/libs/skeleton/src/decoratos/unique-override.decorator.ts b/libs/skeleton/src/decoratos/unique-override.decorator.ts deleted file mode 100644 index 25b698d..0000000 --- a/libs/skeleton/src/decoratos/unique-override.decorator.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { UNIQUE_IDENTIFIER } from '../constants'; - -export const UniqueOverride = (): MethodDecorator => { - return ( - target: object, - key: string | symbol, - descriptor: TypedPropertyDescriptor, - ) => { - // const result = Reflect.getMetadata(UNIQUE_IDENTIFIER, descriptor.value); - // console.log(result); - // console.log(Object.getOwnPropertyNames(props)); - - let result = Reflect.getOwnMetadata(UNIQUE_IDENTIFIER, target); - console.log(target.constructor); - - console.log(result); - return descriptor; - }; -}; diff --git a/libs/skeleton/src/index.ts b/libs/skeleton/src/index.ts index 4d7bb0b..2152dfe 100644 --- a/libs/skeleton/src/index.ts +++ b/libs/skeleton/src/index.ts @@ -1,5 +1,4 @@ export * from './constants'; -export * from './decoratos'; export * from './dto'; export * from './entities'; export * from './executors'; diff --git a/libs/skeleton/src/skeleton-crud.controller.ts b/libs/skeleton/src/skeleton-crud.controller.ts index 147d002..e071766 100644 --- a/libs/skeleton/src/skeleton-crud.controller.ts +++ b/libs/skeleton/src/skeleton-crud.controller.ts @@ -28,54 +28,100 @@ import { UpdateExecutor } from './executors/update.executor'; import { ControllerOption } from './interfaces/controller/controller.option'; import { ISkeletonCRUDController } from './interfaces/controller/skeleton-crud.controller.interface'; -export function getBaseController(option?: ControllerOption): any { - class SkeletonCRUDController implements ISkeletonCRUDController { - constructor( - @Inject(CREATE_PROCESS) - public readonly createProcess, - @Inject(DELETE_PROCESS) - public readonly deleteProcess, - @Inject(LIST_PROCESS) - public readonly listProcess, - @Inject(PAGINATION_PROCESS) - public readonly paginationProcess, - @Inject(READ_PROCESS) - public readonly readProcess, - @Inject(UPDATE_PROCESS) - public readonly updateProcess, - ) {} +class SkeletonCRUDController implements ISkeletonCRUDController { + constructor( + @Inject(CREATE_PROCESS) + public readonly createProcess, + @Inject(DELETE_PROCESS) + public readonly deleteProcess, + @Inject(LIST_PROCESS) + public readonly listProcess, + @Inject(PAGINATION_PROCESS) + public readonly paginationProcess, + @Inject(READ_PROCESS) + public readonly readProcess, + @Inject(UPDATE_PROCESS) + public readonly updateProcess, + ) {} + @Post() + async create(@Body() body): Promise { + return await CreateExcutor.bootstrap(this.createProcess, body); + } + + @Delete(':id') + async delete(@Param('id') providedKey) { + return await DeleteExecutor.bootstrap(this.deleteProcess, providedKey); + } + + @Get('list') + async list() { + return await ListExecutor.bootstrap(this.listProcess); + } + + @Get() + @UsePipes(new ValidationPipe({ transform: true })) + async pagination(@Query() params: PaginationParamDTO) { + return await PaginationExecutor.bootstrap(this.paginationProcess, params); + } + + @Get(':id') + async read(@Param('id') providedKey) { + return await ReadExecutor.bootstrap(this.readProcess, providedKey); + } + + @Patch(':id') + async update(@Param('id') providedKey, @Body() body) { + return await UpdateExecutor.bootstrap( + this.updateProcess, + providedKey, + body, + ); + } +} + +// NOTES: +// - This method only works when return as `any` +// - I know this is not recommended but.... is there any way to pass custom unique identifier ? +// - Everyone still can use SkeletonCRUDController with no issue if don't want or don't like this approach, but... unique identifier must ID for sure and the type should either UUID, String or Number +// - Correct me if I wrong. I already read the main repository of NestJS and they use Reflect for passing some metadata ( I know how to do it ) but... it still not possible for dynamic unique identifier +// Known issue: +// - OpenAPI ( Swagger ) cannot read any decorator inside this +export const AutoCRUDController = (options?: ControllerOption): any => { + const uniqueIdentifier = `${options?.uniqueIdentifier ?? 'id'}`; + + class CRUDController extends SkeletonCRUDController { @Post() async create(@Body() body): Promise { - return await CreateExcutor.bootstrap(this.createProcess, body); + return await super.create(body); } - @Delete(`:${option?.uniqueIdentifier ?? 'id'}`) - async delete(@Param(`${option?.uniqueIdentifier}`) id) { - return await DeleteExecutor.bootstrap(this.deleteProcess, id); + @Delete(`:${uniqueIdentifier}`) + async delete(@Param(uniqueIdentifier) id) { + return await super.delete(id); } @Get('list') async list() { - return await ListExecutor.bootstrap(this.listProcess); + return await super.list(); } @Get() @UsePipes(new ValidationPipe({ transform: true })) async pagination(@Query() params: PaginationParamDTO) { - return await PaginationExecutor.bootstrap(this.paginationProcess, params); + return await super.pagination(params); } - @Get(`:${option?.uniqueIdentifier}`) - async read(@Param(`${option?.uniqueIdentifier}`) id) { - return await ReadExecutor.bootstrap(this.readProcess, id); + @Get(`:${uniqueIdentifier}`) + async read(@Param(uniqueIdentifier) id) { + return await super.read(id); } - @Patch(`:${option?.uniqueIdentifier}`) - async update(@Param(`${option?.uniqueIdentifier}`) id, @Body() body) { - return await UpdateExecutor.bootstrap(this.updateProcess, id, body); + @Patch(`:${uniqueIdentifier}`) + async update(@Param(uniqueIdentifier) id, @Body() body) { + return await super.update(id, body); } } - return SkeletonCRUDController; -} + return CRUDController; +}; diff --git a/src/example/custom/custom.controller.ts b/src/example/custom/custom.controller.ts index b3b60f6..28b6327 100644 --- a/src/example/custom/custom.controller.ts +++ b/src/example/custom/custom.controller.ts @@ -1,7 +1,5 @@ -import { getBaseController } from '@aditama-labs/nest-autocrud/skeleton'; +import { AutoCRUDController } from '@aditama-labs/nest-autocrud/skeleton'; import { Controller } from '@nestjs/common'; @Controller('example/custom') -export class CustomController extends getBaseController({ - uniqueIdentifier: 'key', -}) {} +export class CustomController extends AutoCRUDController() {} diff --git a/src/example/simple/simple.controller.ts b/src/example/simple/simple.controller.ts index a7c17fe..b19bcaa 100644 --- a/src/example/simple/simple.controller.ts +++ b/src/example/simple/simple.controller.ts @@ -1,14 +1,7 @@ -import { UniqueOverride } from '@aditama-labs/nest-autocrud/skeleton/src/decoratos/unique-override.decorator'; -import { Controller, Get } from '@nestjs/common'; -import { getBaseController, SkeletonController, UNIQUE_IDENTIFIER } from 'libs'; +import { Controller } from '@nestjs/common'; +import { AutoCRUDController } from 'libs'; -@SkeletonController() @Controller('example/simple') -export class SimpleController extends getBaseController() { - @UniqueOverride() - @Get('list') - async list(): Promise { - console.log(Reflect.getOwnMetadata(UNIQUE_IDENTIFIER, this.constructor)); - return super.list(); - } -} +export class SimpleController extends AutoCRUDController({ + uniqueIdentifier: 'username', +}) {}