commands.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. "use strict";
  2. var MongoError = require('../error');
  3. // Wire command operation ids
  4. var OP_UPDATE = 2001;
  5. var OP_INSERT = 2002;
  6. var OP_DELETE = 2006;
  7. var Insert = function(requestId, ismaster, bson, ns, documents, options) {
  8. // Basic options needed to be passed in
  9. if(ns == null) throw new MongoError("ns must be specified for query");
  10. if(!Array.isArray(documents) || documents.length == 0) throw new MongoError("documents array must contain at least one document to insert");
  11. // Validate that we are not passing 0x00 in the collection name
  12. if(!!~ns.indexOf("\x00")) {
  13. throw new MongoError("namespace cannot contain a null character");
  14. }
  15. // Set internal
  16. this.requestId = requestId;
  17. this.bson = bson;
  18. this.ns = ns;
  19. this.documents = documents;
  20. this.ismaster = ismaster;
  21. // Ensure empty options
  22. options = options || {};
  23. // Unpack options
  24. this.serializeFunctions = typeof options.serializeFunctions == 'boolean' ? options.serializeFunctions : false;
  25. this.ignoreUndefined = typeof options.ignoreUndefined == 'boolean' ? options.ignoreUndefined : false;
  26. this.checkKeys = typeof options.checkKeys == 'boolean' ? options.checkKeys : true;
  27. this.continueOnError = typeof options.continueOnError == 'boolean' ? options.continueOnError : false;
  28. // Set flags
  29. this.flags = this.continueOnError ? 1 : 0;
  30. }
  31. // To Binary
  32. Insert.prototype.toBin = function() {
  33. // Contains all the buffers to be written
  34. var buffers = [];
  35. // Header buffer
  36. var header = new Buffer(
  37. 4 * 4 // Header
  38. + 4 // Flags
  39. + Buffer.byteLength(this.ns) + 1 // namespace
  40. );
  41. // Add header to buffers
  42. buffers.push(header);
  43. // Total length of the message
  44. var totalLength = header.length;
  45. // Serialize all the documents
  46. for(var i = 0; i < this.documents.length; i++) {
  47. var buffer = this.bson.serialize(this.documents[i], {
  48. checkKeys: this.checkKeys,
  49. serializeFunctions: this.serializeFunctions,
  50. ignoreUndefined: this.ignoreUndefined,
  51. });
  52. // Document is larger than maxBsonObjectSize, terminate serialization
  53. if(buffer.length > this.ismaster.maxBsonObjectSize) {
  54. throw new MongoError("Document exceeds maximum allowed bson size of " + this.ismaster.maxBsonObjectSize + " bytes");
  55. }
  56. // Add to total length of wire protocol message
  57. totalLength = totalLength + buffer.length;
  58. // Add to buffer
  59. buffers.push(buffer);
  60. }
  61. // Command is larger than maxMessageSizeBytes terminate serialization
  62. if(totalLength > this.ismaster.maxMessageSizeBytes) {
  63. throw new MongoError("Command exceeds maximum message size of " + this.ismaster.maxMessageSizeBytes + " bytes");
  64. }
  65. // Add all the metadata
  66. var index = 0;
  67. // Write header length
  68. header[index + 3] = (totalLength >> 24) & 0xff;
  69. header[index + 2] = (totalLength >> 16) & 0xff;
  70. header[index + 1] = (totalLength >> 8) & 0xff;
  71. header[index] = (totalLength) & 0xff;
  72. index = index + 4;
  73. // Write header requestId
  74. header[index + 3] = (this.requestId >> 24) & 0xff;
  75. header[index + 2] = (this.requestId >> 16) & 0xff;
  76. header[index + 1] = (this.requestId >> 8) & 0xff;
  77. header[index] = (this.requestId) & 0xff;
  78. index = index + 4;
  79. // No flags
  80. header[index + 3] = (0 >> 24) & 0xff;
  81. header[index + 2] = (0 >> 16) & 0xff;
  82. header[index + 1] = (0 >> 8) & 0xff;
  83. header[index] = (0) & 0xff;
  84. index = index + 4;
  85. // Operation
  86. header[index + 3] = (OP_INSERT >> 24) & 0xff;
  87. header[index + 2] = (OP_INSERT >> 16) & 0xff;
  88. header[index + 1] = (OP_INSERT >> 8) & 0xff;
  89. header[index] = (OP_INSERT) & 0xff;
  90. index = index + 4;
  91. // Flags
  92. header[index + 3] = (this.flags >> 24) & 0xff;
  93. header[index + 2] = (this.flags >> 16) & 0xff;
  94. header[index + 1] = (this.flags >> 8) & 0xff;
  95. header[index] = (this.flags) & 0xff;
  96. index = index + 4;
  97. // Write collection name
  98. index = index + header.write(this.ns, index, 'utf8') + 1;
  99. header[index - 1] = 0;
  100. // Return the buffers
  101. return buffers;
  102. }
  103. var Update = function(requestId, ismaster, bson, ns, update, options) {
  104. // Basic options needed to be passed in
  105. if(ns == null) throw new MongoError("ns must be specified for query");
  106. // Ensure empty options
  107. options = options || {};
  108. // Set internal
  109. this.requestId = requestId;
  110. this.bson = bson;
  111. this.ns = ns;
  112. this.ismaster = ismaster;
  113. // Unpack options
  114. this.serializeFunctions = typeof options.serializeFunctions == 'boolean' ? options.serializeFunctions : false;
  115. this.ignoreUndefined = typeof options.ignoreUndefined == 'boolean' ? options.ignoreUndefined : false;
  116. this.checkKeys = typeof options.checkKeys == 'boolean' ? options.checkKeys : false;
  117. // Unpack the update document
  118. this.upsert = typeof update[0].upsert == 'boolean' ? update[0].upsert : false;
  119. this.multi = typeof update[0].multi == 'boolean' ? update[0].multi : false;
  120. this.q = update[0].q;
  121. this.u = update[0].u;
  122. // Create flag value
  123. this.flags = this.upsert ? 1 : 0;
  124. this.flags = this.multi ? this.flags | 2 : this.flags;
  125. }
  126. // To Binary
  127. Update.prototype.toBin = function() {
  128. // Contains all the buffers to be written
  129. var buffers = [];
  130. // Header buffer
  131. var header = new Buffer(
  132. 4 * 4 // Header
  133. + 4 // ZERO
  134. + Buffer.byteLength(this.ns) + 1 // namespace
  135. + 4 // Flags
  136. );
  137. // Add header to buffers
  138. buffers.push(header);
  139. // Total length of the message
  140. var totalLength = header.length;
  141. // Serialize the selector
  142. var selector = this.bson.serialize(this.q, {
  143. checkKeys: this.checkKeys,
  144. serializeFunctions: this.serializeFunctions,
  145. ignoreUndefined: this.ignoreUndefined,
  146. });
  147. buffers.push(selector);
  148. totalLength = totalLength + selector.length;
  149. // Serialize the update
  150. var update = this.bson.serialize(this.u, {
  151. checkKeys: this.checkKeys,
  152. serializeFunctions: this.serializeFunctions,
  153. ignoreUndefined: this.ignoreUndefined,
  154. });
  155. buffers.push(update);
  156. totalLength = totalLength + update.length;
  157. // Index in header buffer
  158. var index = 0;
  159. // Write header length
  160. header[index + 3] = (totalLength >> 24) & 0xff;
  161. header[index + 2] = (totalLength >> 16) & 0xff;
  162. header[index + 1] = (totalLength >> 8) & 0xff;
  163. header[index] = (totalLength) & 0xff;
  164. index = index + 4;
  165. // Write header requestId
  166. header[index + 3] = (this.requestId >> 24) & 0xff;
  167. header[index + 2] = (this.requestId >> 16) & 0xff;
  168. header[index + 1] = (this.requestId >> 8) & 0xff;
  169. header[index] = (this.requestId) & 0xff;
  170. index = index + 4;
  171. // No flags
  172. header[index + 3] = (0 >> 24) & 0xff;
  173. header[index + 2] = (0 >> 16) & 0xff;
  174. header[index + 1] = (0 >> 8) & 0xff;
  175. header[index] = (0) & 0xff;
  176. index = index + 4;
  177. // Operation
  178. header[index + 3] = (OP_UPDATE >> 24) & 0xff;
  179. header[index + 2] = (OP_UPDATE >> 16) & 0xff;
  180. header[index + 1] = (OP_UPDATE >> 8) & 0xff;
  181. header[index] = (OP_UPDATE) & 0xff;
  182. index = index + 4;
  183. // Write ZERO
  184. header[index + 3] = (0 >> 24) & 0xff;
  185. header[index + 2] = (0 >> 16) & 0xff;
  186. header[index + 1] = (0 >> 8) & 0xff;
  187. header[index] = (0) & 0xff;
  188. index = index + 4;
  189. // Write collection name
  190. index = index + header.write(this.ns, index, 'utf8') + 1;
  191. header[index - 1] = 0;
  192. // Flags
  193. header[index + 3] = (this.flags >> 24) & 0xff;
  194. header[index + 2] = (this.flags >> 16) & 0xff;
  195. header[index + 1] = (this.flags >> 8) & 0xff;
  196. header[index] = (this.flags) & 0xff;
  197. index = index + 4;
  198. // Return the buffers
  199. return buffers;
  200. }
  201. var Remove = function(requestId, ismaster, bson, ns, remove, options) {
  202. // Basic options needed to be passed in
  203. if(ns == null) throw new MongoError("ns must be specified for query");
  204. // Ensure empty options
  205. options = options || {};
  206. // Set internal
  207. this.requestId = requestId;
  208. this.bson = bson;
  209. this.ns = ns;
  210. this.ismaster = ismaster;
  211. // Unpack options
  212. this.serializeFunctions = typeof options.serializeFunctions == 'boolean' ? options.serializeFunctions : false;
  213. this.ignoreUndefined = typeof options.ignoreUndefined == 'boolean' ? options.ignoreUndefined : false;
  214. this.checkKeys = typeof options.checkKeys == 'boolean' ? options.checkKeys : false;
  215. // Unpack the update document
  216. this.limit = typeof remove[0].limit == 'number' ? remove[0].limit : 1;
  217. this.q = remove[0].q;
  218. // Create flag value
  219. this.flags = this.limit == 1 ? 1 : 0;
  220. }
  221. // To Binary
  222. Remove.prototype.toBin = function() {
  223. // Contains all the buffers to be written
  224. var buffers = [];
  225. // Header buffer
  226. var header = new Buffer(
  227. 4 * 4 // Header
  228. + 4 // ZERO
  229. + Buffer.byteLength(this.ns) + 1 // namespace
  230. + 4 // Flags
  231. );
  232. // Add header to buffers
  233. buffers.push(header);
  234. // Total length of the message
  235. var totalLength = header.length;
  236. // Serialize the selector
  237. var selector = this.bson.serialize(this.q, {
  238. checkKeys: this.checkKeys,
  239. serializeFunctions: this.serializeFunctions,
  240. ignoreUndefined: this.ignoreUndefined,
  241. });
  242. buffers.push(selector);
  243. totalLength = totalLength + selector.length;
  244. // Index in header buffer
  245. var index = 0;
  246. // Write header length
  247. header[index + 3] = (totalLength >> 24) & 0xff;
  248. header[index + 2] = (totalLength >> 16) & 0xff;
  249. header[index + 1] = (totalLength >> 8) & 0xff;
  250. header[index] = (totalLength) & 0xff;
  251. index = index + 4;
  252. // Write header requestId
  253. header[index + 3] = (this.requestId >> 24) & 0xff;
  254. header[index + 2] = (this.requestId >> 16) & 0xff;
  255. header[index + 1] = (this.requestId >> 8) & 0xff;
  256. header[index] = (this.requestId) & 0xff;
  257. index = index + 4;
  258. // No flags
  259. header[index + 3] = (0 >> 24) & 0xff;
  260. header[index + 2] = (0 >> 16) & 0xff;
  261. header[index + 1] = (0 >> 8) & 0xff;
  262. header[index] = (0) & 0xff;
  263. index = index + 4;
  264. // Operation
  265. header[index + 3] = (OP_DELETE >> 24) & 0xff;
  266. header[index + 2] = (OP_DELETE >> 16) & 0xff;
  267. header[index + 1] = (OP_DELETE >> 8) & 0xff;
  268. header[index] = (OP_DELETE) & 0xff;
  269. index = index + 4;
  270. // Write ZERO
  271. header[index + 3] = (0 >> 24) & 0xff;
  272. header[index + 2] = (0 >> 16) & 0xff;
  273. header[index + 1] = (0 >> 8) & 0xff;
  274. header[index] = (0) & 0xff;
  275. index = index + 4;
  276. // Write collection name
  277. index = index + header.write(this.ns, index, 'utf8') + 1;
  278. header[index - 1] = 0;
  279. // Write ZERO
  280. header[index + 3] = (this.flags >> 24) & 0xff;
  281. header[index + 2] = (this.flags >> 16) & 0xff;
  282. header[index + 1] = (this.flags >> 8) & 0xff;
  283. header[index] = (this.flags) & 0xff;
  284. index = index + 4;
  285. // Return the buffers
  286. return buffers;
  287. }
  288. module.exports = {
  289. Insert: Insert
  290. , Update: Update
  291. , Remove: Remove
  292. }