// utils/queryBuilder.js const { Sequelize, Op } = require("sequelize"); /** * Builds a Sequelize `where` clause from an array of filters. * * @param {Array<{ id: string, value: any }>} filters * @returns {Object} Sequelize where clause */ function buildWhere(filters = [], allowedFields = new Set()) { const where = []; for (const { id, value } of filters) { if (!id || value === undefined || value === null || value === "") continue; // Reject fields not in whitelist (if whitelist is provided) if (allowedFields.size && !allowedFields.has(id)) continue; const values = Array.isArray(value) ? value : [value]; const conditions = values.map((v) => id.startsWith("personal_info.") ? Sequelize.where( Sequelize.json(`personal_info.${id.replace("personal_info.", "")}`), { [Op.iLike]: `%${v}%` } ) : Sequelize.where( Sequelize.cast(Sequelize.col(id), "TEXT"), { [Op.iLike]: `%${v}%` } ) ); where.push({ [Op.or]: conditions }); } return where.length ? { [Op.and]: where } : {}; } /** * Builds a Sequelize `order` clause from an array of sort descriptors. * Falls back to [["createdAt", "DESC"]] if no valid sort entries. * * @param {Array<{ id: string, desc: boolean }>} sort * @returns {Array} Sequelize order clause */ function buildOrder(sort = [], allowedFields = new Set()) { const order = []; for (const { id, desc } of sort) { if (!id) continue; // Reject fields not in whitelist (if whitelist is provided) if (allowedFields.size && !allowedFields.has(id)) continue; order.push( id.startsWith("personal_info.") ? [Sequelize.json(id), desc ? "DESC" : "ASC"] : [id, desc ? "DESC" : "ASC"] ); } return order.length ? order : [["createdAt", "DESC"]]; } /** * Convenience wrapper — returns both where and order in one call. * * @param {Array} filters * @param {Array} sort * @returns {{ where: Object, order: Array }} */ function buildQuery(filters = [], sort = [], allowedFields = []) { const fieldSet = new Set(allowedFields); return { where: buildWhere(filters, fieldSet), order: buildOrder(sort, fieldSet), }; } module.exports = { buildWhere, buildOrder, buildQuery };