simple-oracledb
Version:
Extend capabilities of oracledb with simplified API for quicker development.
214 lines (192 loc) • 7.36 kB
JavaScript
;
const debug = require('debuglog')('simple-oracledb');
const rowsReader = require('./rows-reader');
/*jslint debug: true */
/**
* ResultSet object reading helper functions.
*
* @author Sagie Gur-Ari
* @class ResultSetReader
* @private
*/
function ResultSetReader() {
//should not be called
}
/*jslint debug: false */
/**
* Releases the resultset.
*
* @function
* @memberof! ResultSetReader
* @private
* @param {Array} resultSet - The oracle ResultSet object
* @param {Boolean} ignoreErrors - True to ignore errors
* @param {AsyncCallback} callback - called when the result set is released
*/
ResultSetReader.prototype.releaseResultSet = function (resultSet, ignoreErrors, callback) {
if (resultSet) {
resultSet.close(function onClose(error) {
if (error && (!ignoreErrors)) {
callback(error);
} else {
if (error) {
debug('Unable to close resultset, ', error.stack);
}
callback();
}
});
} else {
callback();
}
};
/**
* Reads the next rows data from the provided oracle ResultSet object.
*
* @function
* @memberof! ResultSetReader
* @public
* @param {Array} columnNames - Array of strings holding the column names of the results
* @param {Array} resultSet - The oracle ResultSet object
* @param {Object} [options] - Any options
* @param {Number} [options.bulkRowsAmount=100] - The amount of rows to fetch
* @param {Number} [options.flattenStackEveryRows=Math.max(1, Math.floor(100 / columnNames.length))] - The amount of rows after which the JS stack is flattened, low number can result in performance impact, high number can result in stack overflow error
* @param {AsyncCallback} callback - called when the next rows have been read
*/
ResultSetReader.prototype.readNextRows = function (columnNames, resultSet, options, callback) {
const self = this;
let bulkRowsAmount = 100;
if (arguments.length === 3) {
callback = options;
options = null;
} else if (options) {
bulkRowsAmount = options.bulkRowsAmount || bulkRowsAmount;
}
resultSet.getRows(bulkRowsAmount, function onRows(error, rows) {
if (error) {
self.releaseResultSet(resultSet, true, function onClose() {
callback(error);
});
} else if ((!rows) || (rows.length === 0)) {
self.releaseResultSet(resultSet, false, function onClose(releaseError) {
callback(releaseError, []);
});
} else {
rowsReader.read(columnNames, rows, callback);
}
});
};
/**
* Reads all data from the provided oracle ResultSet object into the provided buffer.
*
* @function
* @memberof! ResultSetReader
* @private
* @param {Array} columnNames - Array of strings holding the column names of the results
* @param {Array} resultSet - The oracle ResultSet object
* @param {Object} options - Any options
* @param {Number} [options.bulkRowsAmount=100] - The amount of rows to fetch
* @param {Number} [options.flattenStackEveryRows] - The amount of rows after which the JS stack is flattened, low number can result in performance impact, high number can result in stack overflow error
* @param {AsyncCallback} callback - called when all rows are fully read or in case of an error
* @param {Array} [jsRowsBuffer] - The result buffer, if not provided, the callback will be called for each bulk
*/
ResultSetReader.prototype.readAllRows = function (columnNames, resultSet, options, callback, jsRowsBuffer) {
const self = this;
self.readNextRows(columnNames, resultSet, options, function onNextRows(error, jsRows) {
if (error) {
callback(error);
} else if (jsRows && jsRows.length) {
if (jsRowsBuffer) {
Array.prototype.push.apply(jsRowsBuffer, jsRows);
} else { //split results
callback(null, jsRows);
}
self.readAllRows(columnNames, resultSet, options, callback, jsRowsBuffer);
} else {
const lastResult = jsRowsBuffer || [];
callback(null, lastResult);
}
});
};
/**
* Reads all data from the provided oracle ResultSet object.
*
* @function
* @memberof! ResultSetReader
* @public
* @param {Array} columnNames - Array of strings holding the column names of the results
* @param {Array} resultSet - The oracle ResultSet object
* @param {Object} options - Any options
* @param {AsyncCallback} callback - called when all rows are fully read or in case of an error
*/
ResultSetReader.prototype.readFully = function (columnNames, resultSet, options, callback) {
this.readAllRows(columnNames, resultSet, options, callback, []);
};
/**
* Reads all data from the provided oracle ResultSet object to the callback in bulks.<br>
* The last callback call will have an empty result.
*
* @function
* @memberof! ResultSetReader
* @public
* @param {Array} columnNames - Array of strings holding the column names of the results
* @param {Array} resultSet - The oracle ResultSet object
* @param {Object} options - Any options
* @param {AsyncCallback} callback - called for each read bulk of rows or in case of an error
*/
ResultSetReader.prototype.readBulks = function (columnNames, resultSet, options, callback) {
this.readAllRows(columnNames, resultSet, options, callback);
};
/**
* Reads all data from the provided oracle ResultSet object to the callback in bulks.<br>
* The last callback call will have an empty result.
*
* @function
* @memberof! ResultSetReader
* @public
* @param {Array} columnNames - Array of strings holding the column names of the results
* @param {Array} resultSet - The oracle ResultSet object
* @param {Object} [options] - Any options
* @param {ResultSetReadStream} stream - The stream used to read the results from
*/
ResultSetReader.prototype.stream = function (columnNames, resultSet, options, stream) {
const self = this;
if (!stream) {
stream = options;
options = null;
}
options = options || {};
let rowsData;
stream.metaData = columnNames;
/*eslint-disable func-name-matching*/
/**
* Reads the next rows from the resultset and pushes via events.
*
* @function
* @memberof! ResultSetReadStream
* @alias ResultSetReadStream.nextRow
* @constiation 1
* @private
* @param {function} streamCallback - The callback function
*/
stream.nextRow = function readNextRow(streamCallback) {
/*istanbul ignore else*/
if (!stream.closed) {
if (rowsData && rowsData.length) {
streamCallback(null, rowsData.shift());
} else {
self.readNextRows(columnNames, resultSet, options, function onRead(error, rows) {
let rowData;
if (!error) {
rowsData = rows;
if (rowsData && rowsData.length) {
rowData = rowsData.shift();
}
}
streamCallback(error, rowData);
});
}
}
};
/*eslint-enable func-name-matching*/
};
module.exports = new ResultSetReader();