First upload
This commit is contained in:
135
server/services/db.service.js
Normal file
135
server/services/db.service.js
Normal file
@@ -0,0 +1,135 @@
|
||||
// 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);
|
||||
Reference in New Issue
Block a user