Files
gameno-api/utils/pagination.js
T
kavehhn f04c797be6 Initial commit: teaching institution management API.
Express/MongoDB backend with JWT auth, RBAC, S3 uploads, notifications, and scheduled jobs.
2026-08-09 04:18:08 +02:00

70 lines
1.7 KiB
JavaScript

// /utils/pagination.js
const parsePaginationAndSort = (query, defaultSortBy = 'createdAt', defaultSortOrder = 'desc', maxLimit = 100) => {
const page = Math.max(1, parseInt(query.page, 10) || 1);
let limit = parseInt(query.limit, 10) || 20;
if (limit <= 0) limit = 20;
if (limit > maxLimit) limit = maxLimit;
const skip = (page - 1) * limit;
const sortBy = query.sortBy || defaultSortBy;
const sortOrder = (query.sortOrder || defaultSortOrder).toLowerCase() === 'asc' ? 1 : -1;
const sort = {};
sort[sortBy] = sortOrder;
return {
page,
limit,
skip,
sort
};
};
const buildFilterQuery = (query, searchFields = [], excludedKeys = ['page', 'limit', 'sortBy', 'sortOrder', 'q', 'lang']) => {
const filter = {};
// Build field-based exact or boolean filters
Object.keys(query).forEach((key) => {
if (!excludedKeys.includes(key) && query[key] !== undefined && query[key] !== '') {
const val = query[key];
if (val === 'true') {
filter[key] = true;
} else if (val === 'false') {
filter[key] = false;
} else if (!isNaN(val) && String(Number(val)) === val) {
filter[key] = Number(val);
} else {
filter[key] = val;
}
}
});
// Build regex search for ?q= across defined text fields
if (query.q && searchFields.length > 0) {
const searchRegex = new RegExp(query.q, 'i');
filter.$or = searchFields.map((field) => ({
[field]: searchRegex
}));
}
return filter;
};
const calculateMeta = (totalCount, page, limit) => {
const totalPages = Math.ceil(totalCount / limit) || 0;
return {
totalCount,
totalPages,
currentPage: page,
limit
};
};
module.exports = {
parsePaginationAndSort,
buildFilterQuery,
calculateMeta
};