@@ -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
@@ -102,6 +103,9 @@ export interface CreateCollectionOptions extends CommandOperationOptions {
102103 * change streams that listen on this collection.
103104 */
104105 changeStreamPreAndPostImages ?: { enabled : boolean } ;
106+
107+ /** @internal */
108+ isEncryptedCollection ?: boolean ;
105109}
106110
107111/* @internal */
@@ -131,15 +135,7 @@ export class CreateCollectionOperation extends CommandOperation<Collection> {
131135 session : ClientSession | undefined ,
132136 timeoutContext : TimeoutContext
133137 ) : 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 ) {
143139 // Creating a QE collection required min server of 7.0.0
144140 // TODO(NODE-5353): Get wire version information from connection.
145141 if (
@@ -150,64 +146,81 @@ export class CreateCollectionOperation extends CommandOperation<Collection> {
150146 `${ INVALID_QE_VERSION } The minimum server version required is ${ MIN_SUPPORTED_QE_SERVER_VERSION } `
151147 ) ;
152148 }
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 ) ;
183149 }
184150
185- return coll ;
186- }
187-
188- private async executeWithoutEncryptedFieldsCheck (
189- server : Server ,
190- session : ClientSession | undefined ,
191- timeoutContext : TimeoutContext
192- ) : Promise < Collection > {
193151 const db = this . db ;
194152 const name = this . name ;
195153 const options = this . options ;
196154
197155 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 ;
205159 }
206160 }
161+
207162 // otherwise just execute the command
208163 await super . executeCommand ( server , session , cmd , timeoutContext ) ;
209164 return new Collection ( db , name , options ) ;
210165 }
211166}
212167
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+
213226defineAspects ( CreateCollectionOperation , [ Aspect . WRITE_OPERATION ] ) ;
0 commit comments