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.

cursor_ops.js 7.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. 'use strict';
  2. const buildCountCommand = require('./collection_ops').buildCountCommand;
  3. const formattedOrderClause = require('../utils').formattedOrderClause;
  4. const handleCallback = require('../utils').handleCallback;
  5. const MongoError = require('mongodb-core').MongoError;
  6. const push = Array.prototype.push;
  7. /**
  8. * Get the count of documents for this cursor.
  9. *
  10. * @method
  11. * @param {Cursor} cursor The Cursor instance on which to count.
  12. * @param {boolean} [applySkipLimit=true] Specifies whether the count command apply limit and skip settings should be applied on the cursor or in the provided options.
  13. * @param {object} [options] Optional settings. See Cursor.prototype.count for a list of options.
  14. * @param {Cursor~countResultCallback} [callback] The result callback.
  15. */
  16. function count(cursor, applySkipLimit, opts, callback) {
  17. if (applySkipLimit) {
  18. if (typeof cursor.cursorSkip() === 'number') opts.skip = cursor.cursorSkip();
  19. if (typeof cursor.cursorLimit() === 'number') opts.limit = cursor.cursorLimit();
  20. }
  21. // Ensure we have the right read preference inheritance
  22. if (opts.readPreference) {
  23. cursor.setReadPreference(opts.readPreference);
  24. }
  25. if (
  26. typeof opts.maxTimeMS !== 'number' &&
  27. cursor.s.cmd &&
  28. typeof cursor.s.cmd.maxTimeMS === 'number'
  29. ) {
  30. opts.maxTimeMS = cursor.s.cmd.maxTimeMS;
  31. }
  32. let options = {};
  33. options.skip = opts.skip;
  34. options.limit = opts.limit;
  35. options.hint = opts.hint;
  36. options.maxTimeMS = opts.maxTimeMS;
  37. // Command
  38. const delimiter = cursor.s.ns.indexOf('.');
  39. options.collectionName = cursor.s.ns.substr(delimiter + 1);
  40. let command;
  41. try {
  42. command = buildCountCommand(cursor, cursor.s.cmd.query, options);
  43. } catch (err) {
  44. return callback(err);
  45. }
  46. // Set cursor server to the same as the topology
  47. cursor.server = cursor.topology.s.coreTopology;
  48. // Execute the command
  49. cursor.s.topology.command(
  50. `${cursor.s.ns.substr(0, delimiter)}.$cmd`,
  51. command,
  52. cursor.s.options,
  53. (err, result) => {
  54. callback(err, result ? result.result.n : null);
  55. }
  56. );
  57. }
  58. /**
  59. * Iterates over all the documents for this cursor. See Cursor.prototype.each for more information.
  60. *
  61. * @method
  62. * @deprecated
  63. * @param {Cursor} cursor The Cursor instance on which to run.
  64. * @param {Cursor~resultCallback} callback The result callback.
  65. */
  66. function each(cursor, callback) {
  67. const Cursor = require('../cursor');
  68. if (!callback) throw MongoError.create({ message: 'callback is mandatory', driver: true });
  69. if (cursor.isNotified()) return;
  70. if (cursor.s.state === Cursor.CLOSED || cursor.isDead()) {
  71. return handleCallback(
  72. callback,
  73. MongoError.create({ message: 'Cursor is closed', driver: true })
  74. );
  75. }
  76. if (cursor.s.state === Cursor.INIT) cursor.s.state = Cursor.OPEN;
  77. // Define function to avoid global scope escape
  78. let fn = null;
  79. // Trampoline all the entries
  80. if (cursor.bufferedCount() > 0) {
  81. while ((fn = loop(cursor, callback))) fn(cursor, callback);
  82. each(cursor, callback);
  83. } else {
  84. cursor.next((err, item) => {
  85. if (err) return handleCallback(callback, err);
  86. if (item == null) {
  87. return cursor.close({ skipKillCursors: true }, () => handleCallback(callback, null, null));
  88. }
  89. if (handleCallback(callback, null, item) === false) return;
  90. each(cursor, callback);
  91. });
  92. }
  93. }
  94. /**
  95. * Check if there is any document still available in the cursor.
  96. *
  97. * @method
  98. * @param {Cursor} cursor The Cursor instance on which to run.
  99. * @param {Cursor~resultCallback} [callback] The result callback.
  100. */
  101. function hasNext(cursor, callback) {
  102. const Cursor = require('../cursor');
  103. if (cursor.s.currentDoc) {
  104. return callback(null, true);
  105. }
  106. if (cursor.isNotified()) {
  107. return callback(null, false);
  108. }
  109. nextObject(cursor, (err, doc) => {
  110. if (err) return callback(err, null);
  111. if (cursor.s.state === Cursor.CLOSED || cursor.isDead()) return callback(null, false);
  112. if (!doc) return callback(null, false);
  113. cursor.s.currentDoc = doc;
  114. callback(null, true);
  115. });
  116. }
  117. // Trampoline emptying the number of retrieved items
  118. // without incurring a nextTick operation
  119. function loop(cursor, callback) {
  120. // No more items we are done
  121. if (cursor.bufferedCount() === 0) return;
  122. // Get the next document
  123. cursor._next(callback);
  124. // Loop
  125. return loop;
  126. }
  127. /**
  128. * Get the next available document from the cursor. Returns null if no more documents are available.
  129. *
  130. * @method
  131. * @param {Cursor} cursor The Cursor instance from which to get the next document.
  132. * @param {Cursor~resultCallback} [callback] The result callback.
  133. */
  134. function next(cursor, callback) {
  135. // Return the currentDoc if someone called hasNext first
  136. if (cursor.s.currentDoc) {
  137. const doc = cursor.s.currentDoc;
  138. cursor.s.currentDoc = null;
  139. return callback(null, doc);
  140. }
  141. // Return the next object
  142. nextObject(cursor, callback);
  143. }
  144. // Get the next available document from the cursor, returns null if no more documents are available.
  145. function nextObject(cursor, callback) {
  146. const Cursor = require('../cursor');
  147. if (cursor.s.state === Cursor.CLOSED || (cursor.isDead && cursor.isDead()))
  148. return handleCallback(
  149. callback,
  150. MongoError.create({ message: 'Cursor is closed', driver: true })
  151. );
  152. if (cursor.s.state === Cursor.INIT && cursor.s.cmd.sort) {
  153. try {
  154. cursor.s.cmd.sort = formattedOrderClause(cursor.s.cmd.sort);
  155. } catch (err) {
  156. return handleCallback(callback, err);
  157. }
  158. }
  159. // Get the next object
  160. cursor._next((err, doc) => {
  161. cursor.s.state = Cursor.OPEN;
  162. if (err) return handleCallback(callback, err);
  163. handleCallback(callback, null, doc);
  164. });
  165. }
  166. /**
  167. * Returns an array of documents. See Cursor.prototype.toArray for more information.
  168. *
  169. * @method
  170. * @param {Cursor} cursor The Cursor instance from which to get the next document.
  171. * @param {Cursor~toArrayResultCallback} [callback] The result callback.
  172. */
  173. function toArray(cursor, callback) {
  174. const Cursor = require('../cursor');
  175. const items = [];
  176. // Reset cursor
  177. cursor.rewind();
  178. cursor.s.state = Cursor.INIT;
  179. // Fetch all the documents
  180. const fetchDocs = () => {
  181. cursor._next((err, doc) => {
  182. if (err) {
  183. return cursor._endSession
  184. ? cursor._endSession(() => handleCallback(callback, err))
  185. : handleCallback(callback, err);
  186. }
  187. if (doc == null) {
  188. return cursor.close({ skipKillCursors: true }, () => handleCallback(callback, null, items));
  189. }
  190. // Add doc to items
  191. items.push(doc);
  192. // Get all buffered objects
  193. if (cursor.bufferedCount() > 0) {
  194. let docs = cursor.readBufferedDocuments(cursor.bufferedCount());
  195. // Transform the doc if transform method added
  196. if (cursor.s.transforms && typeof cursor.s.transforms.doc === 'function') {
  197. docs = docs.map(cursor.s.transforms.doc);
  198. }
  199. push.apply(items, docs);
  200. }
  201. // Attempt a fetch
  202. fetchDocs();
  203. });
  204. };
  205. fetchDocs();
  206. }
  207. module.exports = { count, each, hasNext, next, toArray };