From 3e7547ec065a5c14eeb90322a4180584abe00dca Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Fri, 6 Aug 2021 15:17:17 +0200 Subject: [PATCH 1/2] chore(shell-api): make coll.find() an async function This is in preparation for MONGOSH-537, where it will make things a bit easier if we have the liberty to make async calls inside all methods that perform interactions with the database (i.e. fetching `_baseOptions` can be an async operation). Also tighten up some types in the tests along with this. --- packages/shell-api/src/collection.ts | 4 +- packages/shell-api/src/database.ts | 4 +- packages/shell-api/src/explainable.spec.ts | 8 +- packages/shell-api/src/explainable.ts | 5 +- .../src/field-level-encryption.spec.ts | 12 +-- .../shell-api/src/field-level-encryption.ts | 9 ++- packages/shell-api/src/helpers.ts | 78 +++++++++---------- packages/shell-api/src/integration.spec.ts | 63 +++++++-------- packages/shell-api/src/mongo.spec.ts | 2 +- packages/shell-api/src/mongo.ts | 2 +- packages/shell-api/src/result.ts | 10 +-- packages/shell-api/src/shard.spec.ts | 12 +-- packages/shell-api/src/shard.ts | 2 +- 13 files changed, 106 insertions(+), 105 deletions(-) diff --git a/packages/shell-api/src/collection.ts b/packages/shell-api/src/collection.ts index dfc1b4b55f..46d722a491 100644 --- a/packages/shell-api/src/collection.ts +++ b/packages/shell-api/src/collection.ts @@ -405,9 +405,11 @@ export default class Collection extends ShellApiWithMongoClass { * * @returns {Cursor} The promise of the cursor. */ + // eslint-disable-next-line @typescript-eslint/require-await @returnType('Cursor') @apiVersions([1]) - find(query?: Document, projection?: Document, options: FindOptions = {}): Cursor { + @returnsPromise + async find(query?: Document, projection?: Document, options: FindOptions = {}): Promise { if (projection) { options.projection = projection; } diff --git a/packages/shell-api/src/database.ts b/packages/shell-api/src/database.ts index 2abb082c91..10d800cffe 100644 --- a/packages/shell-api/src/database.ts +++ b/packages/shell-api/src/database.ts @@ -1351,8 +1351,8 @@ export default class Database extends ShellApiWithMongoClass { result.usedMB = olStats.size / (1024 * 1024); result.usedMB = Math.ceil(result.usedMB * 100) / 100; - const first = await ol.find().sort({ $natural: 1 }).limit(1).tryNext(); - const last = await ol.find().sort({ $natural: -1 }).limit(1).tryNext(); + const first = await (await ol.find()).sort({ $natural: 1 }).limit(1).tryNext(); + const last = await (await ol.find()).sort({ $natural: -1 }).limit(1).tryNext(); if (first === null || last === null) { throw new MongoshRuntimeError( 'objects not found in local.oplog.$main -- is this a new and empty db instance?', diff --git a/packages/shell-api/src/explainable.spec.ts b/packages/shell-api/src/explainable.spec.ts index ea6728abe9..32e54a04f3 100644 --- a/packages/shell-api/src/explainable.spec.ts +++ b/packages/shell-api/src/explainable.spec.ts @@ -26,7 +26,7 @@ describe('Explainable', () => { it('attributes', () => { expect(signatures.Explainable.attributes.find).to.deep.equal({ type: 'function', - returnsPromise: false, + returnsPromise: true, deprecated: false, returnType: 'ExplainableCursor', platforms: ALL_PLATFORMS, @@ -103,15 +103,15 @@ describe('Explainable', () => { describe('find', () => { let cursorStub; let explainResult; - beforeEach(() => { + beforeEach(async() => { explainResult = { ok: 1 }; const cursorSpy = { explain: sinon.spy(() => explainResult) } as unknown; - collection.find = sinon.spy(() => (cursorSpy as Cursor)); + collection.find = sinon.spy(() => Promise.resolve(cursorSpy as Cursor)); - cursorStub = explainable.find( + cursorStub = await explainable.find( { query: 1 }, { projection: 1 } ); diff --git a/packages/shell-api/src/explainable.ts b/packages/shell-api/src/explainable.ts index 3105e1dad0..68f34aa41f 100644 --- a/packages/shell-api/src/explainable.ts +++ b/packages/shell-api/src/explainable.ts @@ -85,10 +85,11 @@ export default class Explainable extends ShellApiWithMongoClass { @returnType('ExplainableCursor') @apiVersions([1]) - find(query?: Document, projection?: Document): ExplainableCursor { + @returnsPromise + async find(query?: Document, projection?: Document): Promise { this._emitExplainableApiCall('find', { query, projection }); - const cursor = this._collection.find(query, projection); + const cursor = await this._collection.find(query, projection); return new ExplainableCursor(this._mongo, cursor, this._verbosity); } diff --git a/packages/shell-api/src/field-level-encryption.spec.ts b/packages/shell-api/src/field-level-encryption.spec.ts index 81be56b5b7..343d8a7112 100644 --- a/packages/shell-api/src/field-level-encryption.spec.ts +++ b/packages/shell-api/src/field-level-encryption.spec.ts @@ -287,29 +287,29 @@ describe('Field Level Encryption', () => { }); }); describe('getKey', () => { - it('calls find on key coll', () => { + it('calls find on key coll', async() => { const c = { cursor: 1 } as any; sp.find.returns(c); - const result = keyVault.getKey(KEY_ID); + const result = await keyVault.getKey(KEY_ID); expect(sp.find).to.have.been.calledOnceWithExactly(DB, COLL, { _id: KEY_ID }, {}); expect(result._cursor).to.deep.equal(c); }); }); describe('getKeyByAltName', () => { - it('calls find on key coll', () => { + it('calls find on key coll', async() => { const c = { cursor: 1 } as any; const keyaltname = 'abc'; sp.find.returns(c); - const result = keyVault.getKeyByAltName(keyaltname); + const result = await keyVault.getKeyByAltName(keyaltname); expect(sp.find).to.have.been.calledOnceWithExactly(DB, COLL, { keyAltNames: keyaltname }, {}); expect(result._cursor).to.deep.equal(c); }); }); describe('getKeys', () => { - it('calls find on key coll', () => { + it('calls find on key coll', async() => { const c = { cursor: 1 } as any; sp.find.returns(c); - const result = keyVault.getKeys(); + const result = await keyVault.getKeys(); expect(sp.find).to.have.been.calledOnceWithExactly(DB, COLL, {}, {}); expect(result._cursor).to.deep.equal(c); }); diff --git a/packages/shell-api/src/field-level-encryption.ts b/packages/shell-api/src/field-level-encryption.ts index cb10f8a821..c048dac34d 100644 --- a/packages/shell-api/src/field-level-encryption.ts +++ b/packages/shell-api/src/field-level-encryption.ts @@ -179,21 +179,24 @@ export class KeyVault extends ShellApiWithMongoClass { @returnType('Cursor') @apiVersions([1]) - getKey(keyId: BinaryType): Cursor { + @returnsPromise + async getKey(keyId: BinaryType): Promise { assertArgsDefinedType([keyId], [true], 'KeyVault.getKey'); return this._keyColl.find({ '_id': keyId }); } @returnType('Cursor') @apiVersions([1]) - getKeyByAltName(keyAltName: string): Cursor { + @returnsPromise + async getKeyByAltName(keyAltName: string): Promise { assertArgsDefinedType([keyAltName], ['string'], 'KeyVault.getKeyByAltName'); return this._keyColl.find({ 'keyAltNames': keyAltName }); } @returnType('Cursor') @apiVersions([1]) - getKeys(): Cursor { + @returnsPromise + async getKeys(): Promise { return this._keyColl.find({}); } diff --git a/packages/shell-api/src/helpers.ts b/packages/shell-api/src/helpers.ts index 8f62de873f..9a36f1ccc9 100644 --- a/packages/shell-api/src/helpers.ts +++ b/packages/shell-api/src/helpers.ts @@ -170,7 +170,7 @@ export function processDigestPassword( * @param configDB * @param verbose */ -export async function getPrintableShardStatus(db: Database, verbose: boolean): Promise { +export async function getPrintableShardStatus(db: Database, verbose: boolean): Promise { const result = {} as any; // use array to maintain order // configDB is a DB object that contains the sharding metadata of interest. @@ -185,8 +185,8 @@ export async function getPrintableShardStatus(db: Database, verbose: boolean): P const [ version, shards, mostRecentMongos ] = await Promise.all([ versionColl.findOne(), - shardsColl.find().sort({ _id: 1 }).toArray(), - mongosColl.find().sort({ ping: -1 }).limit(1).tryNext() + shardsColl.find().then(cursor => cursor.sort({ _id: 1 }).toArray()), + mongosColl.find().then(cursor => cursor.sort({ ping: -1 }).limit(1).tryNext()) ]); if (version === null) { throw new MongoshInvalidInputError( @@ -228,8 +228,8 @@ export async function getPrintableShardStatus(db: Database, verbose: boolean): P }; if (verbose) { - result[mongosAdjective] = await mongosColl - .find(recentMongosQuery) + result[mongosAdjective] = await (await mongosColl + .find(recentMongosQuery)) .sort({ ping: -1 }) .toArray(); } else { @@ -277,7 +277,7 @@ export async function getPrintableShardStatus(db: Database, verbose: boolean): P (async(): Promise => { // Output the list of active migrations type Lock = { _id: string; when: Date }; - const activeLocks: Lock[] = await configDB.getCollection('locks').find({ state: { $eq: 2 } }).toArray() as Lock[]; + const activeLocks: Lock[] = await (await configDB.getCollection('locks').find({ state: { $eq: 2 } })).toArray() as Lock[]; if (activeLocks?.length > 0) { balancerRes['Collections with active migrations'] = activeLocks.map((lock) => { return `${lock._id} started at ${lock.when}`; @@ -300,7 +300,7 @@ export async function getPrintableShardStatus(db: Database, verbose: boolean): P if (versionHasActionlog) { // Review config.actionlog for errors - const balErrs = await configDB.getCollection('actionlog').find({ what: 'balancer.round' }).sort({ time: -1 }).limit(5).toArray(); + const balErrs = await (await configDB.getCollection('actionlog').find({ what: 'balancer.round' })).sort({ time: -1 }).limit(5).toArray(); const actionReport = { count: 0, lastErr: '', lastTime: ' ' }; if (balErrs !== null) { balErrs.forEach((r: any) => { @@ -393,7 +393,7 @@ export async function getPrintableShardStatus(db: Database, verbose: boolean): P const dbRes: any[] = []; result.databases = dbRes; - const databases = await configDB.getCollection('databases').find().sort({ name: 1 }).toArray(); + const databases = await (await configDB.getCollection('databases').find()).sort({ name: 1 }).toArray(); // Special case the config db, since it doesn't have a record in config.databases. databases.push({ '_id': 'config', 'primary': 'config', 'partitioned': true }); @@ -405,8 +405,8 @@ export async function getPrintableShardStatus(db: Database, verbose: boolean): P const escapeRegex = (string: string): string => { return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); }; - const colls = await configDB.getCollection('collections') - .find({ _id: new RegExp('^' + escapeRegex(db._id) + '\\.') }) + const colls = await (await configDB.getCollection('collections') + .find({ _id: new RegExp('^' + escapeRegex(db._id) + '\\.') })) .sort({ _id: 1 }) .toArray(); @@ -441,45 +441,39 @@ export async function getPrintableShardStatus(db: Database, verbose: boolean): P // NOTE: this will return the chunk info as a string, and will print ugly BSON if (totalChunks < 20 || verbose) { - (await chunksColl.find(chunksCollMatch) - .sort({ min: 1 }).toArray()) - .forEach((chunk: any) => { - const c = { - min: chunk.min, - max: chunk.max, - 'on shard': chunk.shard, - 'last modified': chunk.lastmod - } as any; - // Displaying a full, multi-line output for each chunk is a bit verbose, - // even if there are only a few chunks. Where supported, we use a custom - // inspection function to inspect a copy of this object with an unlimited - // line break length (i.e. all objects on a single line). - Object.defineProperty(c, Symbol.for('nodejs.util.inspect.custom'), { - value: function(depth: number, options: any): string { - return inspect({ ...this }, { ...options, breakLength: Infinity }); - }, - writable: true, - configurable: true - }); - if (chunk.jumbo) c.jumbo = 'yes'; - chunksRes.push(c); + for await (const chunk of (await chunksColl.find(chunksCollMatch)).sort({ min: 1 })) { + const c = { + min: chunk.min, + max: chunk.max, + 'on shard': chunk.shard, + 'last modified': chunk.lastmod + } as any; + // Displaying a full, multi-line output for each chunk is a bit verbose, + // even if there are only a few chunks. Where supported, we use a custom + // inspection function to inspect a copy of this object with an unlimited + // line break length (i.e. all objects on a single line). + Object.defineProperty(c, Symbol.for('nodejs.util.inspect.custom'), { + value: function(depth: number, options: any): string { + return inspect({ ...this }, { ...options, breakLength: Infinity }); + }, + writable: true, + configurable: true }); + if (chunk.jumbo) c.jumbo = 'yes'; + chunksRes.push(c); + } } else { chunksRes.push('too many chunks to print, use verbose if you want to force print'); } const tagsRes: any[] = []; - (await configDB.getCollection('tags') - .find(chunksCollMatch) - .sort({ min: 1 }) - .toArray()) - .forEach((tag: any) => { - tagsRes.push({ - tag: tag.tag, - min: tag.min, - max: tag.max - }); + for await (const tag of (await configDB.getCollection('tags').find(chunksCollMatch)).sort({ min: 1 })) { + tagsRes.push({ + tag: tag.tag, + min: tag.min, + max: tag.max }); + } collRes.chunks = chunksRes; collRes.tags = tagsRes; return [coll._id, collRes]; diff --git a/packages/shell-api/src/integration.spec.ts b/packages/shell-api/src/integration.spec.ts index 6eee055cad..127036d39b 100644 --- a/packages/shell-api/src/integration.spec.ts +++ b/packages/shell-api/src/integration.spec.ts @@ -1,13 +1,14 @@ import { expect } from 'chai'; import { CliServiceProvider } from '../../service-provider-server'; // avoid cyclic dep just for test import ShellInternalState from './shell-internal-state'; -import Cursor from './cursor'; +import type Cursor from './cursor'; import Explainable from './explainable'; -import Collection from './collection'; -import AggregationCursor from './aggregation-cursor'; +import type Database from './database'; +import type Collection from './collection'; +import type AggregationCursor from './aggregation-cursor'; import { startTestServer, skipIfServerVersion, skipIfApiStrict } from '../../../testing/integration-testing-hooks'; import { toShellResult, Topologies } from './index'; -import { Document } from '@mongosh/service-provider-core'; +import type { Document } from '@mongosh/service-provider-core'; import { ShellUserConfig } from '@mongosh/types'; import { EventEmitter, once } from 'events'; @@ -49,7 +50,7 @@ describe('Shell API (integration)', function() { expect(collectionNames).to.not.include(collectionName); }; - const loadQueryCache = async(collection): Promise => { + const loadQueryCache = async(collection: Collection): Promise => { const res = await collection.insertMany([ { '_id': 1, 'item': 'abc', 'price': 12, 'quantity': 2, 'type': 'apparel' }, { '_id': 2, 'item': 'jkl', 'price': 20, 'quantity': 1, 'type': 'electronics' }, @@ -64,13 +65,13 @@ describe('Shell API (integration)', function() { expect(await collection.createIndex({ quantity: 1 })).to.not.be.undefined; expect(await collection.createIndex({ quantity: 1, type: 1 })).to.not.be.undefined; - await collection.find( { item: 'abc', price: { $gte: 10 } } ).toArray(); - await collection.find( { item: 'abc', price: { $gte: 5 } } ).toArray(); - await collection.find( { quantity: { $gte: 20 } } ).toArray(); - await collection.find( { quantity: { $gte: 5 }, type: 'apparel' } ).toArray(); + await (await collection.find( { item: 'abc', price: { $gte: 10 } } )).toArray(); + await (await collection.find( { item: 'abc', price: { $gte: 5 } } )).toArray(); + await (await collection.find( { quantity: { $gte: 20 } } )).toArray(); + await (await collection.find( { quantity: { $gte: 5 }, type: 'apparel' } )).toArray(); }; - const loadMRExample = async(collection): Promise => { + const loadMRExample = async(collection: Collection): Promise => { const res = await collection.insertMany([ { _id: 1, cust_id: 'Ant O. Knee', ord_date: new Date('2020-03-01'), price: 25, items: [ { sku: 'oranges', qty: 5, price: 2.5 }, { sku: 'apples', qty: 5, price: 2.5 } ], status: 'A' }, { _id: 2, cust_id: 'Ant O. Knee', ord_date: new Date('2020-03-08'), price: 70, items: [ { sku: 'oranges', qty: 8, price: 2.5 }, { sku: 'chocolates', qty: 5, price: 10 } ], status: 'A' }, @@ -98,7 +99,7 @@ describe('Shell API (integration)', function() { let shellApi; let mongo; let dbName; - let database; + let database: Database; let collection: Collection; let collectionName; @@ -134,7 +135,7 @@ describe('Shell API (integration)', function() { describe('when calling it after find', () => { it('returns next batch of docs', async() => { - collection.find({}, { _id: 0 }); + await collection.find({}, { _id: 0 }); await shellApi.it(); expect({ ...await shellApi.it() }).to.deep.equal({ cursorHasMore: false, @@ -146,8 +147,8 @@ describe('Shell API (integration)', function() { describe('when calling limit after skip', () => { let cursor: Cursor; - beforeEach(() => { - cursor = collection.find({}, { _id: 0 }) + beforeEach(async() => { + cursor = (await collection.find({}, { _id: 0 })) .skip(1) .limit(1); }); @@ -939,7 +940,7 @@ describe('Shell API (integration)', function() { const longOne = new serviceProvider.bsonLibrary.Long('1'); await serviceProvider.insertOne(dbName, collectionName, { longOne, _id: 0 }); - const cursor = collection.find({}); + const cursor = await collection.find({}); expect(await cursor.toArray()).to.deep.equal([{ longOne, _id: 0 }]); }); @@ -948,7 +949,7 @@ describe('Shell API (integration)', function() { const longOne = new serviceProvider.bsonLibrary.Long('1'); await serviceProvider.insertOne(dbName, collectionName, { longOne, _id: 0 }); - const cursor = collection.find({}, {}, { promoteLongs: true }); + const cursor = await collection.find({}, {}, { promoteLongs: true }); expect(await cursor.toArray()).to.deep.equal([{ longOne: 1, _id: 0 }]); }); @@ -1226,7 +1227,7 @@ describe('Shell API (integration)', function() { skipIfApiStrict(); it('includes an entry for ping', async() => { - const { ping } = (await database.listCommands()).value; + const { ping } = (await database.listCommands()).value as any; expect(ping.help).to.be.a('string'); expect(ping.adminOnly).to.be.a('boolean'); expect(ping.secondaryOk).to.be.a('boolean'); @@ -1247,7 +1248,7 @@ describe('Shell API (integration)', function() { describe('find', () => { it('returns a cursor that has the explain as result of toShellResult', async() => { - const cursor = explainable.find().skip(1).limit(1); + const cursor = (await explainable.find()).skip(1).limit(1); const result = await toShellResult(cursor); expect(result.printable).to.include.all.keys([ 'ok', @@ -1516,7 +1517,7 @@ describe('Shell API (integration)', function() { describe('invalid verbosity', () => { it('rejects with a server error', async() => { try { - await collection.find().explain('foo'); + await (await collection.find()).explain('foo'); expect.fail('missed exception'); } catch (err) { expect(err.name).to.equal('MongoServerError'); @@ -1786,7 +1787,7 @@ describe('Shell API (integration)', function() { .collation({ locale: 'fr', strength: 1 }) .update({ $set: { customers: 20 } }) .execute(); - expect(await collection.find({ name: 'cafe' }, { _id: 0 }).toArray()).to.deep.equal([{ + expect(await (await collection.find({ name: 'cafe' }, { _id: 0 })).toArray()).to.deep.equal([{ name: 'cafe', customers: 20 }]); }); @@ -2021,7 +2022,7 @@ describe('Shell API (integration)', function() { }`; const result = await collection.mapReduce(mapFn, reduceFn, 'map_reduce_example'); expect(result.ok).to.equal(1); - const outRes = await database.map_reduce_example.find().sort({ _id: 1 }).toArray(); + const outRes = await (await database.getCollection('map_reduce_example').find()).sort({ _id: 1 }).toArray(); expect(outRes).to.deep.equal([ { '_id': 'Ant O. Knee', 'value': 95 }, { '_id': 'Busby Bee', 'value': 125 }, @@ -2040,7 +2041,7 @@ describe('Shell API (integration)', function() { const result = await collection.mapReduce(mapFn, reduceFn.toString(), 'map_reduce_example'); expect(result.ok).to.equal(1); expect(result.result).to.equal('map_reduce_example'); - const outRes = await database.map_reduce_example.find().sort({ _id: 1 }).toArray(); + const outRes = await (await database.getCollection('map_reduce_example').find()).sort({ _id: 1 }).toArray(); expect(outRes).to.deep.equal([ { '_id': 'Ant O. Knee', 'value': 95 }, { '_id': 'Busby Bee', 'value': 125 }, @@ -2176,30 +2177,30 @@ describe('Shell API (integration)', function() { setConfig(key: string, value: any) { cfg[key] = value; return 'success'; }, listConfigOptions() { return Object.keys(cfg); } }); - expect((await collection.find()._it()).documents).to.have.lengthOf(20); + expect((await (await collection.find())._it()).documents).to.have.lengthOf(20); }); it('config changes affect displayBatchSize', async() => { await shellApi.config.set('displayBatchSize', 10); - expect((await collection.find()._it()).documents).to.have.lengthOf(10); + expect((await (await collection.find())._it()).documents).to.have.lengthOf(10); }); it('DBQuery.shellBatchSize takes precedence over config', async() => { await shellApi.config.set('displayBatchSize', 10); shellApi.DBQuery.shellBatchSize = 30; expect(shellApi.DBQuery.shellBatchSize).to.equal(30); - expect((await collection.find()._it()).documents).to.have.lengthOf(30); + expect((await (await collection.find())._it()).documents).to.have.lengthOf(30); }); it('cursor.batchSize does not override config displayBatchSize', async() => { await shellApi.config.set('displayBatchSize', 10); - expect((await collection.find().batchSize(50)._it()).documents).to.have.lengthOf(10); + expect((await (await collection.find()).batchSize(50)._it()).documents).to.have.lengthOf(10); }); it('cursor.batchSize does not override DBQuery.shellBatchSize', async() => { shellApi.DBQuery.shellBatchSize = 5; expect(shellApi.DBQuery.shellBatchSize).to.equal(5); - expect((await collection.find().batchSize(50)._it()).documents).to.have.lengthOf(5); + expect((await (await collection.find()).batchSize(50)._it()).documents).to.have.lengthOf(5); }); }); @@ -2210,13 +2211,13 @@ describe('Shell API (integration)', function() { it('forEach() iterates over input but does not return anything', async() => { let value = 0; - const result = await collection.find().forEach(({ i }) => { value += i; }); + const result = await (await collection.find()).forEach(({ i }) => { value += i; }); expect(result).to.equal(undefined); expect(value).to.equal(45); }); it('map() iterates over input and changes documents in-place', async() => { - const cursor = collection.find(); + const cursor = await collection.find(); cursor.map(({ i }) => ({ j: i })); expect((await cursor._it()).documents[0]).to.deep.equal({ j: 0 }); }); @@ -2225,7 +2226,7 @@ describe('Shell API (integration)', function() { const error = new Error(); let calls = 0; try { - await collection.find().forEach(() => { calls++; throw error; }); + await (await collection.find()).forEach(() => { calls++; throw error; }); expect.fail('missed exception'); } catch (err) { expect(err).to.equal(error); @@ -2235,7 +2236,7 @@ describe('Shell API (integration)', function() { it('map() errors show up when reading the cursor', async() => { const error = new Error(); - const cursor = collection.find(); + const cursor = await collection.find(); let calls = 0; cursor.map(() => { calls++; throw error; }); for (let i = 0; i < 2; i++) { diff --git a/packages/shell-api/src/mongo.spec.ts b/packages/shell-api/src/mongo.spec.ts index 2b9d55c8c9..8191f4244d 100644 --- a/packages/shell-api/src/mongo.spec.ts +++ b/packages/shell-api/src/mongo.spec.ts @@ -283,7 +283,7 @@ describe('Mongo', () => { cursor.toArray.resolves(expectedResult); database.getCollection.returns(syscoll); syscoll.countDocuments.resolves(1); - syscoll.find.returns(cursor); + syscoll.find.resolves(cursor); const result = await mongo.show('profile'); expect(database.getCollection).to.have.been.calledWith('system.profile'); expect(syscoll.countDocuments).to.have.been.calledWith({}); diff --git a/packages/shell-api/src/mongo.ts b/packages/shell-api/src/mongo.ts index 57f417c0d9..9414446dc7 100644 --- a/packages/shell-api/src/mongo.ts +++ b/packages/shell-api/src/mongo.ts @@ -297,7 +297,7 @@ export default class Mongo extends ShellApiClass { const sysprof = this._internalState.currentDb.getCollection('system.profile'); const profiles = { count: await sysprof.countDocuments({}) } as Document; if (profiles.count !== 0) { - profiles.result = await sysprof.find({ millis: { $gt: 0 } }) + profiles.result = await (await sysprof.find({ millis: { $gt: 0 } })) .sort({ $natural: -1 }) .limit(5) .toArray(); diff --git a/packages/shell-api/src/result.ts b/packages/shell-api/src/result.ts index 83aaa4ba41..11e63411ac 100644 --- a/packages/shell-api/src/result.ts +++ b/packages/shell-api/src/result.ts @@ -3,10 +3,10 @@ import { shellApiType, asPrintable } from './enums'; import { Document, ObjectIdType } from '@mongosh/service-provider-core'; @shellApiClassDefault -export class CommandResult extends ShellApiValueClass { - value: unknown; +export class CommandResult extends ShellApiValueClass { + value: T; type: string; - constructor(type: string, value: unknown) { + constructor(type: string, value: T) { super(); this.type = type; this.value = value; @@ -16,11 +16,11 @@ export class CommandResult extends ShellApiValueClass { /** * Internal method to determine what is printed for this class. */ - [asPrintable](): unknown { + [asPrintable](): T { return this.value; } - toJSON(): unknown { + toJSON(): T { return this.value; } } diff --git a/packages/shell-api/src/shard.spec.ts b/packages/shell-api/src/shard.spec.ts index 94fbdfa8e1..4b6ad97ae6 100644 --- a/packages/shell-api/src/shard.spec.ts +++ b/packages/shell-api/src/shard.spec.ts @@ -1197,8 +1197,8 @@ describe('Shard', () => { describe('integration', () => { let serviceProvider: CliServiceProvider; - let internalState; - let sh; + let internalState: ShellInternalState; + let sh: Shard; const dbName = 'test'; const ns = `${dbName}.coll`; const shardId = 'rs-shard0'; @@ -1216,13 +1216,13 @@ describe('Shard', () => { sh = new Shard(internalState.currentDb); // check replset uninitialized - let members = await sh._database.getSiblingDB('config').getCollection('shards').find().sort({ _id: 1 }).toArray(); + let members = await (await sh._database.getSiblingDB('config').getCollection('shards').find()).sort({ _id: 1 }).toArray(); expect(members.length).to.equal(0); // add new shards expect((await sh.addShard(`${shardId}-0/${await rs0.hostport()}`)).shardAdded).to.equal(`${shardId}-0`); expect((await sh.addShard(`${shardId}-1/${await rs1.hostport()}`)).shardAdded).to.equal(`${shardId}-1`); - members = await sh._database.getSiblingDB('config').getCollection('shards').find().sort({ _id: 1 }).toArray(); + members = await (await sh._database.getSiblingDB('config').getCollection('shards').find()).sort({ _id: 1 }).toArray(); expect(members.length).to.equal(2); await sh._database.getSiblingDB(dbName).dropDatabase(); }); @@ -1282,8 +1282,8 @@ describe('Shard', () => { expect((await sh.status()).value.databases[1].collections[ns].shardKey).to.deep.equal({ key: 1 }); const db = internalState.currentDb.getSiblingDB(dbName); - await db.coll.insertMany([{ key: 'A', value: 10 }, { key: 'B', value: 20 }]); - const original = await db.coll.findOneAndUpdate({ key: 'A' }, { $set: { value: 30 } }); + await db.getCollection('coll').insertMany([{ key: 'A', value: 10 }, { key: 'B', value: 20 }]); + const original = await db.getCollection('coll').findOneAndUpdate({ key: 'A' }, { $set: { value: 30 } }); expect(original.key).to.equal('A'); expect(original.value).to.equal(10); diff --git a/packages/shell-api/src/shard.ts b/packages/shell-api/src/shard.ts index 67c9a2becb..4020bbd7d5 100644 --- a/packages/shell-api/src/shard.ts +++ b/packages/shell-api/src/shard.ts @@ -136,7 +136,7 @@ export default class Shard extends ShellApiWithMongoClass { @returnsPromise @apiVersions([1]) - async status(verbose = false): Promise { + async status(verbose = false): Promise> { const result = await getPrintableShardStatus(this._database, verbose); return new CommandResult('StatsResult', result); } From e029675aaa434121b3ea8cb93d7e7dc8d3b707ae Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Mon, 9 Aug 2021 11:44:42 +0200 Subject: [PATCH 2/2] fixup: test changes --- packages/shell-api/src/mongo.spec.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/shell-api/src/mongo.spec.ts b/packages/shell-api/src/mongo.spec.ts index 8191f4244d..af15747f77 100644 --- a/packages/shell-api/src/mongo.spec.ts +++ b/packages/shell-api/src/mongo.spec.ts @@ -714,7 +714,7 @@ describe('Mongo', () => { describe('integration', () => { const testServer = startTestServer('shared'); let serviceProvider; - let internalState; + let internalState: ShellInternalState; let uri: string; beforeEach(async() => { @@ -737,7 +737,7 @@ describe('Mongo', () => { const mongo = await internalState.shellApi.Mongo(uri, null, { api: { version: '1' } }); - await mongo.getDB('test').getCollection('coll').find().toArray(); + await (await mongo.getDB('test').getCollection('coll').find()).toArray(); expect.fail('missed exception'); } catch (err) { expect(err.name).to.match(/MongoServer(Selection)?Error/); @@ -755,7 +755,7 @@ describe('Mongo', () => { }); expect(mongo._apiOptions).to.deep.equal({ version: '1' }); // Does not throw, unlike the 4.4 test case above: - await mongo.getDB('test').getCollection('coll').find().toArray(); + await (await mongo.getDB('test').getCollection('coll').find()).toArray(); }); }); });