From c5c54c45dcbf201260d169bb373beda238f020f1 Mon Sep 17 00:00:00 2001 From: Anand Chowdhary Date: Mon, 16 Nov 2020 13:24:10 +0530 Subject: [PATCH] :recycle: Add select/include pipe --- src/errors/errors.constants.ts | 1 + src/modules/groups/groups.controller.ts | 5 ++++- src/modules/groups/groups.service.ts | 15 +++++++++++++-- src/pipes/select-include.pipe.ts | 23 +++++++++++++++++++++++ 4 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 src/pipes/select-include.pipe.ts diff --git a/src/errors/errors.constants.ts b/src/errors/errors.constants.ts index 283e4a816..5610fcd9e 100644 --- a/src/errors/errors.constants.ts +++ b/src/errors/errors.constants.ts @@ -45,6 +45,7 @@ export const EMAIL_DELETE_PRIMARY = '400016: Cannot delete primary email'; export const CANNOT_UPDATE_ROLE_SOLE_OWNER = '400017: Cannot change the role of the only owner'; export const INVALID_DOMAIN = '400018: Invalid domain'; +export const SELECT_INCLUDE_PIPE_FORMAT = '400014: Invalid query format'; export const EMAIL_USER_CONFLICT = '409001: User with this email already exists'; diff --git a/src/modules/groups/groups.controller.ts b/src/modules/groups/groups.controller.ts index 74a41460f..8fcbe62a7 100644 --- a/src/modules/groups/groups.controller.ts +++ b/src/modules/groups/groups.controller.ts @@ -19,6 +19,7 @@ import { AuditLog } from '../audit-logs/audit-log.decorator'; import { Scopes } from '../auth/scope.decorator'; import { ReplaceGroupDto, UpdateGroupDto } from './groups.dto'; import { GroupsService } from './groups.service'; +import { SelectIncludePipe } from 'src/pipes/select-include.pipe'; @Controller('groups') export class GroupController { @@ -46,8 +47,10 @@ export class GroupController { @Scopes('group-{groupId}:read-info') async get( @Param('groupId', ParseIntPipe) id: number, + @Query('select', SelectIncludePipe) select?: Record, + @Query('include', SelectIncludePipe) include?: Record, ): Promise> { - return this.groupsService.getGroup(Number(id)); + return this.groupsService.getGroup(Number(id), { select, include }); } @Patch(':groupId') diff --git a/src/modules/groups/groups.service.ts b/src/modules/groups/groups.service.ts index 84ac95942..16baf56a4 100644 --- a/src/modules/groups/groups.service.ts +++ b/src/modules/groups/groups.service.ts @@ -60,10 +60,21 @@ export class GroupsService { return groups.map((user) => this.prisma.expose(user)); } - async getGroup(id: number): Promise> { + async getGroup( + id: number, + { + select, + include, + }: { + select?: Record; + include?: Record; + }, + ): Promise> { const group = await this.prisma.groups.findOne({ where: { id }, - }); + select, + include, + } as any); if (!group) throw new NotFoundException(GROUP_NOT_FOUND); return this.prisma.expose(group); } diff --git a/src/pipes/select-include.pipe.ts b/src/pipes/select-include.pipe.ts new file mode 100644 index 000000000..20a434fdd --- /dev/null +++ b/src/pipes/select-include.pipe.ts @@ -0,0 +1,23 @@ +import { BadRequestException, Injectable, PipeTransform } from '@nestjs/common'; +import { SELECT_INCLUDE_PIPE_FORMAT } from '../errors/errors.constants'; +import { object } from 'dot-object'; + +/** + * Convert a string like "id,createdAt,user.name,user.id" + * => { id: true, createdAt: true, user: { name: true, id: true } } + */ +@Injectable() +export class SelectIncludePipe implements PipeTransform { + transform(value: string): Record | undefined { + if (value == null) return undefined; + try { + const testRecord: Record = {}; + value.split(',').forEach((i) => { + if (/^[a-z0-9\.]+$/i.test(i.trim())) testRecord[i.trim()] = true; + }); + return object(testRecord) as Record; + } catch (_) { + throw new BadRequestException(SELECT_INCLUDE_PIPE_FORMAT); + } + } +}