Skip to content

Commit c44af11

Browse files
authored
refactor(NODE-5437): admin operations to use async syntax (#3773)
1 parent f697ee1 commit c44af11

11 files changed

+261
-309
lines changed

src/operations/add_user.ts

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { MongoInvalidArgumentError } from '../error';
66
import type { Server } from '../sdam/server';
77
import type { ClientSession } from '../sessions';
88
import { type Callback, emitWarningOnce, getTopology } from '../utils';
9-
import { CommandCallbackOperation, type CommandOperationOptions } from './command';
9+
import { CommandOperation, type CommandOperationOptions } from './command';
1010
import { Aspect, defineAspects } from './operation';
1111

1212
/**
@@ -35,7 +35,7 @@ export interface AddUserOptions extends CommandOperationOptions {
3535
}
3636

3737
/** @internal */
38-
export class AddUserOperation extends CommandCallbackOperation<Document> {
38+
export class AddUserOperation extends CommandOperation<Document> {
3939
override options: AddUserOptions;
4040
db: Db;
4141
username: string;
@@ -50,11 +50,7 @@ export class AddUserOperation extends CommandCallbackOperation<Document> {
5050
this.options = options ?? {};
5151
}
5252

53-
override executeCallback(
54-
server: Server,
55-
session: ClientSession | undefined,
56-
callback: Callback<Document>
57-
): void {
53+
override execute(server: Server, session: ClientSession | undefined): Promise<Document> {
5854
const db = this.db;
5955
const username = this.username;
6056
const password = this.password;
@@ -64,10 +60,8 @@ export class AddUserOperation extends CommandCallbackOperation<Document> {
6460
// v5 removed the digestPassword option from AddUserOptions but we still want to throw
6561
// an error when digestPassword is provided.
6662
if ('digestPassword' in options && options.digestPassword != null) {
67-
return callback(
68-
new MongoInvalidArgumentError(
69-
'Option "digestPassword" not supported via addUser, use db.command(...) instead'
70-
)
63+
throw new MongoInvalidArgumentError(
64+
'Option "digestPassword" not supported via addUser, use db.command(...) instead'
7165
);
7266
}
7367

@@ -85,12 +79,7 @@ export class AddUserOperation extends CommandCallbackOperation<Document> {
8579
roles = Array.isArray(options.roles) ? options.roles : [options.roles];
8680
}
8781

88-
let topology;
89-
try {
90-
topology = getTopology(db);
91-
} catch (error) {
92-
return callback(error);
93-
}
82+
const topology = getTopology(db);
9483

9584
const digestPassword = topology.lastHello().maxWireVersion >= 7;
9685

@@ -117,7 +106,11 @@ export class AddUserOperation extends CommandCallbackOperation<Document> {
117106
command.pwd = userPassword;
118107
}
119108

120-
super.executeCommandCallback(server, session, command, callback);
109+
return super.executeCommand(server, session, command);
110+
}
111+
112+
executeCallback(_server: Server, _session: ClientSession | undefined, _callback: Callback): void {
113+
throw new Error('Method not implemented');
121114
}
122115
}
123116

src/operations/create_collection.ts

Lines changed: 72 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ import { MongoCompatibilityError } from '../error';
99
import type { PkFactory } from '../mongo_client';
1010
import type { Server } from '../sdam/server';
1111
import type { ClientSession } from '../sessions';
12-
import type { Callback } from '../utils';
13-
import { CommandCallbackOperation, type CommandOperationOptions } from './command';
12+
import { type Callback } from '../utils';
13+
import { CommandOperation, type CommandOperationOptions } from './command';
1414
import { CreateIndexOperation } from './indexes';
1515
import { Aspect, defineAspects } from './operation';
1616

@@ -108,7 +108,7 @@ const INVALID_QE_VERSION =
108108
'Driver support of Queryable Encryption is incompatible with server. Upgrade server to use Queryable Encryption.';
109109

110110
/** @internal */
111-
export class CreateCollectionOperation extends CommandCallbackOperation<Collection> {
111+
export class CreateCollectionOperation extends CommandOperation<Collection> {
112112
override options: CreateCollectionOptions;
113113
db: Db;
114114
name: string;
@@ -121,96 +121,85 @@ export class CreateCollectionOperation extends CommandCallbackOperation<Collecti
121121
this.name = name;
122122
}
123123

124-
override executeCallback(
125-
server: Server,
126-
session: ClientSession | undefined,
127-
callback: Callback<Collection>
128-
): void {
129-
(async () => {
130-
const db = this.db;
131-
const name = this.name;
132-
const options = this.options;
133-
134-
const encryptedFields: Document | undefined =
135-
options.encryptedFields ??
136-
db.client.options.autoEncryption?.encryptedFieldsMap?.[`${db.databaseName}.${name}`];
137-
138-
if (encryptedFields) {
139-
// Creating a QE collection required min server of 7.0.0
140-
// TODO(NODE-5353): Get wire version information from connection.
141-
if (
142-
!server.loadBalanced &&
143-
server.description.maxWireVersion < MIN_SUPPORTED_QE_WIRE_VERSION
144-
) {
145-
throw new MongoCompatibilityError(
146-
`${INVALID_QE_VERSION} The minimum server version required is ${MIN_SUPPORTED_QE_SERVER_VERSION}`
147-
);
148-
}
149-
// Create auxilliary collections for queryable encryption support.
150-
const escCollection = encryptedFields.escCollection ?? `enxcol_.${name}.esc`;
151-
const ecocCollection = encryptedFields.ecocCollection ?? `enxcol_.${name}.ecoc`;
152-
153-
for (const collectionName of [escCollection, ecocCollection]) {
154-
const createOp = new CreateCollectionOperation(db, collectionName, {
155-
clusteredIndex: {
156-
key: { _id: 1 },
157-
unique: true
158-
}
159-
});
160-
await createOp.executeWithoutEncryptedFieldsCheck(server, session);
161-
}
162-
163-
if (!options.encryptedFields) {
164-
this.options = { ...this.options, encryptedFields };
165-
}
124+
override async execute(server: Server, session: ClientSession | undefined): Promise<Collection> {
125+
const db = this.db;
126+
const name = this.name;
127+
const options = this.options;
128+
129+
const encryptedFields: Document | undefined =
130+
options.encryptedFields ??
131+
db.client.options.autoEncryption?.encryptedFieldsMap?.[`${db.databaseName}.${name}`];
132+
133+
if (encryptedFields) {
134+
// Creating a QE collection required min server of 7.0.0
135+
// TODO(NODE-5353): Get wire version information from connection.
136+
if (
137+
!server.loadBalanced &&
138+
server.description.maxWireVersion < MIN_SUPPORTED_QE_WIRE_VERSION
139+
) {
140+
throw new MongoCompatibilityError(
141+
`${INVALID_QE_VERSION} The minimum server version required is ${MIN_SUPPORTED_QE_SERVER_VERSION}`
142+
);
143+
}
144+
// Create auxilliary collections for queryable encryption support.
145+
const escCollection = encryptedFields.escCollection ?? `enxcol_.${name}.esc`;
146+
const ecocCollection = encryptedFields.ecocCollection ?? `enxcol_.${name}.ecoc`;
147+
148+
for (const collectionName of [escCollection, ecocCollection]) {
149+
const createOp = new CreateCollectionOperation(db, collectionName, {
150+
clusteredIndex: {
151+
key: { _id: 1 },
152+
unique: true
153+
}
154+
});
155+
await createOp.executeWithoutEncryptedFieldsCheck(server, session);
166156
}
167157

168-
const coll = await this.executeWithoutEncryptedFieldsCheck(server, session);
169-
170-
if (encryptedFields) {
171-
// Create the required index for queryable encryption support.
172-
const createIndexOp = new CreateIndexOperation(db, name, { __safeContent__: 1 }, {});
173-
await createIndexOp.execute(server, session);
158+
if (!options.encryptedFields) {
159+
this.options = { ...this.options, encryptedFields };
174160
}
161+
}
162+
163+
const coll = await this.executeWithoutEncryptedFieldsCheck(server, session);
175164

176-
return coll;
177-
})().then(
178-
coll => callback(undefined, coll),
179-
err => callback(err)
180-
);
165+
if (encryptedFields) {
166+
// Create the required index for queryable encryption support.
167+
const createIndexOp = new CreateIndexOperation(db, name, { __safeContent__: 1 }, {});
168+
await createIndexOp.execute(server, session);
169+
}
170+
171+
return coll;
181172
}
182173

183-
private executeWithoutEncryptedFieldsCheck(
174+
protected executeCallback(
175+
_server: Server,
176+
_session: ClientSession | undefined,
177+
_callback: Callback<Collection>
178+
): void {
179+
throw new Error('Method not implemented.');
180+
}
181+
182+
private async executeWithoutEncryptedFieldsCheck(
184183
server: Server,
185184
session: ClientSession | undefined
186185
): Promise<Collection> {
187-
return new Promise<Collection>((resolve, reject) => {
188-
const db = this.db;
189-
const name = this.name;
190-
const options = this.options;
191-
192-
const done: Callback = err => {
193-
if (err) {
194-
return reject(err);
195-
}
196-
197-
resolve(new Collection(db, name, options));
198-
};
199-
200-
const cmd: Document = { create: name };
201-
for (const n in options) {
202-
if (
203-
(options as any)[n] != null &&
204-
typeof (options as any)[n] !== 'function' &&
205-
!ILLEGAL_COMMAND_FIELDS.has(n)
206-
) {
207-
cmd[n] = (options as any)[n];
208-
}
186+
const db = this.db;
187+
const name = this.name;
188+
const options = this.options;
189+
190+
const cmd: Document = { create: name };
191+
for (const n in options) {
192+
if (
193+
(options as any)[n] != null &&
194+
typeof (options as any)[n] !== 'function' &&
195+
!ILLEGAL_COMMAND_FIELDS.has(n)
196+
) {
197+
cmd[n] = (options as any)[n];
209198
}
210-
211-
// otherwise just execute the command
212-
super.executeCommandCallback(server, session, cmd, done);
213-
});
199+
}
200+
// otherwise just execute the command
201+
await super.executeCommand(server, session, cmd);
202+
return new Collection(db, name, options);
214203
}
215204
}
216205

0 commit comments

Comments
 (0)