UNPKG

6.08 kBJavaScriptView Raw
1
2var MACHINE_ID = Math.floor(Math.random() * 0xFFFFFF);
3var index = ObjectID.index = parseInt(Math.random() * 0xFFFFFF, 10);
4var pid = (typeof process === 'undefined' || typeof process.pid !== 'number' ? Math.floor(Math.random() * 100000) : process.pid) % 0xFFFF;
5
6/**
7 * Determine if an object is Buffer
8 *
9 * Author: Feross Aboukhadijeh <feross@feross.org> <http://feross.org>
10 * License: MIT
11 *
12 */
13var isBuffer = function (obj) {
14 return !!(
15 obj != null &&
16 obj.constructor &&
17 typeof obj.constructor.isBuffer === 'function' &&
18 obj.constructor.isBuffer(obj)
19 )
20};
21
22/**
23 * Create a new immutable ObjectID instance
24 *
25 * @class Represents the BSON ObjectID type
26 * @param {String|Number} arg Can be a 24 byte hex string, 12 byte binary string or a Number.
27 * @return {Object} instance of ObjectID.
28 */
29function ObjectID(arg) {
30 if(!(this instanceof ObjectID)) return new ObjectID(arg);
31 if(arg && ((arg instanceof ObjectID) || arg._bsontype==="ObjectID"))
32 return arg;
33
34 var buf;
35
36 if(isBuffer(arg) || (Array.isArray(arg) && arg.length===12)) {
37 buf = Array.prototype.slice.call(arg);
38 }
39 else if(typeof arg === "string") {
40 if(arg.length!==12 && !ObjectID.isValid(arg))
41 throw new Error("Argument passed in must be a single String of 12 bytes or a string of 24 hex characters");
42
43 buf = buffer(arg);
44 }
45 else if(/number|undefined/.test(typeof arg)) {
46 buf = buffer(generate(arg));
47 }
48
49 Object.defineProperty(this, "id", {
50 enumerable: true,
51 get: function() { return String.fromCharCode.apply(this, buf); }
52 });
53 Object.defineProperty(this, "str", {
54 get: function() { return buf.map(hex.bind(this, 2)).join(''); }
55 });
56}
57module.exports = ObjectID;
58ObjectID.generate = generate;
59ObjectID.default = ObjectID;
60
61/**
62 * Creates an ObjectID from a second based number, with the rest of the ObjectID zeroed out. Used for comparisons or sorting the ObjectID.
63 *
64 * @param {Number} time an integer number representing a number of seconds.
65 * @return {ObjectID} return the created ObjectID
66 * @api public
67 */
68ObjectID.createFromTime = function(time){
69 time = parseInt(time, 10) % 0xFFFFFFFF;
70 return new ObjectID(hex(8,time)+"0000000000000000");
71};
72
73/**
74 * Creates an ObjectID from a hex string representation of an ObjectID.
75 *
76 * @param {String} hexString create a ObjectID from a passed in 24 byte hexstring.
77 * @return {ObjectID} return the created ObjectID
78 * @api public
79 */
80ObjectID.createFromHexString = function(hexString) {
81 if(!ObjectID.isValid(hexString))
82 throw new Error("Invalid ObjectID hex string");
83
84 return new ObjectID(hexString);
85};
86
87/**
88 * Checks if a value is a valid bson ObjectId
89 *
90 * @param {String} objectid Can be a 24 byte hex string or an instance of ObjectID.
91 * @return {Boolean} return true if the value is a valid bson ObjectID, return false otherwise.
92 * @api public
93 *
94 * THE NATIVE DOCUMENTATION ISN'T CLEAR ON THIS GUY!
95 * http://mongodb.github.io/node-mongodb-native/api-bson-generated/objectid.html#objectid-isvalid
96 */
97ObjectID.isValid = function(objectid) {
98 if(!objectid || (typeof objectid !== 'string' && (typeof objectid !== 'object' || Array.isArray(objectid) || typeof objectid.toString !== 'function'))) return false;
99
100 //call .toString() to get the hex if we're
101 // working with an instance of ObjectID
102 return /^[0-9A-F]{24}$/i.test(objectid.toString());
103};
104
105/**
106 * set a custom machineID
107 *
108 * @param {String|Number} machineid Can be a string, hex-string or a number
109 * @return {void}
110 * @api public
111 */
112ObjectID.setMachineID = function(arg) {
113 var machineID;
114
115 if(typeof arg === "string") {
116 // hex string
117 machineID = parseInt(arg, 16);
118
119 // any string
120 if(isNaN(machineID)) {
121 arg = ('000000' + arg).substr(-7,6);
122
123 machineID = "";
124 for(var i = 0;i<6; i++) {
125 machineID += (arg.charCodeAt(i));
126 }
127 }
128 }
129 else if(/number|undefined/.test(typeof arg)) {
130 machineID = arg | 0;
131 }
132
133 MACHINE_ID = (machineID & 0xFFFFFF);
134}
135
136/**
137 * get the machineID
138 *
139 * @return {number}
140 * @api public
141 */
142ObjectID.getMachineID = function() {
143 return MACHINE_ID;
144}
145
146ObjectID.prototype = {
147 _bsontype: 'ObjectID',
148 constructor: ObjectID,
149
150 /**
151 * Return the ObjectID id as a 24 byte hex string representation
152 *
153 * @return {String} return the 24 byte hex string representation.
154 * @api public
155 */
156 toHexString: function() {
157 return this.str;
158 },
159
160 /**
161 * Compares the equality of this ObjectID with `otherID`.
162 *
163 * @param {Object} other ObjectID instance to compare against.
164 * @return {Boolean} the result of comparing two ObjectID's
165 * @api public
166 */
167 equals: function (other){
168 return !!other && this.str === other.toString();
169 },
170
171 /**
172 * Returns the generation date (accurate up to the second) that this ID was generated.
173 *
174 * @return {Date} the generation date
175 * @api public
176 */
177 getTimestamp: function(){
178 return new Date(parseInt(this.str.substr(0,8), 16) * 1000);
179 }
180};
181
182function next() {
183 return index = (index+1) % 0xFFFFFF;
184}
185
186function generate(time) {
187 if (typeof time !== 'number')
188 time = Date.now()/1000;
189
190 //keep it in the ring!
191 time = parseInt(time, 10) % 0xFFFFFFFF;
192
193 //FFFFFFFF FFFFFF FFFF FFFFFF
194 return hex(8,time) + hex(6,MACHINE_ID) + hex(4,pid) + hex(6,next());
195}
196
197function hex(length, n) {
198 n = n.toString(16);
199 return (n.length===length)? n : "00000000".substring(n.length, length) + n;
200}
201
202function buffer(str) {
203 var i=0,out=[];
204
205 if(str.length===24)
206 for(;i<24; out.push(parseInt(str[i]+str[i+1], 16)),i+=2);
207
208 else if(str.length===12)
209 for(;i<12; out.push(str.charCodeAt(i)),i++);
210
211 return out;
212}
213
214var inspect = (Symbol && Symbol.for('nodejs.util.inspect.custom')) || 'inspect';
215
216/**
217 * Converts to a string representation of this Id.
218 *
219 * @return {String} return the 24 byte hex string representation.
220 * @api private
221 */
222ObjectID.prototype[inspect] = function() { return "ObjectID("+this+")" };
223ObjectID.prototype.toJSON = ObjectID.prototype.toHexString;
224ObjectID.prototype.toString = ObjectID.prototype.toHexString;