@@ -6,7 +6,7 @@ import type { OneOrMore } from '../mongo_types';
66import { ReadPreference } from '../read_preference' ;
77import type { Server } from '../sdam/server' ;
88import type { ClientSession } from '../sessions' ;
9- import { Callback , maxWireVersion , MongoDBNamespace , parseIndexOptions } from '../utils' ;
9+ import { Callback , isObject , maxWireVersion , MongoDBNamespace } from '../utils' ;
1010import {
1111 CollationOptions ,
1212 CommandOperation ,
@@ -51,14 +51,17 @@ const VALID_INDEX_OPTIONS = new Set([
5151
5252/** @public */
5353export type IndexDirection = - 1 | 1 | '2d' | '2dsphere' | 'text' | 'geoHaystack' | number ;
54-
54+ function isIndexDirection ( x : unknown ) : x is IndexDirection {
55+ return (
56+ typeof x === 'number' || x === '2d' || x === '2dsphere' || x === 'text' || x === 'geoHaystack'
57+ ) ;
58+ }
5559/** @public */
5660export type IndexSpecification = OneOrMore <
5761 | string
5862 | [ string , IndexDirection ]
5963 | { [ key : string ] : IndexDirection }
60- | [ string , IndexDirection ] [ ]
61- | { [ key : string ] : IndexDirection } [ ]
64+ | Map < string , IndexDirection >
6265> ;
6366
6467/** @public */
@@ -86,7 +89,7 @@ export interface IndexDescription
8689 > {
8790 collation ?: CollationOptions ;
8891 name ?: string ;
89- key : Document ;
92+ key : { [ key : string ] : IndexDirection } | Map < string , IndexDirection > ;
9093}
9194
9295/** @public */
@@ -130,23 +133,37 @@ export interface CreateIndexesOptions extends CommandOperationOptions {
130133 hidden ?: boolean ;
131134}
132135
133- function makeIndexSpec ( indexSpec : IndexSpecification , options : any ) : IndexDescription {
134- const indexParameters = parseIndexOptions ( indexSpec ) ;
135-
136- // Generate the index name
137- const name = typeof options . name === 'string' ? options . name : indexParameters . name ;
138-
139- // Set up the index
140- const finalIndexSpec : Document = { name, key : indexParameters . fieldHash } ;
136+ function isSingleIndexTuple ( t : unknown ) : t is [ string , IndexDirection ] {
137+ return Array . isArray ( t ) && t . length === 2 && isIndexDirection ( t [ 1 ] ) ;
138+ }
141139
142- // merge valid index options into the index spec
143- for ( const optionName in options ) {
144- if ( VALID_INDEX_OPTIONS . has ( optionName ) ) {
145- finalIndexSpec [ optionName ] = options [ optionName ] ;
140+ function makeIndexSpec (
141+ indexSpec : IndexSpecification ,
142+ options ?: CreateIndexesOptions
143+ ) : IndexDescription {
144+ const key : Map < string , IndexDirection > = new Map ( ) ;
145+
146+ const indexSpecs =
147+ ! Array . isArray ( indexSpec ) || isSingleIndexTuple ( indexSpec ) ? [ indexSpec ] : indexSpec ;
148+
149+ // Iterate through array and handle different types
150+ for ( const spec of indexSpecs ) {
151+ if ( typeof spec === 'string' ) {
152+ key . set ( spec , 1 ) ;
153+ } else if ( Array . isArray ( spec ) ) {
154+ key . set ( spec [ 0 ] , spec [ 1 ] ?? 1 ) ;
155+ } else if ( spec instanceof Map ) {
156+ for ( const [ property , value ] of spec ) {
157+ key . set ( property , value ) ;
158+ }
159+ } else if ( isObject ( spec ) ) {
160+ for ( const [ property , value ] of Object . entries ( spec ) ) {
161+ key . set ( property , value ) ;
162+ }
146163 }
147164 }
148165
149- return finalIndexSpec as IndexDescription ;
166+ return { ... options , key } ;
150167}
151168
152169/** @internal */
@@ -183,7 +200,7 @@ export class CreateIndexesOperation<
183200> extends CommandOperation < T > {
184201 override options : CreateIndexesOptions ;
185202 collectionName : string ;
186- indexes : IndexDescription [ ] ;
203+ indexes : ReadonlyArray < Omit < IndexDescription , 'key' > & { key : Map < string , IndexDirection > } > ;
187204
188205 constructor (
189206 parent : OperationParent ,
@@ -195,8 +212,22 @@ export class CreateIndexesOperation<
195212
196213 this . options = options ?? { } ;
197214 this . collectionName = collectionName ;
198-
199- this . indexes = indexes ;
215+ this . indexes = indexes . map ( userIndex => {
216+ // Ensure the key is a Map to preserve index key ordering
217+ const key =
218+ userIndex . key instanceof Map ? userIndex . key : new Map ( Object . entries ( userIndex . key ) ) ;
219+ const name = userIndex . name != null ? userIndex . name : Array . from ( key ) . flat ( ) . join ( '_' ) ;
220+ const validIndexOptions = Object . fromEntries (
221+ Object . entries ( { ...userIndex } ) . filter ( ( [ optionName ] ) =>
222+ VALID_INDEX_OPTIONS . has ( optionName )
223+ )
224+ ) ;
225+ return {
226+ ...validIndexOptions ,
227+ name,
228+ key
229+ } ;
230+ } ) ;
200231 }
201232
202233 override execute (
@@ -209,31 +240,6 @@ export class CreateIndexesOperation<
209240
210241 const serverWireVersion = maxWireVersion ( server ) ;
211242
212- // Ensure we generate the correct name if the parameter is not set
213- for ( let i = 0 ; i < indexes . length ; i ++ ) {
214- // Did the user pass in a collation, check if our write server supports it
215- if ( indexes [ i ] . collation && serverWireVersion < 5 ) {
216- callback (
217- new MongoCompatibilityError (
218- `Server ${ server . name } , which reports wire version ${ serverWireVersion } , ` +
219- 'does not support collation'
220- )
221- ) ;
222- return ;
223- }
224-
225- if ( indexes [ i ] . name == null ) {
226- const keys = [ ] ;
227-
228- for ( const name in indexes [ i ] . key ) {
229- keys . push ( `${ name } _${ indexes [ i ] . key [ name ] } ` ) ;
230- }
231-
232- // Set the name
233- indexes [ i ] . name = keys . join ( '_' ) ;
234- }
235- }
236-
237243 const cmd : Document = { createIndexes : this . collectionName , indexes } ;
238244
239245 if ( options . commitQuorum != null ) {
@@ -271,12 +277,6 @@ export class CreateIndexOperation extends CreateIndexesOperation<string> {
271277 indexSpec : IndexSpecification ,
272278 options ?: CreateIndexesOptions
273279 ) {
274- // createIndex can be called with a variety of styles:
275- // coll.createIndex('a');
276- // coll.createIndex({ a: 1 });
277- // coll.createIndex([['a', 1]]);
278- // createIndexes is always called with an array of index spec objects
279-
280280 super ( parent , collectionName , [ makeIndexSpec ( indexSpec , options ) ] , options ) ;
281281 }
282282 override execute (
0 commit comments