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  279x 279x       279x 279x                                                               279x         92781x   92781x 92781x 92781x 92781x       92729x                     92693x 4x     92689x 8x     92681x 92681x     4x     92677x         92677x 92421x     92677x 1187x         92677x 244x     92677x             92677x       279x  
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]);