simple-oracledb
Version:
Extend capabilities of oracledb with simplified API for quicker development.
289 lines (259 loc) • 11 kB
JavaScript
;
const emitter = require('./emitter');
const Pool = require('./pool');
const Connection = require('./connection');
const constants = require('./constants');
const promiseHelper = require('./promise-helper');
/**
* This events is triggered when a pool is created.
*
* @event OracleDB#pool-created
* @param {Pool} pool - The pool instance
*/
/**
* This events is triggered after a pool is released.
*
* @event OracleDB#pool-released
* @param {Pool} pool - The pool instance
*/
/**
* This events is triggered when a connection is created via oracledb.
*
* @event OracleDB#connection-created
* @param {Connection} connection - The connection instance
*/
/**
* This events is triggered when a connection is released successfully.
*
* @event OracleDB#connection-released
* @param {Connection} connection - The connection instance
*/
/**
* An action requested by the pool to be invoked.
*
* @callback ConnectionAction
* @param {Connection} connection - A valid connection to be used by the action
* @param {AsyncCallback} callback - The callback to invoke at the end of the action
*/
/*jslint debug: true */
/*istanbul ignore next*/
/**
* This class holds all the extended capabilities added the oracledb.
*
* @author Sagie Gur-Ari
* @class OracleDB
* @public
*/
function OracleDB() {
//should not be called
}
/*jslint debug: false */
/**
* Marker property.
*
* @member {Boolean}
* @alias OracleDB.simplified
* @memberof! OracleDB
* @public
*/
OracleDB.prototype.simplified = true;
/*eslint-disable valid-jsdoc*/
//jscs:disable jsDoc
/**
* Wraps the original oracledb getConnection in order to provide an extended connection object.
*
* @function
* @memberof! OracleDB
* @public
* @param {Object} connectionAttributes - The connection attributes object
* @param {AsyncCallback} [callback] - Invoked with an error or the oracle connection instance
* @returns {Promise} In case of no callback provided in input, this function will return a promise
*/
OracleDB.prototype.getConnection = function (connectionAttributes, callback) {
const self = this;
const onWrapperConnection = function (error, connection) {
/*istanbul ignore else*/
if ((!error) && connection) {
self.emit('connection-created', connection);
connection.once('release', function onRelease() {
self.emit('connection-released', connection);
});
}
callback(error, connection);
};
self.baseGetConnection(connectionAttributes, Connection.wrapOnConnection(onWrapperConnection));
};
//jscs:enable jsDoc
/*eslint-enable valid-jsdoc*/
//add promise support
OracleDB.prototype.getConnection = promiseHelper.promisify(OracleDB.prototype.getConnection);
/*eslint-disable valid-jsdoc*/
//jscs:disable jsDoc
/**
* Wraps the original oracledb createPool in order to provide an extended pool object.
*
* @function
* @memberof! OracleDB
* @public
* @param {Object} poolAttributes - The connection pool attributes object (see https://github.com/oracle/node-oracledb/blob/master/doc/api.md#createpool for more attributes)
* @param {Number} [poolAttributes.retryCount=10] - The max amount of retries to get a connection from the pool in case of any error
* @param {Number} [poolAttributes.retryInterval=250] - The interval in millies between get connection retry attempts
* @param {Boolean} [poolAttributes.runValidationSQL=true] - True to ensure the connection returned is valid by running a test ping or validation SQL
* @param {Boolean} [poolAttributes.usePingValidation=true] - If runValidationSQL, this flag will define if validation should first attempt to use connection.ping instead of running a SQL
* @param {String} [poolAttributes.validationSQL=SELECT 1 FROM DUAL] - The test SQL to invoke before returning a connection to validate the connection is open
* @param {AsyncCallback} [callback] - Invoked with an error or the oracle connection pool instance
* @returns {Promise} In case of no callback provided in input, this function will return a promise
*/
OracleDB.prototype.createPool = function (poolAttributes, callback) {
const self = this;
if ((!callback) && poolAttributes && (typeof poolAttributes === 'function')) {
callback = poolAttributes;
poolAttributes = null;
}
self.baseCreatePool(poolAttributes, function onPool(error, pool) {
if ((!error) && pool) {
Pool.extend(pool, poolAttributes);
self.emit('pool-created', pool);
pool.once('release', function onRelease() {
self.emit('pool-released', pool);
});
}
callback(error, pool);
});
};
//jscs:enable jsDoc
/*eslint-enable valid-jsdoc*/
//add promise support
OracleDB.prototype.createPool = promiseHelper.promisify(OracleDB.prototype.createPool);
/*eslint-disable valid-jsdoc*/
//jscs:disable jsDoc
/**
* This function invokes the provided action (function) with a valid connection object and a callback.<br>
* The action can use the provided connection to run any connection operation/s (execute/query/transaction/...) and after finishing it
* must call the callback with an error (if any) and result.<br>
* For promise support, the action can simply return a promise instead of calling the provided callback.<br>
* This function will ensure the connection is released properly and only afterwards will call the provided callback with the action error/result.<br>
* This function basically will remove the need of caller code to get and release a connection and focus on the actual database operation logic.<br>
* It is recommanded to create a pool and use the pool.run instead of oracledb.run as this function will create a new connection (and release it) for each invocation,
* on the other hand, pool.run will reuse pool managed connections which will result in improved performance.
*
* @function
* @memberof! OracleDB
* @public
* @param {Object} connectionAttributes - The connection attributes object (see oracledb.getConnection for more details)
* @param {Boolean} [connectionAttributes.ignoreReleaseErrors=false] - If true, errors during connection.release() invoked internally will be ignored
* @param {Object} [connectionAttributes.releaseOptions={force: false}] - The connection.release options (see connection.release for more info)
* @param {Boolean} [connectionAttributes.releaseOptions.force=false] - If force=true the connection.break will be called before trying to release to ensure all running activities are aborted
* @param {ConnectionAction} action - An action requested to be invoked.
* @param {AsyncCallback} [callback] - Invoked with an error or the oracle connection instance
* @returns {Promise} In case of no callback provided in input, this function will return a promise
* @example
* ```js
* oracledb.run({
* user: process.env.ORACLE_USER,
* password: process.env.ORACLE_PASSWORD,
* connectString: process.env.ORACLE_CONNECTION_STRING
* }, function onConnection(connection, callback) {
* //run some query and the output will be available in the 'run' callback
* connection.query('SELECT department_id, department_name FROM departments WHERE manager_id < :id', [110], callback);
* }, function onActionDone(error, result) {
* //do something with the result/error
* });
*
* oracledb.run({
* user: process.env.ORACLE_USER,
* password: process.env.ORACLE_PASSWORD,
* connectString: process.env.ORACLE_CONNECTION_STRING
* }, function (connection, callback) {
* //run some database operations in a transaction
* connection.transaction([
* function firstAction(callback) {
* connection.insert(...., callback);
* },
* function secondAction(callback) {
* connection.update(...., callback);
* }
* ], {
* sequence: true
* }, callback); //at end of transaction, call the oracledb provided callback
* }, function onActionDone(error, result) {
* //do something with the result/error
* });
*
* //full promise support for both oracledb.run and the action
* oracledb.run({
* user: process.env.ORACLE_USER,
* password: process.env.ORACLE_PASSWORD,
* connectString: process.env.ORACLE_CONNECTION_STRING
* }, function (connection) {
* //run some database operations in a transaction and return a promise
* return connection.transaction([
* function firstAction() {
* return connection.insert(....); //returns a promise
* },
* function secondAction() {
* return connection.update(....); //returns a promise
* }
* ]);
* }).then(function (result) {
* //do something with the result
* });
* ```
*/
OracleDB.prototype.run = function (connectionAttributes, action, callback) {
if (connectionAttributes && (typeof connectionAttributes === 'object') && action && (typeof action === 'function')) {
const releaseOptions = connectionAttributes.releaseOptions || {};
const simpleOracleDB = require('./simple-oracledb');
const actionRunner = simpleOracleDB.createOnConnectionCallback(action, connectionAttributes, releaseOptions, callback);
this.getConnection(connectionAttributes, actionRunner);
} else {
throw new Error('Illegal input provided.');
}
};
//jscs:enable jsDoc
/*eslint-enable valid-jsdoc*/
//add promise support
OracleDB.prototype.run = promiseHelper.promisify(OracleDB.prototype.run, {
callbackMinIndex: 2
});
module.exports = {
/**
* Extends the provided oracledb instance.
*
* @function
* @memberof! OracleDB
* @public
* @param {Object} oracledb - The oracledb instance
*/
extend: function extend(oracledb) {
if (oracledb && (!oracledb.simplified)) {
//update type meta info
if (oracledb.BLOB !== undefined) {
constants.blobType = oracledb.BLOB;
}
if (oracledb.CLOB !== undefined) {
constants.clobType = oracledb.CLOB;
}
if (oracledb.DATE !== undefined) {
constants.dateType = oracledb.DATE;
}
if (oracledb.NUMBER !== undefined) {
constants.numberType = oracledb.NUMBER;
}
if (oracledb.STRING !== undefined) {
constants.stringType = oracledb.STRING;
}
if (oracledb.BIND_OUT !== undefined) {
constants.bindOut = oracledb.BIND_OUT;
}
const properties = Object.keys(OracleDB.prototype);
properties.forEach(function addProperty(property) {
if (typeof oracledb[property] === 'function') {
oracledb['base' + property.charAt(0).toUpperCase() + property.slice(1)] = oracledb[property];
}
oracledb[property] = OracleDB.prototype[property];
});
emitter(oracledb);
}
}
};