bson 6.0.0 → 6.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bson.d.ts +20 -0
- package/lib/bson.bundle.js +114 -32
- package/lib/bson.bundle.js.map +1 -1
- package/lib/bson.cjs +114 -32
- package/lib/bson.cjs.map +1 -1
- package/lib/bson.mjs +114 -32
- package/lib/bson.mjs.map +1 -1
- package/lib/bson.rn.cjs +114 -32
- package/lib/bson.rn.cjs.map +1 -1
- package/package.json +1 -1
- package/src/decimal128.ts +153 -40
- package/src/parser/serializer.ts +7 -3
package/package.json
CHANGED
package/src/decimal128.ts
CHANGED
|
@@ -158,6 +158,32 @@ export class Decimal128 extends BSONValue {
|
|
|
158
158
|
* @param representation - a numeric string representation.
|
|
159
159
|
*/
|
|
160
160
|
static fromString(representation: string): Decimal128 {
|
|
161
|
+
return Decimal128._fromString(representation, { allowRounding: false });
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Create a Decimal128 instance from a string representation, allowing for rounding to 34
|
|
166
|
+
* significant digits
|
|
167
|
+
*
|
|
168
|
+
* @example Example of a number that will be rounded
|
|
169
|
+
* ```ts
|
|
170
|
+
* > let d = Decimal128.fromString('37.499999999999999196428571428571375')
|
|
171
|
+
* Uncaught:
|
|
172
|
+
* BSONError: "37.499999999999999196428571428571375" is not a valid Decimal128 string - inexact rounding
|
|
173
|
+
* at invalidErr (/home/wajames/js-bson/lib/bson.cjs:1402:11)
|
|
174
|
+
* at Decimal128.fromStringInternal (/home/wajames/js-bson/lib/bson.cjs:1633:25)
|
|
175
|
+
* at Decimal128.fromString (/home/wajames/js-bson/lib/bson.cjs:1424:27)
|
|
176
|
+
*
|
|
177
|
+
* > d = Decimal128.fromStringWithRounding('37.499999999999999196428571428571375')
|
|
178
|
+
* new Decimal128("37.49999999999999919642857142857138")
|
|
179
|
+
* ```
|
|
180
|
+
* @param representation - a numeric string representation.
|
|
181
|
+
*/
|
|
182
|
+
static fromStringWithRounding(representation: string): Decimal128 {
|
|
183
|
+
return Decimal128._fromString(representation, { allowRounding: true });
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
private static _fromString(representation: string, options: { allowRounding: boolean }) {
|
|
161
187
|
// Parse state tracking
|
|
162
188
|
let isNegative = false;
|
|
163
189
|
let sawSign = false;
|
|
@@ -351,59 +377,147 @@ export class Decimal128 extends BSONValue {
|
|
|
351
377
|
exponent = exponent - 1;
|
|
352
378
|
}
|
|
353
379
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
if (
|
|
380
|
+
if (options.allowRounding) {
|
|
381
|
+
while (exponent < EXPONENT_MIN || nDigitsStored < nDigits) {
|
|
382
|
+
// Shift last digit. can only do this if < significant digits than # stored.
|
|
383
|
+
if (lastDigit === 0 && significantDigits < nDigitsStored) {
|
|
358
384
|
exponent = EXPONENT_MIN;
|
|
385
|
+
significantDigits = 0;
|
|
359
386
|
break;
|
|
360
387
|
}
|
|
361
388
|
|
|
362
|
-
|
|
389
|
+
if (nDigitsStored < nDigits) {
|
|
390
|
+
// adjust to match digits not stored
|
|
391
|
+
nDigits = nDigits - 1;
|
|
392
|
+
} else {
|
|
393
|
+
// adjust to round
|
|
394
|
+
lastDigit = lastDigit - 1;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
if (exponent < EXPONENT_MAX) {
|
|
398
|
+
exponent = exponent + 1;
|
|
399
|
+
} else {
|
|
400
|
+
// Check if we have a zero then just hard clamp, otherwise fail
|
|
401
|
+
const digitsString = digits.join('');
|
|
402
|
+
if (digitsString.match(/^0+$/)) {
|
|
403
|
+
exponent = EXPONENT_MAX;
|
|
404
|
+
break;
|
|
405
|
+
}
|
|
406
|
+
invalidErr(representation, 'overflow');
|
|
407
|
+
}
|
|
363
408
|
}
|
|
364
409
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
410
|
+
// Round
|
|
411
|
+
// We've normalized the exponent, but might still need to round.
|
|
412
|
+
if (lastDigit + 1 < significantDigits) {
|
|
413
|
+
let endOfString = nDigitsRead;
|
|
414
|
+
|
|
415
|
+
// If we have seen a radix point, 'string' is 1 longer than we have
|
|
416
|
+
// documented with ndigits_read, so inc the position of the first nonzero
|
|
417
|
+
// digit and the position that digits are read to.
|
|
418
|
+
if (sawRadix) {
|
|
419
|
+
firstNonZero = firstNonZero + 1;
|
|
420
|
+
endOfString = endOfString + 1;
|
|
371
421
|
}
|
|
372
|
-
//
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
invalidErr(representation, 'inexact rounding');
|
|
422
|
+
// if negative, we need to increment again to account for - sign at start.
|
|
423
|
+
if (sawSign) {
|
|
424
|
+
firstNonZero = firstNonZero + 1;
|
|
425
|
+
endOfString = endOfString + 1;
|
|
377
426
|
}
|
|
378
|
-
// adjust to round
|
|
379
|
-
lastDigit = lastDigit - 1;
|
|
380
|
-
}
|
|
381
427
|
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
428
|
+
const roundDigit = parseInt(representation[firstNonZero + lastDigit + 1], 10);
|
|
429
|
+
let roundBit = 0;
|
|
430
|
+
|
|
431
|
+
if (roundDigit >= 5) {
|
|
432
|
+
roundBit = 1;
|
|
433
|
+
if (roundDigit === 5) {
|
|
434
|
+
roundBit = digits[lastDigit] % 2 === 1 ? 1 : 0;
|
|
435
|
+
for (let i = firstNonZero + lastDigit + 2; i < endOfString; i++) {
|
|
436
|
+
if (parseInt(representation[i], 10)) {
|
|
437
|
+
roundBit = 1;
|
|
438
|
+
break;
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
}
|
|
388
443
|
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
444
|
+
if (roundBit) {
|
|
445
|
+
let dIdx = lastDigit;
|
|
446
|
+
|
|
447
|
+
for (; dIdx >= 0; dIdx--) {
|
|
448
|
+
if (++digits[dIdx] > 9) {
|
|
449
|
+
digits[dIdx] = 0;
|
|
450
|
+
|
|
451
|
+
// overflowed most significant digit
|
|
452
|
+
if (dIdx === 0) {
|
|
453
|
+
if (exponent < EXPONENT_MAX) {
|
|
454
|
+
exponent = exponent + 1;
|
|
455
|
+
digits[dIdx] = 1;
|
|
456
|
+
} else {
|
|
457
|
+
return new Decimal128(isNegative ? INF_NEGATIVE_BUFFER : INF_POSITIVE_BUFFER);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
} else {
|
|
461
|
+
break;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
}
|
|
397
465
|
}
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
466
|
+
} else {
|
|
467
|
+
while (exponent < EXPONENT_MIN || nDigitsStored < nDigits) {
|
|
468
|
+
// Shift last digit. can only do this if < significant digits than # stored.
|
|
469
|
+
if (lastDigit === 0) {
|
|
470
|
+
if (significantDigits === 0) {
|
|
471
|
+
exponent = EXPONENT_MIN;
|
|
472
|
+
break;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
invalidErr(representation, 'exponent underflow');
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
if (nDigitsStored < nDigits) {
|
|
479
|
+
if (
|
|
480
|
+
representation[nDigits - 1 + Number(sawSign) + Number(sawRadix)] !== '0' &&
|
|
481
|
+
significantDigits !== 0
|
|
482
|
+
) {
|
|
483
|
+
invalidErr(representation, 'inexact rounding');
|
|
484
|
+
}
|
|
485
|
+
// adjust to match digits not stored
|
|
486
|
+
nDigits = nDigits - 1;
|
|
487
|
+
} else {
|
|
488
|
+
if (digits[lastDigit] !== 0) {
|
|
489
|
+
invalidErr(representation, 'inexact rounding');
|
|
490
|
+
}
|
|
491
|
+
// adjust to round
|
|
492
|
+
lastDigit = lastDigit - 1;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
if (exponent < EXPONENT_MAX) {
|
|
496
|
+
exponent = exponent + 1;
|
|
497
|
+
} else {
|
|
498
|
+
invalidErr(representation, 'overflow');
|
|
499
|
+
}
|
|
401
500
|
}
|
|
402
501
|
|
|
403
|
-
|
|
502
|
+
// Round
|
|
503
|
+
// We've normalized the exponent, but might still need to round.
|
|
504
|
+
if (lastDigit + 1 < significantDigits) {
|
|
505
|
+
// If we have seen a radix point, 'string' is 1 longer than we have
|
|
506
|
+
// documented with ndigits_read, so inc the position of the first nonzero
|
|
507
|
+
// digit and the position that digits are read to.
|
|
508
|
+
if (sawRadix) {
|
|
509
|
+
firstNonZero = firstNonZero + 1;
|
|
510
|
+
}
|
|
511
|
+
// if saw sign, we need to increment again to account for - or + sign at start.
|
|
512
|
+
if (sawSign) {
|
|
513
|
+
firstNonZero = firstNonZero + 1;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
const roundDigit = parseInt(representation[firstNonZero + lastDigit + 1], 10);
|
|
404
517
|
|
|
405
|
-
|
|
406
|
-
|
|
518
|
+
if (roundDigit !== 0) {
|
|
519
|
+
invalidErr(representation, 'inexact rounding');
|
|
520
|
+
}
|
|
407
521
|
}
|
|
408
522
|
}
|
|
409
523
|
|
|
@@ -507,7 +621,6 @@ export class Decimal128 extends BSONValue {
|
|
|
507
621
|
// Return the new Decimal128
|
|
508
622
|
return new Decimal128(buffer);
|
|
509
623
|
}
|
|
510
|
-
|
|
511
624
|
/** Create a string representation of the raw Decimal128 value */
|
|
512
625
|
toString(): string {
|
|
513
626
|
// Note: bits in this routine are referred to starting at 0,
|
package/src/parser/serializer.ts
CHANGED
|
@@ -257,14 +257,18 @@ function serializeObjectId(buffer: Uint8Array, key: string, value: ObjectId, ind
|
|
|
257
257
|
buffer[index++] = 0;
|
|
258
258
|
|
|
259
259
|
// Write the objectId into the shared buffer
|
|
260
|
-
|
|
261
|
-
|
|
260
|
+
const idValue = value.id;
|
|
261
|
+
|
|
262
|
+
if (isUint8Array(idValue)) {
|
|
263
|
+
for (let i = 0; i < 12; i++) {
|
|
264
|
+
buffer[index++] = idValue[i];
|
|
265
|
+
}
|
|
262
266
|
} else {
|
|
263
267
|
throw new BSONError('object [' + JSON.stringify(value) + '] is not a valid ObjectId');
|
|
264
268
|
}
|
|
265
269
|
|
|
266
270
|
// Adjust index
|
|
267
|
-
return index
|
|
271
|
+
return index;
|
|
268
272
|
}
|
|
269
273
|
|
|
270
274
|
function serializeBuffer(buffer: Uint8Array, key: string, value: Uint8Array, index: number) {
|