UNPKG

@softrams/nodejs-mysql-connector

Version:

Database connector wrapper to work with MySQL database from nodejs applications

243 lines (218 loc) 7.49 kB
/* istanbul ignore file */ /* eslint-disable no-restricted-syntax */ /* eslint-disable no-await-in-loop */ /* eslint-disable no-else-return */ const mysql = require("mysql"); const fs = require('fs'); let pools = {}; let config = {}; const genericError = 'An error occurred communicating with the database.'; exports.init = async (cfg) => { config = cfg; }; exports.createPool = async (poolName) => { try { const srcCfg = config.DATASOURCES[poolName]; if (srcCfg) { const options = { connectionLimit: srcCfg.DB_CONNECTION_LIMIT || 5, host: srcCfg.DB_HOST, user: srcCfg.DB_USER, password: srcCfg.DB_PASSWORD, database: srcCfg.DB_DATABASE, port: srcCfg.PORT, multipleStatements: srcCfg.ALLOW_MULTI_STATEMENTS || false, timezone: srcCfg.TIMEZONE || 'local', typeCast: srcCfg.TYPE_CAST || true, dateStrings: srcCfg.DATE_STRINGS || false }; if (srcCfg.SSL) { const sslConfig = {}; if (srcCfg.SSL.CUSTOM_CERT) { sslConfig.ca = srcCfg.SSL.CUSTOM_CERT; } else { sslConfig.rejectUnauthorized = srcCfg.SSL.hasOwnProperty('REJECT_UNAUTHORIZED') ? srcCfg.SSL.REJECT_UNAUTHORIZED : true; } options.ssl = sslConfig; } pools[poolName] = mysql.createPool(options); console.debug(`MySQL Adapter: Pool ${poolName} created`); return true; } else { console.error(`MySQL Adapter: Missing configuration for ${poolName}`); return false; } } catch (err) { console.error("MySQL Adapter: Error while closing connection", err); return false; } }; exports.connect = async (poolName) => { try { if (!pools[poolName]) { await this.createPool(poolName); } return pools[poolName]; } catch (err) { console.error("MySQL Adapter: Error while retrieving a connection", err); throw new Error(err.message); } }; this.query = async (conn, query, params) => { return new Promise((resolve, reject) => { try { conn.query(query, params, (error, results) => { if (error) { console.error("MySQL Adapter: Failure in query: ", error); this.handleError(reject, error); } else { resolve(results); } }); } catch (err) { console.error("MySQL Adapter: Failure in query: ", err); this.handleError(reject, err); } }); }; this.handleError = (reject, error) => { const errorReturn = (config && config.HIDE_DB_ERRORS) ? new Error(genericError) : error; reject(errorReturn); }; exports.execute = async (srcName, query, params = {}) => { try { console.debug(query); if (params) { console.debug(JSON.stringify(params)); } const start = process.hrtime(); const conn = await this.connect(srcName); console.debug( `MySQL Adapter: Connection secured: ${process.hrtime(start)[0]}s ${ process.hrtime(start)[1] / 1000000 }ms` ); const results = await this.query(conn, query, params); console.debug( `MySQL Adapter: Query executed: ${process.hrtime(start)[0]}s ${ process.hrtime(start)[1] / 1000000 }ms` ); return results; } catch (err) { console.error("MySQL Adapter: Error while executing query", err); throw new Error(err.message); } }; exports.closeAllPools = async () => { try { for (const poolAlias of Object.keys(pools)) { await this.closePool(poolAlias); delete pools[poolAlias]; console.debug(`MySQL Adapter: Pool ${poolAlias} closed`); } return true; } catch (err) { console.error("MySQL Adapter: Error while closing connection", err); return false; } }; exports.closePool = async (poolAlias) => { try { if (pools[poolAlias]) { const poolConn = pools[poolAlias]; delete pools[poolAlias]; await poolConn.end((err) => { if (err) { console.error( `Error while closing connection pool ${poolAlias}`, err ); } }); return true; } else { return true; } } catch (err) { console.error("MySQL Adapter: Error while closing connection", err); return false; } }; exports.transactionConnection = (pool) => { return new Promise((resolve, reject) => { pool.getConnection((err, connection) => { let query; if (err) reject(err); if (connection) { console.log("MySQL Pool connected with threadId " + connection.threadId); query = (sql, params) => { return new Promise((resolve, reject) => { connection.query(sql, params, (err, result) => { console.debug("Executing query " + sql); if (params) { console.debug(JSON.stringify(params)); } if (err) reject(err); resolve(result); }); }); }; } const TRANSACTIONS = Object.freeze({ START: 'START TRANSACTION', COMMIT: 'COMMIT', ROLLBACK: 'ROLLBACK' }); const release = () => { return new Promise((resolve, reject) => { if (err) reject(err); if (connection) { console.log("MySQL pool released the thread " + connection.threadId); resolve(connection.release()); } }); }; const beginTransaction = () => { return new Promise((resolve, reject) => { if (err) reject(err); if (connection) { console.log("MySQL beginning transaction with connection thread: " + connection.threadId); resolve(connection.query(TRANSACTIONS.START)); } }); }; const commitTransaction = () => { return new Promise((resolve, reject) => { if (err) reject(err); if (connection) { console.log("MySQL commiting transaction for connection thread: " + connection.threadId); resolve(connection.query(TRANSACTIONS.COMMIT)); } }); }; const rollbackTransaction = () => { return new Promise((resolve, reject) => { if (err) reject(err); if (connection) { console.log("MySQL rolling back the transaction of connection thread: " + connection.threadId); resolve(connection.query(TRANSACTIONS.ROLLBACK)); } }); }; const execute = (sql, params) => { return new Promise((resolve, reject) => { connection.query(sql, params, (err, result) => { console.debug("Executing query " + sql); if (params) { console.debug(JSON.stringify(params)); } if (err) reject(err); resolve(result); }); }); } resolve({ query, execute, release, beginTransaction, commitTransaction, rollbackTransaction}); }); }); };