From c084233e45954c00dee0b966f4b18b8502932564 Mon Sep 17 00:00:00 2001 From: Golu <140903720+GoluScriptMage@users.noreply.github.com> Date: Sun, 5 Jul 2026 10:58:07 +0530 Subject: [PATCH 1/2] feat(vendors): add pagination and limit validation to GET/vendors --- .../vendors/dto/vendor-list-query.dto.ts | 40 +++++++++++++++++++ .../vendors/dto/vendor-list-response.dto.ts | 17 ++++++++ src/modules/vendors/vendors.controller.ts | 12 ++++-- src/modules/vendors/vendors.service.ts | 28 +++++++++++-- 4 files changed, 89 insertions(+), 8 deletions(-) create mode 100644 src/modules/vendors/dto/vendor-list-query.dto.ts create mode 100644 src/modules/vendors/dto/vendor-list-response.dto.ts diff --git a/src/modules/vendors/dto/vendor-list-query.dto.ts b/src/modules/vendors/dto/vendor-list-query.dto.ts new file mode 100644 index 0000000..d074f22 --- /dev/null +++ b/src/modules/vendors/dto/vendor-list-query.dto.ts @@ -0,0 +1,40 @@ +import { ApiPropertyOptional } from '@nestjs/swagger'; +import { Transform } from 'class-transformer'; +import { IsEnum, IsInt, IsOptional, Max, Min } from 'class-validator'; +import { VendorType } from './vendor.dto'; + +export class VendorListQueryDto { + @ApiPropertyOptional({ + description: 'Filter by vendor type', + enum: VendorType, + }) + @IsOptional() + @IsEnum(VendorType) + type?: VendorType; + + @ApiPropertyOptional({ + description: 'Page number (1-indexed)', + example: 1, + default: 1, + minimum: 1, + }) + @IsOptional() + @Transform(({ value }) => parseInt(value, 10)) + @IsInt() + @Min(1) + page?: number = 1; + + @ApiPropertyOptional({ + description: 'Number of items to return per page (max 100)', + example: 20, + default: 20, + minimum: 1, + maximum: 100, + }) + @IsOptional() + @Transform(({ value }) => parseInt(value, 10)) + @IsInt() + @Min(1) + @Max(100) + limit?: number = 20; +} diff --git a/src/modules/vendors/dto/vendor-list-response.dto.ts b/src/modules/vendors/dto/vendor-list-response.dto.ts new file mode 100644 index 0000000..8380af4 --- /dev/null +++ b/src/modules/vendors/dto/vendor-list-response.dto.ts @@ -0,0 +1,17 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { PaginatedResponseDto, PaginationMetaDto } from '../../../common/dto/paginated-response.dto'; +import { VendorResponseDto } from './vendor.dto'; + +export class VendorListResponseDto implements PaginatedResponseDto { + @ApiProperty({ example: true }) + success: boolean; + + @ApiProperty({ type: [VendorResponseDto] }) + data: VendorResponseDto[]; + + @ApiProperty({ type: PaginationMetaDto }) + pagination: PaginationMetaDto; + + @ApiProperty({ example: 'Vendors retrieved successfully' }) + message: string; +} diff --git a/src/modules/vendors/vendors.controller.ts b/src/modules/vendors/vendors.controller.ts index e42687c..1405dd4 100644 --- a/src/modules/vendors/vendors.controller.ts +++ b/src/modules/vendors/vendors.controller.ts @@ -25,6 +25,8 @@ import { VendorsService } from './vendors.service'; import { VendorResponseDto, VendorType } from './dto/vendor.dto'; import { CreateApiKeyDto } from './dto/create-api-key.dto'; import { ApiKeyResponseDto, ApiKeyCreatedResponseDto } from './dto/api-key-response.dto'; +import { VendorListQueryDto } from './dto/vendor-list-query.dto'; +import { VendorListResponseDto } from './dto/vendor-list-response.dto'; @ApiTags('vendors') @Controller('vendors') @@ -33,11 +35,13 @@ export class VendorsController { @Get() @HttpCode(HttpStatus.OK) - @ApiOperation({ summary: 'List all vendors, optionally filtered by type' }) + @ApiOperation({ summary: 'List all vendors, optionally filtered by type with pagination' }) @ApiQuery({ name: 'type', enum: VendorType, required: false }) - @ApiResponse({ status: 200, description: 'List of vendors', type: [VendorResponseDto] }) - async list(@Query('type') type?: VendorType): Promise { - return this.vendorsService.getAll(type); + @ApiQuery({ name: 'page', type: Number, required: false, description: 'Page number (default 1)' }) + @ApiQuery({ name: 'limit', type: Number, required: false, description: 'Page size (default 20, max 100)' }) + @ApiResponse({ status: 200, description: 'List of vendors with pagination', type: VendorListResponseDto }) + async list(@Query() query: VendorListQueryDto): Promise { + return this.vendorsService.getAll(query.page, query.limit, query.type); } @Get(':id') diff --git a/src/modules/vendors/vendors.service.ts b/src/modules/vendors/vendors.service.ts index 0c9a10c..5f41809 100644 --- a/src/modules/vendors/vendors.service.ts +++ b/src/modules/vendors/vendors.service.ts @@ -10,6 +10,7 @@ import { VendorsRepository } from '../../database/repositories/vendors.repositor import { VendorResponseDto, VendorType } from './dto/vendor.dto'; import { CreateApiKeyDto } from './dto/create-api-key.dto'; import { ApiKeyResponseDto, ApiKeyCreatedResponseDto } from './dto/api-key-response.dto'; +import { VendorListResponseDto } from './dto/vendor-list-response.dto'; const API_KEY_PREFIX = 'sfi_'; @@ -48,15 +49,23 @@ export class VendorsService { private readonly vendorsRepository: VendorsRepository, ) {} - async getAll(type?: VendorType): Promise { + async getAll( + page: number = 1, + limit: number = 20, + type?: VendorType, + ): Promise { + const offset = (page - 1) * limit; const client = this.supabaseService.getClient(); - let query = client.from('vendors').select('*').order('created_at', { ascending: false }); + let query = client + .from('vendors') + .select('*', { count: 'exact' }) + .order('created_at', { ascending: false }); if (type) { query = query.eq('type', type); } - const { data, error } = await query; + const { data, error, count } = await query.range(offset, offset + limit - 1); if (error) { this.logger.error(`Failed to list vendors: ${error.message}`); @@ -64,7 +73,18 @@ export class VendorsService { } const rows: VendorRow[] = (data ?? []) as VendorRow[]; - return rows.map((row) => this.mapToDto(row)); + const mappedData = rows.map((row) => this.mapToDto(row)); + + return { + success: true, + data: mappedData, + pagination: { + limit, + offset, + total: count ?? 0, + }, + message: 'Vendors retrieved successfully', + }; } async getById(id: string): Promise { From 288e48ab093d7229ae72a4cd43501e65952ef77c Mon Sep 17 00:00:00 2001 From: Golu <140903720+GoluScriptMage@users.noreply.github.com> Date: Sun, 5 Jul 2026 11:05:56 +0530 Subject: [PATCH 2/2] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- src/modules/vendors/dto/vendor-list-query.dto.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/vendors/dto/vendor-list-query.dto.ts b/src/modules/vendors/dto/vendor-list-query.dto.ts index d074f22..d0dfa47 100644 --- a/src/modules/vendors/dto/vendor-list-query.dto.ts +++ b/src/modules/vendors/dto/vendor-list-query.dto.ts @@ -32,7 +32,7 @@ export class VendorListQueryDto { maximum: 100, }) @IsOptional() - @Transform(({ value }) => parseInt(value, 10)) + @Transform(({ value }) => (value === undefined ? 20 : Number(value))) @IsInt() @Min(1) @Max(100)