Skip to content

Commit

Permalink
fix(shell-api): create vector search index with description options M…
Browse files Browse the repository at this point in the history
…ONGOSH-1851 (#2377)

* fix(shell-api): create vector search index with description options MONGOSH-1851

* refactor: use overloads

* fix: remove unsupported use cases

* docs: fix comment
  • Loading branch information
alenakhineika authored Feb 24, 2025
1 parent 30ec9a9 commit bd0c2ad
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 63 deletions.
1 change: 1 addition & 0 deletions packages/service-provider-core/src/all-transport-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ export type {
ReplaceOptions,
ResumeToken,
RunCommandOptions,
SearchIndexDescription,
ServerSessionId,
TagSet,
TransactionOptions,
Expand Down
10 changes: 3 additions & 7 deletions packages/service-provider-core/src/writable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import type {
DbOptions,
OrderedBulkOperation,
UnorderedBulkOperation,
SearchIndexDescription,
} from './all-transport-types';
import type { ServiceProviderRunCommandCursor } from './cursors';

Expand Down Expand Up @@ -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}
Expand Down Expand Up @@ -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<string[]>;

Expand Down
58 changes: 29 additions & 29 deletions packages/shell-api/src/collection.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 } });

Expand All @@ -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 },
Expand All @@ -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 },
Expand All @@ -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 },
Expand All @@ -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 } },
Expand All @@ -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 () {
Expand Down
82 changes: 55 additions & 27 deletions packages/shell-api/src/collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import type {
FindAndModifyMethodShellOptions,
RemoveShellOptions,
MapReduceShellOptions,
SearchIndexDefinition,
} from './helpers';
import {
adaptAggregateOptions,
Expand Down Expand Up @@ -67,6 +68,7 @@ import type {
DropCollectionOptions,
CheckMetadataConsistencyOptions,
AggregateOptions,
SearchIndexDescription,
} from '@mongosh/service-provider-core';
import type { RunCommandCursor, Database } from './index';
import {
Expand Down Expand Up @@ -2383,51 +2385,77 @@ export default class Collection extends ShellApiWithMongoClass {
);
}

async createSearchIndex(
name: string,
definition: SearchIndexDefinition
): Promise<string>;
async createSearchIndex(
name: string,
type: 'search' | 'vectorSearch',
definition: SearchIndexDefinition
): Promise<string>;
async createSearchIndex(
definition: SearchIndexDefinition,
type?: 'search' | 'vectorSearch'
): Promise<string>;
async createSearchIndex(description: SearchIndexDescription): Promise<string>;
@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<string> {
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];
}

@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<string[]> {
this._emitCollectionApiCall('createSearchIndexes', { specs });
return await this._mongo._serviceProvider.createSearchIndexes(
Expand Down
2 changes: 2 additions & 0 deletions packages/shell-api/src/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;

0 comments on commit bd0c2ad

Please sign in to comment.