Skip to content

Commit d08bfe3

Browse files
Fixed map functionality
1 parent 68c3b37 commit d08bfe3

File tree

3 files changed

+79
-110
lines changed

3 files changed

+79
-110
lines changed

src/operations/indexes.ts

+51-29
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,10 @@ function isIndexDirection(x: any): x is IndexDirection {
5959

6060
/** @public */
6161
export type IndexSpecification = OneOrMore<
62-
string | [string, IndexDirection] | { [key: string]: IndexDirection }
62+
| string
63+
| [string, IndexDirection]
64+
| { [key: string]: IndexDirection }
65+
| Map<string, IndexDirection>
6366
>;
6467

6568
/** @public */
@@ -87,7 +90,7 @@ export interface IndexDescription
8790
> {
8891
collation?: CollationOptions;
8992
name?: string;
90-
key: Document;
93+
key: Document | Map<string, IndexDirection>;
9194
}
9295

9396
/** @public */
@@ -131,31 +134,39 @@ export interface CreateIndexesOptions extends CommandOperationOptions {
131134
hidden?: boolean;
132135
}
133136

137+
function isSingleIndexTuple(t: unknown): t is [string, IndexDirection] {
138+
return Array.isArray(t) && t.length === 2 && isIndexDirection(t[1]);
139+
}
140+
134141
export function makeIndexSpec(indexSpec: IndexSpecification, options: any): IndexDescription {
135142
function getFieldHash(indexSpec: IndexSpecification) {
136-
let fieldHash: Map<string, IndexDirection> = new Map();
143+
const fieldHash: Map<string, IndexDirection> = new Map();
137144

138145
let indexSpecArr: IndexSpecification[];
139146

140-
// wrap in array if needed
141-
if (!Array.isArray(indexSpec) || (indexSpec.length === 2 && isIndexDirection(indexSpec[1]))) {
147+
// Wrap indexSpec in array if needed
148+
if (!Array.isArray(indexSpec) || isSingleIndexTuple(indexSpec)) {
142149
indexSpecArr = [indexSpec];
143150
} else {
144151
indexSpecArr = indexSpec;
145152
}
146153

147-
// iterate through array and handle different types
148-
indexSpecArr.forEach((f: any) => {
149-
if ('string' === typeof f) {
150-
fieldHash.set(f, 1);
151-
} else if (Array.isArray(f)) {
152-
fieldHash.set(f[0], f[1]);
153-
} else if (isObject(f)) {
154-
for (const [key, value] of Object.entries(f)) {
154+
// Iterate through array and handle different types
155+
for (const spec of indexSpecArr) {
156+
if ('string' === typeof spec) {
157+
fieldHash.set(spec, 1);
158+
} else if (Array.isArray(spec)) {
159+
fieldHash.set(spec[0], spec[1]);
160+
} else if (spec instanceof Map) {
161+
for (const [key, value] of spec) {
162+
fieldHash.set(key, value);
163+
}
164+
} else if (isObject(spec)) {
165+
for (const [key, value] of Object.entries(spec)) {
155166
fieldHash.set(key, value);
156167
}
157168
}
158-
});
169+
}
159170

160171
return fieldHash;
161172
}
@@ -225,9 +236,32 @@ export class CreateIndexesOperation<
225236
this.options = options ?? {};
226237
this.collectionName = collectionName;
227238

228-
this.indexes = indexes;
239+
// Ensure we generate the correct name if the parameter is not set
240+
const normalizedIndexes = [];
241+
for (const userIndex of indexes) {
242+
const key =
243+
userIndex.key instanceof Map ? userIndex.key : new Map(Object.entries(userIndex.key));
244+
const index: Omit<IndexDescription, 'key'> & { key: Map<string, IndexDirection> } = {
245+
...userIndex,
246+
key
247+
};
248+
if (index.name == null) {
249+
const keys = [];
250+
251+
for (const [name, direction] of index.key) {
252+
keys.push(`${name}_${direction}`);
253+
}
254+
255+
// Set the name
256+
index.name = keys.join('_');
257+
}
258+
normalizedIndexes.push(index);
259+
}
260+
this.indexes = normalizedIndexes;
229261
}
230262

263+
/* TODO: create name in the parent class constructor */
264+
/* create a type assertion to stop typescript errors */
231265
override execute(
232266
server: Server,
233267
session: ClientSession | undefined,
@@ -238,10 +272,9 @@ export class CreateIndexesOperation<
238272

239273
const serverWireVersion = maxWireVersion(server);
240274

241-
// Ensure we generate the correct name if the parameter is not set
242-
for (let i = 0; i < indexes.length; i++) {
275+
for (const index of indexes) {
243276
// Did the user pass in a collation, check if our write server supports it
244-
if (indexes[i].collation && serverWireVersion < 5) {
277+
if (index.collation && serverWireVersion < 5) {
245278
callback(
246279
new MongoCompatibilityError(
247280
`Server ${server.name}, which reports wire version ${serverWireVersion}, ` +
@@ -250,17 +283,6 @@ export class CreateIndexesOperation<
250283
);
251284
return;
252285
}
253-
254-
if (indexes[i].name == null) {
255-
const keys = [];
256-
257-
for (const name in indexes[i].key) {
258-
keys.push(`${name}_${indexes[i].key[name]}`);
259-
}
260-
261-
// Set the name
262-
indexes[i].name = keys.join('_');
263-
}
264286
}
265287

266288
const cmd: Document = { createIndexes: this.collectionName, indexes };

test/unit/operations/indexes.test.ts

+28-10
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,14 @@ describe('makeIndexSpec()', () => {
1212
{
1313
description: 'single string',
1414
input: 'sample_index',
15-
mapData: new Map<string, IndexDirection>([['sample_index', 1]])
15+
mapData: new Map<string, IndexDirection>([['sample_index', 1]]),
16+
name: 'sample_index_1'
1617
},
1718
{
1819
description: 'single [string, IndexDirection]',
1920
input: ['sample_index', -1],
20-
mapData: new Map<string, IndexDirection>([['sample_index', -1]])
21+
mapData: new Map<string, IndexDirection>([['sample_index', -1]]),
22+
name: 'sample_index_-1'
2123
},
2224
{
2325
description: 'array of strings',
@@ -26,7 +28,8 @@ describe('makeIndexSpec()', () => {
2628
['sample_index1', 1],
2729
['sample_index2', 1],
2830
['sample_index3', 1]
29-
])
31+
]),
32+
name: 'sample_index1_1_sample_index2_1_sample_index3_1'
3033
},
3134
{
3235
description: 'array of [string, IndexDirection]',
@@ -39,12 +42,14 @@ describe('makeIndexSpec()', () => {
3942
['sample_index1', -1],
4043
['sample_index2', 1],
4144
['sample_index3', '2d']
42-
])
45+
]),
46+
name: 'sample_index1_-1_sample_index2_1_sample_index3_2d'
4347
},
4448
{
4549
description: 'single { [key: string]: IndexDirection }',
4650
input: { sample_index: -1 },
47-
mapData: new Map<string, IndexDirection>([['sample_index', -1]])
51+
mapData: new Map<string, IndexDirection>([['sample_index', -1]]),
52+
name: 'sample_index_-1'
4853
},
4954
{
5055
description: 'array of { [key: string]: IndexDirection }',
@@ -53,31 +58,44 @@ describe('makeIndexSpec()', () => {
5358
['sample_index1', -1],
5459
['sample_index2', 1],
5560
['sample_index3', '2d']
56-
])
61+
]),
62+
name: 'sample_index1_-1_sample_index2_1_sample_index3_2d'
5763
},
5864
{
59-
name: 'mixed array of [string, [string, IndexDirection], { [key: string]: IndexDirection }]',
65+
description: 'mixed array of [string, [string, IndexDirection], { [key: string]: IndexDirection }]',
6066
input: ['sample_index1', ['sample_index2', -1], { sample_index3: '2d' }],
6167
mapData: new Map<string, IndexDirection>([
6268
['sample_index1', 1],
6369
['sample_index2', -1],
6470
['sample_index3', '2d']
65-
])
71+
]),
72+
name: 'sample_index1_1_sample_index2_-1_sample_index3_2d'
6673
}
6774
];
6875

6976
const makeIndexOperation = (input, options: CreateIndexesOptions = {}) =>
7077
new CreateIndexOperation({ s: { namespace: ns('a.b') } }, 'b', input, options);
7178

72-
for (const { description, input, mapData } of testCases) {
79+
for (const { description, input, mapData, name } of testCases) {
7380
it(`should create fieldHash correctly when input is: ${description}`, () => {
7481
const realOutput = makeIndexOperation(input);
7582
expect(realOutput.indexes[0].key).to.deep.equal(mapData);
7683
});
7784

7885
it(`should set name to null if none provided with ${description} input `, () => {
7986
const realOutput = makeIndexOperation(input);
80-
expect(realOutput.indexes[0].name).to.equal(null);
87+
expect(realOutput.indexes[0].name).to.equal(name);
8188
});
8289
}
90+
91+
it('should keep numerical keys in chronological ordering', () => {
92+
const desiredMapData = new Map<string, IndexDirection>([
93+
['2', -1],
94+
['1', 1]
95+
]);
96+
const realOutput = makeIndexOperation(desiredMapData);
97+
const desiredName = '2_-1_1_1';
98+
expect(realOutput.indexes[0].key).to.deep.equal(desiredMapData);
99+
expect(realOutput.indexes[0].name).to.equal(desiredName);
100+
});
83101
});

test/unit/utils.test.ts

-71
Original file line numberDiff line numberDiff line change
@@ -526,75 +526,4 @@ describe('driver utils', function () {
526526
expect(isHello(doc)).to.be.false;
527527
});
528528
});
529-
530-
describe('parseIndexOptions()', () => {
531-
const testCases = [
532-
{
533-
description: 'single string',
534-
input: 'sample_index',
535-
output: { name: 'sample_index_1', keys: undefined, fieldHash: { sample_index: 1 } }
536-
},
537-
{
538-
description: 'single [string, IndexDirection]',
539-
input: ['sample_index', -1],
540-
output: { name: 'sample_index_1', keys: undefined, fieldHash: { sample_index: 1 } }
541-
},
542-
{
543-
description: 'array of strings',
544-
input: ['sample_index1', 'sample_index2', 'sample_index3'],
545-
output: {
546-
name: 'sample_index1_1_sample_index2_1_sample_index3_1',
547-
keys: undefined,
548-
fieldHash: { sample_index1: 1, sample_index2: 1, sample_index3: 1 }
549-
}
550-
},
551-
{
552-
description: 'array of [string, IndexDirection]',
553-
input: [
554-
['sample_index1', -1],
555-
['sample_index2', 1],
556-
['sample_index3', '2d']
557-
],
558-
output: {
559-
name: 'sample_index1_-1_sample_index2_1_sample_index3_2d',
560-
keys: undefined,
561-
fieldHash: { sample_index1: -1, sample_index2: 1, sample_index3: '2d' }
562-
}
563-
},
564-
{
565-
description: 'single { [key: string]: IndexDirection }',
566-
input: { d: { sample_index: 1 } },
567-
output: { name: 'd_[object Object]', keys: ['d'], fieldHash: { d: { sample_index: 1 } } }
568-
},
569-
{
570-
description: 'array of { [key: string]: IndexDirection }',
571-
input: { d: { sample_index1: -1 }, k: { sample_index2: 1 }, n: { sample_index2: '2d' }},
572-
output: {
573-
name: 'd_[object Object]_k_[object Object]_n_[object Object]',
574-
keys: ['d', 'k', 'n'],
575-
fieldHash: {
576-
d: { sample_index1: -1 },
577-
k: { sample_index2: 1 },
578-
n: { sample_index2: '2d' }
579-
}
580-
}
581-
},
582-
{
583-
name: 'mixed array of [string, [string, IndexDirection], { [key: string]: IndexDirection }]',
584-
input: ['sample_index1', ['sample_index2', -1], { d: { sample_index2: '2d' } }],
585-
output: {
586-
name: 'sample_index1_1_sample_index2_-1_d_[object Object]',
587-
keys: ['d'],
588-
fieldHash: { sample_index1: 1, sample_index2: -1, d: { sample_index2: '2d' } }
589-
}
590-
}
591-
];
592-
593-
for (const { description, input, output } of testCases) {
594-
it(`should parse index options correctly when input is: ${description}`, () => {
595-
const real_output = parseIndexOptions(input);
596-
expect(real_output).to.eql(output);
597-
});
598-
}
599-
});
600529
});

0 commit comments

Comments
 (0)