import { connection } from '../config/db.js' import dotenv from 'dotenv' dotenv.config() export class GeneralService { // constructor() { // this.devhint = this.devhint.bind(this) // } 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})` if (extra) console.log(formatted, '\n', extra) else console.log(formatted) } // =================================================== // ✅ 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) 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 } // =================================================== // ✅ executeQueryParam() // =================================================== // =================================================== async executeQueryParam(database, sql, params = []) { const formattedSQL = sql.replace(/\${database}/g, database) this.devhint(2, 'executeQueryParam', `📤 Executing Query`, `sql = ${formattedSQL}`) try { const result = await connection.query(formattedSQL, params) this.devhint(2, 'executeQueryParam', `✅ Query Success (${result.rowCount} rows)`) return result.rows } catch (err) { this.devhint(2, 'executeQueryParam', `❌ Query Failed`, err.message) console.error('SQL Error:', err) throw err // <– ส่งต่อ error เพื่อ controller จะจับได้ } } } // =================================================== // 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) // } // }