// /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 escapeRegex = (value) => String(value).replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); const toLatinDigits = (value) => { if (value == null) return ''; const persian = '۰۱۲۳۴۵۶۷۸۹'; const arabic = '٠١٢٣٤٥٦٧٨٩'; return String(value).replace(/[۰-۹٠-٩]/g, (ch) => { const p = persian.indexOf(ch); if (p >= 0) return String(p); const a = arabic.indexOf(ch); return a >= 0 ? String(a) : ch; }); }; const getSearchTerm = (query) => { const raw = query?.q || query?.search; if (raw == null || String(raw).trim() === '') return ''; return toLatinDigits(String(raw).trim()); }; const buildFilterQuery = (query, searchFields = [], excludedKeys = ['page', 'limit', 'sortBy', 'sortOrder', 'q', 'search', '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= or ?search= across defined text fields const searchTerm = getSearchTerm(query); if (searchTerm && searchFields.length > 0) { const searchRegex = new RegExp(escapeRegex(searchTerm), '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, escapeRegex, toLatinDigits, getSearchTerm };