diff --git a/configs/tsconfig-mongosh/tsconfig.common.json b/configs/tsconfig-mongosh/tsconfig.common.json index ecca337371..1743c71bc0 100644 --- a/configs/tsconfig-mongosh/tsconfig.common.json +++ b/configs/tsconfig-mongosh/tsconfig.common.json @@ -14,7 +14,7 @@ "removeComments": true, "target": "es2018", "lib": ["es2019"], - "module": "commonjs", - "moduleResolution": "node" + "module": "node16", + "moduleResolution": "node16" } } diff --git a/package-lock.json b/package-lock.json index e05019ace9..7d6e48aec4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6444,17 +6444,6 @@ "url": "https://opencollective.com/node-fetch" } }, - "node_modules/@mongodb-js/dl-center": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@mongodb-js/dl-center/-/dl-center-1.3.0.tgz", - "integrity": "sha512-5fsbPhmok5uyTdr3G3wf8YUWJm/TQnBHBeqRQV4CsSW15MguAv8YEx8cF8YXB20G01izkHT72xkqb/Ry4SiHcg==", - "license": "Apache-2.0", - "dependencies": { - "ajv": "^6.12.5", - "aws-sdk": "^2.1441.0", - "node-fetch": "^2.6.7" - } - }, "node_modules/@mongodb-js/eslint-config-devtools": { "version": "0.9.9", "resolved": "https://registry.npmjs.org/@mongodb-js/eslint-config-devtools/-/eslint-config-devtools-0.9.9.tgz", @@ -6544,6 +6533,18 @@ "tar": "^6.1.15" } }, + "node_modules/@mongodb-js/mongodb-ts-autocomplete": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@mongodb-js/mongodb-ts-autocomplete/-/mongodb-ts-autocomplete-0.3.4.tgz", + "integrity": "sha512-HE34P91bhL6ZzlS9CxpsmqDW3Eg15CPHHHcNBmTb+ifA8xhnIk2vt4eCkqwxI6mxBry0JVRT3/N3bXK2pSYnBg==", + "license": "Apache-2.0", + "dependencies": { + "@mongodb-js/ts-autocomplete": "^0.3.3", + "mongodb-schema": "^12.6.2", + "node-cache": "^5.1.2", + "typescript": "^5.0.4" + } + }, "node_modules/@mongodb-js/monorepo-tools": { "version": "1.1.16", "resolved": "https://registry.npmjs.org/@mongodb-js/monorepo-tools/-/monorepo-tools-1.1.16.tgz", @@ -6620,6 +6621,20 @@ "node": ">=8" } }, + "node_modules/@mongodb-js/mql-typescript": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@mongodb-js/mql-typescript/-/mql-typescript-0.2.3.tgz", + "integrity": "sha512-5dB+DumMsQxcbn6zCf3K9MPaGJ46xEhVCtSPUnlwCbeC4RxMn9p9vNoNfKpWxLhqKIRhkeB21gilYgnm094m6A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bson": "^6.10.3", + "mongodb": "^6.9.0" + }, + "bin": { + "mql-typescript": "bin/runner.js" + } + }, "node_modules/@mongodb-js/oidc-http-server-pages": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@mongodb-js/oidc-http-server-pages/-/oidc-http-server-pages-1.1.3.tgz", @@ -6868,9 +6883,9 @@ } }, "node_modules/@mongodb-js/ts-autocomplete": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@mongodb-js/ts-autocomplete/-/ts-autocomplete-0.3.1.tgz", - "integrity": "sha512-2ui9y88PM+PIad/3htoGn/8kiNK8V4vVTrqicgAt1Bozt0AwCUqJFUfnpqf40eJVD20XbPWfeKPjPMPkA7SruQ==", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@mongodb-js/ts-autocomplete/-/ts-autocomplete-0.3.3.tgz", + "integrity": "sha512-G7Y9DRcz83ldJkHZjTWygngMPsYSihpiZQCwXgUS3Hd6sYWSOCrx0iHYog0uJwX89ghzraxhB1BAhsWXbdGCIg==", "license": "Apache-2.0", "dependencies": { "debug": "^4.4.0", @@ -34210,7 +34225,7 @@ "license": "Apache-2.0", "dependencies": { "@mongodb-js/mongodb-constants": "^0.10.1", - "@mongodb-js/mongodb-ts-autocomplete": "^0.2.5", + "@mongodb-js/mongodb-ts-autocomplete": "^0.3.4", "@mongosh/shell-api": "^3.13.0", "semver": "^7.5.4" }, @@ -34227,21 +34242,6 @@ "node": ">=14.15.1" } }, - "packages/autocomplete/node_modules/@mongodb-js/mongodb-ts-autocomplete": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/@mongodb-js/mongodb-ts-autocomplete/-/mongodb-ts-autocomplete-0.2.5.tgz", - "integrity": "sha512-9Os75QCF+lSLBP7Wank37bCrFTX27Y6GI4HP889TZ88ArLOyKpboS4BK43ARgB0Rg4/mhog8d7jT6OlVb6VwYA==", - "license": "Apache-2.0", - "dependencies": { - "@mongodb-js/ts-autocomplete": "^0.3.1", - "mongodb-schema": "^12.6.2", - "node-cache": "^5.1.2", - "typescript": "^5.0.4" - }, - "peerDependencies": { - "@mongosh/shell-api": "^3.11.0" - } - }, "packages/browser-repl": { "name": "@mongosh/browser-repl", "version": "3.13.0", @@ -34691,7 +34691,7 @@ }, "devDependencies": { "@mongodb-js/eslint-config-mongosh": "^1.0.0", - "@mongodb-js/mongodb-ts-autocomplete": "^0.2.5", + "@mongodb-js/mongodb-ts-autocomplete": "^0.3.4", "@mongodb-js/prettier-config-devtools": "^1.0.1", "@mongodb-js/tsconfig-mongosh": "^1.0.0", "@mongosh/types": "3.8.0", @@ -34705,22 +34705,6 @@ "node": ">=14.15.1" } }, - "packages/browser-runtime-core/node_modules/@mongodb-js/mongodb-ts-autocomplete": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/@mongodb-js/mongodb-ts-autocomplete/-/mongodb-ts-autocomplete-0.2.5.tgz", - "integrity": "sha512-9Os75QCF+lSLBP7Wank37bCrFTX27Y6GI4HP889TZ88ArLOyKpboS4BK43ARgB0Rg4/mhog8d7jT6OlVb6VwYA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@mongodb-js/ts-autocomplete": "^0.3.1", - "mongodb-schema": "^12.6.2", - "node-cache": "^5.1.2", - "typescript": "^5.0.4" - }, - "peerDependencies": { - "@mongosh/shell-api": "^3.11.0" - } - }, "packages/browser-runtime-electron": { "name": "@mongosh/browser-runtime-electron", "version": "3.13.0", @@ -34759,7 +34743,7 @@ "license": "Apache-2.0", "dependencies": { "@mongodb-js/devtools-github-repo": "^1.4.2", - "@mongodb-js/dl-center": "^1.3.0", + "@mongodb-js/dl-center": "^1.4.1", "@mongodb-js/mongodb-downloader": "^0.3.7", "@mongodb-js/monorepo-tools": "^1.1.16", "@mongodb-js/signing-utils": "^0.3.7", @@ -34812,6 +34796,59 @@ "node": ">= 16" } }, + "packages/build/node_modules/@mongodb-js/dl-center": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@mongodb-js/dl-center/-/dl-center-1.4.2.tgz", + "integrity": "sha512-2JNvj7fxZCrvnOvUyS84pyPkL5WLqPvdR+W+h6NnvlJ1zfv78JBf5zgLDa1OUXWeJx6itjd+kv+2omnPhF+D1Q==", + "license": "Apache-2.0", + "dependencies": { + "ajv": "^6.12.5", + "aws-sdk": "^2.1441.0", + "node-fetch": "^2.7.0" + } + }, + "packages/build/node_modules/@mongodb-js/dl-center/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "packages/build/node_modules/@mongodb-js/dl-center/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "license": "MIT" + }, + "packages/build/node_modules/@mongodb-js/dl-center/node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "packages/build/node_modules/@mongodb-js/signing-utils": { "version": "0.3.7", "resolved": "https://registry.npmjs.org/@mongodb-js/signing-utils/-/signing-utils-0.3.7.tgz", @@ -35605,7 +35642,8 @@ "devDependencies": { "@microsoft/api-extractor": "^7.39.3", "@mongodb-js/eslint-config-mongosh": "^1.0.0", - "@mongodb-js/mongodb-ts-autocomplete": "^0.2.5", + "@mongodb-js/mongodb-ts-autocomplete": "^0.3.4", + "@mongodb-js/mql-typescript": "^0.2.3", "@mongodb-js/prettier-config-devtools": "^1.0.1", "@mongodb-js/tsconfig-mongosh": "^1.0.0", "@mongosh/types": "3.8.0", @@ -35620,22 +35658,6 @@ "node": ">=14.15.1" } }, - "packages/shell-api/node_modules/@mongodb-js/mongodb-ts-autocomplete": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/@mongodb-js/mongodb-ts-autocomplete/-/mongodb-ts-autocomplete-0.2.5.tgz", - "integrity": "sha512-9Os75QCF+lSLBP7Wank37bCrFTX27Y6GI4HP889TZ88ArLOyKpboS4BK43ARgB0Rg4/mhog8d7jT6OlVb6VwYA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@mongodb-js/ts-autocomplete": "^0.3.1", - "mongodb-schema": "^12.6.2", - "node-cache": "^5.1.2", - "typescript": "^5.0.4" - }, - "peerDependencies": { - "@mongosh/shell-api": "^3.11.0" - } - }, "packages/shell-api/node_modules/mongodb-redact": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/mongodb-redact/-/mongodb-redact-1.1.5.tgz", diff --git a/packages/autocomplete/package.json b/packages/autocomplete/package.json index fdb5f5ed5b..085f0a87b9 100644 --- a/packages/autocomplete/package.json +++ b/packages/autocomplete/package.json @@ -45,7 +45,7 @@ "dependencies": { "@mongodb-js/mongodb-constants": "^0.10.1", "@mongosh/shell-api": "^3.13.0", - "@mongodb-js/mongodb-ts-autocomplete": "^0.2.5", + "@mongodb-js/mongodb-ts-autocomplete": "^0.3.4", "semver": "^7.5.4" } } diff --git a/packages/browser-runtime-core/package.json b/packages/browser-runtime-core/package.json index d191e4206f..f448bc9075 100644 --- a/packages/browser-runtime-core/package.json +++ b/packages/browser-runtime-core/package.json @@ -41,7 +41,7 @@ "@mongodb-js/eslint-config-mongosh": "^1.0.0", "@mongodb-js/prettier-config-devtools": "^1.0.1", "@mongodb-js/tsconfig-mongosh": "^1.0.0", - "@mongodb-js/mongodb-ts-autocomplete": "^0.2.5", + "@mongodb-js/mongodb-ts-autocomplete": "^0.3.4", "@mongosh/types": "3.8.0", "bson": "^6.10.3", "depcheck": "^1.4.7", diff --git a/packages/build/package.json b/packages/build/package.json index 774d42c94f..7c33e23a7b 100644 --- a/packages/build/package.json +++ b/packages/build/package.json @@ -65,7 +65,7 @@ }, "dependencies": { "@mongodb-js/devtools-github-repo": "^1.4.2", - "@mongodb-js/dl-center": "^1.3.0", + "@mongodb-js/dl-center": "^1.4.1", "@mongodb-js/mongodb-downloader": "^0.3.7", "@mongodb-js/monorepo-tools": "^1.1.16", "@mongodb-js/signing-utils": "^0.3.7", diff --git a/packages/build/src/download-center/config.ts b/packages/build/src/download-center/config.ts index 30a35c019c..f1ce43bfce 100644 --- a/packages/build/src/download-center/config.ts +++ b/packages/build/src/download-center/config.ts @@ -6,7 +6,7 @@ import { major as majorVersion } from 'semver'; import type { DownloadCenterConfig, PlatformWithPackages, -} from '@mongodb-js/dl-center/dist/download-center-config'; +} from '@mongodb-js/dl-center'; import { ARTIFACTS_BUCKET, ARTIFACTS_BUCKET_NEW, diff --git a/packages/shell-api/package.json b/packages/shell-api/package.json index 3c51d7ea9a..3d1577fb28 100644 --- a/packages/shell-api/package.json +++ b/packages/shell-api/package.json @@ -64,7 +64,8 @@ "devDependencies": { "@microsoft/api-extractor": "^7.39.3", "@mongodb-js/eslint-config-mongosh": "^1.0.0", - "@mongodb-js/mongodb-ts-autocomplete": "^0.2.5", + "@mongodb-js/mongodb-ts-autocomplete": "^0.3.4", + "@mongodb-js/mql-typescript": "^0.2.3", "@mongodb-js/prettier-config-devtools": "^1.0.1", "@mongodb-js/tsconfig-mongosh": "^1.0.0", "@mongosh/types": "3.8.0", diff --git a/packages/shell-api/src/abstract-cursor.ts b/packages/shell-api/src/abstract-cursor.ts index f51f1dad91..705dea1951 100644 --- a/packages/shell-api/src/abstract-cursor.ts +++ b/packages/shell-api/src/abstract-cursor.ts @@ -14,6 +14,7 @@ import type { } from '@mongosh/service-provider-core'; import { asPrintable } from './enums'; import { CursorIterationResult } from './result'; +import type { GenericServerSideSchema } from './helpers'; import { iterate } from './helpers'; @shellApiClassNoHelp @@ -21,15 +22,16 @@ export abstract class AbstractCursor< CursorType extends | ServiceProviderAggregationCursor | ServiceProviderFindCursor - | ServiceProviderRunCommandCursor -> extends ShellApiWithMongoClass { - _mongo: Mongo; + | ServiceProviderRunCommandCursor, + M extends GenericServerSideSchema = GenericServerSideSchema +> extends ShellApiWithMongoClass { + _mongo: Mongo; _cursor: CursorType; _transform: ((doc: any) => any) | null; _currentIterationResult: CursorIterationResult | null = null; - constructor(mongo: Mongo, cursor: CursorType) { + constructor(mongo: Mongo, cursor: CursorType) { super(); this._mongo = mongo; this._cursor = cursor; diff --git a/packages/shell-api/src/aggregate-or-find-cursor.ts b/packages/shell-api/src/aggregate-or-find-cursor.ts index 46cb48e014..558e9264ea 100644 --- a/packages/shell-api/src/aggregate-or-find-cursor.ts +++ b/packages/shell-api/src/aggregate-or-find-cursor.ts @@ -10,6 +10,7 @@ import type { ServiceProviderFindCursor, ServiceProviderAggregationCursor, } from '@mongosh/service-provider-core'; +import type { GenericServerSideSchema } from './helpers'; import { validateExplainableVerbosity, markAsExplainOutput } from './helpers'; import { AbstractCursor } from './abstract-cursor'; @@ -17,8 +18,9 @@ import { AbstractCursor } from './abstract-cursor'; export abstract class AggregateOrFindCursor< CursorType extends | ServiceProviderAggregationCursor - | ServiceProviderFindCursor -> extends AbstractCursor { + | ServiceProviderFindCursor, + M extends GenericServerSideSchema = GenericServerSideSchema +> extends AbstractCursor { @returnType('this') projection(spec: Document): this { this._cursor.project(spec); diff --git a/packages/shell-api/src/aggregation-cursor.ts b/packages/shell-api/src/aggregation-cursor.ts index e142a64eb8..934a93abcc 100644 --- a/packages/shell-api/src/aggregation-cursor.ts +++ b/packages/shell-api/src/aggregation-cursor.ts @@ -2,10 +2,13 @@ import type Mongo from './mongo'; import { shellApiClassDefault } from './decorators'; import type { ServiceProviderAggregationCursor } from '@mongosh/service-provider-core'; import { AggregateOrFindCursor } from './aggregate-or-find-cursor'; +import type { GenericServerSideSchema } from './helpers'; @shellApiClassDefault -export default class AggregationCursor extends AggregateOrFindCursor { - constructor(mongo: Mongo, cursor: ServiceProviderAggregationCursor) { +export default class AggregationCursor< + M extends GenericServerSideSchema = GenericServerSideSchema +> extends AggregateOrFindCursor { + constructor(mongo: Mongo, cursor: ServiceProviderAggregationCursor) { super(mongo, cursor); } } diff --git a/packages/shell-api/src/bulk.ts b/packages/shell-api/src/bulk.ts index c289b1414d..b282a54c54 100644 --- a/packages/shell-api/src/bulk.ts +++ b/packages/shell-api/src/bulk.ts @@ -18,21 +18,32 @@ import type { CollationOptions, } from '@mongosh/service-provider-core'; import { asPrintable } from './enums'; +import type { + GenericCollectionSchema, + GenericDatabaseSchema, + GenericServerSideSchema, + StringKey, +} from './helpers'; import { assertArgsDefinedType, shallowClone } from './helpers'; import { BulkWriteResult } from './result'; import type { CollectionWithSchema } from './collection'; @shellApiClassDefault -export class BulkFindOp extends ShellApiWithMongoClass { +export class BulkFindOp< + M extends GenericServerSideSchema = GenericServerSideSchema, + D extends GenericDatabaseSchema = M[keyof M], + C extends GenericCollectionSchema = D[keyof D], + N extends StringKey = StringKey +> extends ShellApiWithMongoClass { _serviceProviderBulkFindOp: FindOperators; - _parentBulk: Bulk; - constructor(innerFind: FindOperators, parentBulk: Bulk) { + _parentBulk: Bulk; + constructor(innerFind: FindOperators, parentBulk: Bulk) { super(); this._serviceProviderBulkFindOp = innerFind; this._parentBulk = parentBulk; } - get _mongo(): Mongo { + get _mongo(): Mongo { return this._parentBulk._mongo; } @@ -42,21 +53,21 @@ export class BulkFindOp extends ShellApiWithMongoClass { @returnType('BulkFindOp') @apiVersions([1]) - collation(spec: CollationOptions): BulkFindOp { + collation(spec: CollationOptions): BulkFindOp { this._serviceProviderBulkFindOp.collation(spec); return this; } @returnType('BulkFindOp') @apiVersions([1]) - arrayFilters(filters: Document[]): BulkFindOp { + arrayFilters(filters: Document[]): BulkFindOp { this._serviceProviderBulkFindOp.arrayFilters(filters); return this; } @returnType('BulkFindOp') @apiVersions([1]) - hint(hintDoc: Document): BulkFindOp { + hint(hintDoc: Document): BulkFindOp { assertArgsDefinedType([hintDoc], [true], 'BulkFindOp.hint'); this._serviceProviderBulkFindOp.hint(hintDoc); return this; @@ -64,7 +75,7 @@ export class BulkFindOp extends ShellApiWithMongoClass { @returnType('Bulk') @apiVersions([1]) - delete(): Bulk { + delete(): Bulk { this._parentBulk._batchCounts.nRemoveOps++; this._serviceProviderBulkFindOp.delete(); return this._parentBulk; @@ -72,7 +83,7 @@ export class BulkFindOp extends ShellApiWithMongoClass { @returnType('Bulk') @apiVersions([1]) - deleteOne(): Bulk { + deleteOne(): Bulk { this._parentBulk._batchCounts.nRemoveOps++; this._serviceProviderBulkFindOp.deleteOne(); return this._parentBulk; @@ -81,20 +92,20 @@ export class BulkFindOp extends ShellApiWithMongoClass { @returnType('Bulk') @apiVersions([1]) @deprecated - remove(): Bulk { + remove(): Bulk { return this.delete(); } @returnType('Bulk') @apiVersions([1]) @deprecated - removeOne(): Bulk { + removeOne(): Bulk { return this.deleteOne(); } @returnType('Bulk') @apiVersions([1]) - replaceOne(replacement: Document): Bulk { + replaceOne(replacement: Document): Bulk { this._parentBulk._batchCounts.nUpdateOps++; assertArgsDefinedType([replacement], [true], 'BulkFindOp.replacement'); const op = shallowClone(replacement); @@ -104,7 +115,7 @@ export class BulkFindOp extends ShellApiWithMongoClass { @returnType('Bulk') @apiVersions([1]) - updateOne(update: Document | Document[]): Bulk { + updateOne(update: Document | Document[]): Bulk { this._parentBulk._batchCounts.nUpdateOps++; assertArgsDefinedType([update], [true], 'BulkFindOp.update'); const op = shallowClone(update); @@ -113,7 +124,7 @@ export class BulkFindOp extends ShellApiWithMongoClass { } @returnType('Bulk') - update(update: Document | Document[]): Bulk { + update(update: Document | Document[]): Bulk { this._parentBulk._batchCounts.nUpdateOps++; assertArgsDefinedType([update], [true], 'BulkFindOp.update'); const op = shallowClone(update); @@ -122,23 +133,28 @@ export class BulkFindOp extends ShellApiWithMongoClass { } @returnType('Bulk') - upsert(): BulkFindOp { + upsert(): BulkFindOp { this._serviceProviderBulkFindOp.upsert(); return this; } } @shellApiClassDefault -export default class Bulk extends ShellApiWithMongoClass { - _mongo: Mongo; - _collection: CollectionWithSchema; +export default class Bulk< + M extends GenericServerSideSchema = GenericServerSideSchema, + D extends GenericDatabaseSchema = M[keyof M], + C extends GenericCollectionSchema = D[keyof D], + N extends StringKey = StringKey +> extends ShellApiWithMongoClass { + _mongo: Mongo; + _collection: CollectionWithSchema; _batchCounts: any; _executed: boolean; _serviceProviderBulkOp: OrderedBulkOperation | UnorderedBulkOperation; _ordered: boolean; constructor( - collection: CollectionWithSchema, + collection: CollectionWithSchema, innerBulk: OrderedBulkOperation | UnorderedBulkOperation, ordered = false ) { @@ -202,14 +218,17 @@ export default class Bulk extends ShellApiWithMongoClass { @returnType('BulkFindOp') @apiVersions([1]) - find(query: Document): BulkFindOp { + find(query: Document): BulkFindOp { assertArgsDefinedType([query], [true], 'Bulk.find'); - return new BulkFindOp(this._serviceProviderBulkOp.find(query), this); + return new BulkFindOp( + this._serviceProviderBulkOp.find(query), + this + ); } @returnType('Bulk') @apiVersions([1]) - insert(document: Document): Bulk { + insert(document: Document): Bulk { this._batchCounts.nInsertOps++; assertArgsDefinedType([document], [true], 'Bulk.insert'); this._serviceProviderBulkOp.insert(document); diff --git a/packages/shell-api/src/change-stream-cursor.ts b/packages/shell-api/src/change-stream-cursor.ts index cf3c41b260..ca663fa44e 100644 --- a/packages/shell-api/src/change-stream-cursor.ts +++ b/packages/shell-api/src/change-stream-cursor.ts @@ -17,12 +17,15 @@ import { MongoshRuntimeError, MongoshUnimplementedError, } from '@mongosh/errors'; +import type { GenericServerSideSchema } from './helpers'; import { iterate } from './helpers'; import type Mongo from './mongo'; @shellApiClassDefault -export default class ChangeStreamCursor extends ShellApiWithMongoClass { - _mongo: Mongo; +export default class ChangeStreamCursor< + M extends GenericServerSideSchema = GenericServerSideSchema +> extends ShellApiWithMongoClass { + _mongo: Mongo; _cursor: ServiceProviderChangeStream; _currentIterationResult: CursorIterationResult | null = null; _on: string; @@ -30,7 +33,7 @@ export default class ChangeStreamCursor extends ShellApiWithMongoClass { constructor( cursor: ServiceProviderChangeStream, on: string, - mongo: Mongo + mongo: Mongo ) { super(); this._cursor = cursor; @@ -119,7 +122,7 @@ export default class ChangeStreamCursor extends ShellApiWithMongoClass { return this._cursor.resumeToken; } - map(): ChangeStreamCursor { + map(): ChangeStreamCursor { throw new MongoshUnimplementedError( 'Cannot call map on a change stream cursor' ); @@ -141,7 +144,7 @@ export default class ChangeStreamCursor extends ShellApiWithMongoClass { } @returnType('ChangeStreamCursor') - pretty(): ChangeStreamCursor { + pretty(): ChangeStreamCursor { return this; } } diff --git a/packages/shell-api/src/collection.ts b/packages/shell-api/src/collection.ts index 5b4db39410..f5eede6a8f 100644 --- a/packages/shell-api/src/collection.ts +++ b/packages/shell-api/src/collection.ts @@ -36,7 +36,6 @@ import { processFindAndModifyOptions, processRemoveOptions, processMapReduceOptions, - setHideIndex, maybeMarkAsExplainOutput, markAsExplainOutput, assertArgsDefinedType, @@ -73,7 +72,7 @@ import type { AggregateOptions, SearchIndexDescription, } from '@mongosh/service-provider-core'; -import type { RunCommandCursor, Database, DatabaseWithSchema } from './index'; +import type { RunCommandCursor, DatabaseWithSchema } from './index'; import { AggregationCursor, BulkWriteResult, @@ -96,6 +95,7 @@ import { HIDDEN_COMMANDS } from '@mongosh/history'; import PlanCache from './plan-cache'; import ChangeStreamCursor from './change-stream-cursor'; import { ShellApiErrors } from './error-codes'; +import type * as mql from '@mongodb-js/mql-typescript/schema'; export type CollectionWithSchema< M extends GenericServerSideSchema = GenericServerSideSchema, @@ -118,19 +118,15 @@ export class Collection< D extends GenericDatabaseSchema = M[keyof M], C extends GenericCollectionSchema = D[keyof D], N extends StringKey = StringKey -> extends ShellApiWithMongoClass { +> extends ShellApiWithMongoClass { _mongo: Mongo; _database: DatabaseWithSchema; _name: N; _cachedSampleDocs: Document[] = []; - constructor( - mongo: Mongo, - database: DatabaseWithSchema | Database, - name: N - ) { + constructor(mongo: Mongo, database: DatabaseWithSchema, name: N) { super(); this._mongo = mongo; - this._database = database as DatabaseWithSchema; + this._database = database; this._name = name; const proxy = new Proxy(this, { get: (target, prop): any => { @@ -194,12 +190,14 @@ export class Collection< async aggregate( pipeline: Document[], options?: AggregateOptions - ): Promise; - async aggregate(...stages: Document[]): Promise; + ): Promise>; + async aggregate(...stages: Document[]): Promise>; @returnsPromise @returnType('AggregationCursor') @apiVersions([1]) - async aggregate(...args: unknown[]): Promise { + async aggregate( + ...args: unknown[] + ): Promise | Document> { let options: AggregateOptions; let pipeline: Document[]; if (args.length === 0 || Array.isArray(args[0])) { @@ -476,16 +474,16 @@ export class Collection< @apiVersions([1]) @returnsPromise async find( - query?: Document, + query?: mql.Query, projection?: Document, options: FindOptions = {} - ): Promise { + ): Promise> { if (projection) { options.projection = projection; } this._emitCollectionApiCall('find', { query, options }); - const cursor = new Cursor( + const cursor = new Cursor( this._mongo, this._mongo._serviceProvider.find( this._database._name, @@ -569,7 +567,7 @@ export class Collection< } this._emitCollectionApiCall('findOne', { query, options }); - return new Cursor( + return new Cursor( this._mongo, this._mongo._serviceProvider.find( this._database._name, @@ -1634,10 +1632,16 @@ export class Collection< @returnType('Explainable') @apiVersions([1]) - explain(verbosity: ExplainVerbosityLike = 'queryPlanner'): Explainable { + explain( + verbosity: ExplainVerbosityLike = 'queryPlanner' + ): Explainable { verbosity = validateExplainableVerbosity(verbosity); this._emitCollectionApiCall('explain', { verbosity }); - return new Explainable(this._mongo, this, verbosity); + return new Explainable( + this._mongo, + this as CollectionWithSchema, + verbosity + ); } /** @@ -1795,7 +1799,7 @@ export class Collection< } const ns = `${this._database._name}.${this._name}`; - const config = this._mongo.getDB('config' as StringKey); + const config = this._mongo.getDB('config'); if (collStats[0].shard) { result.shards = shardStats; } @@ -2000,7 +2004,7 @@ export class Collection< @returnsPromise @returnType('Bulk') @apiVersions([1]) - async initializeOrderedBulkOp(): Promise { + async initializeOrderedBulkOp(): Promise> { this._emitCollectionApiCall('initializeOrderedBulkOp'); const innerBulk = await this._mongo._serviceProvider.initializeBulkOp( this._database._name, @@ -2008,13 +2012,17 @@ export class Collection< true, await this._database._baseOptions() ); - return new Bulk(this, innerBulk, true); + return new Bulk( + this as CollectionWithSchema, + innerBulk, + true + ); } @returnsPromise @returnType('Bulk') @apiVersions([1]) - async initializeUnorderedBulkOp(): Promise { + async initializeUnorderedBulkOp(): Promise> { this._emitCollectionApiCall('initializeUnorderedBulkOp'); const innerBulk = await this._mongo._serviceProvider.initializeBulkOp( this._database._name, @@ -2022,14 +2030,17 @@ export class Collection< false, await this._database._baseOptions() ); - return new Bulk(this, innerBulk); + return new Bulk( + this as CollectionWithSchema, + innerBulk + ); } @returnType('PlanCache') @apiVersions([]) - getPlanCache(): PlanCache { + getPlanCache(): PlanCache { this._emitCollectionApiCall('getPlanCache'); - return new PlanCache(this); + return new PlanCache(this as CollectionWithSchema); } @returnsPromise @@ -2104,7 +2115,7 @@ export class Collection< * @returns collection info based on given collStats. */ async _getShardedCollectionInfo( - config: DatabaseWithSchema, + config: DatabaseWithSchema, collStats: Document[] ): Promise { const ns = `${this._database._name}.${this._name}`; @@ -2163,10 +2174,7 @@ export class Collection< this._emitCollectionApiCall('getShardDistribution', {}); const result = {} as Document; - // TODO: can we get around casting here? - const config = this._mongo.getDB( - 'config' as StringKey - ) as DatabaseWithSchema; + const config = this._mongo.getDB('config' as any); const collStats = await ( await this.aggregate({ $collStats: { storageStats: {} } }) @@ -2334,13 +2342,13 @@ export class Collection< async watch( pipeline: Document[] | ChangeStreamOptions = [], options: ChangeStreamOptions = {} - ): Promise { + ): Promise> { if (!Array.isArray(pipeline)) { options = pipeline; pipeline = []; } this._emitCollectionApiCall('watch', { pipeline, options }); - const cursor = new ChangeStreamCursor( + const cursor = new ChangeStreamCursor( this._mongo._serviceProvider.watch( pipeline, { @@ -2381,12 +2389,32 @@ export class Collection< return cursor; } + async _setHideIndex( + index: string | Document, + hidden: boolean + ): Promise { + const cmd = + typeof index === 'string' + ? { + name: index, + hidden, + } + : { + keyPattern: index, + hidden, + }; + return await this._database._runCommand({ + collMod: this._name, + index: cmd, + }); + } + @serverVersions(['4.4.0', ServerVersions.latest]) @returnsPromise @apiVersions([1]) async hideIndex(index: string | Document): Promise { this._emitCollectionApiCall('hideIndex'); - return setHideIndex(this, index, true); + return this._setHideIndex(index, true); } @serverVersions(['4.4.0', ServerVersions.latest]) @@ -2394,7 +2422,7 @@ export class Collection< @apiVersions([1]) async unhideIndex(index: string | Document): Promise { this._emitCollectionApiCall('unhideIndex'); - return setHideIndex(this, index, false); + return this._setHideIndex(index, false); } @serverVersions(['7.0.0', ServerVersions.latest]) @@ -2431,7 +2459,7 @@ export class Collection< @returnsPromise async checkMetadataConsistency( options: CheckMetadataConsistencyOptions = {} - ): Promise { + ): Promise> { this._emitCollectionApiCall('checkMetadataConsistency', { options }); return await this._database._runCursorCommand({ diff --git a/packages/shell-api/src/cursor.ts b/packages/shell-api/src/cursor.ts index ed4af384b7..0f7e57ea63 100644 --- a/packages/shell-api/src/cursor.ts +++ b/packages/shell-api/src/cursor.ts @@ -25,12 +25,15 @@ import type { } from '@mongosh/service-provider-core'; import type Mongo from './mongo'; import { AggregateOrFindCursor } from './aggregate-or-find-cursor'; +import { type GenericServerSideSchema } from './helpers'; @shellApiClassDefault -export default class Cursor extends AggregateOrFindCursor { +export default class Cursor< + M extends GenericServerSideSchema = GenericServerSideSchema +> extends AggregateOrFindCursor { _tailable = false; - constructor(mongo: Mongo, cursor: ServiceProviderFindCursor) { + constructor(mongo: Mongo, cursor: ServiceProviderFindCursor) { super(mongo, cursor); } diff --git a/packages/shell-api/src/database.ts b/packages/shell-api/src/database.ts index ccdb61ec5a..cac168a765 100644 --- a/packages/shell-api/src/database.ts +++ b/packages/shell-api/src/database.ts @@ -26,7 +26,6 @@ import { processDigestPassword, tsToSeconds, isValidCollectionName, - getConfigDB, shouldRunAggregationImmediately, adjustRunCommand, getBadge, @@ -85,22 +84,19 @@ export type DatabaseWithSchema< export class Database< M extends GenericServerSideSchema = GenericServerSideSchema, D extends GenericDatabaseSchema = GenericDatabaseSchema -> extends ShellApiWithMongoClass { +> extends ShellApiWithMongoClass { _mongo: Mongo; _name: StringKey; - _collections: Record, CollectionWithSchema>; - _session: Session | undefined; + _collections: { [k in StringKey]: CollectionWithSchema }; + _session: Session | undefined; _cachedCollectionNames: StringKey[] = []; _cachedHello: Document | null = null; - constructor(mongo: Mongo, name: StringKey, session?: Session) { + constructor(mongo: Mongo, name: StringKey, session?: Session) { super(); this._mongo = mongo; this._name = name; - const collections: Record< - string, - CollectionWithSchema - > = Object.create(null); + const collections: typeof this._collections = Object.create(null); this._collections = collections; this._session = session; const proxy = new Proxy(this, { @@ -118,9 +114,9 @@ export class Database< } if (!collections[prop]) { - collections[prop] = new Collection( + collections[prop as StringKey] = new Collection( mongo, - proxy, + proxy as DatabaseWithSchema, prop ) as CollectionWithSchema; } @@ -223,7 +219,7 @@ export class Database< public async _runCursorCommand( cmd: Document, options: CommandOperationOptions = {} - ): Promise { + ): Promise> { const providerCursor = this._mongo._serviceProvider.runCursorCommand( this._name, adjustRunCommand(cmd, this._instanceState.shellBson), @@ -242,7 +238,7 @@ export class Database< public async _runAdminCursorCommand( cmd: Document, options: CommandOperationOptions = {} - ): Promise { + ): Promise> { return this.getSiblingDB('admin')._runCursorCommand(cmd, options); } @@ -449,12 +445,14 @@ export class Database< async aggregate( pipeline: Document[], options?: AggregateOptions - ): Promise; - async aggregate(...stages: Document[]): Promise; + ): Promise>; + async aggregate(...stages: Document[]): Promise>; @returnsPromise @returnType('AggregationCursor') @apiVersions([1]) - async aggregate(...args: unknown[]): Promise { + async aggregate( + ...args: unknown[] + ): Promise | Document> { let options: AggregateOptions; let pipeline: Document[]; if (args.length === 0 || Array.isArray(args[0])) { @@ -500,7 +498,7 @@ export class Database< assertArgsDefinedType([db], ['string'], 'Database.getSiblingDB'); this._emitDatabaseApiCall('getSiblingDB', { db }); if (this._session) { - return this._session.getDatabase(db) as DatabaseWithSchema; + return this._session.getDatabase(db); } return this._mongo._getDb(db); } @@ -518,18 +516,17 @@ export class Database< ); } - const collections: Record> = this - ._collections; + const collections = this._collections; if (!collections[coll]) { - collections[coll] = new Collection( + collections[coll] = new Collection( this._mongo, - this, + this as DatabaseWithSchema, coll - ) as CollectionWithSchema; + ) as CollectionWithSchema; } - return collections[coll] as CollectionWithSchema; + return collections[coll]; } @returnsPromise @@ -835,12 +832,13 @@ export class Database< ); } + // eslint-disable-next-line @typescript-eslint/require-await @returnsPromise @apiVersions([1]) async createEncryptedCollection( name: string, options: CreateEncryptedCollectionOptions - ): Promise<{ collection: Collection; encryptedFields: Document }> { + ): Promise<{ collection: Collection; encryptedFields: Document }> { this._emitDatabaseApiCall('createEncryptedCollection', { name: name, options: options, @@ -1529,13 +1527,23 @@ export class Database< return result.err || null; } + async _getConfigDB(): Promise> { + const helloResult = await this._maybeCachedHello(); + if (helloResult.msg !== 'isdbgrid') { + await this._instanceState.printWarning( + 'MongoshWarning: [SHAPI-10003] You are not connected to a mongos. This command may not work as expected.' + ); + } + return this.getSiblingDB('config'); + } + @returnsPromise @topologies([Topologies.Sharded]) @apiVersions([1]) async printShardingStatus(verbose = false): Promise { this._emitDatabaseApiCall('printShardingStatus', { verbose }); const result = await getPrintableShardStatus( - await getConfigDB(this), + await this._getConfigDB(), verbose ); return new CommandResult('StatsResult', result); @@ -1741,13 +1749,13 @@ export class Database< async watch( pipeline: Document[] | ChangeStreamOptions = [], options: ChangeStreamOptions = {} - ): Promise { + ): Promise> { if (!Array.isArray(pipeline)) { options = pipeline; pipeline = []; } this._emitDatabaseApiCall('watch', { pipeline, options }); - const cursor = new ChangeStreamCursor( + const cursor = new ChangeStreamCursor( this._mongo._serviceProvider.watch( pipeline, { @@ -1777,7 +1785,7 @@ export class Database< async sql( sqlString: string, options?: AggregateOptions - ): Promise { + ): Promise> { this._emitDatabaseApiCall('sql', { sqlString: sqlString, options }); await this._instanceState.shellApi.print( 'Note: this is an experimental feature that may be subject to change in future releases.' @@ -1819,7 +1827,7 @@ export class Database< @returnsPromise async checkMetadataConsistency( options: CheckMetadataConsistencyOptions = {} - ): Promise { + ): Promise> { this._emitDatabaseApiCall('checkMetadataConsistency', { options }); return this._runCursorCommand({ diff --git a/packages/shell-api/src/decorators.ts b/packages/shell-api/src/decorators.ts index 6c7d49a5ba..3db6c69eac 100644 --- a/packages/shell-api/src/decorators.ts +++ b/packages/shell-api/src/decorators.ts @@ -13,6 +13,7 @@ import { shellApiType, } from './enums'; import Help from './help'; +import type { GenericServerSideSchema } from './helpers'; import { addHiddenDataProperty } from './helpers'; const addSourceToResultsSymbol = Symbol.for('@@mongosh.addSourceToResults'); @@ -104,8 +105,10 @@ export abstract class ShellApiClass { * Helper for shell API classes which have access to a {@link Mongo} * object instance. */ -export abstract class ShellApiWithMongoClass extends ShellApiClass { - abstract get _mongo(): Mongo; +export abstract class ShellApiWithMongoClass< + M extends GenericServerSideSchema = GenericServerSideSchema +> extends ShellApiClass { + abstract get _mongo(): Mongo; get _instanceState(): ShellInstanceState { // _mongo can be undefined in tests diff --git a/packages/shell-api/src/explainable-cursor.ts b/packages/shell-api/src/explainable-cursor.ts index c6af0e4915..d70a94e281 100644 --- a/packages/shell-api/src/explainable-cursor.ts +++ b/packages/shell-api/src/explainable-cursor.ts @@ -3,14 +3,21 @@ import Cursor from './cursor'; import type Mongo from './mongo'; import { asPrintable } from './enums'; import type { ExplainVerbosityLike } from '@mongosh/service-provider-core'; +import type { GenericServerSideSchema } from './helpers'; @shellApiClassDefault -export default class ExplainableCursor extends Cursor { - _baseCursor: Cursor; +export default class ExplainableCursor< + M extends GenericServerSideSchema = GenericServerSideSchema +> extends Cursor { + _baseCursor: Cursor; _verbosity: ExplainVerbosityLike; _explained: any; - constructor(mongo: Mongo, cursor: Cursor, verbosity: ExplainVerbosityLike) { + constructor( + mongo: Mongo, + cursor: Cursor, + verbosity: ExplainVerbosityLike + ) { super(mongo, cursor._cursor); this._baseCursor = cursor; this._verbosity = verbosity; diff --git a/packages/shell-api/src/explainable.ts b/packages/shell-api/src/explainable.ts index 875493267e..b10baf4bdd 100644 --- a/packages/shell-api/src/explainable.ts +++ b/packages/shell-api/src/explainable.ts @@ -15,6 +15,10 @@ import type { FindAndModifyShellOptions, FindAndModifyMethodShellOptions, MapReduceShellOptions, + GenericServerSideSchema, + GenericCollectionSchema, + GenericDatabaseSchema, + StringKey, } from './helpers'; import { validateExplainableVerbosity, @@ -35,13 +39,18 @@ import type { } from '@mongosh/service-provider-core'; @shellApiClassDefault -export default class Explainable extends ShellApiWithMongoClass { - _mongo: Mongo; - _collection: CollectionWithSchema; +export default class Explainable< + M extends GenericServerSideSchema = GenericServerSideSchema, + D extends GenericDatabaseSchema = M[keyof M], + C extends GenericCollectionSchema = D[keyof D], + N extends StringKey = StringKey +> extends ShellApiWithMongoClass { + _mongo: Mongo; + _collection: CollectionWithSchema; _verbosity: ExplainVerbosityLike; constructor( - mongo: Mongo, - collection: CollectionWithSchema, + mongo: Mongo, + collection: CollectionWithSchema, verbosity: ExplainVerbosityLike ) { super(); @@ -77,7 +86,7 @@ export default class Explainable extends ShellApiWithMongoClass { }); } - getCollection(): CollectionWithSchema { + getCollection(): CollectionWithSchema { this._emitExplainableApiCall('getCollection'); return this._collection; } @@ -103,8 +112,12 @@ export default class Explainable extends ShellApiWithMongoClass { ): Promise { this._emitExplainableApiCall('find', { query, projection }); - const cursor = await this._collection.find(query, projection, options); - return new ExplainableCursor(this._mongo, cursor, this._verbosity); + const cursor = await this._collection.find( + query as any, + projection, + options + ); + return new ExplainableCursor(this._mongo, cursor, this._verbosity); } async aggregate(pipeline: Document[], options: Document): Promise; diff --git a/packages/shell-api/src/field-level-encryption.ts b/packages/shell-api/src/field-level-encryption.ts index 884d97e3eb..f5868cfc3a 100644 --- a/packages/shell-api/src/field-level-encryption.ts +++ b/packages/shell-api/src/field-level-encryption.ts @@ -19,9 +19,10 @@ import type { GCPEncryptionKeyOptions, } from '@mongosh/service-provider-core'; import type { Document, BinaryType } from '@mongosh/service-provider-core'; -import type { CollectionWithSchema } from './collection'; +import type { Collection } from './collection'; import Cursor from './cursor'; import type { DeleteResult } from './result'; +import type { GenericServerSideSchema, StringKey } from './helpers'; import { assertArgsDefinedType, assertKeysDefined } from './helpers'; import { asPrintable } from './enums'; import { redactURICredentials } from '@mongosh/history'; @@ -33,8 +34,10 @@ import { } from '@mongosh/errors'; import type { CreateEncryptedCollectionOptions } from '@mongosh/service-provider-core'; -export interface ClientSideFieldLevelEncryptionOptions { - keyVaultClient?: Mongo; +export interface ClientSideFieldLevelEncryptionOptions< + M extends GenericServerSideSchema = GenericServerSideSchema +> { + keyVaultClient?: Mongo; keyVaultNamespace: string; kmsProviders: KMSProviders; schemaMap?: Document; @@ -89,11 +92,13 @@ const isMasterKey = ( @shellApiClassDefault @classPlatforms(['CLI']) -export class ClientEncryption extends ShellApiWithMongoClass { - public _mongo: Mongo; +export class ClientEncryption< + M extends GenericServerSideSchema = GenericServerSideSchema +> extends ShellApiWithMongoClass { + public _mongo: Mongo; public _libmongocrypt: MongoCryptClientEncryption; - constructor(mongo: Mongo) { + constructor(mongo: Mongo) { super(); this._mongo = mongo; @@ -173,7 +178,7 @@ export class ClientEncryption extends ShellApiWithMongoClass { dbName: string, collName: string, options: CreateEncryptedCollectionOptions - ): Promise<{ collection: CollectionWithSchema; encryptedFields: Document }> { + ): Promise<{ collection: Collection; encryptedFields: Document }> { assertArgsDefinedType( [dbName], ['string'], @@ -206,7 +211,9 @@ export class ClientEncryption extends ShellApiWithMongoClass { ); return { - collection: this._mongo.getDB(dbName).getCollection(collName), + collection: this._mongo + .getDB(dbName as StringKey) + .getCollection(collName as StringKey]>) as any, encryptedFields, }; } @@ -214,11 +221,14 @@ export class ClientEncryption extends ShellApiWithMongoClass { @shellApiClassDefault @classPlatforms(['CLI']) -export class KeyVault extends ShellApiWithMongoClass { - public _mongo: Mongo; - public _clientEncryption: ClientEncryption; - private _keyColl: CollectionWithSchema; - constructor(clientEncryption: ClientEncryption) { +export class KeyVault< + M extends GenericServerSideSchema = GenericServerSideSchema +> extends ShellApiWithMongoClass { + public _mongo: Mongo; + public _clientEncryption: ClientEncryption; + // TODO: M, D, C, N + private _keyColl: Collection; + constructor(clientEncryption: ClientEncryption) { super(); this._mongo = clientEncryption._mongo; this._clientEncryption = clientEncryption; @@ -237,7 +247,9 @@ export class KeyVault extends ShellApiWithMongoClass { ); } const { db, coll } = parsedNamespace; - this._keyColl = this._mongo.getDB(db).getCollection(coll); + this._keyColl = this._mongo + .getDB(db as StringKey) + .getCollection(coll as StringKey]>) as any; } async _init(): Promise { @@ -377,7 +389,7 @@ export class KeyVault extends ShellApiWithMongoClass { @returnsPromise async getKey(keyId: BinaryType): Promise { assertArgsDefinedType([keyId], [true], 'KeyVault.getKey'); - const cursor = await this._keyColl.find({ _id: keyId }); + const cursor = await this._keyColl.find({ _id: keyId } as any); return await cursor.limit(1).next(); } @@ -385,7 +397,7 @@ export class KeyVault extends ShellApiWithMongoClass { @returnsPromise async getKeyByAltName(keyAltName: string): Promise { assertArgsDefinedType([keyAltName], ['string'], 'KeyVault.getKeyByAltName'); - const cursor = await this._keyColl.find({ keyAltNames: keyAltName }); + const cursor = await this._keyColl.find({ keyAltNames: keyAltName } as any); return await cursor.limit(1).next(); } @@ -393,8 +405,8 @@ export class KeyVault extends ShellApiWithMongoClass { @returnType('Cursor') @apiVersions([1]) @returnsPromise - async getKeys(): Promise { - return new Cursor( + async getKeys(): Promise> { + return new Cursor( this._mongo, this._clientEncryption._libmongocrypt.getKeys() ); diff --git a/packages/shell-api/src/helpers.ts b/packages/shell-api/src/helpers.ts index 1ab76f841e..b5866871b3 100644 --- a/packages/shell-api/src/helpers.ts +++ b/packages/shell-api/src/helpers.ts @@ -16,8 +16,7 @@ import { MongoshUnimplementedError, } from '@mongosh/errors'; import crypto from 'crypto'; -import type { Database } from './database'; -import type { Collection } from './collection'; +import type { DatabaseWithSchema } from './database'; import type { CursorIterationResult } from './result'; import { ShellApiErrors } from './error-codes'; import type { @@ -28,8 +27,6 @@ import type { import type { ClientSideFieldLevelEncryptionOptions } from './field-level-encryption'; import type { AutoEncryptionOptions, Long, ObjectId, Timestamp } from 'mongodb'; import { shellApiType } from './enums'; -import type { AbstractCursor } from './abstract-cursor'; -import type ChangeStreamCursor from './change-stream-cursor'; import type { ShellBson } from './shell-bson'; import { inspect } from 'util'; @@ -223,8 +220,10 @@ export function processDigestPassword( * @param configDB * @param verbose */ -export async function getPrintableShardStatus( - configDB: Database, +export async function getPrintableShardStatus< + M extends GenericServerSideSchema = GenericServerSideSchema +>( + configDB: DatabaseWithSchema, verbose: boolean ): Promise { const result = {} as ShardingStatusResult; @@ -298,7 +297,7 @@ export async function getPrintableShardStatus( if (verbose) { result[`${mongosAdjective} mongoses`] = await ( - await mongosColl.find(recentMongosQuery) + await mongosColl.find(recentMongosQuery as any) ) .sort({ ping: -1 }) .toArray(); @@ -372,7 +371,7 @@ export async function getPrintableShardStatus( // Output the list of active migrations type Lock = { _id: string; when: Date }; const activeLocks: Lock[] = (await ( - await configDB.getCollection('locks').find({ state: { $eq: 2 } }) + await configDB.getCollection('locks').find({ state: { $eq: 2 } } as any) ).toArray()) as Lock[]; if (activeLocks?.length > 0) { balancerRes['Collections with active migrations'] = activeLocks.map( @@ -401,7 +400,7 @@ export async function getPrintableShardStatus( const balErrs = await ( await configDB .getCollection('actionlog') - .find({ what: 'balancer.round' }) + .find({ what: 'balancer.round' } as any) ) .sort({ time: -1 }) .limit(5) @@ -538,7 +537,7 @@ export async function getPrintableShardStatus( await ( await configDB.getCollection('collections').find({ ...onlyShardedCollectionsInConfigFilter, - }) + } as any) ) .sort({ _id: 1 }) .toArray())(), @@ -621,7 +620,7 @@ export async function getPrintableShardStatus( }); for await (const chunk of ( - await chunksColl.find(chunksCollMatch) + await chunksColl.find(chunksCollMatch as any) ).sort({ min: 1 })) { if (chunksRes.length < 20 || verbose) { const c = { @@ -662,7 +661,7 @@ export async function getPrintableShardStatus( for await (const tag of ( await configDB.getCollection('tags').find({ ns: coll._id, - }) + } as any) ).sort({ min: 1 })) { if (tagsRes.length < 20 || verbose) { tagsRes.push({ @@ -757,16 +756,6 @@ export type ShardedDataDistribution = { }[]; }[]; -export async function getConfigDB(db: Database): Promise { - const helloResult = await db._maybeCachedHello(); - if (helloResult.msg !== 'isdbgrid') { - await db._instanceState.printWarning( - 'MongoshWarning: [SHAPI-10003] You are not connected to a mongos. This command may not work as expected.' - ); - } - return db.getSiblingDB('config'); -} - type AnyBsonNumber = | number | typeof bson.Long.prototype @@ -860,7 +849,7 @@ export function addHiddenDataProperty( export async function iterate( results: CursorIterationResult, - cursor: AbstractCursor | ChangeStreamCursor, + cursor: { isClosed(): boolean; tryNext(): Promise }, batchSize: number ): Promise { if (cursor.isClosed()) { @@ -984,27 +973,6 @@ export function processMapReduceOptions( } } -export async function setHideIndex( - coll: Collection, - index: string | Document, - hidden: boolean -): Promise { - const cmd = - typeof index === 'string' - ? { - name: index, - hidden, - } - : { - keyPattern: index, - hidden, - }; - return await coll._database._runCommand({ - collMod: coll._name, - index: cmd, - }); -} - export function assertCLI(platform: ReplPlatform, features: string): void { if (platform !== 'CLI') { throw new MongoshUnimplementedError( @@ -1313,9 +1281,34 @@ export interface GenericCollectionSchema { export interface GenericDatabaseSchema { [key: string]: GenericCollectionSchema; } -export interface GenericServerSideSchema { +export type GenericServerSideSchema = { [key: string]: GenericDatabaseSchema; -} +} & { + admin: {}; + config: { + collections: GenericCollectionSchema; + shards: GenericCollectionSchema; + chunks: GenericCollectionSchema; + mongos: GenericCollectionSchema; + version: GenericCollectionSchema; + settings: GenericCollectionSchema; + changelog: GenericCollectionSchema; + locks: GenericCollectionSchema; + databases: GenericCollectionSchema; + tags: GenericCollectionSchema; + actionlog: GenericCollectionSchema; + }; + local: { + 'system.version': GenericCollectionSchema; + 'system.profile': GenericCollectionSchema; + 'system.replset': GenericCollectionSchema; + 'oplog.rs': GenericCollectionSchema; + }; + /* + _fakeDbForMongoshCSKTH: { + } + */ +}; export type StringKey = keyof T & string; export const aggregateBackgroundOptionNotSupportedHelp = 'the background option is not supported by the aggregate method and will be ignored, ' + diff --git a/packages/shell-api/src/mongo.spec.ts b/packages/shell-api/src/mongo.spec.ts index d85ae6d490..dc93949225 100644 --- a/packages/shell-api/src/mongo.spec.ts +++ b/packages/shell-api/src/mongo.spec.ts @@ -327,7 +327,7 @@ describe('Mongo', function () { it('calls database.count and find when count > 0', async function () { const expectedResult = [{ a: 'a' }, { b: 'b' }]; const syscoll = stubInterface(); - const cursor = stubInterface(); + const cursor = stubInterface>(); cursor.sort.returns(cursor); cursor.limit.returns(cursor); cursor.toArray.resolves(expectedResult); diff --git a/packages/shell-api/src/mongo.ts b/packages/shell-api/src/mongo.ts index 9af7198b77..c084adf1af 100644 --- a/packages/shell-api/src/mongo.ts +++ b/packages/shell-api/src/mongo.ts @@ -81,14 +81,15 @@ export default class Mongo< M extends GenericServerSideSchema = GenericServerSideSchema > extends ShellApiClass { private __serviceProvider: ServiceProvider | null = null; - public readonly _databases: Record, DatabaseWithSchema> = - Object.create(null); + public readonly _databases: { + [k in StringKey]: DatabaseWithSchema; + } = Object.create(null); private _connectionId: number; public _instanceState: ShellInstanceState; public _connectionInfo: ConnectionInfo; private _explicitEncryptionOnly = false; - private _keyVault: KeyVault | undefined; // need to keep it around so that the ShellApi ClientEncryption class can access it - private _clientEncryption: ClientEncryption | undefined; + private _keyVault: KeyVault | undefined; // need to keep it around so that the ShellApi ClientEncryption class can access it + private _clientEncryption: ClientEncryption | undefined; private _readPreferenceWasExplicitlyRequested = false; private _cachedDatabaseNames: StringKey[] = []; @@ -472,7 +473,9 @@ export default class Mongo< count: await sysprof.countDocuments({}), } as Document; if (profiles.count !== 0) { - profiles.result = await (await sysprof.find({ millis: { $gt: 0 } })) + profiles.result = await ( + await sysprof.find({ millis: { $gt: 0 } } as any) + ) .sort({ $natural: -1 }) .limit(5) .toArray(); @@ -745,7 +748,7 @@ export default class Mongo< } @topologies([Topologies.ReplSet]) - startSession(options: Document = {}): Session { + startSession(options: Document = {}): Session { const allTransactionOptions = [ 'readConcern', 'writeConcern', @@ -790,7 +793,7 @@ export default class Mongo< } } - return new Session( + return new Session( this, driverOptions, this._serviceProvider.startSession(driverOptions) @@ -847,13 +850,13 @@ export default class Mongo< async watch( pipeline: Document[] | ChangeStreamOptions = [], options: ChangeStreamOptions = {} - ): Promise { + ): Promise> { if (!Array.isArray(pipeline)) { options = pipeline; pipeline = []; } this._emitMongoApiCall('watch', { pipeline, options }); - const cursor = new ChangeStreamCursor( + const cursor = new ChangeStreamCursor( this._serviceProvider.watch(pipeline, options), redactURICredentials(this._uri), this @@ -872,7 +875,7 @@ export default class Mongo< @platforms(['CLI']) @serverVersions(['4.2.0', ServerVersions.latest]) @returnType('ClientEncryption') - getClientEncryption(): ClientEncryption { + getClientEncryption(): ClientEncryption { if (!this._fleOptions) { throw new MongoshInvalidInputError( 'Cannot call getClientEncryption() without field-level encryption options', @@ -880,7 +883,7 @@ export default class Mongo< ); } if (!this._clientEncryption) { - this._clientEncryption = new ClientEncryption(this); + this._clientEncryption = new ClientEncryption(this); } return this._clientEncryption; } @@ -889,9 +892,9 @@ export default class Mongo< @serverVersions(['4.2.0', ServerVersions.latest]) @returnType('KeyVault') @returnsPromise - async getKeyVault(): Promise { + async getKeyVault(): Promise> { if (!this._keyVault) { - this._keyVault = new KeyVault(this.getClientEncryption()); + this._keyVault = new KeyVault(this.getClientEncryption()); await this._keyVault._init(); } return this._keyVault; diff --git a/packages/shell-api/src/no-db.ts b/packages/shell-api/src/no-db.ts index 8336c6f423..d66efdcb56 100644 --- a/packages/shell-api/src/no-db.ts +++ b/packages/shell-api/src/no-db.ts @@ -1,11 +1,14 @@ import { MongoshInvalidInputError } from '@mongosh/errors'; import { ShellApiErrors } from './error-codes'; import type Mongo from './mongo'; +import type { GenericServerSideSchema } from './helpers'; -export default class NoDatabase { - _mongo: Mongo; +export default class NoDatabase< + M extends GenericServerSideSchema = GenericServerSideSchema +> { + _mongo: Mongo; constructor() { - this._mongo = new NoMongo() as Mongo; + this._mongo = new NoMongo() as Mongo; const proxy = new Proxy(this, { get: (_target, prop): any => { if (prop === '_mongo') return this._mongo; // so we can create rs/sh without erroring diff --git a/packages/shell-api/src/plan-cache.ts b/packages/shell-api/src/plan-cache.ts index 0da8453a62..40214831eb 100644 --- a/packages/shell-api/src/plan-cache.ts +++ b/packages/shell-api/src/plan-cache.ts @@ -11,17 +11,28 @@ import type { CollectionWithSchema } from './collection'; import { asPrintable, ServerVersions } from './enums'; import { MongoshDeprecatedError } from '@mongosh/errors'; import type Mongo from './mongo'; +import type { + GenericServerSideSchema, + GenericDatabaseSchema, + GenericCollectionSchema, + StringKey, +} from './helpers'; @shellApiClassDefault -export default class PlanCache extends ShellApiWithMongoClass { - _collection: CollectionWithSchema; +export default class PlanCache< + M extends GenericServerSideSchema = GenericServerSideSchema, + D extends GenericDatabaseSchema = M[keyof M], + C extends GenericCollectionSchema = D[keyof D], + N extends StringKey = StringKey +> extends ShellApiWithMongoClass { + _collection: CollectionWithSchema; - constructor(collection: CollectionWithSchema) { + constructor(collection: CollectionWithSchema) { super(); this._collection = collection; } - get _mongo(): Mongo { + get _mongo(): Mongo { return this._collection._mongo; } diff --git a/packages/shell-api/src/replica-set.ts b/packages/shell-api/src/replica-set.ts index 064b502118..3b245c756a 100644 --- a/packages/shell-api/src/replica-set.ts +++ b/packages/shell-api/src/replica-set.ts @@ -7,7 +7,7 @@ import { import { redactURICredentials } from '@mongosh/history'; import type { Document } from '@mongosh/service-provider-core'; import type Mongo from './mongo'; -import type { Database, DatabaseWithSchema } from './database'; +import type { DatabaseWithSchema } from './database'; import { deprecated, returnsPromise, @@ -39,12 +39,12 @@ export type ReplSetConfig = { export default class ReplicaSet< M extends GenericServerSideSchema = GenericServerSideSchema, D extends GenericDatabaseSchema = GenericDatabaseSchema -> extends ShellApiWithMongoClass { +> extends ShellApiWithMongoClass { _database: DatabaseWithSchema; - constructor(database: DatabaseWithSchema | Database) { + constructor(database: DatabaseWithSchema) { super(); - this._database = database as DatabaseWithSchema; + this._database = database; } get _mongo(): Mongo { diff --git a/packages/shell-api/src/run-command-cursor.ts b/packages/shell-api/src/run-command-cursor.ts index 20fbc992d2..172d1309a3 100644 --- a/packages/shell-api/src/run-command-cursor.ts +++ b/packages/shell-api/src/run-command-cursor.ts @@ -2,10 +2,13 @@ import type Mongo from './mongo'; import { shellApiClassDefault } from './decorators'; import type { ServiceProviderRunCommandCursor } from '@mongosh/service-provider-core'; import { AbstractCursor } from './abstract-cursor'; +import type { GenericServerSideSchema } from './helpers'; @shellApiClassDefault -export default class RunCommandCursor extends AbstractCursor { - constructor(mongo: Mongo, cursor: ServiceProviderRunCommandCursor) { +export default class RunCommandCursor< + M extends GenericServerSideSchema = GenericServerSideSchema +> extends AbstractCursor { + constructor(mongo: Mongo, cursor: ServiceProviderRunCommandCursor) { super(mongo, cursor); } } diff --git a/packages/shell-api/src/session.ts b/packages/shell-api/src/session.ts index 8619ae64d1..a6e1a8be28 100644 --- a/packages/shell-api/src/session.ts +++ b/packages/shell-api/src/session.ts @@ -24,12 +24,12 @@ import { assertArgsDefinedType, isValidDatabaseName } from './helpers'; @classPlatforms(['CLI']) export default class Session< M extends GenericServerSideSchema = GenericServerSideSchema -> extends ShellApiWithMongoClass { +> extends ShellApiWithMongoClass { public id: ServerSessionId | undefined; public _session: ClientSession; public _options: ClientSessionOptions; public _mongo: Mongo; - private _databases: Record>; + private _databases: Record, DatabaseWithSchema>; constructor( mongo: Mongo, @@ -40,7 +40,7 @@ export default class Session< this._session = session; this._options = options; this._mongo = mongo; - this._databases = {}; + this._databases = Object.create(null); this.id = session.id; } @@ -66,7 +66,7 @@ export default class Session< this._mongo, name, this - ) as DatabaseWithSchema; + ) as unknown as DatabaseWithSchema; } return this._databases[name] as DatabaseWithSchema; } diff --git a/packages/shell-api/src/shard.ts b/packages/shell-api/src/shard.ts index 67520e052a..e1f764f9e8 100644 --- a/packages/shell-api/src/shard.ts +++ b/packages/shell-api/src/shard.ts @@ -1,4 +1,4 @@ -import type { Database, DatabaseWithSchema } from './database'; +import type { DatabaseWithSchema } from './database'; import { shellApiClassDefault, returnsPromise, @@ -18,11 +18,7 @@ import type { GenericDatabaseSchema, GenericServerSideSchema, } from './helpers'; -import { - assertArgsDefinedType, - getConfigDB, - getPrintableShardStatus, -} from './helpers'; +import { assertArgsDefinedType, getPrintableShardStatus } from './helpers'; import { ServerVersions, asPrintable } from './enums'; import type { UpdateResult } from './result'; import { CommandResult } from './result'; @@ -36,12 +32,12 @@ import semver from 'semver'; export default class Shard< M extends GenericServerSideSchema = GenericServerSideSchema, D extends GenericDatabaseSchema = GenericDatabaseSchema -> extends ShellApiWithMongoClass { +> extends ShellApiWithMongoClass { _database: DatabaseWithSchema; - constructor(database: DatabaseWithSchema | Database) { + constructor(database: DatabaseWithSchema) { super(); - this._database = database as DatabaseWithSchema; + this._database = database; } get _mongo(): Mongo { @@ -209,14 +205,24 @@ export default class Shard< } } + async _getConfigDB(): Promise> { + const helloResult = await this._database._maybeCachedHello(); + if (helloResult.msg !== 'isdbgrid') { + await this._instanceState.printWarning( + 'MongoshWarning: [SHAPI-10003] You are not connected to a mongos. This command may not work as expected.' + ); + } + return this._database.getSiblingDB('config'); + } + @returnsPromise @apiVersions([1]) async status( verbose = false, - configDB?: DatabaseWithSchema + configDB?: DatabaseWithSchema ): Promise> { const result = await getPrintableShardStatus( - configDB ?? (await getConfigDB(this._database)), + configDB ?? (await this._getConfigDB()), verbose ); return new CommandResult('StatsResult', result); @@ -226,7 +232,7 @@ export default class Shard< @apiVersions([]) async addShard(url: string): Promise { assertArgsDefinedType([url], ['string'], 'Shard.addShard'); - await getConfigDB(this._database); + await this._getConfigDB(); this._emitShardApiCall('addShard', { url }); return this._database._runAdminCommand({ addShard: url, @@ -243,7 +249,7 @@ export default class Shard< 'Shard.addShardToZone' ); this._emitShardApiCall('addShardToZone', { shard, zone }); - await getConfigDB(this._database); // will error if not connected to mongos + await this._getConfigDB(); // will error if not connected to mongos return this._database._runAdminCommand({ addShardToZone: shard, zone: zone, @@ -285,7 +291,7 @@ export default class Shard< ); this._emitShardApiCall('updateZoneKeyRange', { namespace, min, max, zone }); - await getConfigDB(this._database); // will error if not connected to mongos + await this._getConfigDB(); // will error if not connected to mongos return await this._database._runAdminCommand({ updateZoneKeyRange: namespace, min, @@ -372,7 +378,7 @@ export default class Shard< ); this._emitShardApiCall('removeShardFromZone', { shard, zone }); - await getConfigDB(this._database); // will error if not connected to mongos + await this._getConfigDB(); // will error if not connected to mongos return await this._database._runAdminCommand({ removeShardFromZone: shard, zone: zone, @@ -413,7 +419,7 @@ export default class Shard< ); } this._emitShardApiCall('enableAutoSplit', {}); - const config = await getConfigDB(this._database); + const config = await this._getConfigDB(); return (await config .getCollection('settings') .updateOne( @@ -437,7 +443,7 @@ export default class Shard< ); } this._emitShardApiCall('disableAutoSplit', {}); - const config = await getConfigDB(this._database); + const config = await this._getConfigDB(); return (await config .getCollection('settings') .updateOne( @@ -504,7 +510,7 @@ export default class Shard< ); this._emitShardApiCall('moveRange', { ns, toShard, min, max }); - await getConfigDB(this._database); // will error if not connected to mongos + await this._getConfigDB(); // will error if not connected to mongos return this._database._runAdminCommand({ moveRange: ns, @@ -530,7 +536,7 @@ export default class Shard< async enableBalancing(ns: string): Promise { assertArgsDefinedType([ns], ['string'], 'Shard.enableBalancing'); this._emitShardApiCall('enableBalancing', { ns }); - const config = await getConfigDB(this._database); + const config = await this._getConfigDB(); return (await config .getCollection('collections') .updateOne( @@ -545,7 +551,7 @@ export default class Shard< async disableBalancing(ns: string): Promise { assertArgsDefinedType([ns], ['string'], 'Shard.disableBalancing'); this._emitShardApiCall('disableBalancing', { ns }); - const config = await getConfigDB(this._database); + const config = await this._getConfigDB(); return (await config .getCollection('collections') .updateOne( @@ -559,7 +565,7 @@ export default class Shard< @apiVersions([]) async getBalancerState(): Promise { this._emitShardApiCall('getBalancerState', {}); - const config = await getConfigDB(this._database); + const config = await this._getConfigDB(); const doc = await config .getCollection('settings') .findOne({ _id: 'balancer' }); @@ -573,7 +579,7 @@ export default class Shard< @apiVersions([]) async isBalancerRunning(): Promise { this._emitShardApiCall('isBalancerRunning', {}); - await getConfigDB(this._database); + await this._getConfigDB(); return this._database._runAdminReadCommand({ balancerStatus: 1, }); @@ -616,7 +622,9 @@ export default class Shard< @apiVersions([]) @serverVersions(['6.0.3', ServerVersions.latest]) @returnType('AggregationCursor') - async getShardedDataDistribution(options = {}): Promise { + async getShardedDataDistribution( + options = {} + ): Promise> { this._emitShardApiCall('getShardedDataDistribution', {}); const cursor = await this._database @@ -642,7 +650,7 @@ export default class Shard< @serverVersions(['7.0.0', ServerVersions.latest]) async startAutoMerger(): Promise { this._emitShardApiCall('startAutoMerger', {}); - const config = await getConfigDB(this._database); + const config = await this._getConfigDB(); return (await config .getCollection('settings') .updateOne( @@ -657,7 +665,7 @@ export default class Shard< @serverVersions(['7.0.0', ServerVersions.latest]) async stopAutoMerger(): Promise { this._emitShardApiCall('stopAutoMerger', {}); - const config = await getConfigDB(this._database); + const config = await this._getConfigDB(); return (await config .getCollection('settings') .updateOne( @@ -672,7 +680,7 @@ export default class Shard< @serverVersions(['7.0.0', ServerVersions.latest]) async isAutoMergerEnabled(): Promise { this._emitShardApiCall('isAutoMergerEnabled', {}); - const config = await getConfigDB(this._database); + const config = await this._getConfigDB(); const doc = await config .getCollection('settings') .findOne({ _id: 'automerge' }); @@ -689,7 +697,7 @@ export default class Shard< assertArgsDefinedType([ns], ['string'], 'Shard.disableAutoMerger'); this._emitShardApiCall('disableAutoMerger', { ns }); - const config = await getConfigDB(this._database); + const config = await this._getConfigDB(); return (await config .getCollection('collections') .updateOne( @@ -706,7 +714,7 @@ export default class Shard< assertArgsDefinedType([ns], ['string'], 'Shard.enableAutoMerger'); this._emitShardApiCall('enableAutoMerger', { ns }); - const config = await getConfigDB(this._database); + const config = await this._getConfigDB(); return (await config .getCollection('collections') .updateOne( @@ -720,7 +728,7 @@ export default class Shard< @serverVersions(['7.0.0', ServerVersions.latest]) async checkMetadataConsistency( options: CheckMetadataConsistencyOptions = {} - ): Promise { + ): Promise> { this._emitShardApiCall('checkMetadataConsistency', { options }); return this._database._runAdminCursorCommand({ @@ -824,7 +832,7 @@ export default class Shard< @returnsPromise async listShards(): Promise { this._emitShardApiCall('listShards', {}); - await getConfigDB(this._database); + await this._getConfigDB(); return (await this._database.adminCommand({ listShards: 1 })).shards ?? []; } @@ -834,7 +842,7 @@ export default class Shard< @returnsPromise async isConfigShardEnabled(): Promise { this._emitShardApiCall('isConfigShardEnabled', {}); - await getConfigDB(this._database); + await this._getConfigDB(); const shards = (await this._database.adminCommand({ listShards: 1 })) .shards as Document[] | undefined; diff --git a/packages/shell-api/src/shell-api.spec.ts b/packages/shell-api/src/shell-api.spec.ts index a6ac13caeb..75ebe741b2 100644 --- a/packages/shell-api/src/shell-api.spec.ts +++ b/packages/shell-api/src/shell-api.spec.ts @@ -262,7 +262,7 @@ describe('ShellApi', function () { ); }); it('calls _it on current Cursor', async function () { - instanceState.currentCursor = stubInterface(); + instanceState.currentCursor = stubInterface>(); await instanceState.shellApi.it(); expect(instanceState.currentCursor._it).to.have.been.called; }); @@ -593,7 +593,7 @@ describe('ShellApi', function () { ); }); it('calls _it on current Cursor', async function () { - instanceState.currentCursor = stubInterface(); + instanceState.currentCursor = stubInterface>(); await instanceState.context.it(); expect(instanceState.currentCursor._it).to.have.been.called; }); diff --git a/packages/shell-api/src/shell-instance-state.ts b/packages/shell-api/src/shell-instance-state.ts index d4b736b5b4..076e816f24 100644 --- a/packages/shell-api/src/shell-instance-state.ts +++ b/packages/shell-api/src/shell-instance-state.ts @@ -148,12 +148,12 @@ const CONTROL_CHAR_REGEXP = /[\x00-\x1F\x7F-\x9F]/g; */ export class ShellInstanceState { public currentCursor: - | Cursor - | AggregationCursor - | ChangeStreamCursor - | RunCommandCursor + | Cursor + | AggregationCursor + | ChangeStreamCursor + | RunCommandCursor | null; - public currentDb: DatabaseWithSchema; + public currentDb: DatabaseWithSchema; public messageBus: MongoshBus; public initialServiceProvider: ServiceProvider; // the initial service provider private connectionInfoCache: { @@ -167,7 +167,8 @@ export class ShellInstanceState { info: Promise | ConnectionInfo | undefined; }; public context: any; - public mongos: Mongo[]; + // TODO: shouldn't these somehow be generic? Same with any of the ones used below. + public mongos: Mongo[]; public shellApi: ShellApi; public shellLog: ShellLog; public shellBson: ShellBson; @@ -211,7 +212,7 @@ export class ShellInstanceState { info: undefined, }; if (!cliOptions.nodb) { - const mongo = new Mongo( + const mongo = new Mongo( this, undefined, undefined, @@ -223,7 +224,7 @@ export class ShellInstanceState { initialServiceProvider.initialDb || DEFAULT_DB ); } else { - this.currentDb = new NoDatabase() as DatabaseWithSchema; + this.currentDb = new NoDatabase() as DatabaseWithSchema; } this.currentCursor = null; this.context = {}; @@ -288,9 +289,9 @@ export class ShellInstanceState { public setDbFunc(newDb: any): DatabaseWithSchema { this.currentDb = newDb; - this.context.rs = new ReplicaSet(this.currentDb); - this.context.sh = new Shard(this.currentDb); - this.context.sp = Streams.newInstance(this.currentDb); + this.context.rs = new ReplicaSet(this.currentDb); + this.context.sh = new Shard(this.currentDb); + this.context.sp = Streams.newInstance(this.currentDb); this.fetchConnectionInfo().catch((err) => this.messageBus.emit('mongosh:error', err, 'shell-api') ); @@ -351,9 +352,9 @@ export class ShellInstanceState { } contextObject.console.clear = contextObject.cls; - contextObject.rs = new ReplicaSet(this.currentDb); - contextObject.sh = new Shard(this.currentDb); - contextObject.sp = Streams.newInstance(this.currentDb); + contextObject.rs = new ReplicaSet(this.currentDb); + contextObject.sh = new Shard(this.currentDb); + contextObject.sp = Streams.newInstance(this.currentDb); const setFunc = (newDb: any): DatabaseWithSchema => { if (getShellApiType(newDb) !== 'Database') { diff --git a/packages/shell-api/src/stream-processor.ts b/packages/shell-api/src/stream-processor.ts index 0a436d05c7..c1ba7f9294 100644 --- a/packages/shell-api/src/stream-processor.ts +++ b/packages/shell-api/src/stream-processor.ts @@ -10,14 +10,17 @@ import { } from './decorators'; import type { Streams } from './streams'; +import type { GenericServerSideSchema } from './helpers'; @shellApiClassDefault -export class StreamProcessor extends ShellApiWithMongoClass { - constructor(public _streams: Streams, public name: string) { +export class StreamProcessor< + M extends GenericServerSideSchema = GenericServerSideSchema +> extends ShellApiWithMongoClass { + constructor(public _streams: Streams, public name: string) { super(); } - get _mongo(): Mongo { + get _mongo(): Mongo { return this._streams._mongo; } diff --git a/packages/shell-api/src/streams.ts b/packages/shell-api/src/streams.ts index c0963521b5..7d6b87cf83 100644 --- a/packages/shell-api/src/streams.ts +++ b/packages/shell-api/src/streams.ts @@ -8,20 +8,18 @@ import { } from './decorators'; import StreamProcessor from './stream-processor'; import { ADMIN_DB, asPrintable, shellApiType } from './enums'; -import type { Database, DatabaseWithSchema } from './database'; +import type { DatabaseWithSchema } from './database'; import type Mongo from './mongo'; -import type { GenericDatabaseSchema, GenericServerSideSchema } from './helpers'; +import type { GenericServerSideSchema } from './helpers'; @shellApiClassDefault export class Streams< - M extends GenericServerSideSchema = GenericServerSideSchema, - D extends GenericDatabaseSchema = GenericDatabaseSchema -> extends ShellApiWithMongoClass { + M extends GenericServerSideSchema = GenericServerSideSchema +> extends ShellApiWithMongoClass { public static newInstance< - M extends GenericServerSideSchema = GenericServerSideSchema, - D extends GenericDatabaseSchema = GenericDatabaseSchema - >(database: DatabaseWithSchema) { - return new Proxy(new Streams(database), { + M extends GenericServerSideSchema = GenericServerSideSchema + >(database: DatabaseWithSchema) { + return new Proxy(new Streams(database), { get(target, prop) { const v = (target as any)[prop]; if (v !== undefined) { @@ -34,11 +32,11 @@ export class Streams< }); } - private _database: DatabaseWithSchema; + private _database: DatabaseWithSchema; - constructor(database: DatabaseWithSchema | Database) { + constructor(database: DatabaseWithSchema) { super(); - this._database = database as DatabaseWithSchema; + this._database = database; } get _mongo(): Mongo { @@ -49,8 +47,8 @@ export class Streams< return 'Atlas Stream Processing'; } - getProcessor(name: string): StreamProcessor { - return new StreamProcessor(this, name); + getProcessor(name: string): StreamProcessor { + return new StreamProcessor(this, name); } @returnsPromise @@ -137,7 +135,7 @@ export class Streams< return result; } const rawProcessors = result.streamProcessors; - const sps = rawProcessors.map((sp: StreamProcessor) => + const sps = rawProcessors.map((sp: StreamProcessor) => this.getProcessor(sp.name) );