UNPKG

bug-test-api

Version:

Express.js API project: bug-test-api

183 lines (161 loc) 6.02 kB
const db = require('../models'); const Questions = db.Questions; class QuestionsService { async findAll({ page = 1, limit = 10, filters = {} }) { try { const offset = (page - 1) * limit; const { search, sort, order, ...directFilters } = filters; const where = {}; const orderClause = []; // Apply direct column filters Object.keys(directFilters).forEach(key => { if (directFilters[key] !== undefined && directFilters[key] !== '') { // Support partial matching for text fields const attributes = Object.keys(Questions.rawAttributes); if (attributes.includes(key)) { const fieldType = Questions.rawAttributes[key].type; if (fieldType.key === 'STRING' || fieldType.key === 'TEXT') { const { Op } = require('sequelize'); where[key] = { [Op.iLike]: `%${directFilters[key]}%` }; } else { where[key] = directFilters[key]; } } } }); // Apply search across text fields (only if no direct filters conflict) if (search && search.trim()) { const { Op } = require('sequelize'); const searchTerm = search.trim(); // Get model attributes to search in text fields const attributes = Object.keys(Questions.rawAttributes); const searchableFields = attributes.filter(attr => { const type = Questions.rawAttributes[attr].type; return type.key === 'STRING' || type.key === 'TEXT'; }).filter(field => !directFilters[field]); // Exclude fields already filtered if (searchableFields.length > 0) { // Combine with existing where conditions using AND const searchCondition = { [Op.or]: searchableFields.map(field => ({ [field]: { [Op.iLike]: `%${searchTerm}%` } })) }; // If there are existing conditions, combine with AND if (Object.keys(where).length > 0) { where[Op.and] = [where, searchCondition]; // Clear the direct where conditions since they're now in Op.and Object.keys(where).forEach(key => { if (key !== Op.and) delete where[key]; }); } else { Object.assign(where, searchCondition); } } } // Apply sorting if (sort) { const sortDirection = order && order.toLowerCase() === 'asc' ? 'ASC' : 'DESC'; const attributes = Object.keys(Questions.rawAttributes); if (attributes.includes(sort)) { orderClause.push([sort, sortDirection]); } else { orderClause.push(['id', 'DESC']); } } else { orderClause.push(['id', 'DESC']); } // Try to include related data if associations exist const includeOptions = []; try { if (Questions.associations) { Object.keys(Questions.associations).forEach(associationName => { const association = Questions.associations[associationName]; if (association.associationType === 'BelongsTo' || association.associationType === 'HasMany') { includeOptions.push({ model: association.target, as: associationName, required: false // Use LEFT JOIN to avoid filtering out records }); } }); } } catch (error) { // Associations not available or error occurred, continue without includes console.warn('Could not load associations for Questions:', error.message); } const { count, rows } = await Questions.findAndCountAll({ where, limit: parseInt(limit), offset: parseInt(offset), order: orderClause, include: includeOptions }); return { data: rows, total: count, page: parseInt(page), limit: parseInt(limit) }; } catch (error) { throw new Error(`Error fetching questions: ${error.message}`); } } async findById(id) { try { // Try to include related data if associations exist const includeOptions = []; try { if (Questions.associations) { Object.keys(Questions.associations).forEach(associationName => { const association = Questions.associations[associationName]; if (association.associationType === 'BelongsTo' || association.associationType === 'HasMany') { includeOptions.push({ model: association.target, as: associationName, required: false // Use LEFT JOIN to avoid filtering out records }); } }); } } catch (error) { // Associations not available or error occurred, continue without includes console.warn('Could not load associations for Questions:', error.message); } return await Questions.findByPk(id, { include: includeOptions }); } catch (error) { throw new Error(`Error fetching questions: ${error.message}`); } } async create(data) { try { return await Questions.create(data); } catch (error) { throw new Error(`Error creating questions: ${error.message}`); } } async update(id, data) { try { const [updated] = await Questions.update(data, { where: { id }, returning: true }); if (updated) { return await Questions.findByPk(id); } return null; } catch (error) { throw new Error(`Error updating questions: ${error.message}`); } } async delete(id) { try { const result = await Questions.destroy({ where: { id } }); return result > 0; } catch (error) { throw new Error(`Error deleting questions: ${error.message}`); } } } module.exports = new QuestionsService();