Hola, queria compartirles este Ejemplo basico de como implementar MySQL en Node. Usando Promesas y async/await para dominar la asincronia sin bloquear el Event Loop.
Archivo
mysql.js contiene la conexión a MySQL.
const mysql = require("mysql");
const mysqlConnection = mysql.createConnection({
host: "localhost",
port: 3306,
user: "root",
password: "",
database: "",
});
mysqlConnection.connect((err) => {
if (err) {
console.error("[DB] No se pudo conectar con MYSQL", err);
} else {
console.log("[DB] Conectado con MYSQL", mysqlConnection.threadId);
}
});
module.exports = mysqlConnection;
Archivo con la clase principal. Implementa las 5 funciones básicas de CRUD+L = Create/Crear, Read/Leer, Update/Modificar, Delete/Borrar, List/Listar
const MySQL = require("./mysql");
function list(table) {
return new Promise(async (resolve, reject) => {
const sql = `SELECT * FROM ${table}`;
await MySQL.query(sql, (err, results) => {
if (err) {
console.error("[DB]", err);
return reject({ message: err, code: 401 });
}
return resolve(results);
});
});
}
function get(table, id) {
return new Promise(async (resolve, reject) => {
const sql = `SELECT * FROM ${table} WHERE id=${id}`;
await MySQL.query(sql, (err, results) => {
if (err) {
console.error("[DB]", err);
return reject({ message: err, code: 401 });
}
return resolve(results);
});
});
}
function insert(table, data) {
return new Promise(async (resolve, reject) => {
try {
const fields = Object.keys(data);
const values = Object.values(data);
if (fields.length === 0) {
return reject({ message: "Faltan datos", code: 400 });
}
const sql = `INSERT INTO ${table} (${fields}) VALUES (${values.map(
(h) => `'${h}'`
)})`;
await MySQL.query(sql, async (err, results) => {
if (err) return reject({ message: err.message, code: 400 });
const insertedData = await get(table, results.insertId);
return resolve(insertedData);
});
} catch (error) {
return reject(error);
}
});
}
function update(table, id, data) {
return new Promise(async (resolve, reject) => {
try {
const fields = Object.keys(data);
const values = Object.values(data);
if (fields.length === 0) {
return reject({ message: "Faltan datos", code: 400 });
}
const sql = `UPDATE ${table} SET ? WHERE id=${id}`;
const beforeUpdate = await get(table, id);
await MySQL.query(sql, data, async (err, results) => {
if (err) return reject({ message: err.message, code: 400 });
const updateData = await get(table, id);
return resolve({ ...results, beforeUpdate, updateData });
});
} catch (error) {
return reject(error);
}
});
}
function remove(table, id) {
return new Promise(async (resolve, reject) => {
try {
const beforeUpdate = await get(table, id);
if (beforeUpdate.length === 0)
return reject({ message: `El elemento ${id} no existe`, code: 403 });
const sql = `DELETE FROM ${table} WHERE id=${id} LIMIT 1`;
await MySQL.query(sql, async (err, results) => {
if (err) return reject({ message: err.message, code: 400 });
return resolve({ ...results, beforeUpdate });
});
} catch (error) {
return reject(error);
}
});
}
module.exports = {
list,
get,
insert,
update,
remove,
};
Esta clase no tiene ningún tipo de validación, eso se debería hacer en otra capa, como por ejemplo en el controlador con @hapi/joi.
Para usarse simplemente debe importarse este modulo desde otro e invocar a la función CRUDL, por ejemplo
Ejemplo de Uso
const db = require("./db.js"); // suponiendo que el archivo anterior se llame "db.js y
// ademas este ubicado en el mismo directorio que el presente codigo.
// Usar como funcion asincrona que debuelve un resultado o un error
// Operacion CRUDL: Listar la tabla 'usuarios' completa
// SIEMPRE dentro de una funcion async
async function getUsers(){
const myUsers = await db.get('usuarios')
return await db.get('usuarios')
// return await db.get('usuarios')
}
console.log(getUsers())
// O usar como funciones que devuelven promesas, y gestionarla con then/cath:
// Operacion CRUDL: (D) Borrar el registro de la tabla 'usuarios' cuyo id sea igual a '666'
db.remove('usuarios', 666)//Borrar usuario con id 666
.then(users=>{
// Se borro el usuario, hacer algo
console.log(`Se borro el user 666`)
})
.catch(error=>{
console.log(error)
})
Por ultimo, como tambien hago frontend, una cosa muy util es poder deshacer cualquier accion con un solo click, por cuestiones de UX/UI es una forma muy poderosa de fidelizar al usuario.
Por eso en las consultas '
remove' y '
update' se devuelve un objeto
beforeUpdate y
updateData "beforeUpdate": [
{
"id": 14,
"nombre": "Departamento de Coordinacion y Gestion Cooperativa",
"responsable": ""
}
]
Eso es muy util para revertir la ejecucion de la queri con un simple boton o 'call to action' como tiene gmail.