@@ -9,8 +9,9 @@ import { MongoCompatibilityError } from '../error';
9
9
import type { PkFactory } from '../mongo_client' ;
10
10
import type { Server } from '../sdam/server' ;
11
11
import type { ClientSession } from '../sessions' ;
12
- import { type TimeoutContext } from '../timeout' ;
12
+ import { TimeoutContext } from '../timeout' ;
13
13
import { CommandOperation , type CommandOperationOptions } from './command' ;
14
+ import { executeOperation } from './execute_operation' ;
14
15
import { CreateIndexesOperation } from './indexes' ;
15
16
import { Aspect , defineAspects } from './operation' ;
16
17
@@ -135,79 +136,95 @@ export class CreateCollectionOperation extends CommandOperation<Collection> {
135
136
const name = this . name ;
136
137
const options = this . options ;
137
138
138
- const encryptedFields : Document | undefined =
139
- options . encryptedFields ??
140
- db . client . s . options . autoEncryption ?. encryptedFieldsMap ?. [ `${ db . databaseName } .${ name } ` ] ;
141
-
142
- if ( encryptedFields ) {
143
- // Creating a QE collection required min server of 7.0.0
144
- // TODO(NODE-5353): Get wire version information from connection.
145
- if (
146
- ! server . loadBalanced &&
147
- server . description . maxWireVersion < MIN_SUPPORTED_QE_WIRE_VERSION
148
- ) {
149
- throw new MongoCompatibilityError (
150
- `${ INVALID_QE_VERSION } The minimum server version required is ${ MIN_SUPPORTED_QE_SERVER_VERSION } `
151
- ) ;
152
- }
153
- // Create auxilliary collections for queryable encryption support.
154
- const escCollection = encryptedFields . escCollection ?? `enxcol_.${ name } .esc` ;
155
- const ecocCollection = encryptedFields . ecocCollection ?? `enxcol_.${ name } .ecoc` ;
156
-
157
- for ( const collectionName of [ escCollection , ecocCollection ] ) {
158
- const createOp = new CreateCollectionOperation ( db , collectionName , {
159
- clusteredIndex : {
160
- key : { _id : 1 } ,
161
- unique : true
162
- }
163
- } ) ;
164
- await createOp . executeWithoutEncryptedFieldsCheck ( server , session , timeoutContext ) ;
139
+ const cmd : Document = { create : name } ;
140
+ for ( const [ option , value ] of Object . entries ( options ) ) {
141
+ if ( value != null && typeof value !== 'function' && ! ILLEGAL_COMMAND_FIELDS . has ( option ) ) {
142
+ cmd [ option ] = value ;
165
143
}
144
+ }
166
145
167
- if ( ! options . encryptedFields ) {
168
- this . options = { ...this . options , encryptedFields } ;
146
+ // otherwise just execute the command
147
+ await super . executeCommand ( server , session , cmd , timeoutContext ) ;
148
+ return new Collection ( db , name , options ) ;
149
+ }
150
+ }
151
+
152
+ export async function createCollections < TSchema extends Document > (
153
+ db : Db ,
154
+ name : string ,
155
+ options : CreateCollectionOptions
156
+ ) : Promise < Collection < TSchema > > {
157
+ const timeoutContext = TimeoutContext . create ( {
158
+ session : options . session ,
159
+ serverSelectionTimeoutMS : db . client . s . options . serverSelectionTimeoutMS ,
160
+ waitQueueTimeoutMS : db . client . s . options . waitQueueTimeoutMS ,
161
+ timeoutMS : options . timeoutMS
162
+ } ) ;
163
+
164
+ const encryptedFields : Document | undefined =
165
+ options . encryptedFields ??
166
+ db . client . s . options . autoEncryption ?. encryptedFieldsMap ?. [ `${ db . databaseName } .${ name } ` ] ;
167
+
168
+ if ( encryptedFields ) {
169
+ class CreateSupportingFLEv2CollectionOperation extends CreateCollectionOperation {
170
+ override execute (
171
+ server : Server ,
172
+ session : ClientSession | undefined ,
173
+ timeoutContext : TimeoutContext
174
+ ) : Promise < Collection > {
175
+ // Creating a QE collection required min server of 7.0.0
176
+ // TODO(NODE-5353): Get wire version information from connection.
177
+ if (
178
+ ! server . loadBalanced &&
179
+ server . description . maxWireVersion < MIN_SUPPORTED_QE_WIRE_VERSION
180
+ ) {
181
+ throw new MongoCompatibilityError (
182
+ `${ INVALID_QE_VERSION } The minimum server version required is ${ MIN_SUPPORTED_QE_SERVER_VERSION } `
183
+ ) ;
184
+ }
185
+
186
+ return super . execute ( server , session , timeoutContext ) ;
169
187
}
170
188
}
171
189
172
- const coll = await this . executeWithoutEncryptedFieldsCheck ( server , session , timeoutContext ) ;
173
-
174
- if ( encryptedFields ) {
175
- // Create the required index for queryable encryption support.
176
- const createIndexOp = CreateIndexesOperation . fromIndexSpecification (
177
- db ,
178
- name ,
179
- { __safeContent__ : 1 } ,
180
- { }
181
- ) ;
182
- await createIndexOp . execute ( server , session , timeoutContext ) ;
190
+ // Create auxilliary collections for queryable encryption support.
191
+ const escCollection = encryptedFields . escCollection ?? `enxcol_.${ name } .esc` ;
192
+ const ecocCollection = encryptedFields . ecocCollection ?? `enxcol_.${ name } .ecoc` ;
193
+
194
+ for ( const collectionName of [ escCollection , ecocCollection ] ) {
195
+ const createOp = new CreateSupportingFLEv2CollectionOperation ( db , collectionName , {
196
+ clusteredIndex : {
197
+ key : { _id : 1 } ,
198
+ unique : true
199
+ } ,
200
+ session : options . session
201
+ } ) ;
202
+ await executeOperation ( db . client , createOp , timeoutContext ) ;
183
203
}
184
204
185
- return coll ;
205
+ if ( ! options . encryptedFields ) {
206
+ options = { ...options , encryptedFields } ;
207
+ }
186
208
}
187
209
188
- private async executeWithoutEncryptedFieldsCheck (
189
- server : Server ,
190
- session : ClientSession | undefined ,
191
- timeoutContext : TimeoutContext
192
- ) : Promise < Collection > {
193
- const db = this . db ;
194
- const name = this . name ;
195
- const options = this . options ;
196
-
197
- const cmd : Document = { create : name } ;
198
- for ( const n in options ) {
199
- if (
200
- ( options as any ) [ n ] != null &&
201
- typeof ( options as any ) [ n ] !== 'function' &&
202
- ! ILLEGAL_COMMAND_FIELDS . has ( n )
203
- ) {
204
- cmd [ n ] = ( options as any ) [ n ] ;
205
- }
206
- }
207
- // otherwise just execute the command
208
- await super . executeCommand ( server , session , cmd , timeoutContext ) ;
209
- return new Collection ( db , name , options ) ;
210
+ const coll = await executeOperation (
211
+ db . client ,
212
+ new CreateCollectionOperation ( db , name , options ) ,
213
+ timeoutContext
214
+ ) ;
215
+
216
+ if ( encryptedFields ) {
217
+ // Create the required index for queryable encryption support.
218
+ const createIndexOp = CreateIndexesOperation . fromIndexSpecification (
219
+ db ,
220
+ name ,
221
+ { __safeContent__ : 1 } ,
222
+ { session : options . session }
223
+ ) ;
224
+ await executeOperation ( db . client , createIndexOp , timeoutContext ) ;
210
225
}
226
+
227
+ return coll as unknown as Collection < TSchema > ;
211
228
}
212
229
213
230
defineAspects ( CreateCollectionOperation , [ Aspect . WRITE_OPERATION ] ) ;
0 commit comments