diff --git a/packages/service-provider-core/src/all-transport-types.ts b/packages/service-provider-core/src/all-transport-types.ts index cbf805f6fc..c87f8cb130 100644 --- a/packages/service-provider-core/src/all-transport-types.ts +++ b/packages/service-provider-core/src/all-transport-types.ts @@ -57,6 +57,7 @@ export type { ReplaceOptions, ResumeToken, RunCommandOptions, + SearchIndexDescription, ServerSessionId, TagSet, TransactionOptions, diff --git a/packages/service-provider-core/src/writable.ts b/packages/service-provider-core/src/writable.ts index cc1e312fc2..436b93b4db 100644 --- a/packages/service-provider-core/src/writable.ts +++ b/packages/service-provider-core/src/writable.ts @@ -24,6 +24,7 @@ import type { DbOptions, OrderedBulkOperation, UnorderedBulkOperation, + SearchIndexDescription, } from './all-transport-types'; import type { ServiceProviderRunCommandCursor } from './cursors'; @@ -312,7 +313,7 @@ export default interface Writable { * * @param {String} database - The db name. * @param {String} collection - The collection name. - * @param {Object[]} indexSpecs the spec of the indexes to be created. + * @param {Object[]} indexSpecs - The spec of the indexes to be created. * @param {Object} options - The command options. * @param {DbOptions} dbOptions - The database options * @return {Promise} @@ -385,12 +386,7 @@ export default interface Writable { createSearchIndexes( database: string, collection: string, - // TODO(MONGOSH-1471): use SearchIndexDescription[] once available - specs: { - name: string; - type?: 'search' | 'vectorSearch'; - definition: Document; - }[], + descriptions: SearchIndexDescription[], dbOptions?: DbOptions ): Promise; diff --git a/packages/shell-api/src/collection.spec.ts b/packages/shell-api/src/collection.spec.ts index 95d16c2fae..63b7480072 100644 --- a/packages/shell-api/src/collection.spec.ts +++ b/packages/shell-api/src/collection.spec.ts @@ -2633,31 +2633,7 @@ describe('Collection', function () { serviceProvider.createSearchIndexes.resolves(['index_1']); }); - context('without anything', function () { - it('calls serviceProvider.createIndexes', async function () { - await collection.createSearchIndex(); - - expect(serviceProvider.createSearchIndexes).to.have.been.calledWith( - 'db1', - 'coll1', - [{ name: 'default', definition: {} }] - ); - }); - }); - - context('with name', function () { - it('calls serviceProvider.createIndexes', async function () { - await collection.createSearchIndex('my-index'); - - expect(serviceProvider.createSearchIndexes).to.have.been.calledWith( - 'db1', - 'coll1', - [{ name: 'my-index', definition: {} }] - ); - }); - }); - - context('with options', function () { + context('with definition options', function () { it('calls serviceProvider.createIndexes', async function () { await collection.createSearchIndex({ mappings: { dynamic: true } }); @@ -2669,7 +2645,7 @@ describe('Collection', function () { }); }); - context('with name, options', function () { + context('with name, definition options', function () { it('calls serviceProvider.createIndexes', async function () { await collection.createSearchIndex('my-index', { mappings: { dynamic: true }, @@ -2683,7 +2659,7 @@ describe('Collection', function () { }); }); - context('with name, options and type !== search', function () { + context('with name, definition options and type !== search', function () { it('calls serviceProvider.createSearchIndexes', async function () { await collection.createSearchIndex('my-index', 'vectorSearch', { mappings: { dynamic: true }, @@ -2703,7 +2679,7 @@ describe('Collection', function () { }); }); - context('with name, options and type === search', function () { + context('with name, definition options and type === search', function () { it('calls serviceProvider.createSearchIndexes', async function () { await collection.createSearchIndex('my-index', 'search', { mappings: { dynamic: true }, @@ -2717,7 +2693,7 @@ describe('Collection', function () { }); }); - context('with options and type but no name', function () { + context('with definition options and type but no name', function () { it('calls serviceProvider.createSearchIndexes', async function () { await collection.createSearchIndex( { mappings: { dynamic: true } }, @@ -2737,6 +2713,30 @@ describe('Collection', function () { ); }); }); + + context('with description options', function () { + it('calls serviceProvider.createSearchIndexes', async function () { + await collection.createSearchIndex({ + name: 'my-index', + type: 'vectorSearch', + definition: { + mappings: { dynamic: true }, + }, + }); + + expect(serviceProvider.createSearchIndexes).to.have.been.calledWith( + 'db1', + 'coll1', + [ + { + name: 'my-index', + type: 'vectorSearch', + definition: { mappings: { dynamic: true } }, + }, + ] + ); + }); + }); }); describe('createSearchIndexes', function () { diff --git a/packages/shell-api/src/collection.ts b/packages/shell-api/src/collection.ts index 3375b54a14..7b7432d77b 100644 --- a/packages/shell-api/src/collection.ts +++ b/packages/shell-api/src/collection.ts @@ -22,6 +22,7 @@ import type { FindAndModifyMethodShellOptions, RemoveShellOptions, MapReduceShellOptions, + SearchIndexDefinition, } from './helpers'; import { adaptAggregateOptions, @@ -67,6 +68,7 @@ import type { DropCollectionOptions, CheckMetadataConsistencyOptions, AggregateOptions, + SearchIndexDescription, } from '@mongosh/service-provider-core'; import type { RunCommandCursor, Database } from './index'; import { @@ -2383,37 +2385,68 @@ export default class Collection extends ShellApiWithMongoClass { ); } + async createSearchIndex( + name: string, + definition: SearchIndexDefinition + ): Promise; + async createSearchIndex( + name: string, + type: 'search' | 'vectorSearch', + definition: SearchIndexDefinition + ): Promise; + async createSearchIndex( + definition: SearchIndexDefinition, + type?: 'search' | 'vectorSearch' + ): Promise; + async createSearchIndex(description: SearchIndexDescription): Promise; @serverVersions(['6.0.0', ServerVersions.latest]) @returnsPromise @apiVersions([]) - // TODO(MONGOSH-1471): use SearchIndexDescription once available async createSearchIndex( - indexName?: string | Document, - type?: 'search' | 'vectorSearch' | Document, - definition?: Document + nameOrOptions?: string | SearchIndexDescription | SearchIndexDefinition, + typeOrOptions?: 'search' | 'vectorSearch' | SearchIndexDefinition, + definition?: SearchIndexDefinition ): Promise { - if (typeof type === 'object' && type !== null) { - definition = type; - type = undefined; - } - if (typeof indexName === 'object' && indexName !== null) { - definition = indexName; - indexName = undefined; + let indexDescription: SearchIndexDescription; + + if ( + typeof nameOrOptions === 'object' && + nameOrOptions !== null && + nameOrOptions.definition + ) { + indexDescription = nameOrOptions as SearchIndexDescription; + } else { + let indexName: string | undefined; + let indexType: 'search' | 'vectorSearch' | undefined; + + if (typeof typeOrOptions === 'object' && typeOrOptions !== null) { + definition = typeOrOptions; + } else { + indexType = typeOrOptions; + } + + if (typeof nameOrOptions === 'object' && nameOrOptions !== null) { + definition = nameOrOptions; + } else { + indexName = nameOrOptions; + } + + indexDescription = { + name: indexName ?? 'default', + // Omitting type when it is 'search' for compat with older servers + ...(indexType && + indexType !== 'search' && { + type: indexType as 'search' | 'vectorSearch', + }), + definition: { ...definition }, + }; } - this._emitCollectionApiCall('createSearchIndex', { indexName, definition }); + this._emitCollectionApiCall('createSearchIndex', indexDescription); const results = await this._mongo._serviceProvider.createSearchIndexes( this._database._name, this._name, - [ - { - name: indexName ?? 'default', - // Omitting type when it is 'search' for compat with older servers - ...(type && - type !== 'search' && { type: type as 'search' | 'vectorSearch' }), - definition: { ...definition }, - }, - ] + [indexDescription] ); return results[0]; } @@ -2421,13 +2454,8 @@ export default class Collection extends ShellApiWithMongoClass { @serverVersions(['6.0.0', ServerVersions.latest]) @returnsPromise @apiVersions([]) - // TODO(MONGOSH-1471): use SearchIndexDescription once available async createSearchIndexes( - specs: { - name: string; - type?: 'search' | 'vectorSearch'; - definition: Document; - }[] + specs: SearchIndexDescription[] ): Promise { this._emitCollectionApiCall('createSearchIndexes', { specs }); return await this._mongo._serviceProvider.createSearchIndexes( diff --git a/packages/shell-api/src/helpers.ts b/packages/shell-api/src/helpers.ts index 180137a60f..b05908ac68 100644 --- a/packages/shell-api/src/helpers.ts +++ b/packages/shell-api/src/helpers.ts @@ -1295,3 +1295,5 @@ export function buildConfigChunksCollectionMatch( export const aggregateBackgroundOptionNotSupportedHelp = 'the background option is not supported by the aggregate method and will be ignored, ' + 'use runCommand to use { background: true } with Atlas Data Federation'; + +export type SearchIndexDefinition = Document;