// import mariadb from 'mariadb'; import * as mariadb from 'mariadb'; // Fix para BigInt en la serialización JSON (necesario para IDs grandes en MariaDB) BigInt.prototype.toJSON = function () { return this.toString(); }; // Configuración del Pool export const pool = mariadb.createPool({ host: process.env.DB_HOST, user: process.env.DB_USER, password: process.env.DB_PASSWORD, database: 'Reale', connectionLimit: 20, timezone: 'Z', insertIdAsNumber: true }); // Helper para escapar identificadores (tablas/columnas) const b = (id) => `\`${id.replace(/`/g, '``')}\``; export class Database { constructor(connector) { /** @type {mariadb.Pool | mariadb.PoolConnection} */ this.connector = connector; } async insert(table, data) { const rows = Array.isArray(data) ? data : [data]; if (!rows.length) return null; const fields = Object.keys(rows[0]); const query = `INSERT INTO ${b(table)} (${fields.map(b).join(',')}) VALUES (${fields.map(() => '?').join(',')})`; return this.connector.batch(query, rows.map(r => fields.map(f => r[f]))); } async update(table, data, where) { const fields = Object.keys(data); const wFields = Object.keys(where); const query = `UPDATE ${b(table)} SET ${fields.map(f => `${b(f)}=?`).join(',')} WHERE ${wFields.map(f => `${b(f)}=?`).join(' AND ')}`; return this.connector.query(query, [...fields.map(f => data[f]), ...wFields.map(f => where[f])]); } async upsert(table, data, ignore = false) { const rows = Array.isArray(data) ? data : [data]; if (!rows.length) return null; const fields = Object.keys(rows[0]); const set = fields.filter(f => f !== 'id').map(f => `${b(f)}=VALUES(${b(f)})`).join(','); const query = `INSERT ${ignore ? 'IGNORE' : ''} INTO ${b(table)} (${fields.map(b).join(',')}) VALUES (${fields.map(() => '?').join(',')}) ON DUPLICATE KEY UPDATE ${set}`; return this.connector.batch(query, rows.map(r => fields.map(f => r[f]))); } async delete(table, where) { const keys = Object.keys(where); if (!keys.length) throw new Error('Delete requiere condiciones'); return this.connector.query(`DELETE FROM ${b(table)} WHERE ${keys.map(k => `${b(k)}=?`).join(' AND ')}`, keys.map(k => where[k])); } async select(table, where = {}, opts = { limit: 5000, order: null }) { const keys = Object.keys(where); let sqlStr = `SELECT * FROM ${b(table)}`; if (keys.length) sqlStr += ` WHERE ${keys.map(k => `${b(k)}=?`).join(' AND ')}`; if (opts.order) sqlStr += ` ORDER BY ${b(opts.order)}`; return this.connector.query(sqlStr + ` LIMIT ${opts.limit}`, keys.map(k => where[k])); } async one(table, where) { const res = await this.select(table, where, { limit: 1 }); return res[0] || null; } async count(table, where = {}) { const keys = Object.keys(where); let sqlStr = `SELECT COUNT(*) as total FROM ${b(table)}`; if (keys.length) sqlStr += ` WHERE ${keys.map(k => `${b(k)}=?`).join(' AND ')}`; const res = await this.connector.query(sqlStr, keys.map(k => where[k])); return Number(res[0].total); } async search(table, fields, term, limit = 1000) { if (!fields.length || !term) return []; const where = fields.map(f => `${b(f)} LIKE ?`).join(' OR '); return this.connector.query(`SELECT * FROM ${b(table)} WHERE ${where} LIMIT ${limit}`, fields.map(() => `%${term}%`)); } async unique(table, fields, where = {}) { const f = Array.isArray(fields) ? fields.map(b).join(',') : b(fields); const keys = Object.keys(where); let sqlStr = `SELECT DISTINCT ${f} FROM ${b(table)}`; if (keys.length) sqlStr += ` WHERE ${keys.map(k => `${b(k)}=?`).join(' AND ')}`; const sort = Array.isArray(fields) ? b(fields[0]) : f; return this.connector.query(sqlStr + ` ORDER BY ${sort} ASC`, keys.map(k => where[k])); } async raw(query, data = {}) { const params = []; const sqlStr = query.replace(/:(\w+)/g, (_, key) => { params.push(data[key]); return '?'; }); return this.connector.query(sqlStr, params); } } /** * Lógica de Transacciones */ export const trx = async (opts, actions) => { const tasks = Array.isArray(opts) ? opts : [opts]; const conn = await pool.getConnection(); try { await conn.beginTransaction(); const transactionDb = new Database(conn); const results = {}; for (const item of tasks) { if (typeof actions[item.action] !== 'function') { throw new Error(`Acción ${item.action} no existe`); } results[item.action] = await actions[item.action](transactionDb, item); } await conn.commit(); return results; } catch (err) { console.error('Error en la transacción:', err); await conn.rollback(); throw err; } finally { if (conn) conn.release(); } }; // Exportamos la instancia principal vinculada al Pool export const db = new Database(pool);