-
-
Notifications
You must be signed in to change notification settings - Fork 0
Description
📚 Overview
Build a highly reusable, type-safe Pagination Utility Class that paginates any array (in-memory data). This is a common need across many backend applications — especially when you're dealing with data that's already loaded or not coming directly from a database query.
💡 Why This Is Useful
🔍 Use Case Example
🧠 In-memory filtering A user searches/filter locally loaded data (not DB query)
📋 Static dropdowns or tags Tags, categories, or form options
🔄 Enum lists Role types, statuses, languages
⚡️ Cached data Data pulled once, paginated multiple times
📦 Responses without ORM Data from an API call, file, or mock
This class ensures that developers don’t have to write repetitive .slice() logic in multiple places. It also provides consistent metadata output (like total pages, current page, items per page) for UI and frontend devs.
📁 File Location
src/utils/PaginateArray.ts
🎯 Goal
Create a single reusable utility class called PaginateArray that:
✅ Accepts any array
✅ Accepts page, limit, and maxLimit options
✅ Calculates total count, total pages, and perPage
✅ Returns paginated result + metadata
✅ Works in any controller, service, or standalone script
🧠 Implementation Details
✅ Interface Definitions:
export interface PaginationOptions {
page?: number;
limit?: number;
maxLimit?: number;
}
export interface PaginationMeta {
totalItems: number;
totalPages: number;
currentPage: number;
perPage: number;
}
export interface PaginatedArrayResult {
data: T[];
meta: PaginationMeta;
}
✅ Main Class:
export class PaginateArray {
static paginate(inputArray: T[], options: PaginationOptions = {}): PaginatedArrayResult {
const page = Math.max(1, options.page || 1);
const limit = Math.min(options.limit || 10, options.maxLimit || 100);
const skip = (page - 1) * limit;
const paginatedData = inputArray.slice(skip, skip + limit);
const totalItems = inputArray.length;
const totalPages = Math.ceil(totalItems / limit);
return {
data: paginatedData,
meta: {
totalItems,
totalPages,
currentPage: page,
perPage: limit,
},
};
}
}
💻 Example Usage
🧾 1. In Controller (Express)
import { PaginateArray } from '@/utils/PaginateArray';
const allTags = ['Node.js', 'React', 'Vue', 'Express', 'MongoDB'];
const result = PaginateArray.paginate(allTags, {
page: Number(req.query.page),
limit: Number(req.query.limit),
});
SendResponse.success(res, result, 'Tags fetched successfully');
🧾 2. In a Service
export const getPaginatedCachedLogs = (logs: LogType[], query: any) => {
return PaginateArray.paginate(logs, {
page: Number(query.page),
limit: Number(query.limit),
});
};
✅ Output Format (for frontend)
{
"data": ["React", "Vue"],
"meta": {
"totalItems": 5,
"totalPages": 3,
"currentPage": 2,
"perPage": 2
}
}
📦 Expected Benefits
🧩 Easily used in dropdowns, filtered lists, enums, or reports
♻️ Clean code — no more writing .slice() in every controller
✅ Fully type-safe
🚀 Speeds up feature development
🔧 Optional Enhancements (Future PRs)
[ ] Add sortBy, filterBy parameters
[ ] Add ability to return just meta (for frontend placeholder)
[ ] Add integration with SendResponse.success() as default return
🏷️ Suggested Labels
feature, utils, pagination, core, good first issue, reusable
🙋 Contribution Tips
If you're picking this up:
Keep it framework-agnostic (no Express or Mongoose here)
Use TypeScript generics for flexibility
Return clean and consistent metadata
Write 1-2 usage examples in a demo folder (PaginateArray.demo.ts)
Let me know if you'd like a second version of this that works for database queries or for cursor-based pagination.