From c65a5b5aeffb7f2f6b58415321c6559556124d06 Mon Sep 17 00:00:00 2001 From: Gagik Amaryan Date: Tue, 22 Oct 2024 16:12:54 +0200 Subject: [PATCH] fix(shell-api): Align database and collection aggregate functions MONGOSH-1868 (#2229) --- packages/shell-api/src/collection.ts | 20 +++++++------ packages/shell-api/src/database.spec.ts | 23 +++++++++++--- packages/shell-api/src/database.ts | 40 +++++++++++++++++-------- 3 files changed, 58 insertions(+), 25 deletions(-) diff --git a/packages/shell-api/src/collection.ts b/packages/shell-api/src/collection.ts index a8c699ff5..911dcc45d 100644 --- a/packages/shell-api/src/collection.ts +++ b/packages/shell-api/src/collection.ts @@ -66,6 +66,7 @@ import type { UpdateOptions, DropCollectionOptions, CheckMetadataConsistencyOptions, + AggregateOptions, } from '@mongosh/service-provider-core'; import type { RunCommandCursor, Database } from './index'; import { @@ -159,26 +160,27 @@ export default class Collection extends ShellApiWithMongoClass { */ async aggregate( pipeline: Document[], - options: Document & { explain?: never } - ): Promise; + options: AggregateOptions & { explain: ExplainVerbosityLike } + ): Promise; async aggregate( pipeline: Document[], - options: Document & { explain: ExplainVerbosityLike } - ): Promise; + options?: AggregateOptions + ): Promise; async aggregate(...stages: Document[]): Promise; @returnsPromise @returnType('AggregationCursor') @apiVersions([1]) - async aggregate(...args: any[]): Promise { - let options; - let pipeline; + async aggregate(...args: unknown[]): Promise { + let options: AggregateOptions; + let pipeline: Document[]; if (args.length === 0 || Array.isArray(args[0])) { options = args[1] || {}; - pipeline = args[0] || []; + pipeline = (args[0] as Document[]) || []; } else { options = {}; - pipeline = args || []; + pipeline = (args as Document[]) || []; } + if ('background' in options) { await this._instanceState.printWarning( aggregateBackgroundOptionNotSupportedHelp diff --git a/packages/shell-api/src/database.spec.ts b/packages/shell-api/src/database.spec.ts index a78e97101..4cc7cb7e2 100644 --- a/packages/shell-api/src/database.spec.ts +++ b/packages/shell-api/src/database.spec.ts @@ -401,12 +401,25 @@ describe('Database', function () { }); it('supports a single aggregation stage', async function () { - await database.aggregate({ $piplelineStage: {} }, { options: true }); + await database.aggregate({ $piplelineStage: {} }); expect(serviceProvider.aggregateDb).to.have.been.calledWith( database._name, [{ $piplelineStage: {} }], - { options: true } + {} + ); + }); + + it('supports passing args as aggregation stages', async function () { + await database.aggregate( + { $piplelineStage: {} }, + { $piplelineStage2: {} } + ); + + expect(serviceProvider.aggregateDb).to.have.been.calledWith( + database._name, + [{ $piplelineStage: {} }, { $piplelineStage2: {} }], + {} ); }); @@ -2891,7 +2904,9 @@ describe('Database', function () { it('runs a $sql aggregation', async function () { const serviceProviderCursor = stubInterface(); serviceProvider.aggregateDb.returns(serviceProviderCursor as any); - await database.sql('SELECT * FROM somecollection;', { options: true }); + await database.sql('SELECT * FROM somecollection;', { + serializeFunctions: true, + }); expect(serviceProvider.aggregateDb).to.have.been.calledWith( database._name, [ @@ -2904,7 +2919,7 @@ describe('Database', function () { }, }, ], - { options: true } + { serializeFunctions: true } ); }); diff --git a/packages/shell-api/src/database.ts b/packages/shell-api/src/database.ts index 7c6ce4a3b..c148cc14e 100644 --- a/packages/shell-api/src/database.ts +++ b/packages/shell-api/src/database.ts @@ -52,6 +52,8 @@ import type { CreateEncryptedCollectionOptions, CheckMetadataConsistencyOptions, RunCommandOptions, + ExplainVerbosityLike, + AggregateOptions, } from '@mongosh/service-provider-core'; export type CollectionNamesWithTypes = { @@ -413,27 +415,38 @@ export default class Database extends ShellApiWithMongoClass { } /** - * Run an aggregation against the db. + * Run an aggregation against the database. Accepts array pipeline and options object OR stages as individual arguments. * - * @param pipeline - * @param options * @returns {Promise} The promise of aggregation results. */ + async aggregate( + pipeline: Document[], + options: AggregateOptions & { explain: ExplainVerbosityLike } + ): Promise; + async aggregate( + pipeline: Document[], + options?: AggregateOptions + ): Promise; + async aggregate(...stages: Document[]): Promise; @returnsPromise @returnType('AggregationCursor') @apiVersions([1]) - async aggregate( - pipelineOrSingleStage: Document | Document[], - options?: Document - ): Promise { - if ('background' in (options ?? {})) { + async aggregate(...args: unknown[]): Promise { + let options: AggregateOptions; + let pipeline: Document[]; + if (args.length === 0 || Array.isArray(args[0])) { + options = args[1] || {}; + pipeline = (args[0] as Document[]) || []; + } else { + options = {}; + pipeline = (args as Document[]) || []; + } + + if ('background' in options) { await this._instanceState.printWarning( aggregateBackgroundOptionNotSupportedHelp ); } - const pipeline: Document[] = Array.isArray(pipelineOrSingleStage) - ? pipelineOrSingleStage - : [pipelineOrSingleStage]; assertArgsDefinedType([pipeline], [true], 'Database.aggregate'); @@ -1731,7 +1744,10 @@ export default class Database extends ShellApiWithMongoClass { @serverVersions(['4.4.0', ServerVersions.latest]) @returnsPromise @returnType('AggregationCursor') - async sql(sqlString: string, options?: Document): Promise { + async sql( + sqlString: string, + options?: AggregateOptions + ): 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.'