morsel-sql.db
Version:
Morsel, advanced SQL database for Node.js
313 lines (284 loc) • 11.5 kB
JavaScript
const mysql = require('mysql2/promise');
class morselSQL {
constructor(config) {
this.config = config;
this.pool = mysql.createPool({
...config,
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
});
}
async connect() {
try {
this.connection = await this.pool.getConnection();
console.log('Connected to the database.');
} catch (error) {
console.error('Connection error:', error.message);
throw new Error(`Connection error: ${error.message}`);
}
}
async disconnect() {
try {
if (this.connection) {
await this.connection.release();
console.log('Database connection closed.');
}
} catch (error) {
console.error('Disconnection error:', error.message);
throw new Error(`Disconnection error: ${error.message}`);
}
}
async query(sql, params) {
try {
const [rows] = await this.connection.execute(sql, params);
return rows;
} catch (error) {
console.error('Query error:', error.message);
throw new Error(`Query error: ${error.message}`);
}
}
async transaction(queries) {
try {
await this.connection.beginTransaction();
const results = [];
for (const { sql, params } of queries) {
const result = await this.query(sql, params);
results.push(result);
}
await this.connection.commit();
return results;
} catch (error) {
await this.connection.rollback();
console.error('Transaction error:', error.message);
throw new Error(`Transaction error: ${error.message}`);
}
}
async insert(table, data) {
try {
const keys = Object.keys(data).join(', ');
const values = Object.values(data).map(() => '?').join(', ');
const sql = `INSERT INTO ${table} (${keys}) VALUES (${values})`;
return await this.query(sql, Object.values(data));
} catch (error) {
console.error('Insert error:', error.message);
throw new Error(`Insert error: ${error.message}`);
}
}
async bulkInsert(table, rows) {
try {
if (rows.length === 0) return;
const keys = Object.keys(rows[0]).join(', ');
const values = rows.map(row => `(${Object.values(row).map(() => '?').join(', ')})`).join(', ');
const sql = `INSERT INTO ${table} (${keys}) VALUES ${values}`;
const params = rows.reduce((acc, row) => [...acc, ...Object.values(row)], []);
return await this.query(sql, params);
} catch (error) {
console.error('Bulk insert error:', error.message);
throw new Error(`Bulk insert error: ${error.message}`);
}
}
async select(table, conditions = {}, columns = '*') {
try {
const keys = Object.keys(conditions).map(key => `${key} = ?`).join(' AND ');
const sql = `SELECT ${columns} FROM ${table}` + (keys ? ` WHERE ${keys}` : '');
return await this.query(sql, Object.values(conditions));
} catch (error) {
console.error('Select error:', error.message);
throw new Error(`Select error: ${error.message}`);
}
}
async selectWithJoin(table, joinType, joinTable, joinCondition, conditions = {}, columns = '*') {
try {
const keys = Object.keys(conditions).map(key => `${table}.${key} = ?`).join(' AND ');
const sql = `SELECT ${columns} FROM ${table} ${joinType} JOIN ${joinTable} ON ${joinCondition}` + (keys ? ` WHERE ${keys}` : '');
return await this.query(sql, Object.values(conditions));
} catch (error) {
console.error('Join operation error:', error.message);
throw new Error(`Join operation error: ${error.message}`);
}
}
async update(table, data, conditions) {
try {
const set = Object.keys(data).map(key => `${key} = ?`).join(', ');
const where = Object.keys(conditions).map(key => `${key} = ?`).join(' AND ');
const sql = `UPDATE ${table} SET ${set} WHERE ${where}`;
return await this.query(sql, [...Object.values(data), ...Object.values(conditions)]);
} catch (error) {
console.error('Update error:', error.message);
throw new Error(`Update error: ${error.message}`);
}
}
async delete(table, conditions) {
try {
const where = Object.keys(conditions).map(key => `${key} = ?`).join(' AND ');
const sql = `DELETE FROM ${table} WHERE ${where}`;
return await this.query(sql, Object.values(conditions));
} catch (error) {
console.error('Delete error:', error.message);
throw new Error(`Delete error: ${error.message}`);
}
}
async count(table, conditions = {}) {
try {
const keys = Object.keys(conditions).map(key => `${key} = ?`).join(' AND ');
const sql = `SELECT COUNT(*) as count FROM ${table}` + (keys ? ` WHERE ${keys}` : '');
const result = await this.query(sql, Object.values(conditions));
return result[0].count;
} catch (error) {
console.error('Count error:', error.message);
throw new Error(`Count error: ${error.message}`);
}
}
async exists(table, conditions = {}) {
try {
const keys = Object.keys(conditions).map(key => `${key} = ?`).join(' AND ');
const sql = `SELECT EXISTS(SELECT 1 FROM ${table} WHERE ${keys}) as exists`;
const result = await this.query(sql, Object.values(conditions));
return result[0].exists;
} catch (error) {
console.error('Existence check error:', error.message);
throw new Error(`Existence check error: ${error.message}`);
}
}
async truncate(table) {
try {
const sql = `TRUNCATE TABLE ${table}`;
return await this.query(sql);
} catch (error) {
console.error('Truncate error:', error.message);
throw new Error(`Truncate error: ${error.message}`);
}
}
async dropTable(table) {
try {
const sql = `DROP TABLE IF EXISTS ${table}`;
return await this.query(sql);
} catch (error) {
console.error('Drop table error:', error.message);
throw new Error(`Drop table error: ${error.message}`);
}
}
async createTable(table, columns) {
try {
const cols = Object.keys(columns)
.map(key => `${key} ${columns[key]}`)
.join(', ');
const sql = `CREATE TABLE IF NOT EXISTS ${table} (${cols})`;
return await this.query(sql);
} catch (error) {
console.error('Create table error:', error.message);
throw new Error(`Create table error: ${error.message}`);
}
}
async getTableColumns(table) {
try {
const sql = `SHOW COLUMNS FROM ${table}`;
return await this.query(sql);
} catch (error) {
console.error('Get table columns error:', error.message);
throw new Error(`Get table columns error: ${error.message}`);
}
}
async getTables() {
try {
const sql = `SHOW TABLES`;
return await this.query(sql);
} catch (error) {
console.error('Get tables error:', error.message);
throw new Error(`Get tables error: ${error.message}`);
}
}
async getDatabaseSize() {
try {
const sql = `SELECT table_schema AS database_name, ROUND(SUM(data_length + index_length) / 1024 / 1024, 2) AS size_mb FROM information_schema.tables WHERE table_schema = ? GROUP BY table_schema`;
const result = await this.query(sql, [this.config.database]);
return result[0]?.size_mb || 0;
} catch (error) {
console.error('Get database size error:', error.message);
throw new Error(`Get database size error: ${error.message}`);
}
}
async optimizeTable(table) {
try {
const sql = `OPTIMIZE TABLE ${table}`;
return await this.query(sql);
} catch (error) {
console.error('Optimize table error:', error.message);
throw new Error(`Optimize table error: ${error.message}`);
}
}
async repairTable(table) {
try {
const sql = `REPAIR TABLE ${table}`;
return await this.query(sql);
} catch (error) {
console.error('Repair table error:', error.message);
throw new Error(`Repair table error: ${error.message}`);
}
}
async showProcessList() {
try {
const sql = `SHOW PROCESSLIST`;
return await this.query(sql);
} catch (error) {
console.error('Get process list error:', error.message);
throw new Error(`Get process list error: ${error.message}`);
}
}
async showStatus() {
try {
const sql = `SHOW STATUS`;
return await this.query(sql);
} catch (error) {
console.error('Get status error:', error.message);
throw new Error(`Get status error: ${error.message}`);
}
}
async showVariables() {
try {
const sql = `SHOW VARIABLES`;
return await this.query(sql);
} catch (error) {
console.error('Get variables error:', error.message);
throw new Error(`Get variables error: ${error.message}`);
}
}
async setVariable(name, value) {
try {
const sql = `SET ${name} = ?`;
return await this.query(sql, [value]);
} catch (error) {
console.error('Set variable error:', error.message);
throw new Error(`Set variable error: ${error.message}`);
}
}
async getUserPrivileges(user) {
try {
const sql = `SHOW GRANTS FOR '${user}'@'%'`;
return await this.query(sql);
} catch (error) {
console.error('Get user privileges error:', error.message);
throw new Error(`Get user privileges error: ${error.message}`);
}
}
async grantPrivileges(user, privileges, database = '*') {
try {
const sql = `GRANT ${privileges} ON ${database}.* TO '${user}'@'%'`;
return await this.query(sql);
} catch (error) {
console.error('Grant privileges error:', error.message);
throw new Error(`Grant privileges error: ${error.message}`);
}
}
async revokePrivileges(user, privileges, database = '*') {
try {
const sql = `REVOKE ${privileges} ON ${database}.* FROM '${user}'@'%'`;
return await this.query(sql);
} catch (error) {
console.error('Revoke privileges error:', error.message);
throw new Error(`Revoke privileges error: ${error.message}`);
}
}
}
module.exports = morselSQL;