/** * 数据库查询优化工具 * 提供统一的查询构建和优化方法 */ const { Op } = require('sequelize'); /** * 查询构建器类 */ class QueryBuilder { constructor() { this.whereConditions = {}; this.orderConditions = []; this.includeConditions = []; this.attributes = null; this.limit = null; this.offset = null; this.groupBy = null; this.having = null; } /** * 添加搜索条件 * @param {string} field - 字段名 * @param {*} value - 搜索值 * @param {string} operator - 操作符 * @returns {QueryBuilder} 查询构建器实例 */ search(field, value, operator = 'like') { if (!value || value.toString().trim() === '') { return this; } switch (operator) { case 'like': this.whereConditions[field] = { [Op.like]: `%${value}%` }; break; case 'eq': this.whereConditions[field] = value; break; case 'ne': this.whereConditions[field] = { [Op.ne]: value }; break; case 'gt': this.whereConditions[field] = { [Op.gt]: value }; break; case 'gte': this.whereConditions[field] = { [Op.gte]: value }; break; case 'lt': this.whereConditions[field] = { [Op.lt]: value }; break; case 'lte': this.whereConditions[field] = { [Op.lte]: value }; break; case 'in': this.whereConditions[field] = { [Op.in]: Array.isArray(value) ? value : [value] }; break; case 'notIn': this.whereConditions[field] = { [Op.notIn]: Array.isArray(value) ? value : [value] }; break; case 'between': if (Array.isArray(value) && value.length === 2) { this.whereConditions[field] = { [Op.between]: value }; } break; case 'isNull': this.whereConditions[field] = { [Op.is]: null }; break; case 'notNull': this.whereConditions[field] = { [Op.not]: null }; break; } return this; } /** * 添加多字段搜索条件 * @param {Array} fields - 字段数组 * @param {*} value - 搜索值 * @param {string} operator - 操作符 * @returns {QueryBuilder} 查询构建器实例 */ searchMultiple(fields, value, operator = 'like') { if (!value || value.toString().trim() === '') { return this; } const searchConditions = fields.map(field => { switch (operator) { case 'like': return { [field]: { [Op.like]: `%${value}%` } }; case 'eq': return { [field]: value }; default: return { [field]: { [Op.like]: `%${value}%` } }; } }); if (this.whereConditions[Op.or]) { this.whereConditions[Op.or] = [...this.whereConditions[Op.or], ...searchConditions]; } else { this.whereConditions[Op.or] = searchConditions; } return this; } /** * 添加日期范围条件 * @param {string} field - 日期字段名 * @param {string} startDate - 开始日期 * @param {string} endDate - 结束日期 * @returns {QueryBuilder} 查询构建器实例 */ dateRange(field, startDate, endDate) { if (startDate || endDate) { const dateCondition = {}; if (startDate) { dateCondition[Op.gte] = new Date(startDate); } if (endDate) { dateCondition[Op.lte] = new Date(endDate); } this.whereConditions[field] = dateCondition; } return this; } /** * 添加状态条件 * @param {string} field - 状态字段名 * @param {*} status - 状态值 * @returns {QueryBuilder} 查询构建器实例 */ status(field, status) { if (status !== null && status !== undefined && status !== '') { this.whereConditions[field] = status; } return this; } /** * 添加排序条件 * @param {string} field - 排序字段 * @param {string} direction - 排序方向 ('ASC' 或 'DESC') * @returns {QueryBuilder} 查询构建器实例 */ orderBy(field, direction = 'DESC') { this.orderConditions.push([field, direction.toUpperCase()]); return this; } /** * 添加分页条件 * @param {number} page - 页码 * @param {number} limit - 每页数量 * @returns {QueryBuilder} 查询构建器实例 */ paginate(page = 1, limit = 10) { this.limit = parseInt(limit); this.offset = (parseInt(page) - 1) * this.limit; return this; } /** * 添加关联查询条件 * @param {Object} include - 关联查询配置 * @returns {QueryBuilder} 查询构建器实例 */ include(include) { this.includeConditions.push(include); return this; } /** * 设置查询字段 * @param {Array|Object} attributes - 查询字段 * @returns {QueryBuilder} 查询构建器实例 */ select(attributes) { this.attributes = attributes; return this; } /** * 添加分组条件 * @param {string|Array} groupBy - 分组字段 * @returns {QueryBuilder} 查询构建器实例 */ group(groupBy) { this.groupBy = groupBy; return this; } /** * 添加HAVING条件 * @param {Object} having - HAVING条件 * @returns {QueryBuilder} 查询构建器实例 */ having(having) { this.having = having; return this; } /** * 构建查询选项 * @returns {Object} Sequelize查询选项 */ build() { const options = { where: this.whereConditions, order: this.orderConditions.length > 0 ? this.orderConditions : undefined, include: this.includeConditions.length > 0 ? this.includeConditions : undefined, attributes: this.attributes, limit: this.limit, offset: this.offset, group: this.groupBy, having: this.having }; // 移除undefined值 Object.keys(options).forEach(key => { if (options[key] === undefined) { delete options[key]; } }); return options; } /** * 重置查询构建器 * @returns {QueryBuilder} 查询构建器实例 */ reset() { this.whereConditions = {}; this.orderConditions = []; this.includeConditions = []; this.attributes = null; this.limit = null; this.offset = null; this.groupBy = null; this.having = null; return this; } } /** * 创建查询构建器实例 * @returns {QueryBuilder} 查询构建器实例 */ const createQueryBuilder = () => { return new QueryBuilder(); }; /** * 构建分页查询 * @param {Object} Model - Sequelize模型 * @param {Object} queryOptions - 查询选项 * @param {Object} pagination - 分页参数 * @returns {Promise} 分页查询结果 */ const paginateQuery = async (Model, queryOptions, pagination = {}) => { const { page = 1, limit = 10 } = pagination; const offset = (page - 1) * limit; const options = { ...queryOptions, limit: parseInt(limit), offset: parseInt(offset) }; const { count, rows } = await Model.findAndCountAll(options); return { data: rows, pagination: { current: parseInt(page), pageSize: parseInt(limit), total: count, totalPages: Math.ceil(count / limit) } }; }; /** * 构建统计查询 * @param {Object} Model - Sequelize模型 * @param {Object} queryOptions - 查询选项 * @param {Array} groupFields - 分组字段 * @returns {Promise} 统计查询结果 */ const statsQuery = async (Model, queryOptions, groupFields = []) { const options = { ...queryOptions, attributes: [ ...groupFields, [Model.sequelize.fn('COUNT', Model.sequelize.col('*')), 'count'] ], group: groupFields }; const results = await Model.findAll(options); return results.map(result => ({ ...result.dataValues, count: parseInt(result.dataValues.count) })); }; /** * 构建搜索查询 * @param {Object} searchParams - 搜索参数 * @param {Object} searchConfig - 搜索配置 * @returns {Object} 搜索查询条件 */ const buildSearchQuery = (searchParams, searchConfig) => { const queryBuilder = createQueryBuilder(); // 处理搜索关键词 if (searchParams.search && searchConfig.searchFields) { queryBuilder.searchMultiple(searchConfig.searchFields, searchParams.search); } // 处理状态筛选 if (searchParams.status && searchConfig.statusField) { queryBuilder.status(searchConfig.statusField, searchParams.status); } // 处理日期范围 if (searchParams.dateRange && searchConfig.dateField) { const { start, end } = searchParams.dateRange; queryBuilder.dateRange(searchConfig.dateField, start, end); } // 处理排序 if (searchParams.sortBy && searchConfig.sortFields) { const sortField = searchConfig.sortFields[searchParams.sortBy] || searchParams.sortBy; queryBuilder.orderBy(sortField, searchParams.sortOrder || 'DESC'); } // 处理分页 if (searchParams.page && searchParams.limit) { queryBuilder.paginate(searchParams.page, searchParams.limit); } return queryBuilder.build(); }; /** * 常用查询配置 */ const QUERY_CONFIGS = { // 智能设备查询配置 smartDevices: { searchFields: ['deviceId', 'deviceName', 'serialNumber'], statusField: 'status', dateField: 'created_at', sortFields: { 'created_at': 'created_at', 'updated_at': 'updated_at', 'device_name': 'deviceName', 'status': 'status' } }, // 养殖场查询配置 farms: { searchFields: ['name', 'type', 'address'], statusField: 'status', dateField: 'created_at', sortFields: { 'created_at': 'created_at', 'updated_at': 'updated_at', 'name': 'name', 'type': 'type' } }, // 预警查询配置 alerts: { searchFields: ['deviceId', 'alertType', 'description'], statusField: 'status', dateField: 'alertTime', sortFields: { 'alert_time': 'alertTime', 'created_at': 'created_at', 'alert_type': 'alertType', 'level': 'level' } } }; /** * 获取查询配置 * @param {string} type - 查询类型 * @returns {Object} 查询配置 */ const getQueryConfig = (type) => { return QUERY_CONFIGS[type] || {}; }; module.exports = { QueryBuilder, createQueryBuilder, paginateQuery, statsQuery, buildSearchQuery, getQueryConfig, QUERY_CONFIGS };