All files / src/operations drop.ts

97.29% Statements 36/37
94.11% Branches 16/17
100% Functions 7/7
97.29% Lines 36/37

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 112 113 114 115 116 117    135x       135x 135x                 135x           119209x 119209x 119209x 119209x       113265x               113177x 113177x 113177x   113177x   113177x   113177x         34x     34x     113177x 2862x 2862x   2862x   5724x 5724x 5724x   2x                   113177x               118901x 117315x               135x       23739x 23739x     23686x               23598x 23510x       135x 135x  
import type { Document } from '../bson';
import type { Db } from '../db';
import { MONGODB_ERROR_CODES, MongoServerError } from '../error';
import type { Server } from '../sdam/server';
import type { ClientSession } from '../sessions';
import { type TimeoutContext } from '../timeout';
import { CommandOperation, type CommandOperationOptions } from './command';
import { Aspect, defineAspects } from './operation';
 
/** @public */
export interface DropCollectionOptions extends CommandOperationOptions {
  /** @experimental */
  encryptedFields?: Document;
}
 
/** @internal */
export class DropCollectionOperation extends CommandOperation<boolean> {
  override options: DropCollectionOptions;
  db: Db;
  name: string;
 
  constructor(db: Db, name: string, options: DropCollectionOptions = {}) {
    super(db, options);
    this.db = db;
    this.options = options;
    this.name = name;
  }
 
  override get commandName() {
    return 'drop' as const;
  }
 
  override async execute(
    server: Server,
    session: ClientSession | undefined,
    timeoutContext: TimeoutContext
  ): Promise<boolean> {
    const db = this.db;
    const options = this.options;
    const name = this.name;
 
    const encryptedFieldsMap = db.client.s.options.autoEncryption?.encryptedFieldsMap;
    let encryptedFields: Document | undefined =
      options.encryptedFields ?? encryptedFieldsMap?.[`${db.databaseName}.${name}`];
 
    if (!encryptedFields && encryptedFieldsMap) {
      // If the MongoClient was configured with an encryptedFieldsMap,
      // and no encryptedFields config was available in it or explicitly
      // passed as an argument, the spec tells us to look one up using
      // listCollections().
      const listCollectionsResult = await db
        .listCollections({ name }, { nameOnly: false })
        .toArray();
      encryptedFields = listCollectionsResult?.[0]?.options?.encryptedFields;
    }
 
    if (encryptedFields) {
      const escCollection = encryptedFields.escCollection || `enxcol_.${name}.esc`;
      const ecocCollection = encryptedFields.ecocCollection || `enxcol_.${name}.ecoc`;
 
      for (const collectionName of [escCollection, ecocCollection]) {
        // Drop auxilliary collections, ignoring potential NamespaceNotFound errors.
        const dropOp = new DropCollectionOperation(db, collectionName);
        try {
          await dropOp.executeWithoutEncryptedFieldsCheck(server, session, timeoutContext);
        } catch (err) {
          Iif (
            !(err instanceof MongoServerError) ||
            err.code !== MONGODB_ERROR_CODES.NamespaceNotFound
          ) {
            throw err;
          }
        }
      }
    }
 
    return await this.executeWithoutEncryptedFieldsCheck(server, session, timeoutContext);
  }
 
  private async executeWithoutEncryptedFieldsCheck(
    server: Server,
    session: ClientSession | undefined,
    timeoutContext: TimeoutContext
  ): Promise<boolean> {
    await super.executeCommand(server, session, { drop: this.name }, timeoutContext);
    return true;
  }
}
 
/** @public */
export type DropDatabaseOptions = CommandOperationOptions;
 
/** @internal */
export class DropDatabaseOperation extends CommandOperation<boolean> {
  override options: DropDatabaseOptions;
 
  constructor(db: Db, options: DropDatabaseOptions) {
    super(db, options);
    this.options = options;
  }
  override get commandName() {
    return 'dropDatabase' as const;
  }
 
  override async execute(
    server: Server,
    session: ClientSession | undefined,
    timeoutContext: TimeoutContext
  ): Promise<boolean> {
    await super.executeCommand(server, session, { dropDatabase: 1 }, timeoutContext);
    return true;
  }
}
 
defineAspects(DropCollectionOperation, [Aspect.WRITE_OPERATION]);
defineAspects(DropDatabaseOperation, [Aspect.WRITE_OPERATION]);