mongodb-extjson
Advanced tools
Comparing version 1.0.4 to 1.0.5
"use strict" | ||
var Long = require('./long'); | ||
var Buffer = (typeof Buffer !== 'undefined') ? Buffer : Uint8Array; | ||
@@ -108,31 +109,2 @@ var PARSE_STRING_REGEXP = /^(\+|\-)?(\d+|(\d*\.\d*))?(E|e)?([\-\+])?(\d+)?$/; | ||
var longtoHex = function(value) { | ||
var buffer = new Buffer(8); | ||
var index = 0; | ||
// Encode the low 64 bits of the decimal | ||
// Encode low bits | ||
buffer[index++] = value.low_ & 0xff; | ||
buffer[index++] = (value.low_ >> 8) & 0xff; | ||
buffer[index++] = (value.low_ >> 16) & 0xff; | ||
buffer[index++] = (value.low_ >> 24) & 0xff; | ||
// Encode high bits | ||
buffer[index++] = value.high_ & 0xff; | ||
buffer[index++] = (value.high_ >> 8) & 0xff; | ||
buffer[index++] = (value.high_ >> 16) & 0xff; | ||
buffer[index++] = (value.high_ >> 24) & 0xff; | ||
return buffer.reverse().toString('hex'); | ||
} | ||
var int32toHex = function(value) { | ||
var buffer = new Buffer(4); | ||
var index = 0; | ||
// Encode the low 64 bits of the decimal | ||
// Encode low bits | ||
buffer[index++] = value & 0xff; | ||
buffer[index++] = (value >> 8) & 0xff; | ||
buffer[index++] = (value >> 16) & 0xff; | ||
buffer[index++] = (value >> 24) & 0xff; | ||
return buffer.reverse().toString('hex'); | ||
} | ||
/** | ||
@@ -139,0 +111,0 @@ * A class representation of the BSON Decimal128 type. |
"use strict"; | ||
// 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. | ||
// | ||
// Copyright 2009 Google Inc. All Rights Reserved | ||
var Long = require('./long'); | ||
/** | ||
* Defines a Long class for representing a 64-bit two's-complement | ||
* integer value, which faithfully simulates the behavior of a Java "Long". This | ||
* implementation is derived from LongLib in GWT. | ||
* | ||
* Constructs a 64-bit two's-complement integer, given its low and high 32-bit | ||
* values as *signed* integers. See the from* functions below for more | ||
* convenient ways of constructing Longs. | ||
* | ||
* The internal representation of a Long is the two given signed, 32-bit values. | ||
* We use 32-bit pieces because these are the size of integers on which | ||
* Javascript performs bit-operations. For operations like addition and | ||
* multiplication, we split each number into 16-bit pieces, which can easily be | ||
* multiplied within Javascript's floating-point representation without overflow | ||
* or change in sign. | ||
* | ||
* In the algorithms below, we frequently reduce the negative case to the | ||
* positive case by negating the input(s) and then post-processing the result. | ||
* Note that we must ALWAYS check specially whether those values are MIN_VALUE | ||
* (-2^63) because -MIN_VALUE == MIN_VALUE (since 2^63 cannot be represented as | ||
* a positive number, it overflows back into a negative). Not handling this | ||
* case would often result in infinite recursion. | ||
* | ||
* @class | ||
@@ -46,37 +12,15 @@ * @param {number} low the low (signed) 32 bits of the Timestamp. | ||
var Timestamp = function(low, high) { | ||
if (low instanceof Long) { | ||
Long.call(this, low.low_, low.high_); | ||
} else { | ||
Long.call(this, low, high); | ||
} | ||
this._bsontype = 'Timestamp'; | ||
/** | ||
* @type {number} | ||
* @ignore | ||
*/ | ||
this.low_ = low | 0; // force into 32 signed bits. | ||
/** | ||
* @type {number} | ||
* @ignore | ||
*/ | ||
this.high_ = high | 0; // force into 32 signed bits. | ||
} | ||
/** | ||
* Return the int value. | ||
* | ||
* @method | ||
* @return {number} the value, assuming it is a 32-bit integer. | ||
*/ | ||
Timestamp.prototype.toInt = function() { | ||
return this.low_; | ||
} | ||
Timestamp.prototype = Object.create(Long.prototype); | ||
Timestamp.prototype.constructor = Timestamp; | ||
/** | ||
* Return the Number value. | ||
* | ||
* @method | ||
* @return {number} the closest floating-point representation to this value. | ||
*/ | ||
Timestamp.prototype.toNumber = function() { | ||
return this.high_ * Timestamp.TWO_PWR_32_DBL_ + this.getLowBitsUnsigned(); | ||
} | ||
/** | ||
* Return the JSON value. | ||
@@ -89,634 +33,30 @@ * | ||
return { | ||
$timestamp: this.toString(), | ||
$timestamp: this.toString() | ||
}; | ||
} | ||
/** | ||
* Return the String value. | ||
* | ||
* @method | ||
* @param {number} [opt_radix] the radix in which the text should be written. | ||
* @return {String} the textual representation of this value. | ||
*/ | ||
Timestamp.prototype.toString = function(opt_radix) { | ||
var radix = opt_radix || 10; | ||
if (radix < 2 || 36 < radix) { | ||
throw Error('radix out of range: ' + radix); | ||
} | ||
if (this.isZero()) { | ||
return '0'; | ||
} | ||
if (this.isNegative()) { | ||
if (this.equals(Timestamp.MIN_VALUE)) { | ||
// We need to change the Long value before it can be negated, so we remove | ||
// the bottom-most digit in this base and then recurse to do the rest. | ||
var radixLong = Timestamp.fromNumber(radix); | ||
var div = this.div(radixLong); | ||
var rem = div.multiply(radixLong).subtract(this); | ||
return div.toString(radix) + rem.toInt().toString(radix); | ||
} else { | ||
return '-' + this.negate().toString(radix); | ||
} | ||
} | ||
// Do several (6) digits each time through the loop, so as to | ||
// minimize the calls to the very expensive emulated div. | ||
var radixToPower = Timestamp.fromNumber(Math.pow(radix, 6)); | ||
var rem = this; | ||
var result = ''; | ||
while (true) { | ||
var remDiv = rem.div(radixToPower); | ||
var intval = rem.subtract(remDiv.multiply(radixToPower)).toInt(); | ||
var digits = intval.toString(radix); | ||
rem = remDiv; | ||
if (rem.isZero()) { | ||
return digits + result; | ||
} else { | ||
while (digits.length < 6) { | ||
digits = '0' + digits; | ||
} | ||
result = '' + digits + result; | ||
} | ||
} | ||
}; | ||
/** | ||
* Return the high 32-bits value. | ||
* Returns a Timestamp represented by the given (32-bit) integer value. | ||
* | ||
* @method | ||
* @return {number} the high 32-bits as a signed value. | ||
*/ | ||
Timestamp.prototype.getHighBits = function() { | ||
return this.high_; | ||
}; | ||
/** | ||
* Return the low 32-bits value. | ||
* | ||
* @method | ||
* @return {number} the low 32-bits as a signed value. | ||
*/ | ||
Timestamp.prototype.getLowBits = function() { | ||
return this.low_; | ||
}; | ||
/** | ||
* Return the low unsigned 32-bits value. | ||
* | ||
* @method | ||
* @return {number} the low 32-bits as an unsigned value. | ||
*/ | ||
Timestamp.prototype.getLowBitsUnsigned = function() { | ||
return (this.low_ >= 0) ? | ||
this.low_ : Timestamp.TWO_PWR_32_DBL_ + this.low_; | ||
}; | ||
/** | ||
* Returns the number of bits needed to represent the absolute value of this Timestamp. | ||
* | ||
* @method | ||
* @return {number} Returns the number of bits needed to represent the absolute value of this Timestamp. | ||
*/ | ||
Timestamp.prototype.getNumBitsAbs = function() { | ||
if (this.isNegative()) { | ||
if (this.equals(Timestamp.MIN_VALUE)) { | ||
return 64; | ||
} else { | ||
return this.negate().getNumBitsAbs(); | ||
} | ||
} else { | ||
var val = this.high_ != 0 ? this.high_ : this.low_; | ||
for (var bit = 31; bit > 0; bit--) { | ||
if ((val & (1 << bit)) != 0) { | ||
break; | ||
} | ||
} | ||
return this.high_ != 0 ? bit + 33 : bit + 1; | ||
} | ||
}; | ||
/** | ||
* Return whether this value is zero. | ||
* | ||
* @method | ||
* @return {Boolean} whether this value is zero. | ||
*/ | ||
Timestamp.prototype.isZero = function() { | ||
return this.high_ == 0 && this.low_ == 0; | ||
}; | ||
/** | ||
* Return whether this value is negative. | ||
* | ||
* @method | ||
* @return {Boolean} whether this value is negative. | ||
*/ | ||
Timestamp.prototype.isNegative = function() { | ||
return this.high_ < 0; | ||
}; | ||
/** | ||
* Return whether this value is odd. | ||
* | ||
* @method | ||
* @return {Boolean} whether this value is odd. | ||
*/ | ||
Timestamp.prototype.isOdd = function() { | ||
return (this.low_ & 1) == 1; | ||
}; | ||
/** | ||
* Return whether this Long equals the other | ||
* | ||
* @method | ||
* @param {Timestamp} other Long to compare against. | ||
* @return {Boolean} whether this Long equals the other | ||
*/ | ||
Timestamp.prototype.equals = function(other) { | ||
return (this.high_ == other.high_) && (this.low_ == other.low_); | ||
}; | ||
/** | ||
* Return whether this Long does not equal the other. | ||
* | ||
* @method | ||
* @param {Timestamp} other Long to compare against. | ||
* @return {Boolean} whether this Long does not equal the other. | ||
*/ | ||
Timestamp.prototype.notEquals = function(other) { | ||
return (this.high_ != other.high_) || (this.low_ != other.low_); | ||
}; | ||
/** | ||
* Return whether this Long is less than the other. | ||
* | ||
* @method | ||
* @param {Timestamp} other Long to compare against. | ||
* @return {Boolean} whether this Long is less than the other. | ||
*/ | ||
Timestamp.prototype.lessThan = function(other) { | ||
return this.compare(other) < 0; | ||
}; | ||
/** | ||
* Return whether this Long is less than or equal to the other. | ||
* | ||
* @method | ||
* @param {Timestamp} other Long to compare against. | ||
* @return {Boolean} whether this Long is less than or equal to the other. | ||
*/ | ||
Timestamp.prototype.lessThanOrEqual = function(other) { | ||
return this.compare(other) <= 0; | ||
}; | ||
/** | ||
* Return whether this Long is greater than the other. | ||
* | ||
* @method | ||
* @param {Timestamp} other Long to compare against. | ||
* @return {Boolean} whether this Long is greater than the other. | ||
*/ | ||
Timestamp.prototype.greaterThan = function(other) { | ||
return this.compare(other) > 0; | ||
}; | ||
/** | ||
* Return whether this Long is greater than or equal to the other. | ||
* | ||
* @method | ||
* @param {Timestamp} other Long to compare against. | ||
* @return {Boolean} whether this Long is greater than or equal to the other. | ||
*/ | ||
Timestamp.prototype.greaterThanOrEqual = function(other) { | ||
return this.compare(other) >= 0; | ||
}; | ||
/** | ||
* Compares this Long with the given one. | ||
* | ||
* @method | ||
* @param {Timestamp} other Long to compare against. | ||
* @return {Boolean} 0 if they are the same, 1 if the this is greater, and -1 if the given one is greater. | ||
*/ | ||
Timestamp.prototype.compare = function(other) { | ||
if (this.equals(other)) { | ||
return 0; | ||
} | ||
var thisNeg = this.isNegative(); | ||
var otherNeg = other.isNegative(); | ||
if (thisNeg && !otherNeg) { | ||
return -1; | ||
} | ||
if (!thisNeg && otherNeg) { | ||
return 1; | ||
} | ||
// at this point, the signs are the same, so subtraction will not overflow | ||
if (this.subtract(other).isNegative()) { | ||
return -1; | ||
} else { | ||
return 1; | ||
} | ||
}; | ||
/** | ||
* The negation of this value. | ||
* | ||
* @method | ||
* @return {Timestamp} the negation of this value. | ||
*/ | ||
Timestamp.prototype.negate = function() { | ||
if (this.equals(Timestamp.MIN_VALUE)) { | ||
return Timestamp.MIN_VALUE; | ||
} else { | ||
return this.not().add(Timestamp.ONE); | ||
} | ||
}; | ||
/** | ||
* Returns the sum of this and the given Timestamp. | ||
* | ||
* @method | ||
* @param {Timestamp} other Long to add to this one. | ||
* @return {Timestamp} the sum of this and the given Timestamp. | ||
*/ | ||
Timestamp.prototype.add = function(other) { | ||
// Divide each number into 4 chunks of 16 bits, and then sum the chunks. | ||
var a48 = this.high_ >>> 16; | ||
var a32 = this.high_ & 0xFFFF; | ||
var a16 = this.low_ >>> 16; | ||
var a00 = this.low_ & 0xFFFF; | ||
var b48 = other.high_ >>> 16; | ||
var b32 = other.high_ & 0xFFFF; | ||
var b16 = other.low_ >>> 16; | ||
var b00 = other.low_ & 0xFFFF; | ||
var c48 = 0, c32 = 0, c16 = 0, c00 = 0; | ||
c00 += a00 + b00; | ||
c16 += c00 >>> 16; | ||
c00 &= 0xFFFF; | ||
c16 += a16 + b16; | ||
c32 += c16 >>> 16; | ||
c16 &= 0xFFFF; | ||
c32 += a32 + b32; | ||
c48 += c32 >>> 16; | ||
c32 &= 0xFFFF; | ||
c48 += a48 + b48; | ||
c48 &= 0xFFFF; | ||
return Timestamp.fromBits((c16 << 16) | c00, (c48 << 16) | c32); | ||
}; | ||
/** | ||
* Returns the difference of this and the given Timestamp. | ||
* | ||
* @method | ||
* @param {Timestamp} other Long to subtract from this. | ||
* @return {Timestamp} the difference of this and the given Timestamp. | ||
*/ | ||
Timestamp.prototype.subtract = function(other) { | ||
return this.add(other.negate()); | ||
}; | ||
/** | ||
* Returns the product of this and the given Timestamp. | ||
* | ||
* @method | ||
* @param {Timestamp} other Long to multiply with this. | ||
* @return {Timestamp} the product of this and the other. | ||
*/ | ||
Timestamp.prototype.multiply = function(other) { | ||
if (this.isZero()) { | ||
return Timestamp.ZERO; | ||
} else if (other.isZero()) { | ||
return Timestamp.ZERO; | ||
} | ||
if (this.equals(Timestamp.MIN_VALUE)) { | ||
return other.isOdd() ? Timestamp.MIN_VALUE : Timestamp.ZERO; | ||
} else if (other.equals(Timestamp.MIN_VALUE)) { | ||
return this.isOdd() ? Timestamp.MIN_VALUE : Timestamp.ZERO; | ||
} | ||
if (this.isNegative()) { | ||
if (other.isNegative()) { | ||
return this.negate().multiply(other.negate()); | ||
} else { | ||
return this.negate().multiply(other).negate(); | ||
} | ||
} else if (other.isNegative()) { | ||
return this.multiply(other.negate()).negate(); | ||
} | ||
// If both Longs are small, use float multiplication | ||
if (this.lessThan(Timestamp.TWO_PWR_24_) && | ||
other.lessThan(Timestamp.TWO_PWR_24_)) { | ||
return Timestamp.fromNumber(this.toNumber() * other.toNumber()); | ||
} | ||
// Divide each Long into 4 chunks of 16 bits, and then add up 4x4 products. | ||
// We can skip products that would overflow. | ||
var a48 = this.high_ >>> 16; | ||
var a32 = this.high_ & 0xFFFF; | ||
var a16 = this.low_ >>> 16; | ||
var a00 = this.low_ & 0xFFFF; | ||
var b48 = other.high_ >>> 16; | ||
var b32 = other.high_ & 0xFFFF; | ||
var b16 = other.low_ >>> 16; | ||
var b00 = other.low_ & 0xFFFF; | ||
var c48 = 0, c32 = 0, c16 = 0, c00 = 0; | ||
c00 += a00 * b00; | ||
c16 += c00 >>> 16; | ||
c00 &= 0xFFFF; | ||
c16 += a16 * b00; | ||
c32 += c16 >>> 16; | ||
c16 &= 0xFFFF; | ||
c16 += a00 * b16; | ||
c32 += c16 >>> 16; | ||
c16 &= 0xFFFF; | ||
c32 += a32 * b00; | ||
c48 += c32 >>> 16; | ||
c32 &= 0xFFFF; | ||
c32 += a16 * b16; | ||
c48 += c32 >>> 16; | ||
c32 &= 0xFFFF; | ||
c32 += a00 * b32; | ||
c48 += c32 >>> 16; | ||
c32 &= 0xFFFF; | ||
c48 += a48 * b00 + a32 * b16 + a16 * b32 + a00 * b48; | ||
c48 &= 0xFFFF; | ||
return Timestamp.fromBits((c16 << 16) | c00, (c48 << 16) | c32); | ||
}; | ||
/** | ||
* Returns this Long divided by the given one. | ||
* | ||
* @method | ||
* @param {Timestamp} other Long by which to divide. | ||
* @return {Timestamp} this Long divided by the given one. | ||
*/ | ||
Timestamp.prototype.div = function(other) { | ||
if (other.isZero()) { | ||
throw Error('division by zero'); | ||
} else if (this.isZero()) { | ||
return Timestamp.ZERO; | ||
} | ||
if (this.equals(Timestamp.MIN_VALUE)) { | ||
if (other.equals(Timestamp.ONE) || | ||
other.equals(Timestamp.NEG_ONE)) { | ||
return Timestamp.MIN_VALUE; // recall that -MIN_VALUE == MIN_VALUE | ||
} else if (other.equals(Timestamp.MIN_VALUE)) { | ||
return Timestamp.ONE; | ||
} else { | ||
// At this point, we have |other| >= 2, so |this/other| < |MIN_VALUE|. | ||
var halfThis = this.shiftRight(1); | ||
var approx = halfThis.div(other).shiftLeft(1); | ||
if (approx.equals(Timestamp.ZERO)) { | ||
return other.isNegative() ? Timestamp.ONE : Timestamp.NEG_ONE; | ||
} else { | ||
var rem = this.subtract(other.multiply(approx)); | ||
var result = approx.add(rem.div(other)); | ||
return result; | ||
} | ||
} | ||
} else if (other.equals(Timestamp.MIN_VALUE)) { | ||
return Timestamp.ZERO; | ||
} | ||
if (this.isNegative()) { | ||
if (other.isNegative()) { | ||
return this.negate().div(other.negate()); | ||
} else { | ||
return this.negate().div(other).negate(); | ||
} | ||
} else if (other.isNegative()) { | ||
return this.div(other.negate()).negate(); | ||
} | ||
// Repeat the following until the remainder is less than other: find a | ||
// floating-point that approximates remainder / other *from below*, add this | ||
// into the result, and subtract it from the remainder. It is critical that | ||
// the approximate value is less than or equal to the real value so that the | ||
// remainder never becomes negative. | ||
var res = Timestamp.ZERO; | ||
var rem = this; | ||
while (rem.greaterThanOrEqual(other)) { | ||
// Approximate the result of division. This may be a little greater or | ||
// smaller than the actual value. | ||
var approx = Math.max(1, Math.floor(rem.toNumber() / other.toNumber())); | ||
// We will tweak the approximate result by changing it in the 48-th digit or | ||
// the smallest non-fractional digit, whichever is larger. | ||
var log2 = Math.ceil(Math.log(approx) / Math.LN2); | ||
var delta = (log2 <= 48) ? 1 : Math.pow(2, log2 - 48); | ||
// Decrease the approximation until it is smaller than the remainder. Note | ||
// that if it is too large, the product overflows and is negative. | ||
var approxRes = Timestamp.fromNumber(approx); | ||
var approxRem = approxRes.multiply(other); | ||
while (approxRem.isNegative() || approxRem.greaterThan(rem)) { | ||
approx -= delta; | ||
approxRes = Timestamp.fromNumber(approx); | ||
approxRem = approxRes.multiply(other); | ||
} | ||
// We know the answer can't be zero... and actually, zero would cause | ||
// infinite recursion since we would make no progress. | ||
if (approxRes.isZero()) { | ||
approxRes = Timestamp.ONE; | ||
} | ||
res = res.add(approxRes); | ||
rem = rem.subtract(approxRem); | ||
} | ||
return res; | ||
}; | ||
/** | ||
* Returns this Long modulo the given one. | ||
* | ||
* @method | ||
* @param {Timestamp} other Long by which to mod. | ||
* @return {Timestamp} this Long modulo the given one. | ||
*/ | ||
Timestamp.prototype.modulo = function(other) { | ||
return this.subtract(this.div(other).multiply(other)); | ||
}; | ||
/** | ||
* The bitwise-NOT of this value. | ||
* | ||
* @method | ||
* @return {Timestamp} the bitwise-NOT of this value. | ||
*/ | ||
Timestamp.prototype.not = function() { | ||
return Timestamp.fromBits(~this.low_, ~this.high_); | ||
}; | ||
/** | ||
* Returns the bitwise-AND of this Long and the given one. | ||
* | ||
* @method | ||
* @param {Timestamp} other the Long with which to AND. | ||
* @return {Timestamp} the bitwise-AND of this and the other. | ||
*/ | ||
Timestamp.prototype.and = function(other) { | ||
return Timestamp.fromBits(this.low_ & other.low_, this.high_ & other.high_); | ||
}; | ||
/** | ||
* Returns the bitwise-OR of this Long and the given one. | ||
* | ||
* @method | ||
* @param {Timestamp} other the Long with which to OR. | ||
* @return {Timestamp} the bitwise-OR of this and the other. | ||
*/ | ||
Timestamp.prototype.or = function(other) { | ||
return Timestamp.fromBits(this.low_ | other.low_, this.high_ | other.high_); | ||
}; | ||
/** | ||
* Returns the bitwise-XOR of this Long and the given one. | ||
* | ||
* @method | ||
* @param {Timestamp} other the Long with which to XOR. | ||
* @return {Timestamp} the bitwise-XOR of this and the other. | ||
*/ | ||
Timestamp.prototype.xor = function(other) { | ||
return Timestamp.fromBits(this.low_ ^ other.low_, this.high_ ^ other.high_); | ||
}; | ||
/** | ||
* Returns this Long with bits shifted to the left by the given amount. | ||
* | ||
* @method | ||
* @param {number} numBits the number of bits by which to shift. | ||
* @return {Timestamp} this shifted to the left by the given amount. | ||
*/ | ||
Timestamp.prototype.shiftLeft = function(numBits) { | ||
numBits &= 63; | ||
if (numBits == 0) { | ||
return this; | ||
} else { | ||
var low = this.low_; | ||
if (numBits < 32) { | ||
var high = this.high_; | ||
return Timestamp.fromBits( | ||
low << numBits, | ||
(high << numBits) | (low >>> (32 - numBits))); | ||
} else { | ||
return Timestamp.fromBits(0, low << (numBits - 32)); | ||
} | ||
} | ||
}; | ||
/** | ||
* Returns this Long with bits shifted to the right by the given amount. | ||
* | ||
* @method | ||
* @param {number} numBits the number of bits by which to shift. | ||
* @return {Timestamp} this shifted to the right by the given amount. | ||
*/ | ||
Timestamp.prototype.shiftRight = function(numBits) { | ||
numBits &= 63; | ||
if (numBits == 0) { | ||
return this; | ||
} else { | ||
var high = this.high_; | ||
if (numBits < 32) { | ||
var low = this.low_; | ||
return Timestamp.fromBits( | ||
(low >>> numBits) | (high << (32 - numBits)), | ||
high >> numBits); | ||
} else { | ||
return Timestamp.fromBits( | ||
high >> (numBits - 32), | ||
high >= 0 ? 0 : -1); | ||
} | ||
} | ||
}; | ||
/** | ||
* Returns this Long with bits shifted to the right by the given amount, with the new top bits matching the current sign bit. | ||
* | ||
* @method | ||
* @param {number} numBits the number of bits by which to shift. | ||
* @return {Timestamp} this shifted to the right by the given amount, with zeros placed into the new leading bits. | ||
*/ | ||
Timestamp.prototype.shiftRightUnsigned = function(numBits) { | ||
numBits &= 63; | ||
if (numBits == 0) { | ||
return this; | ||
} else { | ||
var high = this.high_; | ||
if (numBits < 32) { | ||
var low = this.low_; | ||
return Timestamp.fromBits( | ||
(low >>> numBits) | (high << (32 - numBits)), | ||
high >>> numBits); | ||
} else if (numBits == 32) { | ||
return Timestamp.fromBits(high, 0); | ||
} else { | ||
return Timestamp.fromBits(high >>> (numBits - 32), 0); | ||
} | ||
} | ||
}; | ||
/** | ||
* Returns a Long representing the given (32-bit) integer value. | ||
* | ||
* @method | ||
* @param {number} value the 32-bit integer in question. | ||
* @return {Timestamp} the corresponding Long value. | ||
* @return {Timestamp} the timestamp. | ||
*/ | ||
Timestamp.fromInt = function(value) { | ||
if (-128 <= value && value < 128) { | ||
var cachedObj = Timestamp.INT_CACHE_[value]; | ||
if (cachedObj) { | ||
return cachedObj; | ||
} | ||
} | ||
var obj = new Timestamp(value | 0, value < 0 ? -1 : 0); | ||
if (-128 <= value && value < 128) { | ||
Timestamp.INT_CACHE_[value] = obj; | ||
} | ||
return obj; | ||
return new Timestamp(Long.fromInt(value)); | ||
}; | ||
/** | ||
* Returns a Long representing the given value, provided that it is a finite number. Otherwise, zero is returned. | ||
* Returns a Timestamp representing the given number value, provided that it is a finite number. Otherwise, zero is returned. | ||
* | ||
* @method | ||
* @param {number} value the number in question. | ||
* @return {Timestamp} the corresponding Long value. | ||
* @return {Timestamp} the timestamp. | ||
*/ | ||
Timestamp.fromNumber = function(value) { | ||
if (isNaN(value) || !isFinite(value)) { | ||
return Timestamp.ZERO; | ||
} else if (value <= -Timestamp.TWO_PWR_63_DBL_) { | ||
return Timestamp.MIN_VALUE; | ||
} else if (value + 1 >= Timestamp.TWO_PWR_63_DBL_) { | ||
return Timestamp.MAX_VALUE; | ||
} else if (value < 0) { | ||
return Timestamp.fromNumber(-value).negate(); | ||
} else { | ||
return new Timestamp( | ||
(value % Timestamp.TWO_PWR_32_DBL_) | 0, | ||
(value / Timestamp.TWO_PWR_32_DBL_) | 0); | ||
} | ||
return new Timestamp(Long.fromNumber(value)); | ||
}; | ||
/** | ||
* Returns a Long representing the 64-bit integer that comes by concatenating the given high and low bits. Each is assumed to use 32 bits. | ||
* Returns a Timestamp for the given high and low bits. Each is assumed to use 32 bits. | ||
* | ||
@@ -726,3 +66,3 @@ * @method | ||
* @param {number} highBits the high 32-bits. | ||
* @return {Timestamp} the corresponding Long value. | ||
* @return {Timestamp} the timestamp. | ||
*/ | ||
@@ -734,124 +74,13 @@ Timestamp.fromBits = function(lowBits, highBits) { | ||
/** | ||
* Returns a Long representation of the given string, written using the given radix. | ||
* Returns a Timestamp from the given string, optionally using the given radix. | ||
* | ||
* @method | ||
* @param {String} str the textual representation of the Timestamp. | ||
* @param {number} opt_radix the radix in which the text is written. | ||
* @return {Timestamp} the corresponding Long value. | ||
* @param {number} [opt_radix] the radix in which the text is written. | ||
* @return {Timestamp} the timestamp. | ||
*/ | ||
Timestamp.fromString = function(str, opt_radix) { | ||
if (str.length == 0) { | ||
throw Error('number format error: empty string'); | ||
} | ||
var radix = opt_radix || 10; | ||
if (radix < 2 || 36 < radix) { | ||
throw Error('radix out of range: ' + radix); | ||
} | ||
if (str.charAt(0) == '-') { | ||
return Timestamp.fromString(str.substring(1), radix).negate(); | ||
} else if (str.indexOf('-') >= 0) { | ||
throw Error('number format error: interior "-" character: ' + str); | ||
} | ||
// Do several (8) digits each time through the loop, so as to | ||
// minimize the calls to the very expensive emulated div. | ||
var radixToPower = Timestamp.fromNumber(Math.pow(radix, 8)); | ||
var result = Timestamp.ZERO; | ||
for (var i = 0; i < str.length; i += 8) { | ||
var size = Math.min(8, str.length - i); | ||
var value = parseInt(str.substring(i, i + size), radix); | ||
if (size < 8) { | ||
var power = Timestamp.fromNumber(Math.pow(radix, size)); | ||
result = result.multiply(power).add(Timestamp.fromNumber(value)); | ||
} else { | ||
result = result.multiply(radixToPower); | ||
result = result.add(Timestamp.fromNumber(value)); | ||
} | ||
} | ||
return result; | ||
return new Timestamp(Long.fromString(str, opt_radix)); | ||
}; | ||
// NOTE: Common constant values ZERO, ONE, NEG_ONE, etc. are defined below the | ||
// from* methods on which they depend. | ||
/** | ||
* A cache of the Long representations of small integer values. | ||
* @type {Object} | ||
* @ignore | ||
*/ | ||
Timestamp.INT_CACHE_ = {}; | ||
// NOTE: the compiler should inline these constant values below and then remove | ||
// these variables, so there should be no runtime penalty for these. | ||
/** | ||
* Number used repeated below in calculations. This must appear before the | ||
* first call to any from* function below. | ||
* @type {number} | ||
* @ignore | ||
*/ | ||
Timestamp.TWO_PWR_16_DBL_ = 1 << 16; | ||
/** | ||
* @type {number} | ||
* @ignore | ||
*/ | ||
Timestamp.TWO_PWR_24_DBL_ = 1 << 24; | ||
/** | ||
* @type {number} | ||
* @ignore | ||
*/ | ||
Timestamp.TWO_PWR_32_DBL_ = Timestamp.TWO_PWR_16_DBL_ * Timestamp.TWO_PWR_16_DBL_; | ||
/** | ||
* @type {number} | ||
* @ignore | ||
*/ | ||
Timestamp.TWO_PWR_31_DBL_ = Timestamp.TWO_PWR_32_DBL_ / 2; | ||
/** | ||
* @type {number} | ||
* @ignore | ||
*/ | ||
Timestamp.TWO_PWR_48_DBL_ = Timestamp.TWO_PWR_32_DBL_ * Timestamp.TWO_PWR_16_DBL_; | ||
/** | ||
* @type {number} | ||
* @ignore | ||
*/ | ||
Timestamp.TWO_PWR_64_DBL_ = Timestamp.TWO_PWR_32_DBL_ * Timestamp.TWO_PWR_32_DBL_; | ||
/** | ||
* @type {number} | ||
* @ignore | ||
*/ | ||
Timestamp.TWO_PWR_63_DBL_ = Timestamp.TWO_PWR_64_DBL_ / 2; | ||
/** @type {Timestamp} */ | ||
Timestamp.ZERO = Timestamp.fromInt(0); | ||
/** @type {Timestamp} */ | ||
Timestamp.ONE = Timestamp.fromInt(1); | ||
/** @type {Timestamp} */ | ||
Timestamp.NEG_ONE = Timestamp.fromInt(-1); | ||
/** @type {Timestamp} */ | ||
Timestamp.MAX_VALUE = | ||
Timestamp.fromBits(0xFFFFFFFF | 0, 0x7FFFFFFF | 0); | ||
/** @type {Timestamp} */ | ||
Timestamp.MIN_VALUE = Timestamp.fromBits(0, 0x80000000 | 0); | ||
/** | ||
* @type {Timestamp} | ||
* @ignore | ||
*/ | ||
Timestamp.TWO_PWR_24_ = Timestamp.fromInt(1 << 24); | ||
module.exports = Timestamp; |
@@ -43,11 +43,54 @@ "use strict"; | ||
function deseralizeValue(self, value, options) { | ||
if(value['$oid'] != null) { | ||
if (typeof value === 'number') { | ||
if (options.strict) { | ||
if (Math.floor(value) === value && value >= JS_INT_MIN && value <= JS_INT_MAX) { | ||
if (value >= BSON_INT32_MIN && value <= BSON_INT32_MAX) { | ||
return new self.bson.Int32(value); | ||
} | ||
if (value >= JS_INT_MIN && value <= JS_INT_MAX) { | ||
return new self.bson.Double(value); | ||
} | ||
return new self.bson.Long.fromNumber(value); | ||
} | ||
return new self.bson.Double(value); | ||
} | ||
if (Math.floor(value) === value && value >= JS_INT_MIN && value <= JS_INT_MAX) { | ||
if (value >= BSON_INT32_MIN && value <= BSON_INT32_MAX) { | ||
return value; | ||
} | ||
if (value >= JS_INT_MIN && value <= JS_INT_MAX) { | ||
return value; | ||
} | ||
return new self.bson.Long.fromNumber(value); | ||
} | ||
} | ||
// from here on out we're looking for bson types, so bail if its | ||
// not an object | ||
if (value == null || typeof value !== 'object') { | ||
return value; | ||
} | ||
if (value['$oid'] != null) { | ||
return new self.bson.ObjectID(value['$oid']); | ||
} else if(value['$date'] && typeof value['$date'] == 'string') { | ||
}; | ||
if (value['$date'] && typeof value['$date'] === 'string') { | ||
return Date.parse(value['$date']); | ||
} else if(value['$date'] && value['$date'] instanceof self.bson.Long) { | ||
} | ||
if (value['$date'] && value['$date'] instanceof self.bson.Long) { | ||
var date = new Date(); | ||
date.setTime(value['$date'].toNumber()); | ||
return date; | ||
} else if(value['$binary'] != null) { | ||
} | ||
if (value['$binary'] != null) { | ||
if (typeof Buffer !== 'undefined') { | ||
@@ -69,55 +112,57 @@ if (bufferConstructor === Buffer) { | ||
return new self.bson.Binary(data, type); | ||
} else if(value['$maxKey'] != null) { | ||
} | ||
if (value['$maxKey'] != null) { | ||
return new self.bson.MaxKey(); | ||
} else if(value['$minKey'] != null) { | ||
} | ||
if (value['$minKey'] != null) { | ||
return new self.bson.MinKey(); | ||
} else if(value['$code'] != null) { | ||
return new self.bson.Code(value['$code'], deseralizeValue(self, value['$scope'] || {}, options)) | ||
} else if(value['$numberLong'] != null) { | ||
} | ||
if (value['$code'] != null) { | ||
return new self.bson.Code(value['$code'], deseralizeValue(self, value['$scope'] || {}, options)); | ||
} | ||
if (value['$numberLong'] != null) { | ||
return self.bson.Long.fromString(value['$numberLong']); | ||
} else if(value['$numberDouble'] != null && options.strict) { | ||
} | ||
if (value['$numberDouble'] != null && options.strict) { | ||
return new self.bson.Double(parseFloat(value['$numberDouble'])); | ||
} else if(value['$numberDouble'] != null && !options.strict) { | ||
} | ||
if (value['$numberDouble'] != null && !options.strict) { | ||
return parseFloat(value['$numberDouble']); | ||
} else if(value['$numberInt'] != null && options.strict) { | ||
} | ||
if (value['$numberInt'] != null && options.strict) { | ||
return new self.bson.Int32(parseInt(value['$numberInt'], 10)); | ||
} else if(value['$numberInt'] != null && !options.strict) { | ||
} | ||
if (value['$numberInt'] != null && !options.strict) { | ||
return parseInt(value['$numberInt'], 10); | ||
} else if(value['$numberDecimal'] != null) { | ||
} | ||
if (value['$numberDecimal'] != null) { | ||
return self.bson.Decimal128.fromString(value['$numberDecimal']); | ||
} else if(value['$regex'] != null) { | ||
} | ||
if (value['$regex'] != null) { | ||
return new self.bson.BSONRegExp(value['$regex'], value['$options'] || ''); | ||
} else if(value['$symbol'] != null) { | ||
} | ||
if (value['$symbol'] != null) { | ||
return new self.bson.Symbol(value['$symbol']); | ||
} else if(value['$ref'] != null) { | ||
} | ||
if (value['$ref'] != null) { | ||
return new self.bson.DBRef(value['$ref'], deseralizeValue(self, value['$id'], options), value['$db']); | ||
} else if(value['$timestamp'] != null) { | ||
} | ||
if (value['$timestamp'] != null) { | ||
return self.bson.Timestamp.fromString(value['$timestamp']); | ||
} else if(typeof value == 'number' && options.strict) { | ||
if(Math.floor(value) === value && value >= JS_INT_MIN && value <= JS_INT_MAX) { | ||
if(value >= BSON_INT32_MIN && value <= BSON_INT32_MAX) { | ||
return new self.bson.Int32(value); | ||
} else if(value >= JS_INT_MIN && value <= JS_INT_MAX) { | ||
return new self.bson.Double(value); | ||
} else { | ||
return new self.bson.Long.fromNumber(value); | ||
} | ||
} else { | ||
return new self.bson.Double(value); | ||
} | ||
} else if(typeof value == 'number' && !options.strict) { | ||
if(Math.floor(value) === value && value >= JS_INT_MIN && value <= JS_INT_MAX) { | ||
if(value >= BSON_INT32_MIN && value <= BSON_INT32_MAX) { | ||
return value; | ||
} else if(value >= JS_INT_MIN && value <= JS_INT_MAX) { | ||
return value; | ||
} else { | ||
return new self.bson.Long.fromNumber(value); | ||
} | ||
} else { | ||
return value; | ||
} | ||
} else { | ||
return value; | ||
} | ||
return value; | ||
} | ||
@@ -204,17 +249,23 @@ | ||
function serializeDocument(doc) { | ||
if(doc == null || typeof doc !== 'object') throw new Error('not an object instance'); | ||
if (doc == null || typeof doc !== 'object') { | ||
throw new Error('not an object instance'); | ||
} | ||
if (doc != null && doc._bsontype && BSONTypes.indexOf(doc._bsontype) != -1) { | ||
return doc.toJSON(); | ||
} | ||
var _doc = {}; | ||
for(var name in doc) { | ||
if(Array.isArray(doc[name])) { | ||
for (var name in doc) { | ||
if (Array.isArray(doc[name])) { | ||
_doc[name] = serializeArray(doc[name]); | ||
} else if(doc[name] != null && doc[name]._bsontype && BSONTypes.indexOf(doc[name]._bsontype) != -1) { | ||
} else if (doc[name] != null && doc[name]._bsontype && BSONTypes.indexOf(doc[name]._bsontype) != -1) { | ||
_doc[name] = doc[name]; | ||
} else if(doc[name] instanceof Date) { | ||
} else if (doc[name] instanceof Date) { | ||
_doc[name] = serializeValue(doc[name]); | ||
} else if(doc[name] != null && typeof doc[name] === 'object') { | ||
} else if (doc[name] != null && typeof doc[name] === 'object') { | ||
_doc[name] = serializeDocument(doc[name]); | ||
} else { | ||
_doc[name] = serializeValue(doc[name]); | ||
} | ||
_doc[name] = serializeValue(doc[name]); | ||
} | ||
@@ -221,0 +272,0 @@ |
{ | ||
"name": "mongodb-extjson", | ||
"version": "1.0.4", | ||
"version": "1.0.5", | ||
"description": "MongoDB Extended JSON library", | ||
"main": "index.js", | ||
"scripts": { | ||
"test": "mocha test/" | ||
"test": "mocha test/", | ||
"coverage": "istanbul cover _mocha -- --recursive -t --ui tdd test/" | ||
}, | ||
@@ -29,6 +30,6 @@ "repository": { | ||
"devDependencies": { | ||
"mocha": "^3.2.0", | ||
"mongodb": "mongodb/node-mongodb-native#2.2", | ||
"typedarray": "0.0.6" | ||
"istanbul": "^0.4.5", | ||
"mocha": "^3.4.1", | ||
"mongodb": "^2.2.27" | ||
} | ||
} |
@@ -0,1 +1,3 @@ | ||
[](https://travis-ci.org/christkv/mongodb-extjson) | ||
# MongoDB Extended JSON Library | ||
@@ -2,0 +4,0 @@ |
@@ -1,184 +0,231 @@ | ||
var ExtJSON = require('../'), | ||
assert = require('assert'); | ||
var assert = require('assert'), | ||
path = require('path'); | ||
var nodeDoc; | ||
var browserDoc; | ||
function requireUncached(moduleName) { | ||
var resolved = require.resolve(moduleName); | ||
var moduleDir = path.dirname(resolved); | ||
Object.keys(require.cache) | ||
.filter(function(file) { return file.indexOf(moduleDir) === 0; }) | ||
.forEach(function(key) { delete require.cache[key]; }); | ||
describe('Extended JSON', function() { | ||
beforeEach(function() { | ||
var mongodb = ExtJSON.extend(require('mongodb')); | ||
var Binary = mongodb.Binary, | ||
Code = mongodb.Code, | ||
DBRef = mongodb.DBRef, | ||
Decimal128 = mongodb.Decimal128, | ||
Double = mongodb.Double, | ||
Int32 = mongodb.Int32, | ||
Long = mongodb.Long, | ||
MaxKey = mongodb.MaxKey, | ||
MinKey = mongodb.MinKey, | ||
ObjectID = mongodb.ObjectID, | ||
BSONRegExp = mongodb.BSONRegExp, | ||
Symbol = mongodb.Symbol, | ||
Timestamp = mongodb.Timestamp; | ||
return require(moduleName); | ||
} | ||
// Create a new Buffer | ||
var buffer = new Buffer(64); | ||
for(var i = 0; i < buffer.length; i++) buffer[i] = i; | ||
var $Buffer = Buffer, | ||
ExtJSON = null, | ||
mongodb = null; | ||
// Fix the date so test have no variable component | ||
var date = new Date(); | ||
date.setTime(1488372056737); | ||
// BSON types | ||
var Binary, Code, DBRef, Decimal128, Double, | ||
Int32, Long, MaxKey, MinKey, ObjectID, | ||
BSONRegExp, Symbol, Timestamp; | ||
nodeDoc = { | ||
_id: new Int32(100), | ||
gh:new Int32(1), | ||
binary: new Binary(buffer), | ||
date: date, | ||
code: new Code('function() {}', {a: new Int32(1)}), | ||
dbRef: new DBRef('tests', new Int32(1), 'test'), | ||
decimal: Decimal128.fromString("100"), | ||
double: new Double(10.10), | ||
int32: new Int32(10), | ||
long: Long.fromNumber(200), | ||
maxKey: new MaxKey(), | ||
minKey: new MinKey(), | ||
objectId: ObjectID.createFromHexString('111111111111111111111111'), | ||
regexp: new BSONRegExp('hello world', 'i'), | ||
symbol: new Symbol('symbol'), | ||
timestamp: Timestamp.fromNumber(1000), | ||
int32Number: 300, | ||
doubleNumber: 200.20, | ||
longNumberIntFit: 0x19000000000000, | ||
doubleNumberIntFit: 19007199250000000.120 | ||
}; | ||
var mongodb = require('../lib/bson'); | ||
var Binary = mongodb.Binary, | ||
Code = mongodb.Code, | ||
DBRef = mongodb.DBRef, | ||
Decimal128 = mongodb.Decimal128, | ||
Double = mongodb.Double, | ||
Int32 = mongodb.Int32, | ||
Long = mongodb.Long, | ||
MaxKey = mongodb.MaxKey, | ||
MinKey = mongodb.MinKey, | ||
ObjectID = mongodb.ObjectID, | ||
BSONRegExp = mongodb.BSONRegExp, | ||
Symbol = mongodb.Symbol, | ||
var test = {}; | ||
var environments = [ | ||
{ | ||
name: 'node', | ||
setup: function() { | ||
ExtJSON = requireUncached('..'); | ||
}, | ||
teardown: function() { }, | ||
beforeEach: function() { | ||
mongodb = ExtJSON.extend(require('mongodb')); | ||
Binary = mongodb.Binary; | ||
Code = mongodb.Code; | ||
DBRef = mongodb.DBRef; | ||
Decimal128 = mongodb.Decimal128; | ||
Double = mongodb.Double; | ||
Int32 = mongodb.Int32; | ||
Long = mongodb.Long; | ||
MaxKey = mongodb.MaxKey; | ||
MinKey = mongodb.MinKey; | ||
ObjectID = mongodb.ObjectID; | ||
BSONRegExp = mongodb.BSONRegExp; | ||
Symbol = mongodb.Symbol; | ||
Timestamp = mongodb.Timestamp; | ||
buffer = new Uint8Array(64); | ||
for(var i = 0; i < buffer.length; i++) buffer[i] = i; | ||
// Create a new Buffer | ||
var buffer = new Buffer(64); | ||
for(var i = 0; i < buffer.length; i++) buffer[i] = i; | ||
browserDoc = { | ||
_id: new Int32(100), | ||
gh:new Int32(1), | ||
binary: new Binary(buffer), | ||
date: date, | ||
code: new Code('function() {}', {a: new Int32(1)}), | ||
dbRef: new DBRef('tests', new Int32(1), 'test'), | ||
decimal: Decimal128.fromString("100"), | ||
double: new Double(10.10), | ||
int32: new Int32(10), | ||
long: Long.fromNumber(200), | ||
maxKey: new MaxKey(), | ||
minKey: new MinKey(), | ||
objectId: ObjectID.createFromHexString('111111111111111111111111'), | ||
regexp: new BSONRegExp('hello world', 'i'), | ||
symbol: new Symbol('symbol'), | ||
timestamp: Timestamp.fromNumber(1000), | ||
int32Number: 300, | ||
doubleNumber: 200.20, | ||
longNumberIntFit: 0x19000000000000, | ||
doubleNumberIntFit: 19007199250000000.120 | ||
}; | ||
}); | ||
// Fix the date so test have no variable component | ||
var date = new Date(); | ||
date.setTime(1488372056737); | ||
it('should correctly extend the existing mongodb module', function(done) { | ||
// Serialize the document | ||
var json = '{"_id":{"$numberInt":"100"},"gh":{"$numberInt":"1"},"binary":{"$binary":"AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+Pw==","$type":"00"},"date":"2017-03-01T12:40:56.737Z","code":{"$code":"function() {}","$scope":{"a":{"$numberInt":"1"}}},"dbRef":{"$ref":"tests","$id":{"$numberInt":"1"},"$db":"test"},"decimal":{"$numberDecimal":"100"},"double":{"$numberDouble":"10.1"},"int32":{"$numberInt":"10"},"long":{"$numberLong":"200"},"maxKey":{"$maxKey":1},"minKey":{"$minKey":1},"objectId":{"$oid":"111111111111111111111111"},"regexp":{"$regex":"hello world","$options":"i"},"symbol":{"$symbol":"symbol"},"timestamp":{"$timestamp":"1000"},"int32Number":300,"doubleNumber":200.2,"longNumberIntFit":7036874417766400,"doubleNumberIntFit":19007199250000000}'; | ||
assert.equal(json, JSON.stringify(nodeDoc, null, 0)); | ||
done(); | ||
}); | ||
test.doc = { | ||
_id: new Int32(100), | ||
gh:new Int32(1), | ||
binary: new Binary(buffer), | ||
date: date, | ||
code: new Code('function() {}', {a: new Int32(1)}), | ||
dbRef: new DBRef('tests', new Int32(1), 'test'), | ||
decimal: Decimal128.fromString("100"), | ||
double: new Double(10.10), | ||
int32: new Int32(10), | ||
long: Long.fromNumber(200), | ||
maxKey: new MaxKey(), | ||
minKey: new MinKey(), | ||
objectId: ObjectID.createFromHexString('111111111111111111111111'), | ||
regexp: new BSONRegExp('hello world', 'i'), | ||
symbol: new Symbol('symbol'), | ||
timestamp: Timestamp.fromNumber(1000), | ||
int32Number: 300, | ||
doubleNumber: 200.20, | ||
longNumberIntFit: 0x19000000000000, | ||
doubleNumberIntFit: 19007199250000000.120 | ||
}; | ||
} | ||
}, | ||
{ | ||
name: 'web', | ||
setup: function() { | ||
$Buffer = global.Buffer; | ||
global.Buffer = undefined; | ||
ExtJSON = requireUncached('..'); | ||
}, | ||
teardown: function() { | ||
global.Buffer = $Buffer; | ||
}, | ||
beforeEach: function() { | ||
mongodb = require('../lib/bson'); | ||
Binary = mongodb.Binary; | ||
Code = mongodb.Code; | ||
DBRef = mongodb.DBRef; | ||
Decimal128 = mongodb.Decimal128; | ||
Double = mongodb.Double; | ||
Int32 = mongodb.Int32; | ||
Long = mongodb.Long; | ||
MaxKey = mongodb.MaxKey; | ||
MinKey = mongodb.MinKey; | ||
ObjectID = mongodb.ObjectID; | ||
BSONRegExp = mongodb.BSONRegExp; | ||
Symbol = mongodb.Symbol; | ||
Timestamp = mongodb.Timestamp; | ||
it('should correctly deserialize using strict and non-strict mode using nodeDoc', function(done) { | ||
// Create ExtJSON instance | ||
var extJSON = new ExtJSON(); | ||
// Create a new Buffer | ||
var buffer = new Uint8Array(64); | ||
for(var i = 0; i < buffer.length; i++) buffer[i] = i; | ||
// Deserialize the document using non strict mode | ||
var doc1 = extJSON.parse(extJSON.stringify(nodeDoc, null, 0), {strict:false}); | ||
// Fix the date so test have no variable component | ||
var date = new Date(); | ||
date.setTime(1488372056737); | ||
// Validate the values | ||
assert.equal(300, doc1.int32Number); | ||
assert.equal(200.20, doc1.doubleNumber); | ||
assert.equal(0x19000000000000, doc1.longNumberIntFit); | ||
assert.equal(19007199250000000.120, doc1.doubleNumberIntFit); | ||
test.doc = { | ||
_id: new Int32(100), | ||
gh:new Int32(1), | ||
binary: new Binary(buffer), | ||
date: date, | ||
code: new Code('function() {}', {a: new Int32(1)}), | ||
dbRef: new DBRef('tests', new Int32(1), 'test'), | ||
decimal: Decimal128.fromString("100"), | ||
double: new Double(10.10), | ||
int32: new Int32(10), | ||
long: Long.fromNumber(200), | ||
maxKey: new MaxKey(), | ||
minKey: new MinKey(), | ||
objectId: ObjectID.createFromHexString('111111111111111111111111'), | ||
regexp: new BSONRegExp('hello world', 'i'), | ||
symbol: new Symbol('symbol'), | ||
timestamp: Timestamp.fromNumber(1000), | ||
int32Number: 300, | ||
doubleNumber: 200.20, | ||
longNumberIntFit: 0x19000000000000, | ||
doubleNumberIntFit: 19007199250000000.120 | ||
}; | ||
} | ||
} | ||
]; | ||
// Deserialize the document using strict mode | ||
var doc1 = extJSON.parse(JSON.stringify(nodeDoc, null, 0), {strict:true}); | ||
describe('Extended JSON', function() { | ||
environments.forEach(function(env) { | ||
describe('environment: ' + env.name, function() { | ||
before(function() { return env.setup(); }); | ||
after(function() { return env.teardown(); }); | ||
beforeEach(function() { return env.beforeEach(); }); | ||
// Validate the values | ||
assert.equal('Int32', doc1.int32Number._bsontype); | ||
assert.equal('Double', doc1.doubleNumber._bsontype); | ||
assert.equal('Double', doc1.longNumberIntFit._bsontype); | ||
assert.equal('Double', doc1.doubleNumberIntFit._bsontype); | ||
it('should correctly extend an existing mongodb module', function() { | ||
// Serialize the document | ||
var json = '{"_id":{"$numberInt":"100"},"gh":{"$numberInt":"1"},"binary":{"$binary":"AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+Pw==","$type":"00"},"date":"2017-03-01T12:40:56.737Z","code":{"$code":"function() {}","$scope":{"a":{"$numberInt":"1"}}},"dbRef":{"$ref":"tests","$id":{"$numberInt":"1"},"$db":"test"},"decimal":{"$numberDecimal":"100"},"double":{"$numberDouble":"10.1"},"int32":{"$numberInt":"10"},"long":{"$numberLong":"200"},"maxKey":{"$maxKey":1},"minKey":{"$minKey":1},"objectId":{"$oid":"111111111111111111111111"},"regexp":{"$regex":"hello world","$options":"i"},"symbol":{"$symbol":"symbol"},"timestamp":{"$timestamp":"1000"},"int32Number":300,"doubleNumber":200.2,"longNumberIntFit":7036874417766400,"doubleNumberIntFit":19007199250000000}'; | ||
assert.equal(json, JSON.stringify(test.doc, null, 0)); | ||
}); | ||
done(); | ||
}); | ||
it('should correctly deserialize using strict, and non-strict mode', function() { | ||
// Create ExtJSON instance | ||
var extJSON = new ExtJSON(); | ||
it('should correctly deserialize using strict and non-strict mode using browserDoc', function(done) { | ||
// Create ExtJSON instance | ||
var extJSON = new ExtJSON(); | ||
// Deserialize the document using non strict mode | ||
var doc1 = extJSON.parse(extJSON.stringify(test.doc, null, 0), {strict:false}); | ||
// Deserialize the document using non strict mode | ||
var doc1 = extJSON.parse(extJSON.stringify(browserDoc, null, 0), {strict:false}); | ||
// Validate the values | ||
assert.equal(300, doc1.int32Number); | ||
assert.equal(200.20, doc1.doubleNumber); | ||
assert.equal(0x19000000000000, doc1.longNumberIntFit); | ||
assert.equal(19007199250000000.120, doc1.doubleNumberIntFit); | ||
// Validate the values | ||
assert.equal(300, doc1.int32Number); | ||
assert.equal(200.20, doc1.doubleNumber); | ||
assert.equal(0x19000000000000, doc1.longNumberIntFit); | ||
assert.equal(19007199250000000.120, doc1.doubleNumberIntFit); | ||
// Deserialize the document using strict mode | ||
var doc1 = extJSON.parse(JSON.stringify(test.doc, null, 0), {strict:true}); | ||
// Deserialize the document using strict mode | ||
var doc1 = extJSON.parse(JSON.stringify(browserDoc, null, 0), {strict:true}); | ||
// Validate the values | ||
assert.equal('Int32', doc1.int32Number._bsontype); | ||
assert.equal('Double', doc1.doubleNumber._bsontype); | ||
assert.equal('Double', doc1.longNumberIntFit._bsontype); | ||
assert.equal('Double', doc1.doubleNumberIntFit._bsontype); | ||
}); | ||
// Validate the values | ||
assert.equal('Int32', doc1.int32Number._bsontype); | ||
assert.equal('Double', doc1.doubleNumber._bsontype); | ||
assert.equal('Double', doc1.longNumberIntFit._bsontype); | ||
assert.equal('Double', doc1.doubleNumberIntFit._bsontype); | ||
it('should correctly serialize, and deserialize using built-in BSON', function() { | ||
// Create ExtJSON instance | ||
var extJSON = new ExtJSON(); | ||
var Int32 = ExtJSON.BSON.Int32; | ||
// Create a doc | ||
var doc1 = { | ||
int32: new Int32(10) | ||
}; | ||
done(); | ||
}); | ||
// Serialize the document | ||
var text = extJSON.stringify(doc1, null, 0); | ||
assert.equal('{"int32":{"$numberInt":"10"}}', text); | ||
it('should correctly serialize and deserialize using built in BSON', function(done) { | ||
// Create ExtJSON instance | ||
var extJSON = new ExtJSON(); | ||
var Int32 = ExtJSON.BSON.Int32; | ||
// Create a doc | ||
var doc1 = { | ||
int32: new Int32(10) | ||
}; | ||
// Deserialize the json in strict and non strict mode | ||
var doc2 = extJSON.parse(text, {strict: true}); | ||
assert.equal('Int32', doc2.int32._bsontype); | ||
doc2 = extJSON.parse(text, {strict: false}); | ||
assert.equal(10, doc2.int32); | ||
}); | ||
// Serialize the document | ||
var text = extJSON.stringify(doc1, null, 0); | ||
assert.equal('{"int32":{"$numberInt":"10"}}', text); | ||
it('should correctly serialize bson types when they are values', function() { | ||
var extJSON = new ExtJSON(); | ||
var Int32 = ExtJSON.BSON.Int32, | ||
ObjectId = ExtJSON.BSON.ObjectID; | ||
// Deserialize the json in strict and non strict mode | ||
var doc2 = extJSON.parse(text, {strict: true}); | ||
assert.equal('Int32', doc2.int32._bsontype); | ||
doc2 = extJSON.parse(text, {strict: false}); | ||
assert.equal(10, doc2.int32); | ||
done(); | ||
}); | ||
var serialized = extJSON.stringify(new ObjectID('591801a468f9e7024b6235ea')); | ||
assert.equal(serialized, '{"$oid":"591801a468f9e7024b6235ea"}'); | ||
serialized = extJSON.stringify(new Int32(42)); | ||
assert.equal(serialized, '{"$numberInt":"42"}'); | ||
serialized = | ||
extJSON.stringify({ _id: { $nin: [ new ObjectID('591801a468f9e7024b6235ea') ] } }); | ||
assert.equal(serialized, '{"_id":{"$nin":[{"$oid":"591801a468f9e7024b6235ea"}]}}'); | ||
}); | ||
it('should correctly throw when passed a non string to parse', function(done) { | ||
// Create ExtJSON instance | ||
var extJSON = new ExtJSON(); | ||
assert.throws(() => { | ||
extJSON.parse({}, {strict: true}) | ||
}, Error); | ||
it('should correctly parse null values', function() { | ||
var extJSON = new ExtJSON(); | ||
var ObjectId = ExtJSON.BSON.ObjectID; | ||
done(); | ||
assert.equal(extJSON.parse('null'), null); | ||
assert.deepEqual(extJSON.parse('[null]'), [ null ]); | ||
var input = '{"result":[{"_id":{"$oid":"591801a468f9e7024b623939"},"emptyField":null}]}'; | ||
var parsed = extJSON.parse(input, { strict: false }); | ||
assert.deepEqual(parsed, { | ||
result: [ | ||
{ _id: new ObjectID('591801a468f9e7024b623939'), emptyField: null } | ||
] | ||
}); | ||
}); | ||
it('should correctly throw when passed a non-string to parse', function() { | ||
// Create ExtJSON instance | ||
var extJSON = new ExtJSON(); | ||
assert.throws(function() { extJSON.parse({}, {strict: true}); }, Error); | ||
}); | ||
}); | ||
}); | ||
}); |
Sorry, the diff of this file is not supported yet
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
114
102218
2684
2