Skip to content

Commit

Permalink
move explain cmd/options to separate file
Browse files Browse the repository at this point in the history
  • Loading branch information
HanaPearlman committed Nov 2, 2020
1 parent 7090c39 commit 7f19744
Show file tree
Hide file tree
Showing 12 changed files with 84 additions and 69 deletions.
6 changes: 0 additions & 6 deletions src/cmap/wire_protocol/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import type { Topology } from '../../sdam/topology';
import type { ReadPreferenceLike } from '../../read_preference';
import type { WriteConcernOptions, WriteConcern, W } from '../../write_concern';
import type { WriteCommandOptions } from './write_command';
import { decorateWithExplain } from '../../explain';

/** @internal */
export interface CommandOptions extends BSONSerializeOptions {
Expand Down Expand Up @@ -69,11 +68,6 @@ export function command(
return callback(new MongoError(`command ${JSON.stringify(cmd)} does not return a cursor`));
}

// TODO: should not modify the command here
if (cmd.explain !== undefined) {
cmd = decorateWithExplain(cmd, cmd.explain);
}

if (!isClientEncryptionEnabled(server)) {
_command(server, ns, cmd, options, callback);
return;
Expand Down
11 changes: 6 additions & 5 deletions src/cmap/wire_protocol/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { Document, pluckBSONSerializeOptions } from '../../bson';
import type { Server } from '../../sdam/server';
import type { ReadPreferenceLike } from '../../read_preference';
import type { FindOptions } from '../../operations/find';
import { Explain } from '../../explain';

/** @internal */
export interface QueryOptions extends CommandOptions {
Expand Down Expand Up @@ -63,7 +62,7 @@ export function query(
}

function prepareFindCommand(server: Server, ns: string, cmd: Document) {
const findCmd: Document = {
let findCmd: Document = {
find: collectionNamespace(ns)
};

Expand Down Expand Up @@ -147,9 +146,11 @@ function prepareFindCommand(server: Server, ns: string, cmd: Document) {
if (cmd.collation) findCmd.collation = cmd.collation;
if (cmd.readConcern) findCmd.readConcern = cmd.readConcern;

// TODO: Quick fix to make tests pass; will be updated during NODE-2853
if (cmd.explain !== undefined) {
findCmd.explain = Explain.fromOptions({ explain: cmd.explain });
// If we have explain, we need to rewrite the find command
if (cmd.explain) {
findCmd = {
explain: findCmd
};
}

return findCmd;
Expand Down
12 changes: 9 additions & 3 deletions src/cmap/wire_protocol/write_command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import { command, CommandOptions } from './command';
import type { Server } from '../../sdam/server';
import type { Document, BSONSerializeOptions } from '../../bson';
import type { WriteConcern } from '../../write_concern';
import { Explain, ExplainOptions } from '../../explain';
import { decorateWithExplain, Explain } from '../../explain';
import type { ExplainOptions } from '../../operations/explainable_command';

/** @public */
export interface CollationOptions {
Expand Down Expand Up @@ -44,7 +45,7 @@ export function writeCommand(
options = options || {};
const ordered = typeof options.ordered === 'boolean' ? options.ordered : true;
const writeConcern = options.writeConcern;
const writeCommand: Document = {};
let writeCommand: Document = {};
writeCommand[type] = collectionNamespace(ns);
writeCommand[opsField] = ops;
writeCommand.ordered = ordered;
Expand All @@ -65,8 +66,13 @@ export function writeCommand(
writeCommand.bypassDocumentValidation = options.bypassDocumentValidation;
}

// If a command is to be explained, we need to reformat the command after
// the other command properties are specified.
if (options.explain !== undefined) {
writeCommand.explain = Explain.fromOptions(options);
const explain = Explain.fromOptions(options);
if (explain) {
writeCommand = decorateWithExplain(writeCommand, explain);
}
}

const commandOptions = Object.assign(
Expand Down
46 changes: 3 additions & 43 deletions src/explain.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import type { Callback, Document } from '.';
import { MongoError } from './error';
import { CommandOperation, CommandOperationOptions, OperationParent } from './operations/command';
import type { Document } from '.';
import type { ExplainOptions } from './operations/explainable_command';
import type { Server } from './sdam/server';
import { maxWireVersion } from './utils';

Expand All @@ -10,45 +9,6 @@ const SUPPORTS_EXPLAIN_WITH_DISTINCT = 3.2;
const SUPPORTS_EXPLAIN_WITH_FIND_AND_MODIFY = 3.2;
const SUPPORTS_EXPLAIN_WITH_MAP_REDUCE = 4.4;

/** @internal */
export abstract class ExplainableCommand<
T extends ExplainOptions = ExplainOptions,
TResult = Document
> extends CommandOperation<T, TResult> {
explain?: Explain;

constructor(parent?: OperationParent, options?: T) {
super(parent, options);

if (!Explain.explainOptionsValid(options)) {
throw new MongoError(`explain must be one of ${Object.keys(Verbosity)} or a boolean`);
}

this.explain = Explain.fromOptions(options);
}

get canRetryWrite(): boolean {
return this.explain === undefined;
}

executeCommand(server: Server, cmd: Document, callback: Callback): void {
if (this.explain) {
if (!Explain.explainSupportedOnCmd(server, cmd)) {
callback(new MongoError(`server ${server.name} does not support explain on this command`));
return;
}

cmd.explain = this.explain;
}
super.executeCommand(server, cmd, callback);
}
}

/** @public */
export interface ExplainOptions extends CommandOperationOptions {
explain?: VerbosityLike;
}

/** @public */
export enum Verbosity {
queryPlanner = 'queryPlanner',
Expand Down Expand Up @@ -81,7 +41,7 @@ export class Explain {
return new Explain(options.explain);
}

static explainOptionsValid(options?: ExplainOptions): boolean {
static valid(options?: ExplainOptions): boolean {
if (options == null || options.explain === undefined) {
return true;
}
Expand Down
7 changes: 7 additions & 0 deletions src/operations/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import type { Server } from '../sdam/server';
import { BSONSerializeOptions, Document, resolveBSONOptions } from '../bson';
import type { CollationOptions } from '../cmap/wire_protocol/write_command';
import type { ReadConcernLike } from './../read_concern';
import { decorateWithExplain } from '../explain';

const SUPPORTS_WRITE_CONCERN_AND_COLLATION = 5;

Expand Down Expand Up @@ -139,6 +140,12 @@ export abstract class CommandOperation<
this.logger.debug(`executing command ${JSON.stringify(cmd)} against ${this.ns}`);
}

// If a command is to be explained, we need to reformat the command after
// the other command properties are specified.
if (cmd.explain) {
cmd = decorateWithExplain(cmd, cmd.explain);
}

server.command(
this.ns.toString(),
cmd,
Expand Down
5 changes: 3 additions & 2 deletions src/operations/delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ import type { Server } from '../sdam/server';
import type { Collection } from '../collection';
import type { WriteCommandOptions } from '../cmap/wire_protocol/write_command';
import type { Connection } from '../cmap/connection';
import { ExplainableCommand, ExplainOptions } from '../explain';
import { ExplainableCommand, ExplainOptions } from '../operations/explainable_command';
import type { CommandOperationOptions } from './command';

/** @public */
export interface DeleteOptions extends ExplainOptions {
export interface DeleteOptions extends CommandOperationOptions, ExplainOptions {
single?: boolean;
hint?: Hint;
}
Expand Down
5 changes: 3 additions & 2 deletions src/operations/distinct.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ import { decorateWithCollation, decorateWithReadConcern, Callback } from '../uti
import type { Document } from '../bson';
import type { Server } from '../sdam/server';
import type { Collection } from '../collection';
import { ExplainableCommand, ExplainOptions } from '../explain';
import { ExplainableCommand, ExplainOptions } from '../operations/explainable_command';
import type { CommandOperationOptions } from './command';

/** @public */
export type DistinctOptions = ExplainOptions;
export interface DistinctOptions extends CommandOperationOptions, ExplainOptions {}

/**
* Return a list of distinct values for the given key across a collection.
Expand Down
42 changes: 42 additions & 0 deletions src/operations/explainable_command.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { CommandOperation, OperationParent, CommandOperationOptions } from './command';
import { Explain, Verbosity, VerbosityLike } from '../explain';
import { Callback, Document, MongoError, Server } from '..';

/** @public */
export interface ExplainOptions {
explain?: VerbosityLike;
}

/** @internal */
export abstract class ExplainableCommand<
T extends ExplainOptions & CommandOperationOptions,
TResult = Document
> extends CommandOperation<T, TResult> {
explain?: Explain;

constructor(parent?: OperationParent, options?: T) {
super(parent, options);

if (!Explain.valid(options)) {
throw new MongoError(`explain must be one of ${Object.keys(Verbosity)} or a boolean`);
}

this.explain = Explain.fromOptions(options);
}

get canRetryWrite(): boolean {
return this.explain === undefined;
}

executeCommand(server: Server, cmd: Document, callback: Callback): void {
if (this.explain) {
if (!Explain.explainSupportedOnCmd(server, cmd)) {
callback(new MongoError(`server ${server.name} does not support explain on this command`));
return;
}

cmd.explain = this.explain;
}
super.executeCommand(server, cmd, callback);
}
}
5 changes: 3 additions & 2 deletions src/operations/find_and_modify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@ import type { Document } from '../bson';
import type { Server } from '../sdam/server';
import type { Collection } from '../collection';
import { Sort, formatSort } from '../sort';
import { ExplainableCommand, ExplainOptions } from '../explain';
import { ExplainableCommand, ExplainOptions } from '../operations/explainable_command';
import type { CommandOperationOptions } from './command';

/** @public */
export interface FindAndModifyOptions extends ExplainOptions {
export interface FindAndModifyOptions extends CommandOperationOptions, ExplainOptions {
/** When false, returns the updated document rather than the original. The default is true. */
returnOriginal?: boolean;
/** Upsert the document if it does not exist. */
Expand Down
5 changes: 3 additions & 2 deletions src/operations/map_reduce.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ import type { Collection } from '../collection';
import type { Sort } from '../sort';
import { MongoError } from '../error';
import type { ObjectId } from '../bson';
import { ExplainableCommand, ExplainOptions } from '../explain';
import { ExplainableCommand, ExplainOptions } from '../operations/explainable_command';
import type { CommandOperationOptions } from './command';

const exclusionList = [
'explain',
Expand All @@ -35,7 +36,7 @@ export type ReduceFunction = (key: string, values: Document[]) => Document;
export type FinalizeFunction = (key: string, reducedValue: Document) => Document;

/** @public */
export interface MapReduceOptions extends ExplainOptions {
export interface MapReduceOptions extends CommandOperationOptions, ExplainOptions {
/** Sets the output target for the map reduce job. */
out?: 'inline' | { inline: 1 } | { replace: string } | { merge: string } | { reduce: string };
/** Query filter object. */
Expand Down
5 changes: 3 additions & 2 deletions src/operations/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ import type { Server } from '../sdam/server';
import type { Collection } from '../collection';
import type { CollationOptions, WriteCommandOptions } from '../cmap/wire_protocol/write_command';
import type { ObjectId, Document } from '../bson';
import { ExplainableCommand, ExplainOptions } from '../explain';
import { ExplainableCommand, ExplainOptions } from '../operations/explainable_command';
import type { CommandOperationOptions } from './command';

/** @public */
export interface UpdateOptions extends ExplainOptions {
export interface UpdateOptions extends CommandOperationOptions, ExplainOptions {
/** A set of filters specifying to which array elements an update should apply */
arrayFilters?: Document[];
/** If true, allows the write to opt-out of document level validation */
Expand Down
4 changes: 2 additions & 2 deletions test/functional/explain.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ describe('Explain', function () {
expect(res).to.exist;

// Verify explanation result contains properties of executionStats output
collection.deleteOne({ a: 1 }, { explain: 'executionStats' }, (err, explanation) => {
collection.findOneAndDelete({ a: 1 }, { explain: 'executionStats' }, (err, explanation) => {
expect(err).to.not.exist;
expect(explanation).to.exist;
expect(explanation).property('queryPlanner').to.exist;
Expand All @@ -283,7 +283,7 @@ describe('Explain', function () {
expect(res).to.exist;

// Verify explanation result contains properties of allPlansExecution output
collection.deleteOne({ a: 1 }, { explain: 'allPlansExecution' }, (err, explanation) => {
collection.distinct('a', {}, { explain: 'allPlansExecution' }, (err, explanation) => {
expect(err).to.not.exist;
expect(explanation).to.exist;
expect(explanation).property('queryPlanner').to.exist;
Expand Down

0 comments on commit 7f19744

Please sign in to comment.