Skip to content

Commit 232bf3c

Browse files
authored
fix(NODE-6029): update types for collection listing indexes (#4072)
1 parent 67d7bab commit 232bf3c

File tree

5 files changed

+154
-17
lines changed

5 files changed

+154
-17
lines changed

src/collection.ts

+32-10
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ import type {
5252
CreateIndexesOptions,
5353
DropIndexesOptions,
5454
IndexDescription,
55-
IndexDirection,
55+
IndexDescriptionCompact,
56+
IndexDescriptionInfo,
5657
IndexInformationOptions,
5758
IndexSpecification,
5859
ListIndexesOptions
@@ -695,8 +696,23 @@ export class Collection<TSchema extends Document = Document> {
695696
*
696697
* @param options - Optional settings for the command
697698
*/
698-
async indexInformation(options?: IndexInformationOptions): Promise<Document> {
699-
return await this.indexes({ ...options, full: options?.full ?? false });
699+
indexInformation(
700+
options: IndexInformationOptions & { full: true }
701+
): Promise<IndexDescriptionInfo[]>;
702+
indexInformation(
703+
options: IndexInformationOptions & { full?: false }
704+
): Promise<IndexDescriptionCompact>;
705+
indexInformation(
706+
options: IndexInformationOptions
707+
): Promise<IndexDescriptionCompact | IndexDescriptionInfo[]>;
708+
indexInformation(): Promise<IndexDescriptionCompact>;
709+
async indexInformation(
710+
options?: IndexInformationOptions
711+
): Promise<IndexDescriptionCompact | IndexDescriptionInfo[]> {
712+
return await this.indexes({
713+
...options,
714+
full: options?.full ?? false
715+
});
700716
}
701717

702718
/**
@@ -800,19 +816,25 @@ export class Collection<TSchema extends Document = Document> {
800816
*
801817
* @param options - Optional settings for the command
802818
*/
803-
async indexes(options?: IndexInformationOptions): Promise<Document[]> {
804-
const indexes = await this.listIndexes(options).toArray();
819+
indexes(options: IndexInformationOptions & { full?: true }): Promise<IndexDescriptionInfo[]>;
820+
indexes(options: IndexInformationOptions & { full: false }): Promise<IndexDescriptionCompact>;
821+
indexes(
822+
options: IndexInformationOptions
823+
): Promise<IndexDescriptionCompact | IndexDescriptionInfo[]>;
824+
indexes(options?: ListIndexesOptions): Promise<IndexDescriptionInfo[]>;
825+
async indexes(
826+
options?: IndexInformationOptions
827+
): Promise<IndexDescriptionCompact | IndexDescriptionInfo[]> {
828+
const indexes: IndexDescriptionInfo[] = await this.listIndexes(options).toArray();
805829
const full = options?.full ?? true;
806830
if (full) {
807831
return indexes;
808832
}
809833

810-
const object: Record<
811-
string,
812-
Array<[name: string, direction: IndexDirection]>
813-
> = Object.fromEntries(indexes.map(({ name, key }) => [name, Object.entries(key)]));
834+
const object: IndexDescriptionCompact = Object.fromEntries(
835+
indexes.map(({ name, key }) => [name, Object.entries(key)])
836+
);
814837

815-
// @ts-expect-error TODO(NODE-6029): fix return type of `indexes()` and `indexInformation()`
816838
return object;
817839
}
818840

src/db.ts

+19-1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ import { executeOperation } from './operations/execute_operation';
2525
import {
2626
CreateIndexesOperation,
2727
type CreateIndexesOptions,
28+
type IndexDescriptionCompact,
29+
type IndexDescriptionInfo,
2830
type IndexInformationOptions,
2931
type IndexSpecification
3032
} from './operations/indexes';
@@ -485,7 +487,23 @@ export class Db {
485487
* @param name - The name of the collection.
486488
* @param options - Optional settings for the command
487489
*/
488-
async indexInformation(name: string, options?: IndexInformationOptions): Promise<Document> {
490+
indexInformation(
491+
name: string,
492+
options: IndexInformationOptions & { full: true }
493+
): Promise<IndexDescriptionInfo[]>;
494+
indexInformation(
495+
name: string,
496+
options: IndexInformationOptions & { full?: false }
497+
): Promise<IndexDescriptionCompact>;
498+
indexInformation(
499+
name: string,
500+
options: IndexInformationOptions
501+
): Promise<IndexDescriptionCompact | IndexDescriptionInfo[]>;
502+
indexInformation(name: string): Promise<IndexDescriptionCompact>;
503+
async indexInformation(
504+
name: string,
505+
options?: IndexInformationOptions
506+
): Promise<IndexDescriptionCompact | IndexDescriptionInfo[]> {
489507
return await this.collection(name).indexInformation(resolveOptions(this, options));
490508
}
491509

src/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,8 @@ export type {
471471
CreateIndexesOptions,
472472
DropIndexesOptions,
473473
IndexDescription,
474+
IndexDescriptionCompact,
475+
IndexDescriptionInfo,
474476
IndexDirection,
475477
IndexSpecification,
476478
ListIndexesOptions

src/operations/indexes.ts

+12
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,18 @@ function resolveIndexDescription(
214214
);
215215
}
216216

217+
/**
218+
* @public
219+
* The index information returned by the listIndexes command. https://www.mongodb.com/docs/manual/reference/command/listIndexes/#mongodb-dbcommand-dbcmd.listIndexes
220+
*/
221+
export type IndexDescriptionInfo = Omit<IndexDescription, 'key' | 'version'> & {
222+
key: { [key: string]: IndexDirection };
223+
v?: IndexDescription['version'];
224+
} & Document;
225+
226+
/** @public */
227+
export type IndexDescriptionCompact = Record<string, [name: string, direction: IndexDirection][]>;
228+
217229
/**
218230
* @internal
219231
*

test/types/indexes_test-d.ts

+89-6
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,99 @@
1-
import { expectType } from 'tsd';
1+
import { expectAssignable, expectType } from 'tsd';
22

3-
import { type Document, MongoClient } from '../../src';
3+
import { type IndexInformationOptions, MongoClient } from '../../src';
4+
import { type IndexDescriptionCompact, type IndexDescriptionInfo } from '../mongodb';
45

56
const client = new MongoClient('');
67
const db = client.db('test');
78
const collection = db.collection('test.find');
89

9-
// Promise variant testing
10-
expectType<Promise<Document[]>>(collection.indexes());
11-
expectType<Promise<Document[]>>(collection.indexes({}));
10+
const exampleFullIndexes: IndexDescriptionInfo[] = [
11+
{ v: 2, key: { _id: 1 }, name: '_id_' },
12+
{ v: 2, key: { listingName: 'hashed' }, name: 'listingName_hashed' },
13+
{
14+
v: 2,
15+
key: { 'auctionDetails.listingId': 1 },
16+
name: 'auctionDetails_listingId_1',
17+
unique: true
18+
}
19+
];
20+
const exampleCompactIndexes: IndexDescriptionCompact = {
21+
_id_: [['_id', 1]],
22+
listingName_hashed: [['listingName', 'hashed']],
23+
auctionDetails_listingId_1: [['auctionDetails.listingId', 1]]
24+
};
25+
26+
const ambiguousFullness = Math.random() > 0.5;
27+
28+
// test Collection.prototype.indexes
29+
30+
const defaultIndexes = await collection.indexes();
31+
const emptyOptionsIndexes = await collection.indexes({});
32+
const fullIndexes = await collection.indexes({ full: true });
33+
const notFullIndexes = await collection.indexes({ full: false });
34+
const ambiguousIndexes = await collection.indexes({ full: ambiguousFullness });
35+
36+
expectAssignable<typeof fullIndexes>(exampleFullIndexes);
37+
expectAssignable<typeof ambiguousIndexes>(exampleFullIndexes);
38+
expectAssignable<typeof ambiguousIndexes>(exampleCompactIndexes);
39+
expectAssignable<typeof notFullIndexes>(exampleCompactIndexes);
40+
41+
expectType<IndexDescriptionInfo[]>(defaultIndexes);
42+
expectType<IndexDescriptionInfo[]>(emptyOptionsIndexes);
43+
expectType<IndexDescriptionInfo[]>(fullIndexes);
44+
expectType<IndexDescriptionCompact>(notFullIndexes);
45+
expectType<IndexDescriptionInfo[] | IndexDescriptionCompact>(ambiguousIndexes);
46+
47+
// test Collection.prototype.indexInformation
48+
49+
const defaultIndexInfo = await collection.indexInformation();
50+
const emptyOptionsIndexInfo = await collection.indexInformation({});
51+
const fullIndexInfo = await collection.indexInformation({ full: true });
52+
const notFullIndexInfo = await collection.indexInformation({ full: false });
53+
const ambiguousIndexInfo = await collection.indexInformation({ full: ambiguousFullness });
54+
55+
expectAssignable<typeof fullIndexInfo>(exampleFullIndexes);
56+
expectAssignable<typeof ambiguousIndexInfo>(exampleFullIndexes);
57+
expectAssignable<typeof ambiguousIndexInfo>(exampleCompactIndexes);
58+
expectAssignable<typeof notFullIndexInfo>(exampleCompactIndexes);
59+
60+
expectType<IndexDescriptionCompact>(defaultIndexInfo);
61+
expectType<IndexDescriptionCompact>(emptyOptionsIndexInfo);
62+
expectType<IndexDescriptionInfo[]>(fullIndexInfo);
63+
expectType<IndexDescriptionCompact>(notFullIndexInfo);
64+
expectType<IndexDescriptionInfo[] | IndexDescriptionCompact>(ambiguousIndexInfo);
1265

1366
// Explicit check for iterable result
1467
for (const index of await collection.indexes()) {
15-
expectType<Document>(index);
68+
expectType<IndexDescriptionInfo>(index);
1669
}
70+
71+
// test Db.prototype.indexInformation
72+
73+
const dbDefaultIndexInfo = await db.indexInformation('some-collection');
74+
const dbEmptyOptionsIndexInfo = await db.indexInformation('some-collection', {});
75+
const dbFullIndexInfo = await db.indexInformation('some-collection', { full: true });
76+
const dbNotFullIndexInfo = await db.indexInformation('some-collection', { full: false });
77+
const dbAmbiguousIndexInfo = await db.indexInformation('some-collection', {
78+
full: ambiguousFullness
79+
});
80+
81+
expectAssignable<typeof dbFullIndexInfo>(exampleFullIndexes);
82+
expectAssignable<typeof dbAmbiguousIndexInfo>(exampleFullIndexes);
83+
expectAssignable<typeof dbAmbiguousIndexInfo>(exampleCompactIndexes);
84+
85+
expectType<IndexDescriptionCompact>(dbDefaultIndexInfo);
86+
expectType<IndexDescriptionCompact>(dbEmptyOptionsIndexInfo);
87+
expectType<IndexDescriptionInfo[]>(dbFullIndexInfo);
88+
expectType<IndexDescriptionCompact>(dbNotFullIndexInfo);
89+
expectType<IndexDescriptionInfo[] | IndexDescriptionCompact>(dbAmbiguousIndexInfo);
90+
91+
// test indexInformation with non-literal options
92+
const options: IndexInformationOptions = {};
93+
const indexInfo = await db.collection('some-collection').indexInformation(options);
94+
const indexes = await db.collection('some-collection').indexes(options);
95+
const indexDbInfo = await db.indexInformation('some-collection', options);
96+
97+
expectType<IndexDescriptionCompact | IndexDescriptionInfo[]>(indexInfo);
98+
expectType<IndexDescriptionCompact | IndexDescriptionInfo[]>(indexes);
99+
expectType<IndexDescriptionCompact | IndexDescriptionInfo[]>(indexDbInfo);

0 commit comments

Comments
 (0)