From b1074976deff3d8f979a2ed827ded9d3c4a3c73f Mon Sep 17 00:00:00 2001 From: Anand Chowdhary Date: Thu, 22 Oct 2020 18:10:29 +0530 Subject: [PATCH] :sparkles: Add pipes for optional int, order by --- src/modules/user/user.controller.ts | 22 +++++++++++++------ src/modules/user/user.service.ts | 3 ++- src/pipes/optional-int.pipe.ts | 22 +++++++++++++++++++ src/pipes/order-by.pipe.ts | 33 +++++++++++++++++++++++++++++ 4 files changed, 72 insertions(+), 8 deletions(-) create mode 100644 src/pipes/optional-int.pipe.ts create mode 100644 src/pipes/order-by.pipe.ts diff --git a/src/modules/user/user.controller.ts b/src/modules/user/user.controller.ts index a9b5c1fda..40ddf4016 100644 --- a/src/modules/user/user.controller.ts +++ b/src/modules/user/user.controller.ts @@ -1,6 +1,8 @@ -import { Controller, Get } from '@nestjs/common'; +import { Controller, Get, Param, ParseIntPipe, Query } from '@nestjs/common'; import { users } from '@prisma/client'; import { OmitSecrets } from 'src/modules/prisma/prisma.interface'; +import { OptionalIntPipe } from 'src/pipes/optional-int.pipe'; +import { OrderByPipe } from 'src/pipes/order-by.pipe'; import { UsersService } from './user.service'; @Controller('users') @@ -8,12 +10,18 @@ export class UserController { constructor(private usersService: UsersService) {} @Get() - async getAll(): Promise[]> { - return this.usersService.users({}); + async getAll( + @Query('skip', OptionalIntPipe) skip?: number, + @Query('take', OptionalIntPipe) take?: number, + @Query('orderBy', OrderByPipe) orderBy?: Record, + ): Promise[]> { + return this.usersService.users({ skip, take, orderBy }); } - // @Get('post/:id') - // async getPostById(@Param('id') id: string): Promise { - // return this.postService.post({ id: Number(id) }); - // } + @Get(':id') + async get( + @Param('id', ParseIntPipe) id: number, + ): Promise> { + return this.usersService.user({ id: Number(id) }); + } } diff --git a/src/modules/user/user.service.ts b/src/modules/user/user.service.ts index 90f642dad..e374c131e 100644 --- a/src/modules/user/user.service.ts +++ b/src/modules/user/user.service.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@nestjs/common'; +import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; import { PrismaService } from '../prisma/prisma.service'; import { usersUpdateInput, @@ -20,6 +20,7 @@ export class UsersService { const user = await this.prisma.users.findOne({ where: userWhereUniqueInput, }); + if (!user) throw new HttpException('User not found', HttpStatus.NOT_FOUND); return this.prisma.expose(user); } diff --git a/src/pipes/optional-int.pipe.ts b/src/pipes/optional-int.pipe.ts new file mode 100644 index 000000000..7809528da --- /dev/null +++ b/src/pipes/optional-int.pipe.ts @@ -0,0 +1,22 @@ +import { + PipeTransform, + Injectable, + HttpException, + HttpStatus, + ArgumentMetadata, +} from '@nestjs/common'; + +/** Convert a string like "1" to a number, but without NaN */ +@Injectable() +export class OptionalIntPipe implements PipeTransform { + transform(value: string, metadata: ArgumentMetadata): number | undefined { + if (value == null) return undefined; + const num = Number(value); + if (isNaN(num)) + throw new HttpException( + `"${metadata.data}" should be a number, provided "${value}"`, + HttpStatus.UNPROCESSABLE_ENTITY, + ); + return num; + } +} diff --git a/src/pipes/order-by.pipe.ts b/src/pipes/order-by.pipe.ts new file mode 100644 index 000000000..badd243ea --- /dev/null +++ b/src/pipes/order-by.pipe.ts @@ -0,0 +1,33 @@ +import { + PipeTransform, + Injectable, + HttpException, + HttpStatus, + ArgumentMetadata, +} from '@nestjs/common'; + +/** Convert a string like "name asc, address desc" to { name: "asc", address: "desc" } */ +@Injectable() +export class OrderByPipe implements PipeTransform { + transform( + value: string, + metadata: ArgumentMetadata, + ): Record | undefined { + if (value == null) return undefined; + try { + const rules = value.split(',').map(val => val.trim()); + const orderBy: Record = {}; + rules.forEach(rule => { + const [key, order] = rule.split(' '); + if (!['asc', 'desc'].includes(order)) throw new Error(); + rules[key] = order; + }); + return orderBy; + } catch (_) { + throw new HttpException( + `"${metadata.data}" should be like "key1 asc, key2 desc", provided "${value}"`, + HttpStatus.UNPROCESSABLE_ENTITY, + ); + } + } +}