bson
Advanced tools
Comparing version 6.0.0 to 6.1.0
@@ -384,2 +384,22 @@ /** | ||
static fromString(representation: string): Decimal128; | ||
/** | ||
* Create a Decimal128 instance from a string representation, allowing for rounding to 34 | ||
* significant digits | ||
* | ||
* @example Example of a number that will be rounded | ||
* ```ts | ||
* > let d = Decimal128.fromString('37.499999999999999196428571428571375') | ||
* Uncaught: | ||
* BSONError: "37.499999999999999196428571428571375" is not a valid Decimal128 string - inexact rounding | ||
* at invalidErr (/home/wajames/js-bson/lib/bson.cjs:1402:11) | ||
* at Decimal128.fromStringInternal (/home/wajames/js-bson/lib/bson.cjs:1633:25) | ||
* at Decimal128.fromString (/home/wajames/js-bson/lib/bson.cjs:1424:27) | ||
* | ||
* > d = Decimal128.fromStringWithRounding('37.499999999999999196428571428571375') | ||
* new Decimal128("37.49999999999999919642857142857138") | ||
* ``` | ||
* @param representation - a numeric string representation. | ||
*/ | ||
static fromStringWithRounding(representation: string): Decimal128; | ||
private static _fromString; | ||
/** Create a string representation of the raw Decimal128 value */ | ||
@@ -386,0 +406,0 @@ toString(): string; |
@@ -17,3 +17,3 @@ { | ||
"types": "bson.d.ts", | ||
"version": "6.0.0", | ||
"version": "6.1.0", | ||
"author": { | ||
@@ -20,0 +20,0 @@ "name": "The MongoDB NodeJS Team", |
@@ -161,2 +161,28 @@ import { BSONValue } from './bson_value'; | ||
static fromString(representation: string): Decimal128 { | ||
return Decimal128._fromString(representation, { allowRounding: false }); | ||
} | ||
/** | ||
* Create a Decimal128 instance from a string representation, allowing for rounding to 34 | ||
* significant digits | ||
* | ||
* @example Example of a number that will be rounded | ||
* ```ts | ||
* > let d = Decimal128.fromString('37.499999999999999196428571428571375') | ||
* Uncaught: | ||
* BSONError: "37.499999999999999196428571428571375" is not a valid Decimal128 string - inexact rounding | ||
* at invalidErr (/home/wajames/js-bson/lib/bson.cjs:1402:11) | ||
* at Decimal128.fromStringInternal (/home/wajames/js-bson/lib/bson.cjs:1633:25) | ||
* at Decimal128.fromString (/home/wajames/js-bson/lib/bson.cjs:1424:27) | ||
* | ||
* > d = Decimal128.fromStringWithRounding('37.499999999999999196428571428571375') | ||
* new Decimal128("37.49999999999999919642857142857138") | ||
* ``` | ||
* @param representation - a numeric string representation. | ||
*/ | ||
static fromStringWithRounding(representation: string): Decimal128 { | ||
return Decimal128._fromString(representation, { allowRounding: true }); | ||
} | ||
private static _fromString(representation: string, options: { allowRounding: boolean }) { | ||
// Parse state tracking | ||
@@ -355,55 +381,143 @@ let isNegative = false; | ||
while (exponent < EXPONENT_MIN || nDigitsStored < nDigits) { | ||
// Shift last digit. can only do this if < significant digits than # stored. | ||
if (lastDigit === 0) { | ||
if (significantDigits === 0) { | ||
if (options.allowRounding) { | ||
while (exponent < EXPONENT_MIN || nDigitsStored < nDigits) { | ||
// Shift last digit. can only do this if < significant digits than # stored. | ||
if (lastDigit === 0 && significantDigits < nDigitsStored) { | ||
exponent = EXPONENT_MIN; | ||
significantDigits = 0; | ||
break; | ||
} | ||
invalidErr(representation, 'exponent underflow'); | ||
if (nDigitsStored < nDigits) { | ||
// adjust to match digits not stored | ||
nDigits = nDigits - 1; | ||
} else { | ||
// adjust to round | ||
lastDigit = lastDigit - 1; | ||
} | ||
if (exponent < EXPONENT_MAX) { | ||
exponent = exponent + 1; | ||
} else { | ||
// Check if we have a zero then just hard clamp, otherwise fail | ||
const digitsString = digits.join(''); | ||
if (digitsString.match(/^0+$/)) { | ||
exponent = EXPONENT_MAX; | ||
break; | ||
} | ||
invalidErr(representation, 'overflow'); | ||
} | ||
} | ||
if (nDigitsStored < nDigits) { | ||
if ( | ||
representation[nDigits - 1 + Number(sawSign) + Number(sawRadix)] !== '0' && | ||
significantDigits !== 0 | ||
) { | ||
invalidErr(representation, 'inexact rounding'); | ||
// Round | ||
// We've normalized the exponent, but might still need to round. | ||
if (lastDigit + 1 < significantDigits) { | ||
let endOfString = nDigitsRead; | ||
// If we have seen a radix point, 'string' is 1 longer than we have | ||
// documented with ndigits_read, so inc the position of the first nonzero | ||
// digit and the position that digits are read to. | ||
if (sawRadix) { | ||
firstNonZero = firstNonZero + 1; | ||
endOfString = endOfString + 1; | ||
} | ||
// adjust to match digits not stored | ||
nDigits = nDigits - 1; | ||
} else { | ||
if (digits[lastDigit] !== 0) { | ||
invalidErr(representation, 'inexact rounding'); | ||
// if negative, we need to increment again to account for - sign at start. | ||
if (sawSign) { | ||
firstNonZero = firstNonZero + 1; | ||
endOfString = endOfString + 1; | ||
} | ||
// adjust to round | ||
lastDigit = lastDigit - 1; | ||
} | ||
if (exponent < EXPONENT_MAX) { | ||
exponent = exponent + 1; | ||
} else { | ||
invalidErr(representation, 'overflow'); | ||
const roundDigit = parseInt(representation[firstNonZero + lastDigit + 1], 10); | ||
let roundBit = 0; | ||
if (roundDigit >= 5) { | ||
roundBit = 1; | ||
if (roundDigit === 5) { | ||
roundBit = digits[lastDigit] % 2 === 1 ? 1 : 0; | ||
for (let i = firstNonZero + lastDigit + 2; i < endOfString; i++) { | ||
if (parseInt(representation[i], 10)) { | ||
roundBit = 1; | ||
break; | ||
} | ||
} | ||
} | ||
} | ||
if (roundBit) { | ||
let dIdx = lastDigit; | ||
for (; dIdx >= 0; dIdx--) { | ||
if (++digits[dIdx] > 9) { | ||
digits[dIdx] = 0; | ||
// overflowed most significant digit | ||
if (dIdx === 0) { | ||
if (exponent < EXPONENT_MAX) { | ||
exponent = exponent + 1; | ||
digits[dIdx] = 1; | ||
} else { | ||
return new Decimal128(isNegative ? INF_NEGATIVE_BUFFER : INF_POSITIVE_BUFFER); | ||
} | ||
} | ||
} else { | ||
break; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} else { | ||
while (exponent < EXPONENT_MIN || nDigitsStored < nDigits) { | ||
// Shift last digit. can only do this if < significant digits than # stored. | ||
if (lastDigit === 0) { | ||
if (significantDigits === 0) { | ||
exponent = EXPONENT_MIN; | ||
break; | ||
} | ||
// Round | ||
// We've normalized the exponent, but might still need to round. | ||
if (lastDigit + 1 < significantDigits) { | ||
// If we have seen a radix point, 'string' is 1 longer than we have | ||
// documented with ndigits_read, so inc the position of the first nonzero | ||
// digit and the position that digits are read to. | ||
if (sawRadix) { | ||
firstNonZero = firstNonZero + 1; | ||
invalidErr(representation, 'exponent underflow'); | ||
} | ||
if (nDigitsStored < nDigits) { | ||
if ( | ||
representation[nDigits - 1 + Number(sawSign) + Number(sawRadix)] !== '0' && | ||
significantDigits !== 0 | ||
) { | ||
invalidErr(representation, 'inexact rounding'); | ||
} | ||
// adjust to match digits not stored | ||
nDigits = nDigits - 1; | ||
} else { | ||
if (digits[lastDigit] !== 0) { | ||
invalidErr(representation, 'inexact rounding'); | ||
} | ||
// adjust to round | ||
lastDigit = lastDigit - 1; | ||
} | ||
if (exponent < EXPONENT_MAX) { | ||
exponent = exponent + 1; | ||
} else { | ||
invalidErr(representation, 'overflow'); | ||
} | ||
} | ||
// if saw sign, we need to increment again to account for - or + sign at start. | ||
if (sawSign) { | ||
firstNonZero = firstNonZero + 1; | ||
} | ||
const roundDigit = parseInt(representation[firstNonZero + lastDigit + 1], 10); | ||
// Round | ||
// We've normalized the exponent, but might still need to round. | ||
if (lastDigit + 1 < significantDigits) { | ||
// If we have seen a radix point, 'string' is 1 longer than we have | ||
// documented with ndigits_read, so inc the position of the first nonzero | ||
// digit and the position that digits are read to. | ||
if (sawRadix) { | ||
firstNonZero = firstNonZero + 1; | ||
} | ||
// if saw sign, we need to increment again to account for - or + sign at start. | ||
if (sawSign) { | ||
firstNonZero = firstNonZero + 1; | ||
} | ||
if (roundDigit !== 0) { | ||
invalidErr(representation, 'inexact rounding'); | ||
const roundDigit = parseInt(representation[firstNonZero + lastDigit + 1], 10); | ||
if (roundDigit !== 0) { | ||
invalidErr(representation, 'inexact rounding'); | ||
} | ||
} | ||
@@ -512,3 +626,2 @@ } | ||
} | ||
/** Create a string representation of the raw Decimal128 value */ | ||
@@ -515,0 +628,0 @@ toString(): string { |
@@ -260,4 +260,8 @@ import { Binary } from '../binary'; | ||
// Write the objectId into the shared buffer | ||
if (isUint8Array(value.id)) { | ||
buffer.set(value.id.subarray(0, 12), index); | ||
const idValue = value.id; | ||
if (isUint8Array(idValue)) { | ||
for (let i = 0; i < 12; i++) { | ||
buffer[index++] = idValue[i]; | ||
} | ||
} else { | ||
@@ -268,3 +272,3 @@ throw new BSONError('object [' + JSON.stringify(value) + '] is not a valid ObjectId'); | ||
// Adjust index | ||
return index + 12; | ||
return index; | ||
} | ||
@@ -271,0 +275,0 @@ |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
2274613
28845