@@ -9,8 +9,9 @@ import { MongoCompatibilityError } from '../error';
99import type { PkFactory } from '../mongo_client' ;
1010import type { Server } from '../sdam/server' ;
1111import type { ClientSession } from '../sessions' ;
12- import { type TimeoutContext } from '../timeout' ;
12+ import { TimeoutContext } from '../timeout' ;
1313import { CommandOperation , type CommandOperationOptions } from './command' ;
14+ import { executeOperation } from './execute_operation' ;
1415import { CreateIndexesOperation } from './indexes' ;
1516import { Aspect , defineAspects } from './operation' ;
1617
@@ -135,79 +136,95 @@ export class CreateCollectionOperation extends CommandOperation<Collection> {
135136 const name = this . name ;
136137 const options = this . options ;
137138
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 ;
165143 }
144+ }
166145
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 ) ;
169187 }
170188 }
171189
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 ) ;
183203 }
184204
185- return coll ;
205+ if ( ! options . encryptedFields ) {
206+ options = { ...options , encryptedFields } ;
207+ }
186208 }
187209
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 ) ;
210225 }
226+
227+ return coll as unknown as Collection < TSchema > ;
211228}
212229
213230defineAspects ( CreateCollectionOperation , [ Aspect . WRITE_OPERATION ] ) ;
0 commit comments