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.
		
		
		
		
		
			
		
			
				
					168 lines
				
				4.7 KiB
			
		
		
			
		
	
	
					168 lines
				
				4.7 KiB
			| 
											3 years ago
										 | 'use strict'; | ||
|  | 
 | ||
|  | const buildCountCommand = require('./collection_ops').buildCountCommand; | ||
|  | const handleCallback = require('../utils').handleCallback; | ||
|  | const MongoError = require('../core').MongoError; | ||
|  | const push = Array.prototype.push; | ||
|  | const CursorState = require('../core/cursor').CursorState; | ||
|  | 
 | ||
|  | /** | ||
|  |  * Get the count of documents for this cursor. | ||
|  |  * | ||
|  |  * @method | ||
|  |  * @param {Cursor} cursor The Cursor instance on which to count. | ||
|  |  * @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. | ||
|  |  * @param {object} [options] Optional settings. See Cursor.prototype.count for a list of options. | ||
|  |  * @param {Cursor~countResultCallback} [callback] The result callback. | ||
|  |  */ | ||
|  | function count(cursor, applySkipLimit, opts, callback) { | ||
|  |   if (applySkipLimit) { | ||
|  |     if (typeof cursor.cursorSkip() === 'number') opts.skip = cursor.cursorSkip(); | ||
|  |     if (typeof cursor.cursorLimit() === 'number') opts.limit = cursor.cursorLimit(); | ||
|  |   } | ||
|  | 
 | ||
|  |   // Ensure we have the right read preference inheritance
 | ||
|  |   if (opts.readPreference) { | ||
|  |     cursor.setReadPreference(opts.readPreference); | ||
|  |   } | ||
|  | 
 | ||
|  |   if ( | ||
|  |     typeof opts.maxTimeMS !== 'number' && | ||
|  |     cursor.cmd && | ||
|  |     typeof cursor.cmd.maxTimeMS === 'number' | ||
|  |   ) { | ||
|  |     opts.maxTimeMS = cursor.cmd.maxTimeMS; | ||
|  |   } | ||
|  | 
 | ||
|  |   let options = {}; | ||
|  |   options.skip = opts.skip; | ||
|  |   options.limit = opts.limit; | ||
|  |   options.hint = opts.hint; | ||
|  |   options.maxTimeMS = opts.maxTimeMS; | ||
|  | 
 | ||
|  |   // Command
 | ||
|  |   options.collectionName = cursor.namespace.collection; | ||
|  | 
 | ||
|  |   let command; | ||
|  |   try { | ||
|  |     command = buildCountCommand(cursor, cursor.cmd.query, options); | ||
|  |   } catch (err) { | ||
|  |     return callback(err); | ||
|  |   } | ||
|  | 
 | ||
|  |   // Set cursor server to the same as the topology
 | ||
|  |   cursor.server = cursor.topology.s.coreTopology; | ||
|  | 
 | ||
|  |   // Execute the command
 | ||
|  |   cursor.topology.command( | ||
|  |     cursor.namespace.withCollection('$cmd'), | ||
|  |     command, | ||
|  |     cursor.options, | ||
|  |     (err, result) => { | ||
|  |       callback(err, result ? result.result.n : null); | ||
|  |     } | ||
|  |   ); | ||
|  | } | ||
|  | 
 | ||
|  | /** | ||
|  |  * Iterates over all the documents for this cursor. See Cursor.prototype.each for more information. | ||
|  |  * | ||
|  |  * @method | ||
|  |  * @deprecated | ||
|  |  * @param {Cursor} cursor The Cursor instance on which to run. | ||
|  |  * @param {Cursor~resultCallback} callback The result callback. | ||
|  |  */ | ||
|  | function each(cursor, callback) { | ||
|  |   if (!callback) throw MongoError.create({ message: 'callback is mandatory', driver: true }); | ||
|  |   if (cursor.isNotified()) return; | ||
|  |   if (cursor.s.state === CursorState.CLOSED || cursor.isDead()) { | ||
|  |     return handleCallback( | ||
|  |       callback, | ||
|  |       MongoError.create({ message: 'Cursor is closed', driver: true }) | ||
|  |     ); | ||
|  |   } | ||
|  | 
 | ||
|  |   if (cursor.s.state === CursorState.INIT) { | ||
|  |     cursor.s.state = CursorState.OPEN; | ||
|  |   } | ||
|  | 
 | ||
|  |   // Define function to avoid global scope escape
 | ||
|  |   let fn = null; | ||
|  |   // Trampoline all the entries
 | ||
|  |   if (cursor.bufferedCount() > 0) { | ||
|  |     while ((fn = loop(cursor, callback))) fn(cursor, callback); | ||
|  |     each(cursor, callback); | ||
|  |   } else { | ||
|  |     cursor.next((err, item) => { | ||
|  |       if (err) return handleCallback(callback, err); | ||
|  |       if (item == null) { | ||
|  |         return cursor.close({ skipKillCursors: true }, () => handleCallback(callback, null, null)); | ||
|  |       } | ||
|  | 
 | ||
|  |       if (handleCallback(callback, null, item) === false) return; | ||
|  |       each(cursor, callback); | ||
|  |     }); | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | // Trampoline emptying the number of retrieved items
 | ||
|  | // without incurring a nextTick operation
 | ||
|  | function loop(cursor, callback) { | ||
|  |   // No more items we are done
 | ||
|  |   if (cursor.bufferedCount() === 0) return; | ||
|  |   // Get the next document
 | ||
|  |   cursor._next(callback); | ||
|  |   // Loop
 | ||
|  |   return loop; | ||
|  | } | ||
|  | 
 | ||
|  | /** | ||
|  |  * Returns an array of documents. See Cursor.prototype.toArray for more information. | ||
|  |  * | ||
|  |  * @method | ||
|  |  * @param {Cursor} cursor The Cursor instance from which to get the next document. | ||
|  |  * @param {Cursor~toArrayResultCallback} [callback] The result callback. | ||
|  |  */ | ||
|  | function toArray(cursor, callback) { | ||
|  |   const items = []; | ||
|  | 
 | ||
|  |   // Reset cursor
 | ||
|  |   cursor.rewind(); | ||
|  |   cursor.s.state = CursorState.INIT; | ||
|  | 
 | ||
|  |   // Fetch all the documents
 | ||
|  |   const fetchDocs = () => { | ||
|  |     cursor._next((err, doc) => { | ||
|  |       if (err) { | ||
|  |         return handleCallback(callback, err); | ||
|  |       } | ||
|  | 
 | ||
|  |       if (doc == null) { | ||
|  |         return cursor.close({ skipKillCursors: true }, () => handleCallback(callback, null, items)); | ||
|  |       } | ||
|  | 
 | ||
|  |       // Add doc to items
 | ||
|  |       items.push(doc); | ||
|  | 
 | ||
|  |       // Get all buffered objects
 | ||
|  |       if (cursor.bufferedCount() > 0) { | ||
|  |         let docs = cursor.readBufferedDocuments(cursor.bufferedCount()); | ||
|  | 
 | ||
|  |         // Transform the doc if transform method added
 | ||
|  |         if (cursor.s.transforms && typeof cursor.s.transforms.doc === 'function') { | ||
|  |           docs = docs.map(cursor.s.transforms.doc); | ||
|  |         } | ||
|  | 
 | ||
|  |         push.apply(items, docs); | ||
|  |       } | ||
|  | 
 | ||
|  |       // Attempt a fetch
 | ||
|  |       fetchDocs(); | ||
|  |     }); | ||
|  |   }; | ||
|  | 
 | ||
|  |   fetchDocs(); | ||
|  | } | ||
|  | 
 | ||
|  | module.exports = { count, each, toArray }; |