import { connection } from '../config/db.js' import dotenv from 'dotenv' import { sendError } from '../utils/response.js' dotenv.config() export class GeneralService { devhint(level, location, message, extra = null) { const isEnabled = process.env.DEVHINT === 'true' const currentLevel = parseInt(process.env.DEVHINT_LEVEL || '1', 10) if (!isEnabled || level > currentLevel) return const timestamp = new Date().toISOString() const prefix = `🧩 [DEVHINT:${location}]` const formatted = `${prefix} → ${message} (${timestamp})` // 🔹 highlight jumpout if (message.includes('Jumpout')) { console.log('\x1b[31m%s\x1b[0m', formatted) // แดง = jumpout } else if (message.includes('Error')) { console.log('\x1b[33m%s\x1b[0m', formatted) // เหลือง = error } else { console.log(formatted) } if (extra) console.log(extra) } // =================================================== // ✅ executeQueryParam() — เจ๊งจริง แล้ว controller catch ได้จริง // =================================================== async executeQueryParam(database, sql, params = []) { const formattedSQL = sql.replace(/\${database}/g, database) try { this.devhint(2, 'executeQueryParam', `📤 Executing Query`, `sql = ${formattedSQL}`) const result = await connection.query(formattedSQL, params) this.devhint(2, 'executeQueryParam', `✅ Query Success (${result.rowCount} rows)`) return result.rows } catch (err) { this.devhint(1, 'executeQueryParam', `❌ SQL Error`, err.message) console.error('🧨 SQL Error:', err.message) throw new Error(`SQL_EXECUTION_FAILED::${err.message}`) // ✅ “เจ๊ง” แล้วโยนขึ้น controller จริง } } // =================================================== // ✅ executeQueryConditions() — เหมือนกัน // =================================================== async executeQueryConditions(database, baseQuery, conditions = {}) { this.devhint(2, 'GeneralService', 'executeQueryConditions() start') let whereClauses = [] let params = [] let idx = 1 for (const [key, value] of Object.entries(conditions)) { if (value === undefined || value === null || value === '') continue const match = String(value).match(/^(ILIKE|LIKE)\s+(.+)$/i) if (match) { const operator = match[1].toUpperCase() const pattern = match[2].trim() whereClauses.push(`${key} ${operator} $${idx}`) params.push(pattern) } else { whereClauses.push(`${key} = $${idx}`) params.push(value) } idx++ } let finalQuery = baseQuery if (whereClauses.length > 0) finalQuery += ' AND ' + whereClauses.join(' AND ') const formattedSQL = finalQuery.replace(/\${database}/g, database) try { this.devhint(2, 'executeQueryConditions', `📤 Executing Query`, { database, sql: formattedSQL, params }) const result = await connection.query(formattedSQL, params) this.devhint(2, 'executeQueryConditions', `✅ Query Success (${result.rowCount} rows)`) return result.rows } catch (err) { this.devhint(1, 'executeQueryConditions', `❌ SQL Error`, err.message) console.error('🧨 SQL Error:', err.message) throw new Error(`SQL_EXECUTION_FAILED::${err.message}`) } } } // =================================================== // Export สำหรับ controller หรืออื่นๆ เรียกใช้ได้ด้วย // =================================================== // /** // * ✅ executeQueryParam (ของเดิม) // * ใช้กับ SQL + database schema + params // */ // export async function executeQueryParam(sql, database, params = []) { // try { // if (!database) throw new Error('Database is not defined') // const formattedSQL = sql.replace(/\${database}/g, database) // console.log(`[DB:${database}] → ${formattedSQL}`) // const result = await connection.query(formattedSQL, params) // return result.rows // } catch (err) { // console.error('[executeQueryParam Error]', err.message) // throw err // } // } /** * ✅ executeQueryConditions (ใหม่) * ใช้สร้าง WHERE อัตโนมัติจาก object เงื่อนไข * ตัวที่ไม่มีค่า (null, undefined, '') จะไม่ถูกนำมาสร้างใน WHERE */ // export async function executeQueryConditions(database, baseQuery, conditions = {}) { // try { // if (!database) throw new Error('Database is not defined') // let whereClauses = [] // let params = [] // let idx = 1 // for (const [key, value] of Object.entries(conditions)) { // if (value === undefined || value === null || value === '') continue // // ✅ ตรวจว่า value มีคำว่า LIKE หรือ ILIKE ไหม // const match = String(value).match(/^(ILIKE|LIKE)\s+(.+)$/i) // if (match) { // const operator = match[1].toUpperCase() // const pattern = match[2].trim() // whereClauses.push(`${key} ${operator} $${idx}`) // params.push(pattern) // } else { // whereClauses.push(`${key} = $${idx}`) // params.push(value) // } // idx++ // } // let finalQuery = baseQuery // if (whereClauses.length > 0) { // finalQuery += ' AND ' + whereClauses.join(' AND ') // } // const formattedSQL = finalQuery.replace(/\${database}/g, database) // console.log(`[DB:${database}] → ${formattedSQL}`) // const result = await connection.query(formattedSQL, params) // return result.rows // } catch (err) { // console.error('[executeQueryConditions Error]', err.message) // throw err // } // } // /** // * 🧩 devhint — Debug tracer ที่เปิดปิดได้จาก .env // * @param {string} fileName - ชื่อไฟล์หรือโมดูล (เช่น 'usercontroller.js') // * @param {string} message - ข้อความหรือจุดใน flow (เช่น 'onNavigate') // * @param {object|string} [extra] - ข้อมูลเพิ่มเติม (optional) // */ // export function devhint(fileName, message, extra = null) { // if (process.env.DEVHINT === 'true') { // const timestamp = new Date().toISOString() // const prefix = `🧩 [DEVHINT:${fileName}]` // const formatted = `${prefix} → ${message} (${timestamp})` // if (extra) console.log(formatted, '\n', extra) // else console.log(formatted) // } // }