All files / src/operations get_more.ts

100% Statements 28/28
100% Branches 16/16
100% Functions 3/3
100% Lines 28/28

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111  540x 540x       540x 540x                                                               540x         468294x   468294x 468294x 468294x 468294x       468242x                     467866x 4x     467862x 8x     467854x 467854x     4x     467850x         467850x 466544x     467850x 6377x         467850x 1369x     467850x             467850x       540x  
import type { Long } from '../bson';
import { CursorResponse } from '../cmap/wire_protocol/responses';
import { MongoRuntimeError } from '../error';
import type { Server } from '../sdam/server';
import type { ClientSession } from '../sessions';
import { type TimeoutContext } from '../timeout';
import { maxWireVersion, type MongoDBNamespace } from '../utils';
import { AbstractOperation, Aspect, defineAspects, type OperationOptions } from './operation';
 
/** @internal */
export interface GetMoreOptions extends OperationOptions {
  /** Set the batchSize for the getMoreCommand when iterating over the query results. */
  batchSize?: number;
  /**
   * Comment to apply to the operation.
   *
   * getMore only supports 'comment' in server versions 4.4 and above.
   */
  comment?: unknown;
  /** Number of milliseconds to wait before aborting the query. */
  maxTimeMS?: number;
  /** TODO(NODE-4413): Address bug with maxAwaitTimeMS not being passed in from the cursor correctly */
  maxAwaitTimeMS?: number;
}
 
/**
 * GetMore command: https://www.mongodb.com/docs/manual/reference/command/getMore/
 * @internal
 */
export interface GetMoreCommand {
  getMore: Long;
  collection: string;
  batchSize?: number;
  maxTimeMS?: number;
  /** Only supported on wire versions 10 or greater */
  comment?: unknown;
}
 
/** @internal */
export class GetMoreOperation extends AbstractOperation {
  cursorId: Long;
  override options: GetMoreOptions;
 
  constructor(ns: MongoDBNamespace, cursorId: Long, server: Server, options: GetMoreOptions) {
    super(options);
 
    this.options = options;
    this.ns = ns;
    this.cursorId = cursorId;
    this.server = server;
  }
 
  override get commandName() {
    return 'getMore' as const;
  }
  /**
   * Although there is a server already associated with the get more operation, the signature
   * for execute passes a server so we will just use that one.
   */
  override async execute(
    server: Server,
    _session: ClientSession | undefined,
    timeoutContext: TimeoutContext
  ): Promise<CursorResponse> {
    if (server !== this.server) {
      throw new MongoRuntimeError('Getmore must run on the same server operation began on');
    }
 
    if (this.cursorId == null || this.cursorId.isZero()) {
      throw new MongoRuntimeError('Unable to iterate cursor with no id');
    }
 
    const collection = this.ns.collection;
    if (collection == null) {
      // Cursors should have adopted the namespace returned by MongoDB
      // which should always defined a collection name (even a pseudo one, ex. db.aggregate())
      throw new MongoRuntimeError('A collection name must be determined before getMore');
    }
 
    const getMoreCmd: GetMoreCommand = {
      getMore: this.cursorId,
      collection
    };
 
    if (typeof this.options.batchSize === 'number') {
      getMoreCmd.batchSize = Math.abs(this.options.batchSize);
    }
 
    if (typeof this.options.maxAwaitTimeMS === 'number') {
      getMoreCmd.maxTimeMS = this.options.maxAwaitTimeMS;
    }
 
    // we check for undefined specifically here to allow falsy values
    // eslint-disable-next-line no-restricted-syntax
    if (this.options.comment !== undefined && maxWireVersion(server) >= 9) {
      getMoreCmd.comment = this.options.comment;
    }
 
    const commandOptions = {
      returnFieldSelector: null,
      documentsReturnedIn: 'nextBatch',
      timeoutContext,
      ...this.options
    };
 
    return await server.command(this.ns, getMoreCmd, commandOptions, CursorResponse);
  }
}
 
defineAspects(GetMoreOperation, [Aspect.READ_OPERATION, Aspect.MUST_SELECT_SAME_SERVER]);