bson.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. 'use strict';
  2. const Buffer = require('buffer').Buffer;
  3. const Map = require('./map');
  4. const Long = require('./long');
  5. const Double = require('./double');
  6. const Timestamp = require('./timestamp');
  7. const ObjectId = require('./objectid');
  8. const BSONRegExp = require('./regexp');
  9. const BSONSymbol = require('./symbol');
  10. const Int32 = require('./int_32');
  11. const Code = require('./code');
  12. const Decimal128 = require('./decimal128');
  13. const MinKey = require('./min_key');
  14. const MaxKey = require('./max_key');
  15. const DBRef = require('./db_ref');
  16. const Binary = require('./binary');
  17. const constants = require('./constants');
  18. const EJSON = require('./extended_json');
  19. // Parts of the parser
  20. const internalDeserialize = require('./parser/deserializer');
  21. const internalSerialize = require('./parser/serializer');
  22. const internalCalculateObjectSize = require('./parser/calculate_size');
  23. const ensureBuffer = require('./ensure_buffer');
  24. /**
  25. * @ignore
  26. */
  27. // Default Max Size
  28. const MAXSIZE = 1024 * 1024 * 17;
  29. // Current Internal Temporary Serialization Buffer
  30. let buffer = Buffer.alloc(MAXSIZE);
  31. /**
  32. * Sets the size of the internal serialization buffer.
  33. *
  34. * @method
  35. * @param {number} size The desired size for the internal serialization buffer
  36. */
  37. function setInternalBufferSize(size) {
  38. // Resize the internal serialization buffer if needed
  39. if (buffer.length < size) {
  40. buffer = Buffer.alloc(size);
  41. }
  42. }
  43. /**
  44. * Serialize a Javascript object.
  45. *
  46. * @param {Object} object the Javascript object to serialize.
  47. * @param {Boolean} [options.checkKeys] the serializer will check if keys are valid.
  48. * @param {Boolean} [options.serializeFunctions=false] serialize the javascript functions **(default:false)**.
  49. * @param {Boolean} [options.ignoreUndefined=true] ignore undefined fields **(default:true)**.
  50. * @return {Buffer} returns the Buffer object containing the serialized object.
  51. */
  52. function serialize(object, options) {
  53. options = options || {};
  54. // Unpack the options
  55. const checkKeys = typeof options.checkKeys === 'boolean' ? options.checkKeys : false;
  56. const serializeFunctions =
  57. typeof options.serializeFunctions === 'boolean' ? options.serializeFunctions : false;
  58. const ignoreUndefined =
  59. typeof options.ignoreUndefined === 'boolean' ? options.ignoreUndefined : true;
  60. const minInternalBufferSize =
  61. typeof options.minInternalBufferSize === 'number' ? options.minInternalBufferSize : MAXSIZE;
  62. // Resize the internal serialization buffer if needed
  63. if (buffer.length < minInternalBufferSize) {
  64. buffer = Buffer.alloc(minInternalBufferSize);
  65. }
  66. // Attempt to serialize
  67. const serializationIndex = internalSerialize(
  68. buffer,
  69. object,
  70. checkKeys,
  71. 0,
  72. 0,
  73. serializeFunctions,
  74. ignoreUndefined,
  75. []
  76. );
  77. // Create the final buffer
  78. const finishedBuffer = Buffer.alloc(serializationIndex);
  79. // Copy into the finished buffer
  80. buffer.copy(finishedBuffer, 0, 0, finishedBuffer.length);
  81. // Return the buffer
  82. return finishedBuffer;
  83. }
  84. /**
  85. * Serialize a Javascript object using a predefined Buffer and index into the buffer, useful when pre-allocating the space for serialization.
  86. *
  87. * @param {Object} object the Javascript object to serialize.
  88. * @param {Buffer} buffer the Buffer you pre-allocated to store the serialized BSON object.
  89. * @param {Boolean} [options.checkKeys] the serializer will check if keys are valid.
  90. * @param {Boolean} [options.serializeFunctions=false] serialize the javascript functions **(default:false)**.
  91. * @param {Boolean} [options.ignoreUndefined=true] ignore undefined fields **(default:true)**.
  92. * @param {Number} [options.index] the index in the buffer where we wish to start serializing into.
  93. * @return {Number} returns the index pointing to the last written byte in the buffer.
  94. */
  95. function serializeWithBufferAndIndex(object, finalBuffer, options) {
  96. options = options || {};
  97. // Unpack the options
  98. const checkKeys = typeof options.checkKeys === 'boolean' ? options.checkKeys : false;
  99. const serializeFunctions =
  100. typeof options.serializeFunctions === 'boolean' ? options.serializeFunctions : false;
  101. const ignoreUndefined =
  102. typeof options.ignoreUndefined === 'boolean' ? options.ignoreUndefined : true;
  103. const startIndex = typeof options.index === 'number' ? options.index : 0;
  104. // Attempt to serialize
  105. const serializationIndex = internalSerialize(
  106. buffer,
  107. object,
  108. checkKeys,
  109. 0,
  110. 0,
  111. serializeFunctions,
  112. ignoreUndefined
  113. );
  114. buffer.copy(finalBuffer, startIndex, 0, serializationIndex);
  115. // Return the index
  116. return startIndex + serializationIndex - 1;
  117. }
  118. /**
  119. * Deserialize data as BSON.
  120. *
  121. * @param {Buffer} buffer the buffer containing the serialized set of BSON documents.
  122. * @param {Object} [options.evalFunctions=false] evaluate functions in the BSON document scoped to the object deserialized.
  123. * @param {Object} [options.cacheFunctions=false] cache evaluated functions for reuse.
  124. * @param {Object} [options.cacheFunctionsCrc32=false] use a crc32 code for caching, otherwise use the string of the function.
  125. * @param {Object} [options.promoteLongs=true] when deserializing a Long will fit it into a Number if it's smaller than 53 bits
  126. * @param {Object} [options.promoteBuffers=false] when deserializing a Binary will return it as a node.js Buffer instance.
  127. * @param {Object} [options.promoteValues=false] when deserializing will promote BSON values to their Node.js closest equivalent types.
  128. * @param {Object} [options.fieldsAsRaw=null] allow to specify if there what fields we wish to return as unserialized raw buffer.
  129. * @param {Object} [options.bsonRegExp=false] return BSON regular expressions as BSONRegExp instances.
  130. * @param {boolean} [options.allowObjectSmallerThanBufferSize=false] allows the buffer to be larger than the parsed BSON object
  131. * @return {Object} returns the deserialized Javascript Object.
  132. */
  133. function deserialize(buffer, options) {
  134. buffer = ensureBuffer(buffer);
  135. return internalDeserialize(buffer, options);
  136. }
  137. /**
  138. * Calculate the bson size for a passed in Javascript object.
  139. *
  140. * @param {Object} object the Javascript object to calculate the BSON byte size for.
  141. * @param {Boolean} [options.serializeFunctions=false] serialize the javascript functions **(default:false)**.
  142. * @param {Boolean} [options.ignoreUndefined=true] ignore undefined fields **(default:true)**.
  143. * @return {Number} returns the number of bytes the BSON object will take up.
  144. */
  145. function calculateObjectSize(object, options) {
  146. options = options || {};
  147. const serializeFunctions =
  148. typeof options.serializeFunctions === 'boolean' ? options.serializeFunctions : false;
  149. const ignoreUndefined =
  150. typeof options.ignoreUndefined === 'boolean' ? options.ignoreUndefined : true;
  151. return internalCalculateObjectSize(object, serializeFunctions, ignoreUndefined);
  152. }
  153. /**
  154. * Deserialize stream data as BSON documents.
  155. *
  156. * @param {Buffer} data the buffer containing the serialized set of BSON documents.
  157. * @param {Number} startIndex the start index in the data Buffer where the deserialization is to start.
  158. * @param {Number} numberOfDocuments number of documents to deserialize.
  159. * @param {Array} documents an array where to store the deserialized documents.
  160. * @param {Number} docStartIndex the index in the documents array from where to start inserting documents.
  161. * @param {Object} [options] additional options used for the deserialization.
  162. * @param {Object} [options.evalFunctions=false] evaluate functions in the BSON document scoped to the object deserialized.
  163. * @param {Object} [options.cacheFunctions=false] cache evaluated functions for reuse.
  164. * @param {Object} [options.cacheFunctionsCrc32=false] use a crc32 code for caching, otherwise use the string of the function.
  165. * @param {Object} [options.promoteLongs=true] when deserializing a Long will fit it into a Number if it's smaller than 53 bits
  166. * @param {Object} [options.promoteBuffers=false] when deserializing a Binary will return it as a node.js Buffer instance.
  167. * @param {Object} [options.promoteValues=false] when deserializing will promote BSON values to their Node.js closest equivalent types.
  168. * @param {Object} [options.fieldsAsRaw=null] allow to specify if there what fields we wish to return as unserialized raw buffer.
  169. * @param {Object} [options.bsonRegExp=false] return BSON regular expressions as BSONRegExp instances.
  170. * @return {Number} returns the next index in the buffer after deserialization **x** numbers of documents.
  171. */
  172. function deserializeStream(data, startIndex, numberOfDocuments, documents, docStartIndex, options) {
  173. options = Object.assign({ allowObjectSmallerThanBufferSize: true }, options);
  174. data = ensureBuffer(data);
  175. let index = startIndex;
  176. // Loop over all documents
  177. for (let i = 0; i < numberOfDocuments; i++) {
  178. // Find size of the document
  179. const size =
  180. data[index] | (data[index + 1] << 8) | (data[index + 2] << 16) | (data[index + 3] << 24);
  181. // Update options with index
  182. options.index = index;
  183. // Parse the document at this point
  184. documents[docStartIndex + i] = internalDeserialize(data, options);
  185. // Adjust index by the document size
  186. index = index + size;
  187. }
  188. // Return object containing end index of parsing and list of documents
  189. return index;
  190. }
  191. module.exports = {
  192. // constants
  193. // NOTE: this is done this way because rollup can't resolve an `Object.assign`ed export
  194. BSON_INT32_MAX: constants.BSON_INT32_MAX,
  195. BSON_INT32_MIN: constants.BSON_INT32_MIN,
  196. BSON_INT64_MAX: constants.BSON_INT64_MAX,
  197. BSON_INT64_MIN: constants.BSON_INT64_MIN,
  198. JS_INT_MAX: constants.JS_INT_MAX,
  199. JS_INT_MIN: constants.JS_INT_MIN,
  200. BSON_DATA_NUMBER: constants.BSON_DATA_NUMBER,
  201. BSON_DATA_STRING: constants.BSON_DATA_STRING,
  202. BSON_DATA_OBJECT: constants.BSON_DATA_OBJECT,
  203. BSON_DATA_ARRAY: constants.BSON_DATA_ARRAY,
  204. BSON_DATA_BINARY: constants.BSON_DATA_BINARY,
  205. BSON_DATA_UNDEFINED: constants.BSON_DATA_UNDEFINED,
  206. BSON_DATA_OID: constants.BSON_DATA_OID,
  207. BSON_DATA_BOOLEAN: constants.BSON_DATA_BOOLEAN,
  208. BSON_DATA_DATE: constants.BSON_DATA_DATE,
  209. BSON_DATA_NULL: constants.BSON_DATA_NULL,
  210. BSON_DATA_REGEXP: constants.BSON_DATA_REGEXP,
  211. BSON_DATA_DBPOINTER: constants.BSON_DATA_DBPOINTER,
  212. BSON_DATA_CODE: constants.BSON_DATA_CODE,
  213. BSON_DATA_SYMBOL: constants.BSON_DATA_SYMBOL,
  214. BSON_DATA_CODE_W_SCOPE: constants.BSON_DATA_CODE_W_SCOPE,
  215. BSON_DATA_INT: constants.BSON_DATA_INT,
  216. BSON_DATA_TIMESTAMP: constants.BSON_DATA_TIMESTAMP,
  217. BSON_DATA_LONG: constants.BSON_DATA_LONG,
  218. BSON_DATA_DECIMAL128: constants.BSON_DATA_DECIMAL128,
  219. BSON_DATA_MIN_KEY: constants.BSON_DATA_MIN_KEY,
  220. BSON_DATA_MAX_KEY: constants.BSON_DATA_MAX_KEY,
  221. BSON_BINARY_SUBTYPE_DEFAULT: constants.BSON_BINARY_SUBTYPE_DEFAULT,
  222. BSON_BINARY_SUBTYPE_FUNCTION: constants.BSON_BINARY_SUBTYPE_FUNCTION,
  223. BSON_BINARY_SUBTYPE_BYTE_ARRAY: constants.BSON_BINARY_SUBTYPE_BYTE_ARRAY,
  224. BSON_BINARY_SUBTYPE_UUID: constants.BSON_BINARY_SUBTYPE_UUID,
  225. BSON_BINARY_SUBTYPE_MD5: constants.BSON_BINARY_SUBTYPE_MD5,
  226. BSON_BINARY_SUBTYPE_USER_DEFINED: constants.BSON_BINARY_SUBTYPE_USER_DEFINED,
  227. // wrapped types
  228. Code,
  229. Map,
  230. BSONSymbol,
  231. DBRef,
  232. Binary,
  233. ObjectId,
  234. Long,
  235. Timestamp,
  236. Double,
  237. Int32,
  238. MinKey,
  239. MaxKey,
  240. BSONRegExp,
  241. Decimal128,
  242. // methods
  243. serialize,
  244. serializeWithBufferAndIndex,
  245. deserialize,
  246. calculateObjectSize,
  247. deserializeStream,
  248. setInternalBufferSize,
  249. // legacy support
  250. ObjectID: ObjectId,
  251. // Extended JSON
  252. EJSON
  253. };