@@ -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
@@ -102,6 +103,9 @@ export interface CreateCollectionOptions extends CommandOperationOptions {
102
103
* change streams that listen on this collection.
103
104
*/
104
105
changeStreamPreAndPostImages ?: { enabled : boolean } ;
106
+
107
+ /** @internal */
108
+ isEncryptedCollection ?: boolean ;
105
109
}
106
110
107
111
/* @internal */
@@ -131,15 +135,7 @@ export class CreateCollectionOperation extends CommandOperation<Collection> {
131
135
session : ClientSession | undefined ,
132
136
timeoutContext : TimeoutContext
133
137
) : Promise < Collection > {
134
- const db = this . db ;
135
- const name = this . name ;
136
- const options = this . options ;
137
-
138
- const encryptedFields : Document | undefined =
139
- options . encryptedFields ??
140
- db . client . s . options . autoEncryption ?. encryptedFieldsMap ?. [ `${ db . databaseName } .${ name } ` ] ;
141
-
142
- if ( encryptedFields ) {
138
+ if ( this . options . isEncryptedCollection ) {
143
139
// Creating a QE collection required min server of 7.0.0
144
140
// TODO(NODE-5353): Get wire version information from connection.
145
141
if (
@@ -150,64 +146,81 @@ export class CreateCollectionOperation extends CommandOperation<Collection> {
150
146
`${ INVALID_QE_VERSION } The minimum server version required is ${ MIN_SUPPORTED_QE_SERVER_VERSION } `
151
147
) ;
152
148
}
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 ) ;
165
- }
166
-
167
- if ( ! options . encryptedFields ) {
168
- this . options = { ...this . options , encryptedFields } ;
169
- }
170
- }
171
-
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 ) ;
183
149
}
184
150
185
- return coll ;
186
- }
187
-
188
- private async executeWithoutEncryptedFieldsCheck (
189
- server : Server ,
190
- session : ClientSession | undefined ,
191
- timeoutContext : TimeoutContext
192
- ) : Promise < Collection > {
193
151
const db = this . db ;
194
152
const name = this . name ;
195
153
const options = this . options ;
196
154
197
155
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 ] ;
156
+ for ( const [ option , value ] of Object . entries ( options ) ) {
157
+ if ( value != null && typeof value !== 'function' && ! ILLEGAL_COMMAND_FIELDS . has ( option ) ) {
158
+ cmd [ option ] = value ;
205
159
}
206
160
}
161
+
207
162
// otherwise just execute the command
208
163
await super . executeCommand ( server , session , cmd , timeoutContext ) ;
209
164
return new Collection ( db , name , options ) ;
210
165
}
211
166
}
212
167
168
+ export async function createCollections < TSchema extends Document > (
169
+ db : Db ,
170
+ name : string ,
171
+ options : CreateCollectionOptions
172
+ ) : Promise < Collection < TSchema > > {
173
+ const timeoutContext = TimeoutContext . create ( {
174
+ session : options . session ,
175
+ serverSelectionTimeoutMS : db . client . s . options . serverSelectionTimeoutMS ,
176
+ waitQueueTimeoutMS : db . client . s . options . waitQueueTimeoutMS ,
177
+ timeoutMS : options . timeoutMS
178
+ } ) ;
179
+
180
+ const encryptedFields : Document | undefined =
181
+ options . encryptedFields ??
182
+ db . client . s . options . autoEncryption ?. encryptedFieldsMap ?. [ `${ db . databaseName } .${ name } ` ] ;
183
+
184
+ if ( encryptedFields ) {
185
+ // Create auxilliary collections for queryable encryption support.
186
+ const escCollection = encryptedFields . escCollection ?? `enxcol_.${ name } .esc` ;
187
+ const ecocCollection = encryptedFields . ecocCollection ?? `enxcol_.${ name } .ecoc` ;
188
+
189
+ for ( const collectionName of [ escCollection , ecocCollection ] ) {
190
+ const createOp = new CreateCollectionOperation ( db , collectionName , {
191
+ clusteredIndex : {
192
+ key : { _id : 1 } ,
193
+ unique : true
194
+ } ,
195
+ isEncryptedCollection : true ,
196
+ session : options . session
197
+ } ) ;
198
+ await executeOperation ( db . client , createOp , timeoutContext ) ;
199
+ }
200
+
201
+ if ( ! options . encryptedFields ) {
202
+ options = { ...options , encryptedFields } ;
203
+ }
204
+ }
205
+
206
+ const coll = await executeOperation (
207
+ db . client ,
208
+ new CreateCollectionOperation ( db , name , options ) ,
209
+ timeoutContext
210
+ ) ;
211
+
212
+ if ( encryptedFields ) {
213
+ // Create the required index for queryable encryption support.
214
+ const createIndexOp = CreateIndexesOperation . fromIndexSpecification (
215
+ db ,
216
+ name ,
217
+ { __safeContent__ : 1 } ,
218
+ { session : options . session }
219
+ ) ;
220
+ await executeOperation ( db . client , createIndexOp , timeoutContext ) ;
221
+ }
222
+
223
+ return coll as unknown as Collection < TSchema > ;
224
+ }
225
+
213
226
defineAspects ( CreateCollectionOperation , [ Aspect . WRITE_OPERATION ] ) ;
0 commit comments