qeasy
Version:
Query Easy: Simple SQL helper like Mongoose for MySQL/MariaDB
255 lines (192 loc) • 6.8 kB
JavaScript
const { checkConnection } = require("../dbConnection/db");
const { validateIdentifier } = require("../validator/validateIdentifier");
exports.insert = async (table, data) => {
try {
/** @type {import('mysql2/promise').Pool} */
const pool = checkConnection();
let query;
validateIdentifier(table, "table");
const columns = Object.keys(data);
const values = Object.values(data);
const questionParams = values.map(() => "?").join(", ");
query = `INSERT INTO ${table} (${columns}) VALUES (${questionParams})`;
const [result] = await pool.execute(query, values);
return result;
} catch (err) {
console.error("QEasy Insert Error:", err.message);
throw err;
}
};
exports.findWithJoins = async (options) => {
try {
const pool = checkConnection();
validateIdentifier(options.table, "table");
if (options.selectedColumns && Array.isArray(options.selectedColumns)) {
options.selectedColumns.forEach((col) => {
const parts = col.split(".");
if (parts.length === 2) {
validateIdentifier(parts[0], "table");
validateIdentifier(parts[1], "column");
} else {
validateIdentifier(parts[0], "column");
}
});
}
const columnsPart =
options.selectedColumns && options.selectedColumns.length > 0
? options.selectedColumns.join(", ")
: "*";
const aliasPart = options.as ? ` AS \`${options.as}\`` : "";
let query = `SELECT ${columnsPart} FROM \`${options.table}\`${aliasPart}`;
if (options.joins && Array.isArray(options.joins)) {
options.joins.forEach((join) => {
const validJoinTypes = ["INNER", "LEFT", "RIGHT"];
const joinType =
join.type && validJoinTypes.includes(join.type.toUpperCase())
? join.type.toUpperCase()
: "INNER";
validateIdentifier(join.table, "table");
const alias = join.as ? ` AS \`${join.as}\`` : "";
const leftKey = Object.keys(join.on)[0];
const rightKey = Object.values(join.on)[0];
const left = leftKey.split(".");
const right = rightKey.split(".");
validateIdentifier(left[0], "table");
validateIdentifier(left[1], "column");
validateIdentifier(right[0], "table");
validateIdentifier(right[1], "column");
const onClause = `\`${left[0]}\`.\`${left[1]}\` = \`${right[0]}\`.\`${right[1]}\``;
query += ` ${joinType} JOIN \`${join.table}\`${alias} ON ${onClause}`;
});
}
let params = [];
if (options.where && Array.isArray(options.where)) {
const conditions = [];
for (const cond of options.where) {
const parts = cond.column.split(".");
validateIdentifier(parts[0], "table");
validateIdentifier(parts[1], "column");
const op = cond.operator || "=";
conditions.push(`\`${parts[0]}\`.\`${parts[1]}\` ${op} ?`);
params.push(cond.value);
}
if (conditions.length > 0) {
query += ` WHERE ${conditions.join(" AND ")}`;
}
}
// ORDER BY
if (options.orderBy && Array.isArray(options.orderBy)) {
const orderParts = [];
for (const order of options.orderBy) {
const parts = order.column.split(".");
validateIdentifier(parts[0], "table");
validateIdentifier(parts[1], "column");
const dir =
order.direction && order.direction.toUpperCase() === "DESC"
? "DESC"
: "ASC";
orderParts.push(`\`${parts[0]}\`.\`${parts[1]}\` ${dir}`);
}
if (orderParts.length > 0) {
query += ` ORDER BY ${orderParts.join(", ")}`;
}
}
// LIMIT
if (options.limit && Number.isInteger(options.limit)) {
query += ` LIMIT ?`;
params.push(options.limit);
}
// OFFSET
if (options.offset && Number.isInteger(options.offset)) {
query += ` OFFSET ?`;
params.push(options.offset);
}
console.log("Final SQL:", query);
const [rows] = await pool.execute(query , params);
return rows;
} catch (err) {
console.error("QEasy Select Error:", err.message);
throw err;
}
};
/**
@param {string} table
*/
exports.findAll = async (table) => {
try {
const pool = checkConnection();
validateIdentifier(table, "table");
query = `SELECT * FROM \`${table}\``;
const [result] = await pool.execute(query);
return result;
} catch (error) {
console.error("QEasy FindAll Error :", err.message);
throw err;
}
};
/**
@param {string} table
@param {string} idField
@param {string|number} id
@returns {Promise<object|null>}
*/
exports.findById = async (table, idField, id) => {
try {
const pool = checkConnection();
validateIdentifier(table, "table");
validateIdentifier(idField, "idField");
const query = `SELECT * FROM \`${table}\` WHERE \`${idField}\` = ?`;
const [result] = await pool.execute(query, [id]);
if (result.length === 0) {
return [];
}
return result[0];
} catch (err) {
console.error("QEasy FindById Error :", err.message);
throw err;
}
};
/**
* @param {string} table
* @param {string} idField
* @param {string | number} id
* @param {object | string} data
* @returns {Promise<object|null>}
*/
exports.findByIdAndUpdate = async (table, idField, id, data) => {
try {
const pool = checkConnection();
let updateSubQueries;
validateIdentifier(table, "table");
validateIdentifier(idField, "idField");
const columns = Object.keys(data);
const values = Object.values(data);
updateSubQueries = columns.map((col) => `\`${col}\` = ?`).join(` ,`);
const params = [...values, id];
query = `UPDATE \`${table}\` SET ${updateSubQueries} WHERE \`${idField}\` = ?`;
const [result] = await pool.execute(query, params);
return result;
} catch (err) {
console.error("QEasy Update Error:", err.message);
throw err;
}
};
/**
* @param {string} table
* @param {string} idField
* @param {string|number} id
* @returns {Promise<object>}
*/
exports.findByIdAndDelete = async (table, idField, id) => {
try {
const pool = checkConnection();
validateIdentifier(table, "table");
validateIdentifier(idField, "idField");
const query = `DELETE FROM \`${table}\` WHERE \`${idField}\` = ?`;
const [result] = await pool.execute(query, [id]);
return result;
} catch (err) {
console.error("QEasy Delete Error:", err.message);
throw err;
}
};