@@ -16,7 +16,7 @@ import { FindOperation, type FindOptions } from '../operations/find';
1616import type { Hint } from '../operations/operation' ;
1717import type { ClientSession } from '../sessions' ;
1818import { formatSort , type Sort , type SortDirection } from '../sort' ;
19- import { emitWarningOnce , mergeOptions , type MongoDBNamespace , squashError } from '../utils' ;
19+ import { emitWarningOnce , mergeOptions , type MongoDBNamespace , noop , squashError } from '../utils' ;
2020import { type InitialCursorResponse } from './abstract_cursor' ;
2121import { ExplainableCursor } from './explainable_cursor' ;
2222
@@ -98,37 +98,50 @@ export class FindCursor<TSchema = any> extends ExplainableCursor<TSchema> {
9898 }
9999
100100 /** @internal */
101- override async getMore ( batchSize : number ) : Promise < CursorResponse > {
101+ override async getMore ( ) : Promise < CursorResponse > {
102102 const numReturned = this . numReturned ;
103- if ( numReturned ) {
104- // TODO(DRIVERS-1448): Remove logic to enforce `limit` in the driver
105- const limit = this . findOptions . limit ;
106- batchSize =
107- limit && limit > 0 && numReturned + batchSize > limit ? limit - numReturned : batchSize ;
108-
109- if ( batchSize <= 0 ) {
110- try {
111- await this . close ( ) ;
112- } catch ( error ) {
113- squashError ( error ) ;
114- // this is an optimization for the special case of a limit for a find command to avoid an
115- // extra getMore when the limit has been reached and the limit is a multiple of the batchSize.
116- // This is a consequence of the new query engine in 5.0 having no knowledge of the limit as it
117- // produces results for the find command. Once a batch is filled up, it is returned and only
118- // on the subsequent getMore will the query framework consider the limit, determine the cursor
119- // is exhausted and return a cursorId of zero.
120- // instead, if we determine there are no more documents to request from the server, we preemptively
121- // close the cursor
122- }
123- return CursorResponse . emptyGetMore ;
103+ const limit = this . findOptions . limit ?? Infinity ;
104+ const remaining = limit - numReturned ;
105+
106+ if ( numReturned === limit && ! this . id ?. isZero ( ) ) {
107+ // this is an optimization for the special case of a limit for a find command to avoid an
108+ // extra getMore when the limit has been reached and the limit is a multiple of the batchSize.
109+ // This is a consequence of the new query engine in 5.0 having no knowledge of the limit as it
110+ // produces results for the find command. Once a batch is filled up, it is returned and only
111+ // on the subsequent getMore will the query framework consider the limit, determine the cursor
112+ // is exhausted and return a cursorId of zero.
113+ // instead, if we determine there are no more documents to request from the server, we preemptively
114+ // close the cursor
115+ try {
116+ await this . close ( ) ;
117+ } catch ( error ) {
118+ squashError ( error ) ;
124119 }
120+ return CursorResponse . emptyGetMore ;
121+ }
122+
123+ // TODO(DRIVERS-1448): Remove logic to enforce `limit` in the driver
124+ let cleanup : ( ) => void = noop ;
125+ const { batchSize } = this . cursorOptions ;
126+ if ( batchSize != null && batchSize > remaining ) {
127+ this . cursorOptions . batchSize = remaining ;
128+
129+ // After executing the final getMore, re-assign the batchSize back to its original value so that
130+ // if the cursor is rewound and executed, the batchSize is still correct.
131+ cleanup = ( ) => {
132+ this . cursorOptions . batchSize = batchSize ;
133+ } ;
125134 }
126135
127- const response = await super . getMore ( batchSize ) ;
128- // TODO: wrap this in some logic to prevent it from happening if we don't need this support
129- this . numReturned = this . numReturned + response . batchSize ;
136+ try {
137+ const response = await super . getMore ( ) ;
130138
131- return response ;
139+ this . numReturned = this . numReturned + response . batchSize ;
140+
141+ return response ;
142+ } finally {
143+ cleanup ?.( ) ;
144+ }
132145 }
133146
134147 /**
0 commit comments