Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(NODE-5919): support new type option in create search index helpers #4060

Merged
merged 1 commit into from
Apr 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/operations/search_indexes/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,15 @@ import { AbstractOperation } from '../operation';
/**
* @public
*/
export interface SearchIndexDescription {
export interface SearchIndexDescription extends Document {
nbbeeken marked this conversation as resolved.
Show resolved Hide resolved
/** The name of the index. */
name?: string;

/** The index definition. */
definition: Document;

/** The type of the index. Currently `search` or `vectorSearch` are supported. */
type?: string;
}

/** @internal */
Expand Down
162 changes: 162 additions & 0 deletions test/manual/search-index-management.prose.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -340,5 +340,167 @@ describe('Index Management Prose Tests', function () {
.to.deep.equal({ dynamic: false });
}
);

it(
'Case 7: Driver can successfully handle search index types when creating indexes',
metadata,
async function () {
// 01. Create a collection with the "create" command using a randomly generated name (referred to as `coll0`).
const coll0 = collection;
{
// 02. Create a new search index on `coll0` with the `createSearchIndex` helper. Use the following definition:
// ```typescript
// {
// name: 'test-search-index-case7-implicit',
// definition: {
// mappings: { dynamic: false }
// }
// }
// ```
const indexName = await coll0.createSearchIndex({
name: 'test-search-index-case7-implicit',
definition: {
mappings: { dynamic: false }
}
});
// 03. Assert that the command returns the name of the index: `"test-search-index-case7-implicit"`.
expect(indexName).to.equal('test-search-index-case7-implicit');
// 04. Run `coll0.listSearchIndexes('test-search-index-case7-implicit')` repeatedly every 5 seconds until the following
// condition is satisfied and store the value in a variable `index1`:

// - An index with the `name` of `test-search-index-case7-implicit` is present and the index has a field `queryable`
// with a value of `true`.

const [index1] = await waitForIndexes({
predicate: indexes => indexes.every(index => index.queryable),
indexNames: 'test-search-index-case7-implicit',
collection: coll0
});

// 05. Assert that `index1` has a property `type` whose value is `search`.
expect(index1).to.have.property('type', 'search');
}
{
// 06. Create a new search index on `coll0` with the `createSearchIndex` helper. Use the following definition:
// ```typescript
// {
// name: 'test-search-index-case7-explicit',
// type: 'search',
// definition: {
// mappings: { dynamic: false }
// }
// }
// ```
const indexName = await coll0.createSearchIndex({
name: 'test-search-index-case7-explicit',
type: 'search',
definition: {
mappings: { dynamic: false }
}
});
// 07. Assert that the command returns the name of the index: `"test-search-index-case7-explicit"`.
expect(indexName).to.equal('test-search-index-case7-explicit');
// 08. Run `coll0.listSearchIndexes('test-search-index-case7-explicit')` repeatedly every 5 seconds until the following
// condition is satisfied and store the value in a variable `index2`:

// - An index with the `name` of `test-search-index-case7-explicit` is present and the index has a field `queryable`
// with a value of `true`.

const [index2] = await waitForIndexes({
predicate: indexes => indexes.every(index => index.queryable),
indexNames: 'test-search-index-case7-explicit',
collection: coll0
});
// 09. Assert that `index2` has a property `type` whose value is `search`.
expect(index2).to.have.property('type', 'search');
}
{
// 10. Create a new vector search index on `coll0` with the `createSearchIndex` helper. Use the following definition:
// ```typescript
// {
// name: 'test-search-index-case7-vector',
// type: 'vectorSearch',
// definition: {
// "fields": [
// {
// "type": "vector",
// "path": "plot_embedding",
// "numDimensions": 1536,
// "similarity": "euclidean",
// },
// ]
// }
// }
// ```

const indexName = await coll0.createSearchIndex({
name: 'test-search-index-case7-vector',
type: 'vectorSearch',
definition: {
fields: [
{
type: 'vector',
path: 'plot_embedding',
numDimensions: 1536,
similarity: 'euclidean'
}
]
}
});
// 11. Assert that the command returns the name of the index: `"test-search-index-case7-vector"`.
expect(indexName).to.equal('test-search-index-case7-vector');
// 12. Run `coll0.listSearchIndexes('test-search-index-case7-vector')` repeatedly every 5 seconds until the following
// condition is satisfied and store the value in a variable `index3`:
// - An index with the `name` of `test-search-index-case7-vector` is present and the index has a field `queryable` with
// a value of `true`.
const [index3] = await waitForIndexes({
predicate: indexes => indexes.every(index => index.queryable),
indexNames: 'test-search-index-case7-vector',
collection: coll0
});

// 13. Assert that `index3` has a property `type` whose value is `vectorSearch`.
expect(index3).to.have.property('type', 'vectorSearch');
}
}
);

it('Case 8: Driver requires explicit type to create a vector search index', async function () {
// 1. Create a collection with the "create" command using a randomly generated name (referred to as `coll0`).
const coll0 = collection;

// 2. Create a new vector search index on `coll0` with the `createSearchIndex` helper. Use the following definition:
// {
// name: 'test-search-index-case8-error',
// definition: {
// fields: [
// {
// type: 'vector',
// path: 'plot_embedding',
// numDimensions: 1536,
// similarity: 'euclidean',
// },
// ]
// }
// }
const definition = {
name: 'test-search-index-case8-error',
definition: {
fields: [
{
type: 'vector',
path: 'plot_embedding',
numDimensions: 1536,
similarity: 'euclidean'
}
]
}
};
const error = await coll0.createSearchIndex(definition).catch(e => e);

// 3. Assert that the command throws an exception containing the string "Attribute mappings missing" due to the `mappings`
// field missing.
expect(error).to.match(/Attribute mappings missing/i);
});
});
});
72 changes: 68 additions & 4 deletions test/spec/index-management/createSearchIndex.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@
"mappings": {
"dynamic": true
}
}
},
"type": "search"
}
},
"expectError": {
Expand All @@ -73,7 +74,8 @@
"mappings": {
"dynamic": true
}
}
},
"type": "search"
}
],
"$db": "database0"
Expand All @@ -97,7 +99,8 @@
"dynamic": true
}
},
"name": "test index"
"name": "test index",
"type": "search"
}
},
"expectError": {
Expand All @@ -121,7 +124,68 @@
"dynamic": true
}
},
"name": "test index"
"name": "test index",
"type": "search"
}
],
"$db": "database0"
}
}
}
]
}
]
},
{
"description": "create a vector search index",
"operations": [
{
"name": "createSearchIndex",
"object": "collection0",
"arguments": {
"model": {
"definition": {
"fields": [
{
"type": "vector",
"path": "plot_embedding",
"numDimensions": 1536,
"similarity": "euclidean"
}
]
},
"name": "test index",
"type": "vectorSearch"
}
},
"expectError": {
"isError": true,
"errorContains": "Atlas"
}
}
],
"expectEvents": [
{
"client": "client0",
"events": [
{
"commandStartedEvent": {
"command": {
"createSearchIndexes": "collection0",
"indexes": [
{
"definition": {
"fields": [
{
"type": "vector",
"path": "plot_embedding",
"numDimensions": 1536,
"similarity": "euclidean"
}
]
},
"name": "test index",
"type": "vectorSearch"
}
],
"$db": "database0"
Expand Down
30 changes: 26 additions & 4 deletions test/spec/index-management/createSearchIndex.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ tests:
- name: createSearchIndex
object: *collection0
arguments:
model: { definition: &definition { mappings: { dynamic: true } } }
model: { definition: &definition { mappings: { dynamic: true } } , type: 'search' }
expectError:
# This test always errors in a non-Atlas environment. The test functions as a unit test by asserting
# that the driver constructs and sends the correct command.
Expand All @@ -39,15 +39,15 @@ tests:
- commandStartedEvent:
command:
createSearchIndexes: *collection0
indexes: [ { definition: *definition } ]
indexes: [ { definition: *definition, type: 'search'} ]
$db: *database0

- description: "name provided for an index definition"
operations:
- name: createSearchIndex
object: *collection0
arguments:
model: { definition: &definition { mappings: { dynamic: true } } , name: 'test index' }
model: { definition: &definition { mappings: { dynamic: true } } , name: 'test index', type: 'search' }
expectError:
# This test always errors in a non-Atlas environment. The test functions as a unit test by asserting
# that the driver constructs and sends the correct command.
Expand All @@ -60,5 +60,27 @@ tests:
- commandStartedEvent:
command:
createSearchIndexes: *collection0
indexes: [ { definition: *definition, name: 'test index' } ]
indexes: [ { definition: *definition, name: 'test index', type: 'search' } ]
$db: *database0

- description: "create a vector search index"
operations:
- name: createSearchIndex
object: *collection0
arguments:
model: { definition: &definition { fields: [ {"type": "vector", "path": "plot_embedding", "numDimensions": 1536, "similarity": "euclidean"} ] }
, name: 'test index', type: 'vectorSearch' }
expectError:
# This test always errors in a non-Atlas environment. The test functions as a unit test by asserting
# that the driver constructs and sends the correct command.
# The expected error message was changed in SERVER-83003. Check for the substring "Atlas" shared by both error messages.
isError: true
errorContains: Atlas
expectEvents:
- client: *client0
events:
- commandStartedEvent:
command:
createSearchIndexes: *collection0
indexes: [ { definition: *definition, name: 'test index', type: 'vectorSearch' } ]
$db: *database0
Loading
Loading