Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions src/modules/vendors/dto/vendor-list-query.dto.ts
Original file line number Diff line number Diff line change
@@ -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 }) => (value === undefined ? 20 : Number(value)))
@IsInt()
@Min(1)
@Max(100)
limit?: number = 20;
}
17 changes: 17 additions & 0 deletions src/modules/vendors/dto/vendor-list-response.dto.ts
Original file line number Diff line number Diff line change
@@ -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<VendorResponseDto> {
@ApiProperty({ example: true })
success: boolean;

@ApiProperty({ type: [VendorResponseDto] })
data: VendorResponseDto[];

@ApiProperty({ type: PaginationMetaDto })
pagination: PaginationMetaDto;

@ApiProperty({ example: 'Vendors retrieved successfully' })
message: string;
}
12 changes: 8 additions & 4 deletions src/modules/vendors/vendors.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand All @@ -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<VendorResponseDto[]> {
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<VendorListResponseDto> {
return this.vendorsService.getAll(query.page, query.limit, query.type);
}

@Get(':id')
Expand Down
28 changes: 24 additions & 4 deletions src/modules/vendors/vendors.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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_';

Expand Down Expand Up @@ -48,23 +49,42 @@ export class VendorsService {
private readonly vendorsRepository: VendorsRepository,
) {}

async getAll(type?: VendorType): Promise<VendorResponseDto[]> {
async getAll(
page: number = 1,
limit: number = 20,
type?: VendorType,
): Promise<VendorListResponseDto> {
const offset = (page - 1) * limit;
const client = this.supabaseService.getClient();
Comment on lines +52 to 58
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}`);
throw new Error('Failed to list vendors.');
}
Comment on lines 70 to 73

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<VendorResponseDto> {
Expand Down
Loading