UNPKG

cassandra-driver

Version:

DataStax Node.js Driver for Apache Cassandra

271 lines (252 loc) 8.52 kB
/* * Copyright DataStax, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ 'use strict'; const Integer = require('./integer'); const utils = require('../utils'); /** @module types */ /** * Constructs an immutable arbitrary-precision signed decimal number. * A <code>BigDecimal</code> consists of an [arbitrary precision integer]{@link module:types~Integer} * <i>unscaled value</i> and a 32-bit integer <i>scale</i>. If zero * or positive, the scale is the number of digits to the right of the * decimal point. If negative, the unscaled value of the number is * multiplied by ten to the power of the negation of the scale. The * value of the number represented by the <code>BigDecimal</code> is * therefore <tt>(unscaledValue &times; 10<sup>-scale</sup>)</tt>. * @class * @classdesc The <code>BigDecimal</code> class provides operations for * arithmetic, scale manipulation, rounding, comparison and * format conversion. The {@link #toString} method provides a * canonical representation of a <code>BigDecimal</code>. * @param {Integer|Number} unscaledValue The integer part of the decimal. * @param {Number} scale The scale of the decimal. * @constructor */ function BigDecimal(unscaledValue, scale) { if (typeof unscaledValue === 'number') { unscaledValue = Integer.fromNumber(unscaledValue); } /** * @type {Integer} * @private */ this._intVal = unscaledValue; /** * @type {Number} * @private */ this._scale = scale; } /** * Returns the BigDecimal representation of a buffer composed of the scale (int32BE) and the unsigned value (varint BE) * @param {Buffer} buf * @returns {BigDecimal} */ BigDecimal.fromBuffer = function (buf) { const scale = buf.readInt32BE(0); const unscaledValue = Integer.fromBuffer(buf.slice(4)); return new BigDecimal(unscaledValue, scale); }; /** * Returns a buffer representation composed of the scale as a BE int 32 and the unsigned value as a BE varint * @param {BigDecimal} value * @returns {Buffer} */ BigDecimal.toBuffer = function (value) { const unscaledValueBuffer = Integer.toBuffer(value._intVal); const scaleBuffer = utils.allocBufferUnsafe(4); scaleBuffer.writeInt32BE(value._scale, 0); return Buffer.concat([scaleBuffer, unscaledValueBuffer], scaleBuffer.length + unscaledValueBuffer.length); }; /** * Returns a BigDecimal representation of the string * @param {String} value * @returns {BigDecimal} */ BigDecimal.fromString = function (value) { if (!value) { throw new TypeError('Invalid null or undefined value'); } value = value.trim(); const scaleIndex = value.indexOf('.'); let scale = 0; if (scaleIndex >= 0) { scale = value.length - 1 - scaleIndex; value = value.substr(0, scaleIndex) + value.substr(scaleIndex + 1); } return new BigDecimal(Integer.fromString(value), scale); }; /** * Returns a BigDecimal representation of the Number * @param {Number} value * @returns {BigDecimal} */ BigDecimal.fromNumber = function (value) { if (isNaN(value)) { return new BigDecimal(Integer.ZERO, 0); } let textValue = value.toString(); if (textValue.indexOf('e') >= 0) { //get until scale 20 textValue = value.toFixed(20); } return BigDecimal.fromString(textValue); }; /** * Returns true if the value of the BigDecimal instance and other are the same * @param {BigDecimal} other * @returns {Boolean} */ BigDecimal.prototype.equals = function (other) { return ((other instanceof BigDecimal) && this.compare(other) === 0); }; BigDecimal.prototype.inspect = function () { return this.constructor.name + ': ' + this.toString(); }; /** * @param {BigDecimal} other * @returns {boolean} */ BigDecimal.prototype.notEquals = function (other) { return !this.equals(other); }; /** * Compares this BigDecimal with the given one. * @param {BigDecimal} other Integer to compare against. * @return {number} 0 if they are the same, 1 if the this is greater, and -1 * if the given one is greater. */ BigDecimal.prototype.compare = function (other) { const diff = this.subtract(other); if (diff.isNegative()) { return -1; } if (diff.isZero()) { return 0; } return +1; }; /** * Returns the difference of this and the given BigDecimal. * @param {BigDecimal} other The BigDecimal to subtract from this. * @return {!BigDecimal} The BigDecimal result. */ BigDecimal.prototype.subtract = function (other) { const first = this; if (first._scale === other._scale) { return new BigDecimal(first._intVal.subtract(other._intVal), first._scale); } let diffScale; let unscaledValue; if (first._scale < other._scale) { //The scale of this is lower diffScale = other._scale - first._scale; //multiple this unScaledValue to compare in the same scale unscaledValue = first._intVal .multiply(Integer.fromNumber(Math.pow(10, diffScale))) .subtract(other._intVal); return new BigDecimal(unscaledValue, other._scale); } //The scale of this is higher diffScale = first._scale - other._scale; //multiple this unScaledValue to compare in the same scale unscaledValue = first._intVal .subtract( other._intVal.multiply(Integer.fromNumber(Math.pow(10, diffScale)))); return new BigDecimal(unscaledValue, first._scale); }; /** * Returns the sum of this and the given <code>BigDecimal</code>. * @param {BigDecimal} other The BigDecimal to sum to this. * @return {!BigDecimal} The BigDecimal result. */ BigDecimal.prototype.add = function (other) { const first = this; if (first._scale === other._scale) { return new BigDecimal(first._intVal.add(other._intVal), first._scale); } let diffScale; let unscaledValue; if (first._scale < other._scale) { //The scale of this is lower diffScale = other._scale - first._scale; //multiple this unScaledValue to compare in the same scale unscaledValue = first._intVal .multiply(Integer.fromNumber(Math.pow(10, diffScale))) .add(other._intVal); return new BigDecimal(unscaledValue, other._scale); } //The scale of this is higher diffScale = first._scale - other._scale; //multiple this unScaledValue to compare in the same scale unscaledValue = first._intVal .add( other._intVal.multiply(Integer.fromNumber(Math.pow(10, diffScale)))); return new BigDecimal(unscaledValue, first._scale); }; /** * Returns true if the current instance is greater than the other * @param {BigDecimal} other * @returns {boolean} */ BigDecimal.prototype.greaterThan = function (other) { return this.compare(other) === 1; }; /** @return {boolean} Whether this value is negative. */ BigDecimal.prototype.isNegative = function () { return this._intVal.isNegative(); }; /** @return {boolean} Whether this value is zero. */ BigDecimal.prototype.isZero = function () { return this._intVal.isZero(); }; /** * Returns the string representation of this <code>BigDecimal</code> * @returns {string} */ BigDecimal.prototype.toString = function () { let intString = this._intVal.toString(); if (this._scale === 0) { return intString; } let signSymbol = ''; if (intString.charAt(0) === '-') { signSymbol = '-'; intString = intString.substr(1); } let separatorIndex = intString.length - this._scale; if (separatorIndex <= 0) { //add zeros at the beginning, plus an additional zero intString = utils.stringRepeat('0', (-separatorIndex) + 1) + intString; separatorIndex = intString.length - this._scale; } return signSymbol + intString.substr(0, separatorIndex) + '.' + intString.substr(separatorIndex); }; /** * Returns a Number representation of this <code>BigDecimal</code>. * @returns {Number} */ BigDecimal.prototype.toNumber = function () { return parseFloat(this.toString()); }; /** * Returns the string representation. * Method used by the native JSON.stringify() to serialize this instance. */ BigDecimal.prototype.toJSON = function () { return this.toString(); }; module.exports = BigDecimal;