Skip to content

Commit 0aac1fb

Browse files
refactor(NODE-7086): refactor misc operations (#4613)
Co-authored-by: bailey <[email protected]>
1 parent 48c3376 commit 0aac1fb

17 files changed

+209
-262
lines changed

src/admin.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@ import {
88
type ListDatabasesResult
99
} from './operations/list_databases';
1010
import { RemoveUserOperation, type RemoveUserOptions } from './operations/remove_user';
11-
import { RunAdminCommandOperation, type RunCommandOptions } from './operations/run_command';
11+
import { RunCommandOperation, type RunCommandOptions } from './operations/run_command';
1212
import {
1313
ValidateCollectionOperation,
1414
type ValidateCollectionOptions
1515
} from './operations/validate_collection';
16+
import { MongoDBNamespace } from './utils';
1617

1718
/** @internal */
1819
export interface AdminPrivate {
@@ -75,7 +76,7 @@ export class Admin {
7576
async command(command: Document, options?: RunCommandOptions): Promise<Document> {
7677
return await executeOperation(
7778
this.s.db.client,
78-
new RunAdminCommandOperation(command, {
79+
new RunCommandOperation(new MongoDBNamespace('admin'), command, {
7980
...resolveBSONOptions(options),
8081
session: options?.session,
8182
readPreference: options?.readPreference,

src/collection.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
} from './cursor/list_search_indexes_cursor';
1818
import type { Db } from './db';
1919
import { MongoAPIError, MongoInvalidArgumentError, MongoOperationTimeoutError } from './error';
20+
import { type ExplainCommandOptions, type ExplainVerbosityLike } from './explain';
2021
import type { MongoClient, PkFactory } from './mongo_client';
2122
import type {
2223
Abortable,
@@ -863,6 +864,11 @@ export class Collection<TSchema extends Document = Document> {
863864
filter: Filter<TSchema>,
864865
options: DistinctOptions
865866
): Promise<Array<Flatten<WithId<TSchema>[Key]>>>;
867+
distinct<Key extends keyof WithId<TSchema>>(
868+
key: Key,
869+
filter: Filter<TSchema>,
870+
options: DistinctOptions & { explain: ExplainVerbosityLike | ExplainCommandOptions }
871+
): Promise<Document>;
866872

867873
// Embedded documents overload
868874
distinct(key: string): Promise<any[]>;

src/cursor/run_command_cursor.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import type { BSONSerializeOptions, Document } from '../bson';
2-
import { CursorResponse } from '../cmap/wire_protocol/responses';
2+
import { type CursorResponse } from '../cmap/wire_protocol/responses';
33
import type { Db } from '../db';
44
import { MongoAPIError, MongoRuntimeError } from '../error';
55
import { executeOperation } from '../operations/execute_operation';
66
import { GetMoreOperation } from '../operations/get_more';
7-
import { RunCommandOperation } from '../operations/run_command';
7+
import { RunCursorCommandOperation } from '../operations/run_command';
88
import type { ReadConcernLike } from '../read_concern';
99
import type { ReadPreferenceLike } from '../read_preference';
1010
import type { ClientSession } from '../sessions';
@@ -143,11 +143,10 @@ export class RunCommandCursor extends AbstractCursor {
143143

144144
/** @internal */
145145
protected async _initialize(session: ClientSession): Promise<InitialCursorResponse> {
146-
const operation = new RunCommandOperation<CursorResponse>(this.db, this.command, {
146+
const operation = new RunCursorCommandOperation(this.db.s.namespace, this.command, {
147147
...this.cursorOptions,
148148
session: session,
149-
readPreference: this.cursorOptions.readPreference,
150-
responseType: CursorResponse
149+
readPreference: this.cursorOptions.readPreference
151150
});
152151

153152
const response = await executeOperation(this.client, operation, this.timeoutContext);

src/db.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ export class Db {
272272
return await executeOperation(
273273
this.client,
274274
new RunCommandOperation(
275-
this,
275+
this.s.namespace,
276276
command,
277277
resolveOptions(undefined, {
278278
...resolveBSONOptions(options),

src/mongo_client.ts

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { promises as fs } from 'fs';
22
import type { TcpNetConnectOpts } from 'net';
33
import type { ConnectionOptions as TLSConnectionOptions, TLSSocketOptions } from 'tls';
44

5+
import { type ServerCommandOptions, type TimeoutContext } from '.';
56
import { type BSONSerializeOptions, type Document, resolveBSONOptions } from './bson';
67
import { ChangeStream, type ChangeStreamDocument, type ChangeStreamOptions } from './change_stream';
78
import type { AutoEncrypter, AutoEncryptionOptions } from './client-side-encryption/auto_encrypter';
@@ -20,6 +21,7 @@ import {
2021
makeClientMetadata
2122
} from './cmap/handshake/client_metadata';
2223
import type { CompressorName } from './cmap/wire_protocol/compression';
24+
import { MongoDBResponse } from './cmap/wire_protocol/responses';
2325
import { parseOptions, resolveSRVRecord } from './connection_string';
2426
import { MONGO_CLIENT_EVENTS } from './constants';
2527
import { type AbstractCursor } from './cursor/abstract_cursor';
@@ -42,7 +44,7 @@ import {
4244
} from './operations/client_bulk_write/common';
4345
import { ClientBulkWriteExecutor } from './operations/client_bulk_write/executor';
4446
import { executeOperation } from './operations/execute_operation';
45-
import { RunAdminCommandOperation } from './operations/run_command';
47+
import { ModernizedOperation } from './operations/operation';
4648
import type { ReadConcern, ReadConcernLevel, ReadConcernLike } from './read_concern';
4749
import { ReadPreference, type ReadPreferenceMode } from './read_preference';
4850
import { type AsyncDisposable, configureResourceManagement } from './resource_management';
@@ -60,7 +62,7 @@ import {
6062
type HostAddress,
6163
hostMatchesWildcards,
6264
isHostMatch,
63-
type MongoDBNamespace,
65+
MongoDBNamespace,
6466
noop,
6567
ns,
6668
resolveOptions,
@@ -790,13 +792,26 @@ export class MongoClient extends TypedEventEmitter<MongoClientEvents> implements
790792
const endSessions = Array.from(this.s.sessionPool.sessions, ({ id }) => id);
791793
if (endSessions.length !== 0) {
792794
try {
793-
await executeOperation(
794-
this,
795-
new RunAdminCommandOperation(
796-
{ endSessions },
797-
{ readPreference: ReadPreference.primaryPreferred, noResponse: true }
798-
)
799-
);
795+
class EndSessionsOperation extends ModernizedOperation<void> {
796+
override ns = MongoDBNamespace.fromString('admin.$cmd');
797+
override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse;
798+
override buildCommand(_connection: Connection, _session?: ClientSession): Document {
799+
return {
800+
endSessions
801+
};
802+
}
803+
override buildOptions(timeoutContext: TimeoutContext): ServerCommandOptions {
804+
return {
805+
timeoutContext,
806+
readPreference: ReadPreference.primaryPreferred,
807+
noResponse: true
808+
};
809+
}
810+
override get commandName(): string {
811+
return 'endSessions';
812+
}
813+
}
814+
await executeOperation(this, new EndSessionsOperation());
800815
} catch (error) {
801816
squashError(error);
802817
}

src/operations/distinct.ts

Lines changed: 24 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
import type { Document } from '../bson';
1+
import { type Document } from '../bson';
2+
import { type Connection } from '../cmap/connection';
3+
import { MongoDBResponse } from '../cmap/wire_protocol/responses';
24
import type { Collection } from '../collection';
3-
import type { Server } from '../sdam/server';
4-
import type { ClientSession } from '../sessions';
5-
import { type TimeoutContext } from '../timeout';
6-
import { decorateWithCollation, decorateWithReadConcern } from '../utils';
7-
import { CommandOperation, type CommandOperationOptions } from './command';
5+
import { type CommandOperationOptions, ModernizedCommandOperation } from './command';
86
import { Aspect, defineAspects } from './operation';
97

108
/** @public */
@@ -27,7 +25,8 @@ export type DistinctOptions = CommandOperationOptions & {
2725
* Return a list of distinct values for the given key across a collection.
2826
* @internal
2927
*/
30-
export class DistinctOperation extends CommandOperation<any[]> {
28+
export class DistinctOperation extends ModernizedCommandOperation<any[] | Document> {
29+
override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse;
3130
override options: DistinctOptions;
3231
collection: Collection;
3332
/** Field of the document to find distinct values for. */
@@ -56,48 +55,32 @@ export class DistinctOperation extends CommandOperation<any[]> {
5655
return 'distinct' as const;
5756
}
5857

59-
override async execute(
60-
server: Server,
61-
session: ClientSession | undefined,
62-
timeoutContext: TimeoutContext
63-
): Promise<any[]> {
64-
const coll = this.collection;
65-
const key = this.key;
66-
const query = this.query;
67-
const options = this.options;
68-
69-
// Distinct command
70-
const cmd: Document = {
71-
distinct: coll.collectionName,
72-
key: key,
73-
query: query
58+
override buildCommandDocument(_connection: Connection): Document {
59+
const command: Document = {
60+
distinct: this.collection.collectionName,
61+
key: this.key,
62+
query: this.query
7463
};
75-
76-
// Add maxTimeMS if defined
77-
if (typeof options.maxTimeMS === 'number') {
78-
cmd.maxTimeMS = options.maxTimeMS;
79-
}
80-
8164
// we check for undefined specifically here to allow falsy values
8265
// eslint-disable-next-line no-restricted-syntax
83-
if (typeof options.comment !== 'undefined') {
84-
cmd.comment = options.comment;
66+
if (this.options.comment !== undefined) {
67+
command.comment = this.options.comment;
8568
}
8669

87-
if (options.hint != null) {
88-
cmd.hint = options.hint;
70+
if (this.options.hint != null) {
71+
command.hint = this.options.hint;
8972
}
9073

91-
// Do we have a readConcern specified
92-
decorateWithReadConcern(cmd, coll, options);
93-
94-
// Have we specified collation
95-
decorateWithCollation(cmd, coll, options);
96-
97-
const result = await super.executeCommand(server, session, cmd, timeoutContext);
74+
return command;
75+
}
9876

99-
// @ts-expect-error: Explain always returns a document
100-
return this.explain ? result : result.values;
77+
override handleOk(
78+
response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>
79+
): any[] | Document {
80+
if (this.explain) {
81+
return response.toObject(this.bsonOptions);
82+
}
83+
return response.toObject(this.bsonOptions).values;
10184
}
10285
}
10386

src/operations/profiling_level.ts

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,22 @@
1+
import { BSONType, type Document } from '../bson';
2+
import { type Connection } from '../cmap/connection';
3+
import { MongoDBResponse } from '../cmap/wire_protocol/responses';
14
import type { Db } from '../db';
25
import { MongoUnexpectedServerResponseError } from '../error';
3-
import type { Server } from '../sdam/server';
4-
import type { ClientSession } from '../sessions';
5-
import { type TimeoutContext } from '../timeout';
6-
import { CommandOperation, type CommandOperationOptions } from './command';
6+
import { type CommandOperationOptions, ModernizedCommandOperation } from './command';
77

88
/** @public */
99
export type ProfilingLevelOptions = CommandOperationOptions;
1010

11+
class ProfilingLevelResponse extends MongoDBResponse {
12+
get was() {
13+
return this.get('was', BSONType.int, true);
14+
}
15+
}
16+
1117
/** @internal */
12-
export class ProfilingLevelOperation extends CommandOperation<string> {
18+
export class ProfilingLevelOperation extends ModernizedCommandOperation<string> {
19+
override SERVER_COMMAND_RESPONSE_TYPE = ProfilingLevelResponse;
1320
override options: ProfilingLevelOptions;
1421

1522
constructor(db: Db, options: ProfilingLevelOptions) {
@@ -21,14 +28,13 @@ export class ProfilingLevelOperation extends CommandOperation<string> {
2128
return 'profile' as const;
2229
}
2330

24-
override async execute(
25-
server: Server,
26-
session: ClientSession | undefined,
27-
timeoutContext: TimeoutContext
28-
): Promise<string> {
29-
const doc = await super.executeCommand(server, session, { profile: -1 }, timeoutContext);
30-
if (doc.ok === 1) {
31-
const was = doc.was;
31+
override buildCommandDocument(_connection: Connection): Document {
32+
return { profile: -1 };
33+
}
34+
35+
override handleOk(response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>): string {
36+
if (response.ok === 1) {
37+
const was = response.was;
3238
if (was === 0) return 'off';
3339
if (was === 1) return 'slow_only';
3440
if (was === 2) return 'all';

src/operations/remove_user.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
1+
import { type Document } from '../bson';
2+
import { type Connection } from '../cmap/connection';
3+
import { MongoDBResponse } from '../cmap/wire_protocol/responses';
14
import type { Db } from '../db';
2-
import type { Server } from '../sdam/server';
3-
import type { ClientSession } from '../sessions';
4-
import { type TimeoutContext } from '../timeout';
5-
import { CommandOperation, type CommandOperationOptions } from './command';
5+
import { type CommandOperationOptions, ModernizedCommandOperation } from './command';
66
import { Aspect, defineAspects } from './operation';
77

88
/** @public */
99
export type RemoveUserOptions = CommandOperationOptions;
1010

1111
/** @internal */
12-
export class RemoveUserOperation extends CommandOperation<boolean> {
12+
export class RemoveUserOperation extends ModernizedCommandOperation<boolean> {
13+
override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse;
1314
override options: RemoveUserOptions;
1415
username: string;
1516

@@ -23,12 +24,11 @@ export class RemoveUserOperation extends CommandOperation<boolean> {
2324
return 'dropUser' as const;
2425
}
2526

26-
override async execute(
27-
server: Server,
28-
session: ClientSession | undefined,
29-
timeoutContext: TimeoutContext
30-
): Promise<boolean> {
31-
await super.executeCommand(server, session, { dropUser: this.username }, timeoutContext);
27+
override buildCommandDocument(_connection: Connection): Document {
28+
return { dropUser: this.username };
29+
}
30+
31+
override handleOk(_response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>): boolean {
3232
return true;
3333
}
3434
}

0 commit comments

Comments
 (0)