Ohm-Management - Projektarbeit B-ME
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2_6_support.js 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. 'use strict';
  2. var copy = require('../connection/utils').copy,
  3. retrieveBSON = require('../connection/utils').retrieveBSON,
  4. KillCursor = require('../connection/commands').KillCursor,
  5. GetMore = require('../connection/commands').GetMore,
  6. Query = require('../connection/commands').Query,
  7. f = require('util').format,
  8. MongoError = require('../error').MongoError,
  9. getReadPreference = require('./shared').getReadPreference;
  10. var BSON = retrieveBSON(),
  11. Long = BSON.Long;
  12. var WireProtocol = function() {};
  13. //
  14. // Execute a write operation
  15. var executeWrite = function(pool, bson, type, opsField, ns, ops, options, callback) {
  16. if (ops.length === 0) throw new MongoError('insert must contain at least one document');
  17. if (typeof options === 'function') {
  18. callback = options;
  19. options = {};
  20. options = options || {};
  21. }
  22. // Split the ns up to get db and collection
  23. var p = ns.split('.');
  24. var d = p.shift();
  25. // Options
  26. var ordered = typeof options.ordered === 'boolean' ? options.ordered : true;
  27. var writeConcern = options.writeConcern;
  28. // return skeleton
  29. var writeCommand = {};
  30. writeCommand[type] = p.join('.');
  31. writeCommand[opsField] = ops;
  32. writeCommand.ordered = ordered;
  33. // Did we specify a write concern
  34. if (writeConcern && Object.keys(writeConcern).length > 0) {
  35. writeCommand.writeConcern = writeConcern;
  36. }
  37. // Do we have bypassDocumentValidation set, then enable it on the write command
  38. if (options.bypassDocumentValidation === true) {
  39. writeCommand.bypassDocumentValidation = options.bypassDocumentValidation;
  40. }
  41. // Options object
  42. var opts = { command: true };
  43. if (typeof options.session !== 'undefined') opts.session = options.session;
  44. var queryOptions = { checkKeys: false, numberToSkip: 0, numberToReturn: 1 };
  45. if (type === 'insert') queryOptions.checkKeys = true;
  46. if (typeof options.checkKeys === 'boolean') queryOptions.checkKeys = options.checkKeys;
  47. // Ensure we support serialization of functions
  48. if (options.serializeFunctions) queryOptions.serializeFunctions = options.serializeFunctions;
  49. // Do not serialize the undefined fields
  50. if (options.ignoreUndefined) queryOptions.ignoreUndefined = options.ignoreUndefined;
  51. try {
  52. // Create write command
  53. var cmd = new Query(bson, f('%s.$cmd', d), writeCommand, queryOptions);
  54. // Execute command
  55. pool.write(cmd, opts, callback);
  56. } catch (err) {
  57. callback(err);
  58. }
  59. };
  60. //
  61. // Needs to support legacy mass insert as well as ordered/unordered legacy
  62. // emulation
  63. //
  64. WireProtocol.prototype.insert = function(pool, ns, bson, ops, options, callback) {
  65. executeWrite(pool, bson, 'insert', 'documents', ns, ops, options, callback);
  66. };
  67. WireProtocol.prototype.update = function(pool, ns, bson, ops, options, callback) {
  68. executeWrite(pool, bson, 'update', 'updates', ns, ops, options, callback);
  69. };
  70. WireProtocol.prototype.remove = function(pool, ns, bson, ops, options, callback) {
  71. executeWrite(pool, bson, 'delete', 'deletes', ns, ops, options, callback);
  72. };
  73. WireProtocol.prototype.killCursor = function(bson, ns, cursorState, pool, callback) {
  74. var cursorId = cursorState.cursorId;
  75. // Create a kill cursor command
  76. var killCursor = new KillCursor(bson, ns, [cursorId]);
  77. // Build killCursor options
  78. const options = {
  79. immediateRelease: true,
  80. noResponse: true
  81. };
  82. if (typeof cursorState.session === 'object') {
  83. options.session = cursorState.session;
  84. }
  85. // Execute the kill cursor command
  86. if (pool && pool.isConnected()) {
  87. try {
  88. pool.write(killCursor, options, callback);
  89. } catch (err) {
  90. if (typeof callback === 'function') {
  91. callback(err, null);
  92. } else {
  93. console.warn(err);
  94. }
  95. }
  96. }
  97. };
  98. WireProtocol.prototype.getMore = function(
  99. bson,
  100. ns,
  101. cursorState,
  102. batchSize,
  103. raw,
  104. connection,
  105. options,
  106. callback
  107. ) {
  108. // Create getMore command
  109. var getMore = new GetMore(bson, ns, cursorState.cursorId, { numberToReturn: batchSize });
  110. // Query callback
  111. var queryCallback = function(err, result) {
  112. if (err) return callback(err);
  113. // Get the raw message
  114. var r = result.message;
  115. // If we have a timed out query or a cursor that was killed
  116. if ((r.responseFlags & (1 << 0)) !== 0) {
  117. return callback(new MongoError('cursor does not exist, was killed or timed out'), null);
  118. }
  119. // Ensure we have a Long valie cursor id
  120. var cursorId = typeof r.cursorId === 'number' ? Long.fromNumber(r.cursorId) : r.cursorId;
  121. // Set all the values
  122. cursorState.documents = r.documents;
  123. cursorState.cursorId = cursorId;
  124. // Return
  125. callback(null, null, r.connection);
  126. };
  127. // Contains any query options
  128. var queryOptions = {};
  129. // If we have a raw query decorate the function
  130. if (raw) {
  131. queryOptions.raw = raw;
  132. }
  133. // Check if we need to promote longs
  134. if (typeof cursorState.promoteLongs === 'boolean') {
  135. queryOptions.promoteLongs = cursorState.promoteLongs;
  136. }
  137. if (typeof cursorState.promoteValues === 'boolean') {
  138. queryOptions.promoteValues = cursorState.promoteValues;
  139. }
  140. if (typeof cursorState.promoteBuffers === 'boolean') {
  141. queryOptions.promoteBuffers = cursorState.promoteBuffers;
  142. }
  143. if (typeof cursorState.session === 'object') {
  144. queryOptions.session = cursorState.session;
  145. }
  146. // Write out the getMore command
  147. connection.write(getMore, queryOptions, queryCallback);
  148. };
  149. WireProtocol.prototype.command = function(bson, ns, cmd, cursorState, topology, options) {
  150. // Establish type of command
  151. if (cmd.find) {
  152. return setupClassicFind(bson, ns, cmd, cursorState, topology, options);
  153. } else if (cursorState.cursorId != null) {
  154. return;
  155. } else if (cmd) {
  156. return setupCommand(bson, ns, cmd, cursorState, topology, options);
  157. } else {
  158. throw new MongoError(f('command %s does not return a cursor', JSON.stringify(cmd)));
  159. }
  160. };
  161. //
  162. // Execute a find command
  163. var setupClassicFind = function(bson, ns, cmd, cursorState, topology, options) {
  164. // Ensure we have at least some options
  165. options = options || {};
  166. // Get the readPreference
  167. var readPreference = getReadPreference(cmd, options);
  168. // Set the optional batchSize
  169. cursorState.batchSize = cmd.batchSize || cursorState.batchSize;
  170. var numberToReturn = 0;
  171. // Unpack the limit and batchSize values
  172. if (cursorState.limit === 0) {
  173. numberToReturn = cursorState.batchSize;
  174. } else if (
  175. cursorState.limit < 0 ||
  176. cursorState.limit < cursorState.batchSize ||
  177. (cursorState.limit > 0 && cursorState.batchSize === 0)
  178. ) {
  179. numberToReturn = cursorState.limit;
  180. } else {
  181. numberToReturn = cursorState.batchSize;
  182. }
  183. var numberToSkip = cursorState.skip || 0;
  184. // Build actual find command
  185. var findCmd = {};
  186. // We have a Mongos topology, check if we need to add a readPreference
  187. if (topology.type === 'mongos' && readPreference) {
  188. findCmd['$readPreference'] = readPreference.toJSON();
  189. }
  190. // Add special modifiers to the query
  191. if (cmd.sort) findCmd['$orderby'] = cmd.sort;
  192. if (cmd.hint) findCmd['$hint'] = cmd.hint;
  193. if (cmd.snapshot) findCmd['$snapshot'] = cmd.snapshot;
  194. if (typeof cmd.returnKey !== 'undefined') findCmd['$returnKey'] = cmd.returnKey;
  195. if (cmd.maxScan) findCmd['$maxScan'] = cmd.maxScan;
  196. if (cmd.min) findCmd['$min'] = cmd.min;
  197. if (cmd.max) findCmd['$max'] = cmd.max;
  198. if (typeof cmd.showDiskLoc !== 'undefined') findCmd['$showDiskLoc'] = cmd.showDiskLoc;
  199. if (cmd.comment) findCmd['$comment'] = cmd.comment;
  200. if (cmd.maxTimeMS) findCmd['$maxTimeMS'] = cmd.maxTimeMS;
  201. if (cmd.explain) {
  202. // nToReturn must be 0 (match all) or negative (match N and close cursor)
  203. // nToReturn > 0 will give explain results equivalent to limit(0)
  204. numberToReturn = -Math.abs(cmd.limit || 0);
  205. findCmd['$explain'] = true;
  206. }
  207. // Add the query
  208. findCmd['$query'] = cmd.query;
  209. // Throw on majority readConcern passed in
  210. if (cmd.readConcern && cmd.readConcern.level !== 'local') {
  211. throw new MongoError(
  212. f('server find command does not support a readConcern level of %s', cmd.readConcern.level)
  213. );
  214. }
  215. // Remove readConcern, ensure no failing commands
  216. if (cmd.readConcern) {
  217. cmd = copy(cmd);
  218. delete cmd['readConcern'];
  219. }
  220. // Serialize functions
  221. var serializeFunctions =
  222. typeof options.serializeFunctions === 'boolean' ? options.serializeFunctions : false;
  223. var ignoreUndefined =
  224. typeof options.ignoreUndefined === 'boolean' ? options.ignoreUndefined : false;
  225. // Build Query object
  226. var query = new Query(bson, ns, findCmd, {
  227. numberToSkip: numberToSkip,
  228. numberToReturn: numberToReturn,
  229. pre32Limit: typeof cmd.limit !== 'undefined' ? cmd.limit : undefined,
  230. checkKeys: false,
  231. returnFieldSelector: cmd.fields,
  232. serializeFunctions: serializeFunctions,
  233. ignoreUndefined: ignoreUndefined
  234. });
  235. // Set query flags
  236. query.slaveOk = readPreference.slaveOk();
  237. // Set up the option bits for wire protocol
  238. if (typeof cmd.tailable === 'boolean') {
  239. query.tailable = cmd.tailable;
  240. }
  241. if (typeof cmd.oplogReplay === 'boolean') {
  242. query.oplogReplay = cmd.oplogReplay;
  243. }
  244. if (typeof cmd.noCursorTimeout === 'boolean') {
  245. query.noCursorTimeout = cmd.noCursorTimeout;
  246. }
  247. if (typeof cmd.awaitData === 'boolean') {
  248. query.awaitData = cmd.awaitData;
  249. }
  250. if (typeof cmd.partial === 'boolean') {
  251. query.partial = cmd.partial;
  252. }
  253. // Return the query
  254. return query;
  255. };
  256. //
  257. // Set up a command cursor
  258. var setupCommand = function(bson, ns, cmd, cursorState, topology, options) {
  259. // Set empty options object
  260. options = options || {};
  261. // Get the readPreference
  262. var readPreference = getReadPreference(cmd, options);
  263. // Final query
  264. var finalCmd = {};
  265. for (var name in cmd) {
  266. finalCmd[name] = cmd[name];
  267. }
  268. // Build command namespace
  269. var parts = ns.split(/\./);
  270. // Serialize functions
  271. var serializeFunctions =
  272. typeof options.serializeFunctions === 'boolean' ? options.serializeFunctions : false;
  273. var ignoreUndefined =
  274. typeof options.ignoreUndefined === 'boolean' ? options.ignoreUndefined : false;
  275. // Throw on majority readConcern passed in
  276. if (cmd.readConcern && cmd.readConcern.level !== 'local') {
  277. throw new MongoError(
  278. f(
  279. 'server %s command does not support a readConcern level of %s',
  280. JSON.stringify(cmd),
  281. cmd.readConcern.level
  282. )
  283. );
  284. }
  285. // Remove readConcern, ensure no failing commands
  286. if (cmd.readConcern) delete cmd['readConcern'];
  287. // We have a Mongos topology, check if we need to add a readPreference
  288. if (topology.type === 'mongos' && readPreference && readPreference.preference !== 'primary') {
  289. finalCmd = {
  290. $query: finalCmd,
  291. $readPreference: readPreference.toJSON()
  292. };
  293. }
  294. // Build Query object
  295. var query = new Query(bson, f('%s.$cmd', parts.shift()), finalCmd, {
  296. numberToSkip: 0,
  297. numberToReturn: -1,
  298. checkKeys: false,
  299. serializeFunctions: serializeFunctions,
  300. ignoreUndefined: ignoreUndefined
  301. });
  302. // Set query flags
  303. query.slaveOk = readPreference.slaveOk();
  304. // Return the query
  305. return query;
  306. };
  307. module.exports = WireProtocol;