samoulla-backend / utils /apiFeatures.js
Samoulla Sync Bot
Auto-deploy Samoulla Backend: b68e45770de26ed39feb4b1c0925e5345eb3a61d
634b9bb
class APIFeatures {
constructor(query, queryString) {
this.query = query;
this.queryString = queryString;
}
filter() {
// eslint-disable-next-line node/no-unsupported-features/es-syntax
const queryObj = { ...this.queryString };
const excludedFields = ['page', 'sort', 'limit', 'fields'];
excludedFields.forEach((el) => delete queryObj[el]);
// Advanced filtering
let queryStr = JSON.stringify(queryObj);
queryStr = queryStr.replace(/\b(gte|gt|lte|lt)\b/g, (match) => `$${match}`);
const parsedQuery = JSON.parse(queryStr);
// If the user searches by name → use regex for partial match
if (parsedQuery.nameAr) {
parsedQuery.nameAr = { $regex: parsedQuery.nameAr, $options: 'i' }; // 'i' = ignore case
}
this.query = this.query.find(parsedQuery);
return this;
}
sort() {
if (this.queryString.sort) {
const sortBy = this.queryString.sort.split(',').join(' ');
this.query = this.query.sort(sortBy);
} else {
// Default: sort by newest first, with _id as tiebreaker for stable pagination
// This ensures consistent ordering when multiple products have the same createdAt
this.query = this.query.sort('-createdAt _id');
}
return this;
}
limitFields() {
if (this.queryString.fields) {
const fields = this.queryString.fields.split(',').join(' ');
this.query = this.query.select(fields);
} else {
// FIXME: exclude __v field by default
this.query = this.query.select('-__v');
}
return this;
}
paginate() {
const page = this.queryString.page * 1 || 1;
const limit = this.queryString.limit * 1 || 100;
const skip = (page - 1) * limit;
this.query = this.query.skip(skip).limit(limit);
return this;
}
}
module.exports = APIFeatures;