simple-oracledb
Version:
Extend capabilities of oracledb with simplified API for quicker development.
209 lines (181 loc) • 6.01 kB
JavaScript
;
const funcs = require('funcs-js');
/**
* Promise utility class.
*
* @author Sagie Gur-Ari
* @class PromiseHelper
* @private
*/
function PromiseHelper() {
this.extensions = {
pool: {},
connection: {}
};
}
/**
* Empty function.
*
* @function
* @memberof! PromiseHelper
* @private
* @returns {undefined} Empty return
*/
PromiseHelper.prototype.noop = function () {
return undefined;
};
/**
* Returns true if the provided object supports the basic promise capabilities.
*
* @function
* @memberof! PromiseHelper
* @private
* @param {Object} promise - The promise object to validate
* @returns {Boolean} True if the provided object supports the basic promise capabilities
*/
PromiseHelper.prototype.isPromise = function (promise) {
let valid = false;
if (promise && promise.then && promise.catch && (typeof promise.then === 'function') && (typeof promise.catch === 'function')) {
valid = true;
}
return valid;
};
/**
* Ensures the provided function is invoked as an async function even if returning a promise.
*
* @function
* @memberof! PromiseHelper
* @private
* @param {Object} func - The function to invoke
* @param {function} callback - The callback to provide to the invoked function
*/
PromiseHelper.prototype.runAsync = function (func, callback) {
callback = funcs.once(callback, {
callbackStyle: true
});
const promise = func(callback);
if (this.isPromise(promise)) {
promise.then(function onDone(result) {
callback(null, result);
}).catch(callback);
}
};
/**
* Calls the provided function with a callback.
*
* @function
* @memberof! PromiseHelper
* @private
* @param {function} run - The async function to call (callback will be provided)
* @returns {Promise} In case of no callback provided in input, this function will return a promise
*/
PromiseHelper.prototype.runPromise = function (run) {
let promise;
let promiseCallback;
if (global.Promise) {
promise = new global.Promise(function runViaPromise(resolve, reject) {
promiseCallback = function (error, output) {
if (error) {
reject(error);
} else {
resolve(output);
}
};
run(promiseCallback);
});
} else {
throw new Error('No callback provided and promise not supported.');
}
return promise;
};
/**
* Calls the provided function with a callback and if needed, return a promise.
*
* @function
* @memberof! PromiseHelper
* @private
* @param {function} run - The async function to call (callback will be provided)
* @param {function} [callback] - An optional callback function
* @param {Boolean} [force=false] - If true, do not check if promise is supported
* @returns {Promise} In case of no callback provided in input, this function will return a promise
* @example
* ```js
* promiseHelper.run(function myFunc(promiseCallback) {
* //do some async activity...
* }, function onFuncDone(error, result) {
* if (error) {
* //function failed.
* } else {
* //function done
* }
* });
* ```
*/
PromiseHelper.prototype.run = function (run, callback, force) {
//if promise requested and supported by current platform
let promise;
if ((force || global.Promise) && (!callback)) {
promise = this.runPromise(run);
} else {
run(callback);
}
return promise;
};
/**
* Adds promise support for the provided function.
*
* @function
* @memberof! PromiseHelper
* @private
* @param {function} func - The function to promisify
* @param {Object} [options] - Holds constious behaviour options
* @param {Boolean} [options.force=false] - If true, do not check if promise is supported
* @param {Boolean} [options.defaultCallback=false] - If true and no callback provided, generate an empty callback
* @param {Number} [options.callbackMinIndex=0] - The minimum index in the arguments that the callback is found in
* @returns {function} The wrapper function
* @example
* ```js
* Connection.prototype.query = promiseHelper.promisify(Connection.prototype.query);
* ```
*/
PromiseHelper.prototype.promisify = function (func, options) {
//jscs:disable safeContextKeyword
const promiseHelper = this;
//jscs:enable safeContextKeyword
options = options || {};
return function promiseWrapper() {
/*eslint-disable no-invalid-this*/
const self = this;
/*eslint-enable no-invalid-this*/
const argumentsArray = Array.prototype.slice.call(arguments, 0);
//if last element is callback but undefined was provided
let continueRemove = true;
do {
if (argumentsArray.length && (argumentsArray[argumentsArray.length - 1] === undefined)) {
argumentsArray.pop();
} else {
continueRemove = false;
}
} while (continueRemove);
const minArgs = (options.callbackMinIndex || 0) + 1;
let callback;
let output;
if ((argumentsArray.length >= minArgs) && (typeof argumentsArray[argumentsArray.length - 1] === 'function')) {
output = func.apply(self, argumentsArray);
} else { //promise
if ((!options.force) && (!options.defaultCallback) && (!global.Promise)) {
throw new Error('No callback provided and promise not supported.');
}
output = promiseHelper.run(function asyncFunction(promiseCallback) {
callback = callback || promiseCallback;
if ((!callback) && options.defaultCallback) {
callback = promiseHelper.noop;
}
argumentsArray.push(callback);
func.apply(self, argumentsArray);
}, callback, options.force);
}
return output;
};
};
module.exports = new PromiseHelper();