123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387 |
- // Custom inspect property name / symbol.
- var inspect = 'inspect';
-
- /**
- * Machine id.
- *
- * Create a random 3-byte value (i.e. unique for this
- * process). Other drivers use a md5 of the machine id here, but
- * that would mean an asyc call to gethostname, so we don't bother.
- * @ignore
- */
- var MACHINE_ID = parseInt(Math.random() * 0xffffff, 10);
-
- // Regular expression that checks for hex value
- var checkForHexRegExp = new RegExp('^[0-9a-fA-F]{24}$');
-
- // Check if buffer exists
- try {
- if (Buffer && Buffer.from) {
- var hasBufferType = true;
- inspect = require('util').inspect.custom || 'inspect';
- }
- } catch (err) {
- hasBufferType = false;
- }
-
- /**
- * Create a new ObjectID instance
- *
- * @class
- * @param {(string|number)} id Can be a 24 byte hex string, 12 byte binary string or a Number.
- * @property {number} generationTime The generation time of this ObjectId instance
- * @return {ObjectID} instance of ObjectID.
- */
- var ObjectID = function ObjectID(id) {
- // Duck-typing to support ObjectId from different npm packages
- if (id instanceof ObjectID) return id;
- if (!(this instanceof ObjectID)) return new ObjectID(id);
-
- this._bsontype = 'ObjectID';
-
- // The most common usecase (blank id, new objectId instance)
- if (id == null || typeof id === 'number') {
- // Generate a new id
- this.id = this.generate(id);
- // If we are caching the hex string
- if (ObjectID.cacheHexString) this.__id = this.toString('hex');
- // Return the object
- return;
- }
-
- // Check if the passed in id is valid
- var valid = ObjectID.isValid(id);
-
- // Throw an error if it's not a valid setup
- if (!valid && id != null) {
- throw new Error(
- 'Argument passed in must be a single String of 12 bytes or a string of 24 hex characters'
- );
- } else if (valid && typeof id === 'string' && id.length === 24 && hasBufferType) {
- return new ObjectID(new Buffer(id, 'hex'));
- } else if (valid && typeof id === 'string' && id.length === 24) {
- return ObjectID.createFromHexString(id);
- } else if (id != null && id.length === 12) {
- // assume 12 byte string
- this.id = id;
- } else if (id != null && id.toHexString) {
- // Duck-typing to support ObjectId from different npm packages
- return id;
- } else {
- throw new Error(
- 'Argument passed in must be a single String of 12 bytes or a string of 24 hex characters'
- );
- }
-
- if (ObjectID.cacheHexString) this.__id = this.toString('hex');
- };
-
- // Allow usage of ObjectId as well as ObjectID
- // var ObjectId = ObjectID;
-
- // Precomputed hex table enables speedy hex string conversion
- var hexTable = [];
- for (var i = 0; i < 256; i++) {
- hexTable[i] = (i <= 15 ? '0' : '') + i.toString(16);
- }
-
- /**
- * Return the ObjectID id as a 24 byte hex string representation
- *
- * @method
- * @return {string} return the 24 byte hex string representation.
- */
- ObjectID.prototype.toHexString = function() {
- if (ObjectID.cacheHexString && this.__id) return this.__id;
-
- var hexString = '';
- if (!this.id || !this.id.length) {
- throw new Error(
- 'invalid ObjectId, ObjectId.id must be either a string or a Buffer, but is [' +
- JSON.stringify(this.id) +
- ']'
- );
- }
-
- if (this.id instanceof _Buffer) {
- hexString = convertToHex(this.id);
- if (ObjectID.cacheHexString) this.__id = hexString;
- return hexString;
- }
-
- for (var i = 0; i < this.id.length; i++) {
- hexString += hexTable[this.id.charCodeAt(i)];
- }
-
- if (ObjectID.cacheHexString) this.__id = hexString;
- return hexString;
- };
-
- /**
- * Update the ObjectID index used in generating new ObjectID's on the driver
- *
- * @method
- * @return {number} returns next index value.
- * @ignore
- */
- ObjectID.prototype.get_inc = function() {
- return (ObjectID.index = (ObjectID.index + 1) % 0xffffff);
- };
-
- /**
- * Update the ObjectID index used in generating new ObjectID's on the driver
- *
- * @method
- * @return {number} returns next index value.
- * @ignore
- */
- ObjectID.prototype.getInc = function() {
- return this.get_inc();
- };
-
- /**
- * Generate a 12 byte id buffer used in ObjectID's
- *
- * @method
- * @param {number} [time] optional parameter allowing to pass in a second based timestamp.
- * @return {Buffer} return the 12 byte id buffer string.
- */
- ObjectID.prototype.generate = function(time) {
- if ('number' !== typeof time) {
- time = ~~(Date.now() / 1000);
- }
-
- // Use pid
- var pid =
- (typeof process === 'undefined' || process.pid === 1
- ? Math.floor(Math.random() * 100000)
- : process.pid) % 0xffff;
- var inc = this.get_inc();
- // Buffer used
- var buffer = new Buffer(12);
- // Encode time
- buffer[3] = time & 0xff;
- buffer[2] = (time >> 8) & 0xff;
- buffer[1] = (time >> 16) & 0xff;
- buffer[0] = (time >> 24) & 0xff;
- // Encode machine
- buffer[6] = MACHINE_ID & 0xff;
- buffer[5] = (MACHINE_ID >> 8) & 0xff;
- buffer[4] = (MACHINE_ID >> 16) & 0xff;
- // Encode pid
- buffer[8] = pid & 0xff;
- buffer[7] = (pid >> 8) & 0xff;
- // Encode index
- buffer[11] = inc & 0xff;
- buffer[10] = (inc >> 8) & 0xff;
- buffer[9] = (inc >> 16) & 0xff;
- // Return the buffer
- return buffer;
- };
-
- /**
- * Converts the id into a 24 byte hex string for printing
- *
- * @param {String} format The Buffer toString format parameter.
- * @return {String} return the 24 byte hex string representation.
- * @ignore
- */
- ObjectID.prototype.toString = function(format) {
- // Is the id a buffer then use the buffer toString method to return the format
- if (this.id && this.id.copy) {
- return this.id.toString(typeof format === 'string' ? format : 'hex');
- }
-
- // if(this.buffer )
- return this.toHexString();
- };
-
- /**
- * Converts to a string representation of this Id.
- *
- * @return {String} return the 24 byte hex string representation.
- * @ignore
- */
- ObjectID.prototype[inspect] = ObjectID.prototype.toString;
-
- /**
- * Converts to its JSON representation.
- *
- * @return {String} return the 24 byte hex string representation.
- * @ignore
- */
- ObjectID.prototype.toJSON = function() {
- return this.toHexString();
- };
-
- /**
- * Compares the equality of this ObjectID with `otherID`.
- *
- * @method
- * @param {object} otherID ObjectID instance to compare against.
- * @return {boolean} the result of comparing two ObjectID's
- */
- ObjectID.prototype.equals = function equals(otherId) {
- // var id;
-
- if (otherId instanceof ObjectID) {
- return this.toString() === otherId.toString();
- } else if (
- typeof otherId === 'string' &&
- ObjectID.isValid(otherId) &&
- otherId.length === 12 &&
- this.id instanceof _Buffer
- ) {
- return otherId === this.id.toString('binary');
- } else if (typeof otherId === 'string' && ObjectID.isValid(otherId) && otherId.length === 24) {
- return otherId.toLowerCase() === this.toHexString();
- } else if (typeof otherId === 'string' && ObjectID.isValid(otherId) && otherId.length === 12) {
- return otherId === this.id;
- } else if (otherId != null && (otherId instanceof ObjectID || otherId.toHexString)) {
- return otherId.toHexString() === this.toHexString();
- } else {
- return false;
- }
- };
-
- /**
- * Returns the generation date (accurate up to the second) that this ID was generated.
- *
- * @method
- * @return {date} the generation date
- */
- ObjectID.prototype.getTimestamp = function() {
- var timestamp = new Date();
- var time = this.id[3] | (this.id[2] << 8) | (this.id[1] << 16) | (this.id[0] << 24);
- timestamp.setTime(Math.floor(time) * 1000);
- return timestamp;
- };
-
- /**
- * @ignore
- */
- ObjectID.index = ~~(Math.random() * 0xffffff);
-
- /**
- * @ignore
- */
- ObjectID.createPk = function createPk() {
- return new ObjectID();
- };
-
- /**
- * Creates an ObjectID from a second based number, with the rest of the ObjectID zeroed out. Used for comparisons or sorting the ObjectID.
- *
- * @method
- * @param {number} time an integer number representing a number of seconds.
- * @return {ObjectID} return the created ObjectID
- */
- ObjectID.createFromTime = function createFromTime(time) {
- var buffer = new Buffer([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
- // Encode time into first 4 bytes
- buffer[3] = time & 0xff;
- buffer[2] = (time >> 8) & 0xff;
- buffer[1] = (time >> 16) & 0xff;
- buffer[0] = (time >> 24) & 0xff;
- // Return the new objectId
- return new ObjectID(buffer);
- };
-
- // Lookup tables
- //var encodeLookup = '0123456789abcdef'.split('');
- var decodeLookup = [];
- i = 0;
- while (i < 10) decodeLookup[0x30 + i] = i++;
- while (i < 16) decodeLookup[0x41 - 10 + i] = decodeLookup[0x61 - 10 + i] = i++;
-
- var _Buffer = Buffer;
- var convertToHex = function(bytes) {
- return bytes.toString('hex');
- };
-
- /**
- * Creates an ObjectID from a hex string representation of an ObjectID.
- *
- * @method
- * @param {string} hexString create a ObjectID from a passed in 24 byte hexstring.
- * @return {ObjectID} return the created ObjectID
- */
- ObjectID.createFromHexString = function createFromHexString(string) {
- // Throw an error if it's not a valid setup
- if (typeof string === 'undefined' || (string != null && string.length !== 24)) {
- throw new Error(
- 'Argument passed in must be a single String of 12 bytes or a string of 24 hex characters'
- );
- }
-
- // Use Buffer.from method if available
- if (hasBufferType) return new ObjectID(new Buffer(string, 'hex'));
-
- // Calculate lengths
- var array = new _Buffer(12);
- var n = 0;
- var i = 0;
-
- while (i < 24) {
- array[n++] = (decodeLookup[string.charCodeAt(i++)] << 4) | decodeLookup[string.charCodeAt(i++)];
- }
-
- return new ObjectID(array);
- };
-
- /**
- * Checks if a value is a valid bson ObjectId
- *
- * @method
- * @return {boolean} return true if the value is a valid bson ObjectId, return false otherwise.
- */
- ObjectID.isValid = function isValid(id) {
- if (id == null) return false;
-
- if (typeof id === 'number') {
- return true;
- }
-
- if (typeof id === 'string') {
- return id.length === 12 || (id.length === 24 && checkForHexRegExp.test(id));
- }
-
- if (id instanceof ObjectID) {
- return true;
- }
-
- if (id instanceof _Buffer) {
- return true;
- }
-
- // Duck-Typing detection of ObjectId like objects
- if (id.toHexString) {
- return id.id.length === 12 || (id.id.length === 24 && checkForHexRegExp.test(id.id));
- }
-
- return false;
- };
-
- /**
- * @ignore
- */
- Object.defineProperty(ObjectID.prototype, 'generationTime', {
- enumerable: true,
- get: function() {
- return this.id[3] | (this.id[2] << 8) | (this.id[1] << 16) | (this.id[0] << 24);
- },
- set: function(value) {
- // Encode time into first 4 bytes
- this.id[3] = value & 0xff;
- this.id[2] = (value >> 8) & 0xff;
- this.id[1] = (value >> 16) & 0xff;
- this.id[0] = (value >> 24) & 0xff;
- }
- });
-
- /**
- * Expose.
- */
- module.exports = ObjectID;
- module.exports.ObjectID = ObjectID;
- module.exports.ObjectId = ObjectID;
|