From 7b57a24b7ac5a004f914eae81f2bfb4a74dc6d0e Mon Sep 17 00:00:00 2001 From: chibuezemicahe Date: Sat, 1 Mar 2025 00:02:38 +0100 Subject: [PATCH 1/4] feat: Implemented pagination to getAllBilling Plans Endpoint --- .husky/pre-commit | 4 ---- 1 file changed, 4 deletions(-) delete mode 100755 .husky/pre-commit diff --git a/.husky/pre-commit b/.husky/pre-commit deleted file mode 100755 index 36af21989..000000000 --- a/.husky/pre-commit +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -. "$(dirname "$0")/_/husky.sh" - -npx lint-staged From bd6b11333287daa9c8e5c83f137e8953500bb587 Mon Sep 17 00:00:00 2001 From: chibuezemicahe Date: Sat, 1 Mar 2025 00:24:07 +0100 Subject: [PATCH 2/4] docs: added pagination to the getallbilling plan end point doc --- .../billing-plans/docs/billing-plan-docs.ts | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/modules/billing-plans/docs/billing-plan-docs.ts b/src/modules/billing-plans/docs/billing-plan-docs.ts index 97faf5c4e..27c91f4ba 100644 --- a/src/modules/billing-plans/docs/billing-plan-docs.ts +++ b/src/modules/billing-plans/docs/billing-plan-docs.ts @@ -1,6 +1,6 @@ import { applyDecorators } from '@nestjs/common'; import { BillingPlanDto } from '../dto/billing-plan.dto'; -import { ApiBearerAuth, ApiBody, ApiOperation, ApiResponse } from '@nestjs/swagger'; +import { ApiBearerAuth, ApiBody, ApiOperation, ApiResponse, ApiQuery} from '@nestjs/swagger'; import { BillingPlan } from '../entities/billing-plan.entity'; export function createBillingPlanDocs() { @@ -15,8 +15,29 @@ export function createBillingPlanDocs() { export function getAllBillingPlansDocs() { return applyDecorators( - ApiOperation({ summary: 'Get all billing plans' }), - ApiResponse({ status: 200, description: 'Billing plans retrieved successfully.', type: [BillingPlanDto] }), + ApiOperation({ summary: 'Get all billing plans (paginated)' }), + ApiQuery({ name: 'page', required: false, description: 'Page number (default: 1)' }), + ApiQuery({ name: 'limit', required: false, description: 'Number of items per page (default: 10)' }), + ApiResponse({ + status: 200, + description: 'Billing plans retrieved successfully.', + schema: { + type: 'object', + properties: { + message: { type: 'string', example: 'Billing plans retrieved successfully' }, + data: { + type: 'object', + properties: { + plans: { + type: 'array', + items: { type: 'object', $ref: '#/components/schemas/BillingPlanDto' }, // Use a $ref to your BillingPlanDto schema + }, + total: { type: 'number', example: 123 }, + }, + }, + }, + }, + }), ApiResponse({ status: 404, description: 'No billing plans found.' }) ); } From 119519aa90fafbe8345451ffc445ef20a1881874 Mon Sep 17 00:00:00 2001 From: chibuezemicahe Date: Sat, 1 Mar 2025 18:31:24 +0100 Subject: [PATCH 3/4] feat: implemented pagination to get all billing plans endpoint --- .../billing-plans/billing-plan.controller.ts | 11 ++++- .../billing-plans/billing-plan.service.ts | 16 +++++-- .../tests/billing-plan.service.spec.ts | 48 ++++++++++--------- 3 files changed, 48 insertions(+), 27 deletions(-) diff --git a/src/modules/billing-plans/billing-plan.controller.ts b/src/modules/billing-plans/billing-plan.controller.ts index 55e68de44..c6822c846 100644 --- a/src/modules/billing-plans/billing-plan.controller.ts +++ b/src/modules/billing-plans/billing-plan.controller.ts @@ -10,6 +10,7 @@ import { Delete, HttpCode, HttpStatus, + Query } from '@nestjs/common'; import { ApiTags } from '@nestjs/swagger'; import { BillingPlanService } from './billing-plan.service'; @@ -40,8 +41,14 @@ export class BillingPlanController { @skipAuth() @getAllBillingPlansDocs() @Get('/') - async getAllBillingPlans() { - return this.billingPlanService.getAllBillingPlans(); + async getAllBillingPlans( + @Query('page') page: string, + @Query('limit') limit: string, + ) { + const pageNumber = page ? parseInt(page, 10) : 1; + const limitNumber = limit ? parseInt(limit, 10) : 10; + + return this.billingPlanService.getAllBillingPlans(pageNumber, limitNumber); } @skipAuth() diff --git a/src/modules/billing-plans/billing-plan.service.ts b/src/modules/billing-plans/billing-plan.service.ts index 29eae7e7c..7d4a3e1bf 100644 --- a/src/modules/billing-plans/billing-plan.service.ts +++ b/src/modules/billing-plans/billing-plan.service.ts @@ -36,8 +36,15 @@ export class BillingPlanService { }; } - async getAllBillingPlans() { - const allPlans = await this.billingPlanRepository.find(); + async getAllBillingPlans(page: number = 1, limit: number = 10) { + const skip = (page - 1) * limit; + const take = limit; + + const [allPlans, total] = await this.billingPlanRepository.findAndCount({ + skip, + take, + }); + if (allPlans.length === 0) { throw new NotFoundException('No billing plans found'); } @@ -45,7 +52,10 @@ export class BillingPlanService { return { message: 'Billing plans retrieved successfully', - data: plans, + data: { + plans, + total, + }, }; } diff --git a/src/modules/billing-plans/tests/billing-plan.service.spec.ts b/src/modules/billing-plans/tests/billing-plan.service.spec.ts index c37daa762..a6fed1357 100644 --- a/src/modules/billing-plans/tests/billing-plan.service.spec.ts +++ b/src/modules/billing-plans/tests/billing-plan.service.spec.ts @@ -59,7 +59,7 @@ describe('BillingPlanService', () => { }); describe('getAllBillingPlans', () => { - it('should return all billing plans', async () => { + it('should return paginated billing plans', async () => { const billingPlans = [ { id: '1', @@ -81,35 +81,39 @@ describe('BillingPlanService', () => { created_at: new Date(), updated_at: new Date(), }, - { - id: '1', - name: 'Premium', - description: 'premium plan', - amount: 120, - frequency: 'monthly', - is_active: true, - created_at: new Date(), - updated_at: new Date(), - }, ]; - - jest.spyOn(repository, 'find').mockResolvedValue(billingPlans as BillingPlan[]); - - const result = await service.getAllBillingPlans(); - + + const total = 2; // Total number of billing plans in the database + + // Mock findAndCount to return paginated results + jest.spyOn(repository, 'findAndCount').mockResolvedValue([billingPlans as BillingPlan[], total]); + + const result = await service.getAllBillingPlans(1, 10); + + // Verify the response structure expect(result).toEqual({ message: 'Billing plans retrieved successfully', - data: billingPlans.map(plan => BillingPlanMapper.mapToResponseFormat(plan)), + data: { + plans: billingPlans.map(plan => BillingPlanMapper.mapToResponseFormat(plan)), + total, + }, + }); + + // Verify that findAndCount was called with the correct pagination parameters + expect(repository.findAndCount).toHaveBeenCalledWith({ + skip: 0, // (page - 1) * limit = (1 - 1) * 10 = 0 + take: 10, // limit = 10 }); }); - + it('should throw a NotFoundException if no billing plans are found', async () => { - jest.spyOn(repository, 'find').mockResolvedValue([]); - - await expect(service.getAllBillingPlans()).rejects.toThrow(NotFoundException); + // Mock findAndCount to return an empty array + jest.spyOn(repository, 'findAndCount').mockResolvedValue([[], 0]); + + await expect(service.getAllBillingPlans(1, 10)).rejects.toThrow(NotFoundException); }); }); - + describe('getSingleBillingPlan', () => { it('should return a single billing plan', async () => { const billingPlan = { From 764e688d9e58099058a5d47b3c0de7d4c146f937 Mon Sep 17 00:00:00 2001 From: chibuezemicahe Date: Sat, 1 Mar 2025 19:07:22 +0100 Subject: [PATCH 4/4] refactor: femporary commit to switch branches --- src/modules/billing-plans/billing-plan.controller.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/modules/billing-plans/billing-plan.controller.ts b/src/modules/billing-plans/billing-plan.controller.ts index c6822c846..a552ccca1 100644 --- a/src/modules/billing-plans/billing-plan.controller.ts +++ b/src/modules/billing-plans/billing-plan.controller.ts @@ -42,12 +42,11 @@ export class BillingPlanController { @getAllBillingPlansDocs() @Get('/') async getAllBillingPlans( - @Query('page') page: string, - @Query('limit') limit: string, - ) { - const pageNumber = page ? parseInt(page, 10) : 1; - const limitNumber = limit ? parseInt(limit, 10) : 10; - + @Query('page') page: string, + @Query('limit') limit: string, ) + { + const pageNumber = page ? parseInt(page, 10) : 1; + const limitNumber = limit ? parseInt(limit, 10) : 10; return this.billingPlanService.getAllBillingPlans(pageNumber, limitNumber); }