@mastra/chroma 0.0.0-trigger-playground-ui-package-20250506151043 → 0.0.0-tsconfig-compile-20250703214351
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +348 -4
- package/dist/_tsup-dts-rollup.d.cts +49 -22
- package/dist/_tsup-dts-rollup.d.ts +49 -22
- package/dist/index.cjs +214 -75
- package/dist/index.js +213 -74
- package/package.json +13 -10
- package/src/vector/filter.test.ts +24 -19
- package/src/vector/filter.ts +35 -4
- package/src/vector/index.test.ts +89 -138
- package/src/vector/index.ts +229 -110
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mastra/chroma",
|
|
3
|
-
"version": "0.0.0-
|
|
3
|
+
"version": "0.0.0-tsconfig-compile-20250703214351",
|
|
4
4
|
"description": "Chroma vector store provider for Mastra",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -20,17 +20,20 @@
|
|
|
20
20
|
},
|
|
21
21
|
"license": "MIT",
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"chromadb": "^2.
|
|
24
|
-
"@mastra/core": "0.0.0-trigger-playground-ui-package-20250506151043"
|
|
23
|
+
"chromadb": "^2.4.6"
|
|
25
24
|
},
|
|
26
25
|
"devDependencies": {
|
|
27
|
-
"@microsoft/api-extractor": "^7.52.
|
|
28
|
-
"@types/node": "^20.
|
|
29
|
-
"eslint": "^9.
|
|
30
|
-
"tsup": "^8.
|
|
31
|
-
"typescript": "^5.8.
|
|
32
|
-
"vitest": "^3.
|
|
33
|
-
"@internal/lint": "0.0.0-
|
|
26
|
+
"@microsoft/api-extractor": "^7.52.8",
|
|
27
|
+
"@types/node": "^20.19.0",
|
|
28
|
+
"eslint": "^9.29.0",
|
|
29
|
+
"tsup": "^8.5.0",
|
|
30
|
+
"typescript": "^5.8.3",
|
|
31
|
+
"vitest": "^3.2.4",
|
|
32
|
+
"@internal/lint": "0.0.0-tsconfig-compile-20250703214351",
|
|
33
|
+
"@mastra/core": "0.0.0-tsconfig-compile-20250703214351"
|
|
34
|
+
},
|
|
35
|
+
"peerDependencies": {
|
|
36
|
+
"@mastra/core": "0.0.0-tsconfig-compile-20250703214351"
|
|
34
37
|
},
|
|
35
38
|
"scripts": {
|
|
36
39
|
"build": "tsup src/index.ts --format esm,cjs --experimental-dts --clean --treeshake=smallest --splitting",
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
2
|
|
|
3
|
+
import type { ChromaVectorFilter } from './filter';
|
|
3
4
|
import { ChromaFilterTranslator } from './filter';
|
|
4
5
|
|
|
5
6
|
describe('ChromaFilterTranslator', () => {
|
|
@@ -13,17 +14,17 @@ describe('ChromaFilterTranslator', () => {
|
|
|
13
14
|
describe('basic operations', () => {
|
|
14
15
|
it('handles empty filters', () => {
|
|
15
16
|
expect(translator.translate({})).toEqual({});
|
|
16
|
-
expect(translator.translate(null
|
|
17
|
-
expect(translator.translate(undefined
|
|
17
|
+
expect(translator.translate(null)).toEqual(null);
|
|
18
|
+
expect(translator.translate(undefined)).toEqual(undefined);
|
|
18
19
|
});
|
|
19
20
|
|
|
20
21
|
it('retains implicit equality', () => {
|
|
21
|
-
const filter = { field: 'value' };
|
|
22
|
+
const filter: ChromaVectorFilter = { field: 'value' };
|
|
22
23
|
expect(translator.translate(filter)).toEqual({ field: 'value' });
|
|
23
24
|
});
|
|
24
25
|
|
|
25
26
|
it('converts multiple top-level fields to $and', () => {
|
|
26
|
-
const filter = {
|
|
27
|
+
const filter: ChromaVectorFilter = {
|
|
27
28
|
field1: 'value1',
|
|
28
29
|
field2: 'value2',
|
|
29
30
|
};
|
|
@@ -33,7 +34,7 @@ describe('ChromaFilterTranslator', () => {
|
|
|
33
34
|
});
|
|
34
35
|
|
|
35
36
|
it('handles multiple operators on same field', () => {
|
|
36
|
-
const filter = {
|
|
37
|
+
const filter: ChromaVectorFilter = {
|
|
37
38
|
price: { $gt: 100, $lt: 200 },
|
|
38
39
|
quantity: { $gte: 10, $lte: 20 },
|
|
39
40
|
};
|
|
@@ -49,7 +50,7 @@ describe('ChromaFilterTranslator', () => {
|
|
|
49
50
|
|
|
50
51
|
it('normalizes date values', () => {
|
|
51
52
|
const date = new Date('2024-01-01');
|
|
52
|
-
const filter = { timestamp: { $gt: date } };
|
|
53
|
+
const filter: ChromaVectorFilter = { timestamp: { $gt: date } };
|
|
53
54
|
expect(translator.translate(filter)).toEqual({ timestamp: { $gt: date.toISOString() } });
|
|
54
55
|
});
|
|
55
56
|
});
|
|
@@ -57,7 +58,7 @@ describe('ChromaFilterTranslator', () => {
|
|
|
57
58
|
// Array Operations
|
|
58
59
|
describe('array operations', () => {
|
|
59
60
|
it('handles arrays as $in operator', () => {
|
|
60
|
-
const filter = { tags: ['tag1', 'tag2'] };
|
|
61
|
+
const filter: ChromaVectorFilter = { tags: ['tag1', 'tag2'] };
|
|
61
62
|
expect(translator.translate(filter)).toEqual({ tags: { $in: ['tag1', 'tag2'] } });
|
|
62
63
|
});
|
|
63
64
|
|
|
@@ -68,10 +69,14 @@ describe('ChromaFilterTranslator', () => {
|
|
|
68
69
|
|
|
69
70
|
it('handles arrays as direct values', () => {
|
|
70
71
|
// Direct array value should be converted to $in
|
|
71
|
-
|
|
72
|
+
const filter: ChromaVectorFilter = { field: ['value1', 'value2'] };
|
|
73
|
+
expect(translator.translate(filter)).toEqual({
|
|
74
|
+
field: { $in: ['value1', 'value2'] },
|
|
75
|
+
});
|
|
72
76
|
|
|
73
77
|
// Empty direct array
|
|
74
|
-
|
|
78
|
+
const filter2 = { field: [] };
|
|
79
|
+
expect(translator.translate(filter2)).toEqual({ field: { $in: [] } });
|
|
75
80
|
});
|
|
76
81
|
|
|
77
82
|
describe('$in operator variations', () => {
|
|
@@ -99,7 +104,7 @@ describe('ChromaFilterTranslator', () => {
|
|
|
99
104
|
// Logical Operators
|
|
100
105
|
describe('logical operators', () => {
|
|
101
106
|
it('handles logical operators', () => {
|
|
102
|
-
const filter = {
|
|
107
|
+
const filter: ChromaVectorFilter = {
|
|
103
108
|
$or: [{ status: { $eq: 'active' } }, { age: { $gt: 25 } }],
|
|
104
109
|
};
|
|
105
110
|
expect(translator.translate(filter)).toEqual({
|
|
@@ -108,7 +113,7 @@ describe('ChromaFilterTranslator', () => {
|
|
|
108
113
|
});
|
|
109
114
|
|
|
110
115
|
it('handles nested logical operators', () => {
|
|
111
|
-
const filter = {
|
|
116
|
+
const filter: ChromaVectorFilter = {
|
|
112
117
|
$and: [
|
|
113
118
|
{ status: { $eq: 'active' } },
|
|
114
119
|
{
|
|
@@ -142,7 +147,7 @@ describe('ChromaFilterTranslator', () => {
|
|
|
142
147
|
});
|
|
143
148
|
|
|
144
149
|
it('handles complex nested conditions', () => {
|
|
145
|
-
const filter = {
|
|
150
|
+
const filter: ChromaVectorFilter = {
|
|
146
151
|
$or: [
|
|
147
152
|
{ age: { $gt: 25 } },
|
|
148
153
|
{
|
|
@@ -176,7 +181,7 @@ describe('ChromaFilterTranslator', () => {
|
|
|
176
181
|
});
|
|
177
182
|
|
|
178
183
|
it('preserves empty objects as exact match conditions', () => {
|
|
179
|
-
const filter = {
|
|
184
|
+
const filter: ChromaVectorFilter = {
|
|
180
185
|
metadata: {},
|
|
181
186
|
'user.profile': {},
|
|
182
187
|
};
|
|
@@ -187,7 +192,7 @@ describe('ChromaFilterTranslator', () => {
|
|
|
187
192
|
});
|
|
188
193
|
|
|
189
194
|
it('handles empty objects in logical operators', () => {
|
|
190
|
-
const filter = {
|
|
195
|
+
const filter: ChromaVectorFilter = {
|
|
191
196
|
$or: [{}, { status: 'active' }],
|
|
192
197
|
};
|
|
193
198
|
|
|
@@ -211,7 +216,7 @@ describe('ChromaFilterTranslator', () => {
|
|
|
211
216
|
});
|
|
212
217
|
|
|
213
218
|
it('handles empty objects in comparison operators', () => {
|
|
214
|
-
const filter = {
|
|
219
|
+
const filter: ChromaVectorFilter = {
|
|
215
220
|
metadata: { $eq: {} },
|
|
216
221
|
};
|
|
217
222
|
|
|
@@ -221,7 +226,7 @@ describe('ChromaFilterTranslator', () => {
|
|
|
221
226
|
});
|
|
222
227
|
|
|
223
228
|
it('handles empty objects in array operators', () => {
|
|
224
|
-
const filter = {
|
|
229
|
+
const filter: ChromaVectorFilter = {
|
|
225
230
|
tags: { $in: [{}] },
|
|
226
231
|
};
|
|
227
232
|
|
|
@@ -335,7 +340,7 @@ describe('ChromaFilterTranslator', () => {
|
|
|
335
340
|
});
|
|
336
341
|
|
|
337
342
|
it('throws error for unsupported logical operators', () => {
|
|
338
|
-
const invalidFilters = [
|
|
343
|
+
const invalidFilters: any = [
|
|
339
344
|
{
|
|
340
345
|
$not: { field: 'value' },
|
|
341
346
|
},
|
|
@@ -374,7 +379,7 @@ describe('ChromaFilterTranslator', () => {
|
|
|
374
379
|
});
|
|
375
380
|
|
|
376
381
|
it('throws error for unsupported operators', () => {
|
|
377
|
-
const unsupportedFilters = [
|
|
382
|
+
const unsupportedFilters: any = [
|
|
378
383
|
{ field: { $regex: 'pattern' } },
|
|
379
384
|
{ field: { $contains: 'value' } },
|
|
380
385
|
{ field: { $exists: true } },
|
|
@@ -395,7 +400,7 @@ describe('ChromaFilterTranslator', () => {
|
|
|
395
400
|
expect(() => translator.translate(filter)).toThrow();
|
|
396
401
|
});
|
|
397
402
|
it('throws error for non-logical operators at top level', () => {
|
|
398
|
-
const invalidFilters = [{ $gt: 100 }, { $in: ['value1', 'value2'] }, { $eq: true }];
|
|
403
|
+
const invalidFilters: any = [{ $gt: 100 }, { $in: ['value1', 'value2'] }, { $eq: true }];
|
|
399
404
|
|
|
400
405
|
invalidFilters.forEach(filter => {
|
|
401
406
|
expect(() => translator.translate(filter)).toThrow(/Invalid top-level operator/);
|
package/src/vector/filter.ts
CHANGED
|
@@ -1,12 +1,43 @@
|
|
|
1
1
|
import { BaseFilterTranslator } from '@mastra/core/vector/filter';
|
|
2
|
-
import type {
|
|
2
|
+
import type {
|
|
3
|
+
VectorFilter,
|
|
4
|
+
OperatorSupport,
|
|
5
|
+
QueryOperator,
|
|
6
|
+
OperatorValueMap,
|
|
7
|
+
LogicalOperatorValueMap,
|
|
8
|
+
BlacklistedRootOperators,
|
|
9
|
+
} from '@mastra/core/vector/filter';
|
|
10
|
+
|
|
11
|
+
type ChromaOperatorValueMap = Omit<OperatorValueMap, '$exists' | '$elemMatch' | '$regex' | '$options'>;
|
|
12
|
+
|
|
13
|
+
type ChromaLogicalOperatorValueMap = Omit<LogicalOperatorValueMap, '$nor' | '$not'>;
|
|
14
|
+
|
|
15
|
+
type ChromaBlacklisted = BlacklistedRootOperators | '$nor' | '$not';
|
|
16
|
+
|
|
17
|
+
export type ChromaVectorFilter = VectorFilter<
|
|
18
|
+
keyof ChromaOperatorValueMap,
|
|
19
|
+
ChromaOperatorValueMap,
|
|
20
|
+
ChromaLogicalOperatorValueMap,
|
|
21
|
+
ChromaBlacklisted
|
|
22
|
+
>;
|
|
23
|
+
|
|
24
|
+
type ChromaDocumentOperatorValueMap = ChromaOperatorValueMap;
|
|
25
|
+
|
|
26
|
+
type ChromaDocumentBlacklisted = Exclude<ChromaBlacklisted, '$contains'>;
|
|
27
|
+
|
|
28
|
+
export type ChromaVectorDocumentFilter = VectorFilter<
|
|
29
|
+
keyof ChromaDocumentOperatorValueMap,
|
|
30
|
+
ChromaDocumentOperatorValueMap,
|
|
31
|
+
ChromaLogicalOperatorValueMap,
|
|
32
|
+
ChromaDocumentBlacklisted
|
|
33
|
+
>;
|
|
3
34
|
|
|
4
35
|
/**
|
|
5
36
|
* Translator for Chroma filter queries.
|
|
6
37
|
* Maintains MongoDB-compatible syntax while ensuring proper validation
|
|
7
38
|
* and normalization of values.
|
|
8
39
|
*/
|
|
9
|
-
export class ChromaFilterTranslator extends BaseFilterTranslator {
|
|
40
|
+
export class ChromaFilterTranslator extends BaseFilterTranslator<ChromaVectorFilter> {
|
|
10
41
|
protected override getSupportedOperators(): OperatorSupport {
|
|
11
42
|
return {
|
|
12
43
|
...BaseFilterTranslator.DEFAULT_OPERATORS,
|
|
@@ -18,14 +49,14 @@ export class ChromaFilterTranslator extends BaseFilterTranslator {
|
|
|
18
49
|
};
|
|
19
50
|
}
|
|
20
51
|
|
|
21
|
-
translate(filter?:
|
|
52
|
+
translate(filter?: ChromaVectorFilter): ChromaVectorFilter {
|
|
22
53
|
if (this.isEmpty(filter)) return filter;
|
|
23
54
|
this.validateFilter(filter);
|
|
24
55
|
|
|
25
56
|
return this.translateNode(filter);
|
|
26
57
|
}
|
|
27
58
|
|
|
28
|
-
private translateNode(node:
|
|
59
|
+
private translateNode(node: ChromaVectorFilter, currentPath: string = ''): any {
|
|
29
60
|
// Handle primitive values and arrays
|
|
30
61
|
if (this.isRegex(node)) {
|
|
31
62
|
throw new Error('Regex is not supported in Chroma');
|
package/src/vector/index.test.ts
CHANGED
|
@@ -16,7 +16,7 @@ describe('ChromaVector Integration Tests', () => {
|
|
|
16
16
|
beforeEach(async () => {
|
|
17
17
|
// Clean up any existing test index
|
|
18
18
|
try {
|
|
19
|
-
await vectorDB.deleteIndex(testIndexName);
|
|
19
|
+
await vectorDB.deleteIndex({ indexName: testIndexName });
|
|
20
20
|
} catch {
|
|
21
21
|
// Ignore errors if index doesn't exist
|
|
22
22
|
}
|
|
@@ -26,7 +26,7 @@ describe('ChromaVector Integration Tests', () => {
|
|
|
26
26
|
afterEach(async () => {
|
|
27
27
|
// Cleanup after tests
|
|
28
28
|
try {
|
|
29
|
-
await vectorDB.deleteIndex(testIndexName);
|
|
29
|
+
await vectorDB.deleteIndex({ indexName: testIndexName });
|
|
30
30
|
} catch {
|
|
31
31
|
// Ignore cleanup errors
|
|
32
32
|
}
|
|
@@ -39,14 +39,14 @@ describe('ChromaVector Integration Tests', () => {
|
|
|
39
39
|
});
|
|
40
40
|
|
|
41
41
|
it('should describe index correctly', async () => {
|
|
42
|
-
const stats: IndexStats = await vectorDB.describeIndex(testIndexName);
|
|
42
|
+
const stats: IndexStats = await vectorDB.describeIndex({ indexName: testIndexName });
|
|
43
43
|
expect(stats.dimension).toBe(dimension);
|
|
44
44
|
expect(stats.count).toBe(0);
|
|
45
45
|
expect(stats.metric).toBe('cosine');
|
|
46
46
|
});
|
|
47
47
|
|
|
48
48
|
it('should delete index', async () => {
|
|
49
|
-
await vectorDB.deleteIndex(testIndexName);
|
|
49
|
+
await vectorDB.deleteIndex({ indexName: testIndexName });
|
|
50
50
|
const indexes = await vectorDB.listIndexes();
|
|
51
51
|
expect(indexes).not.toContain(testIndexName);
|
|
52
52
|
});
|
|
@@ -58,10 +58,10 @@ describe('ChromaVector Integration Tests', () => {
|
|
|
58
58
|
const testIndex = `test-index-${metric}`;
|
|
59
59
|
await vectorDB.createIndex({ indexName: testIndex, dimension, metric });
|
|
60
60
|
|
|
61
|
-
const stats = await vectorDB.describeIndex(testIndex);
|
|
61
|
+
const stats = await vectorDB.describeIndex({ indexName: testIndex });
|
|
62
62
|
expect(stats.metric).toBe(metric);
|
|
63
63
|
|
|
64
|
-
await vectorDB.deleteIndex(testIndex);
|
|
64
|
+
await vectorDB.deleteIndex({ indexName: testIndex });
|
|
65
65
|
}
|
|
66
66
|
});
|
|
67
67
|
});
|
|
@@ -80,14 +80,14 @@ describe('ChromaVector Integration Tests', () => {
|
|
|
80
80
|
expect(ids).toHaveLength(testVectors.length);
|
|
81
81
|
ids.forEach(id => expect(typeof id).toBe('string'));
|
|
82
82
|
|
|
83
|
-
const stats = await vectorDB.describeIndex(testIndexName);
|
|
83
|
+
const stats = await vectorDB.describeIndex({ indexName: testIndexName });
|
|
84
84
|
expect(stats.count).toBe(testVectors.length);
|
|
85
85
|
});
|
|
86
86
|
|
|
87
87
|
it('should upsert vectors with provided ids and metadata', async () => {
|
|
88
88
|
await vectorDB.upsert({ indexName: testIndexName, vectors: testVectors, metadata: testMetadata, ids: testIds });
|
|
89
89
|
|
|
90
|
-
const stats = await vectorDB.describeIndex(testIndexName);
|
|
90
|
+
const stats = await vectorDB.describeIndex({ indexName: testIndexName });
|
|
91
91
|
expect(stats.count).toBe(testVectors.length);
|
|
92
92
|
|
|
93
93
|
// Query each vector to verify metadata
|
|
@@ -133,7 +133,7 @@ describe('ChromaVector Integration Tests', () => {
|
|
|
133
133
|
metadata: newMetaData,
|
|
134
134
|
};
|
|
135
135
|
|
|
136
|
-
await vectorDB.
|
|
136
|
+
await vectorDB.updateVector({ indexName: testIndexName, id: idToBeUpdated, update });
|
|
137
137
|
|
|
138
138
|
const results: QueryResult[] = await vectorDB.query({
|
|
139
139
|
indexName: testIndexName,
|
|
@@ -159,7 +159,7 @@ describe('ChromaVector Integration Tests', () => {
|
|
|
159
159
|
metadata: newMetaData,
|
|
160
160
|
};
|
|
161
161
|
|
|
162
|
-
await vectorDB.
|
|
162
|
+
await vectorDB.updateVector({ indexName: testIndexName, id: idToBeUpdated, update });
|
|
163
163
|
|
|
164
164
|
const results: QueryResult[] = await vectorDB.query({
|
|
165
165
|
indexName: testIndexName,
|
|
@@ -183,7 +183,7 @@ describe('ChromaVector Integration Tests', () => {
|
|
|
183
183
|
vector: newVector,
|
|
184
184
|
};
|
|
185
185
|
|
|
186
|
-
await vectorDB.
|
|
186
|
+
await vectorDB.updateVector({ indexName: testIndexName, id: idToBeUpdated, update });
|
|
187
187
|
|
|
188
188
|
const results: QueryResult[] = await vectorDB.query({
|
|
189
189
|
indexName: testIndexName,
|
|
@@ -196,7 +196,9 @@ describe('ChromaVector Integration Tests', () => {
|
|
|
196
196
|
});
|
|
197
197
|
|
|
198
198
|
it('should throw exception when no updates are given', async () => {
|
|
199
|
-
await expect(vectorDB.
|
|
199
|
+
await expect(vectorDB.updateVector({ indexName: testIndexName, id: 'id', update: {} })).rejects.toThrow(
|
|
200
|
+
'No updates provided',
|
|
201
|
+
);
|
|
200
202
|
});
|
|
201
203
|
|
|
202
204
|
it('should delete the vector by id', async () => {
|
|
@@ -204,7 +206,7 @@ describe('ChromaVector Integration Tests', () => {
|
|
|
204
206
|
expect(ids).toHaveLength(3);
|
|
205
207
|
const idToBeDeleted = ids[0];
|
|
206
208
|
|
|
207
|
-
await vectorDB.
|
|
209
|
+
await vectorDB.deleteVector({ indexName: testIndexName, id: idToBeDeleted });
|
|
208
210
|
|
|
209
211
|
const results: QueryResult[] = await vectorDB.query({
|
|
210
212
|
indexName: testIndexName,
|
|
@@ -273,8 +275,17 @@ describe('ChromaVector Integration Tests', () => {
|
|
|
273
275
|
});
|
|
274
276
|
|
|
275
277
|
describe('Error Handling', () => {
|
|
278
|
+
const testIndexName = 'test_index_error';
|
|
279
|
+
beforeAll(async () => {
|
|
280
|
+
await vectorDB.createIndex({ indexName: testIndexName, dimension: 3 });
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
afterAll(async () => {
|
|
284
|
+
await vectorDB.deleteIndex({ indexName: testIndexName });
|
|
285
|
+
});
|
|
286
|
+
|
|
276
287
|
it('should handle non-existent index queries', async () => {
|
|
277
|
-
await expect(vectorDB.query({ indexName: 'non-existent-index
|
|
288
|
+
await expect(vectorDB.query({ indexName: 'non-existent-index', queryVector: [1, 2, 3] })).rejects.toThrow();
|
|
278
289
|
});
|
|
279
290
|
|
|
280
291
|
it('should handle invalid dimension vectors', async () => {
|
|
@@ -282,10 +293,59 @@ describe('ChromaVector Integration Tests', () => {
|
|
|
282
293
|
await expect(vectorDB.upsert({ indexName: testIndexName, vectors: [invalidVector] })).rejects.toThrow();
|
|
283
294
|
});
|
|
284
295
|
|
|
285
|
-
it('should handle
|
|
286
|
-
const
|
|
287
|
-
const
|
|
288
|
-
|
|
296
|
+
it('should handle duplicate index creation gracefully', async () => {
|
|
297
|
+
const infoSpy = vi.spyOn(vectorDB['logger'], 'info');
|
|
298
|
+
const warnSpy = vi.spyOn(vectorDB['logger'], 'warn');
|
|
299
|
+
|
|
300
|
+
const duplicateIndexName = `duplicate-test`;
|
|
301
|
+
const dimension = 768;
|
|
302
|
+
|
|
303
|
+
try {
|
|
304
|
+
// Create index first time
|
|
305
|
+
await vectorDB.createIndex({
|
|
306
|
+
indexName: duplicateIndexName,
|
|
307
|
+
dimension,
|
|
308
|
+
metric: 'cosine',
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
// Try to create with same dimensions - should not throw
|
|
312
|
+
await expect(
|
|
313
|
+
vectorDB.createIndex({
|
|
314
|
+
indexName: duplicateIndexName,
|
|
315
|
+
dimension,
|
|
316
|
+
metric: 'cosine',
|
|
317
|
+
}),
|
|
318
|
+
).resolves.not.toThrow();
|
|
319
|
+
|
|
320
|
+
expect(infoSpy).toHaveBeenCalledWith(expect.stringContaining('already exists with'));
|
|
321
|
+
|
|
322
|
+
// Try to create with same dimensions and different metric - should not throw
|
|
323
|
+
await expect(
|
|
324
|
+
vectorDB.createIndex({
|
|
325
|
+
indexName: duplicateIndexName,
|
|
326
|
+
dimension,
|
|
327
|
+
metric: 'euclidean',
|
|
328
|
+
}),
|
|
329
|
+
).resolves.not.toThrow();
|
|
330
|
+
|
|
331
|
+
expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining('Attempted to create index with metric'));
|
|
332
|
+
|
|
333
|
+
// Try to create with different dimensions - should throw
|
|
334
|
+
await expect(
|
|
335
|
+
vectorDB.createIndex({
|
|
336
|
+
indexName: duplicateIndexName,
|
|
337
|
+
dimension: dimension + 1,
|
|
338
|
+
metric: 'cosine',
|
|
339
|
+
}),
|
|
340
|
+
).rejects.toThrow(
|
|
341
|
+
`Index "${duplicateIndexName}" already exists with ${dimension} dimensions, but ${dimension + 1} dimensions were requested`,
|
|
342
|
+
);
|
|
343
|
+
} finally {
|
|
344
|
+
infoSpy.mockRestore();
|
|
345
|
+
warnSpy.mockRestore();
|
|
346
|
+
// Cleanup
|
|
347
|
+
await vectorDB.deleteIndex({ indexName: duplicateIndexName });
|
|
348
|
+
}
|
|
289
349
|
});
|
|
290
350
|
});
|
|
291
351
|
|
|
@@ -318,7 +378,7 @@ describe('ChromaVector Integration Tests', () => {
|
|
|
318
378
|
indexName: testIndexName,
|
|
319
379
|
queryVector: [1, 0, 0],
|
|
320
380
|
filter: {
|
|
321
|
-
tags: { $in: null },
|
|
381
|
+
tags: { $in: null } as any,
|
|
322
382
|
},
|
|
323
383
|
}),
|
|
324
384
|
).rejects.toThrow();
|
|
@@ -419,9 +479,9 @@ describe('ChromaVector Integration Tests', () => {
|
|
|
419
479
|
indexName: testIndexName,
|
|
420
480
|
queryVector: [1, 0, 0],
|
|
421
481
|
filter: {
|
|
422
|
-
field1: { $in: 'not-array' },
|
|
423
|
-
field2: { $exists: 'not-boolean' },
|
|
424
|
-
field3: { $gt: 'not-number' },
|
|
482
|
+
field1: { $in: 'not-array' } as any,
|
|
483
|
+
field2: { $exists: 'not-boolean' } as any,
|
|
484
|
+
field3: { $gt: 'not-number' } as any,
|
|
425
485
|
},
|
|
426
486
|
}),
|
|
427
487
|
).rejects.toThrow();
|
|
@@ -461,7 +521,7 @@ describe('ChromaVector Integration Tests', () => {
|
|
|
461
521
|
// Set up test vectors and metadata
|
|
462
522
|
beforeAll(async () => {
|
|
463
523
|
try {
|
|
464
|
-
await vectorDB.deleteIndex(testIndexName2);
|
|
524
|
+
await vectorDB.deleteIndex({ indexName: testIndexName2 });
|
|
465
525
|
} catch {
|
|
466
526
|
// Ignore errors if index doesn't exist
|
|
467
527
|
}
|
|
@@ -509,7 +569,7 @@ describe('ChromaVector Integration Tests', () => {
|
|
|
509
569
|
afterAll(async () => {
|
|
510
570
|
// Cleanup after tests
|
|
511
571
|
try {
|
|
512
|
-
await vectorDB.deleteIndex(testIndexName2);
|
|
572
|
+
await vectorDB.deleteIndex({ indexName: testIndexName2 });
|
|
513
573
|
} catch {
|
|
514
574
|
// Ignore cleanup errors
|
|
515
575
|
}
|
|
@@ -1180,7 +1240,7 @@ describe('ChromaVector Integration Tests', () => {
|
|
|
1180
1240
|
|
|
1181
1241
|
beforeAll(async () => {
|
|
1182
1242
|
try {
|
|
1183
|
-
await vectorDB.deleteIndex(testIndexName3);
|
|
1243
|
+
await vectorDB.deleteIndex({ indexName: testIndexName3 });
|
|
1184
1244
|
} catch {
|
|
1185
1245
|
// Ignore errors if index doesn't exist
|
|
1186
1246
|
}
|
|
@@ -1214,7 +1274,7 @@ describe('ChromaVector Integration Tests', () => {
|
|
|
1214
1274
|
afterAll(async () => {
|
|
1215
1275
|
// Cleanup after tests
|
|
1216
1276
|
try {
|
|
1217
|
-
await vectorDB.deleteIndex(testIndexName3);
|
|
1277
|
+
await vectorDB.deleteIndex({ indexName: testIndexName3 });
|
|
1218
1278
|
} catch {
|
|
1219
1279
|
// Ignore cleanup errors
|
|
1220
1280
|
}
|
|
@@ -1402,122 +1462,13 @@ describe('ChromaVector Integration Tests', () => {
|
|
|
1402
1462
|
});
|
|
1403
1463
|
});
|
|
1404
1464
|
});
|
|
1405
|
-
describe('Deprecation Warnings', () => {
|
|
1406
|
-
const indexName = 'testdeprecationwarnings';
|
|
1407
|
-
|
|
1408
|
-
const indexName2 = 'testdeprecationwarnings2';
|
|
1409
|
-
|
|
1410
|
-
let warnSpy;
|
|
1411
|
-
|
|
1412
|
-
beforeAll(async () => {
|
|
1413
|
-
await vectorDB.createIndex({ indexName: indexName, dimension: 3 });
|
|
1414
|
-
});
|
|
1415
|
-
|
|
1416
|
-
afterAll(async () => {
|
|
1417
|
-
try {
|
|
1418
|
-
await vectorDB.deleteIndex(indexName);
|
|
1419
|
-
} catch {
|
|
1420
|
-
// Ignore errors if index doesn't exist
|
|
1421
|
-
}
|
|
1422
|
-
try {
|
|
1423
|
-
await vectorDB.deleteIndex(indexName2);
|
|
1424
|
-
} catch {
|
|
1425
|
-
// Ignore errors if index doesn't exist
|
|
1426
|
-
}
|
|
1427
|
-
});
|
|
1428
|
-
|
|
1429
|
-
beforeEach(async () => {
|
|
1430
|
-
warnSpy = vi.spyOn(vectorDB['logger'], 'warn');
|
|
1431
|
-
});
|
|
1432
|
-
|
|
1433
|
-
afterEach(async () => {
|
|
1434
|
-
warnSpy.mockRestore();
|
|
1435
|
-
try {
|
|
1436
|
-
await vectorDB.deleteIndex(indexName2);
|
|
1437
|
-
} catch {
|
|
1438
|
-
// Ignore errors if index doesn't exist
|
|
1439
|
-
}
|
|
1440
|
-
});
|
|
1441
|
-
|
|
1442
|
-
it('should show deprecation warning when using individual args for createIndex', async () => {
|
|
1443
|
-
await vectorDB.createIndex(indexName2, 3, 'cosine');
|
|
1444
|
-
|
|
1445
|
-
expect(warnSpy).toHaveBeenCalledWith(
|
|
1446
|
-
expect.stringContaining('Deprecation Warning: Passing individual arguments to createIndex() is deprecated'),
|
|
1447
|
-
);
|
|
1448
|
-
});
|
|
1449
|
-
|
|
1450
|
-
it('should show deprecation warning when using individual args for upsert', async () => {
|
|
1451
|
-
await vectorDB.upsert(indexName, [[1, 2, 3]], [{ test: 'data' }]);
|
|
1452
|
-
|
|
1453
|
-
expect(warnSpy).toHaveBeenCalledWith(
|
|
1454
|
-
expect.stringContaining('Deprecation Warning: Passing individual arguments to upsert() is deprecated'),
|
|
1455
|
-
);
|
|
1456
|
-
});
|
|
1457
|
-
|
|
1458
|
-
it('should show deprecation warning when using individual args for query', async () => {
|
|
1459
|
-
await vectorDB.query(indexName, [1, 2, 3], 5);
|
|
1460
|
-
|
|
1461
|
-
expect(warnSpy).toHaveBeenCalledWith(
|
|
1462
|
-
expect.stringContaining('Deprecation Warning: Passing individual arguments to query() is deprecated'),
|
|
1463
|
-
);
|
|
1464
|
-
});
|
|
1465
|
-
|
|
1466
|
-
it('should not show deprecation warning when using object param for query', async () => {
|
|
1467
|
-
await vectorDB.query({
|
|
1468
|
-
indexName,
|
|
1469
|
-
queryVector: [1, 2, 3],
|
|
1470
|
-
topK: 5,
|
|
1471
|
-
});
|
|
1472
|
-
|
|
1473
|
-
expect(warnSpy).not.toHaveBeenCalled();
|
|
1474
|
-
});
|
|
1475
|
-
|
|
1476
|
-
it('should not show deprecation warning when using object param for createIndex', async () => {
|
|
1477
|
-
await vectorDB.createIndex({
|
|
1478
|
-
indexName: indexName2,
|
|
1479
|
-
dimension: 3,
|
|
1480
|
-
metric: 'cosine',
|
|
1481
|
-
});
|
|
1482
|
-
|
|
1483
|
-
expect(warnSpy).not.toHaveBeenCalled();
|
|
1484
|
-
});
|
|
1485
|
-
|
|
1486
|
-
it('should not show deprecation warning when using object param for upsert', async () => {
|
|
1487
|
-
await vectorDB.upsert({
|
|
1488
|
-
indexName,
|
|
1489
|
-
vectors: [[1, 2, 3]],
|
|
1490
|
-
metadata: [{ test: 'data' }],
|
|
1491
|
-
});
|
|
1492
|
-
|
|
1493
|
-
expect(warnSpy).not.toHaveBeenCalled();
|
|
1494
|
-
});
|
|
1495
|
-
|
|
1496
|
-
it('should maintain backward compatibility with individual args', async () => {
|
|
1497
|
-
// Query
|
|
1498
|
-
const queryResults = await vectorDB.query(indexName, [1, 2, 3], 5);
|
|
1499
|
-
expect(Array.isArray(queryResults)).toBe(true);
|
|
1500
|
-
|
|
1501
|
-
// CreateIndex
|
|
1502
|
-
await expect(vectorDB.createIndex(indexName2, 3, 'cosine')).resolves.not.toThrow();
|
|
1503
|
-
|
|
1504
|
-
// Upsert
|
|
1505
|
-
const upsertResults = await vectorDB.upsert({
|
|
1506
|
-
indexName,
|
|
1507
|
-
vectors: [[1, 2, 3]],
|
|
1508
|
-
metadata: [{ test: 'data' }],
|
|
1509
|
-
});
|
|
1510
|
-
expect(Array.isArray(upsertResults)).toBe(true);
|
|
1511
|
-
expect(upsertResults).toHaveLength(1);
|
|
1512
|
-
});
|
|
1513
|
-
});
|
|
1514
1465
|
|
|
1515
1466
|
describe('Performance and Concurrency', () => {
|
|
1516
1467
|
const perfTestIndex = 'perf-test-index';
|
|
1517
1468
|
|
|
1518
1469
|
beforeEach(async () => {
|
|
1519
1470
|
try {
|
|
1520
|
-
await vectorDB.deleteIndex(perfTestIndex);
|
|
1471
|
+
await vectorDB.deleteIndex({ indexName: perfTestIndex });
|
|
1521
1472
|
} catch {
|
|
1522
1473
|
// Ignore errors if index doesn't exist
|
|
1523
1474
|
}
|
|
@@ -1526,7 +1477,7 @@ describe('ChromaVector Integration Tests', () => {
|
|
|
1526
1477
|
|
|
1527
1478
|
afterEach(async () => {
|
|
1528
1479
|
try {
|
|
1529
|
-
await vectorDB.deleteIndex(perfTestIndex);
|
|
1480
|
+
await vectorDB.deleteIndex({ indexName: perfTestIndex });
|
|
1530
1481
|
} catch {
|
|
1531
1482
|
// Ignore cleanup errors
|
|
1532
1483
|
}
|
|
@@ -1569,7 +1520,7 @@ describe('ChromaVector Integration Tests', () => {
|
|
|
1569
1520
|
});
|
|
1570
1521
|
|
|
1571
1522
|
// Verify all vectors were inserted
|
|
1572
|
-
const stats = await vectorDB.describeIndex(perfTestIndex);
|
|
1523
|
+
const stats = await vectorDB.describeIndex({ indexName: perfTestIndex });
|
|
1573
1524
|
expect(stats.count).toBe(batchSize);
|
|
1574
1525
|
|
|
1575
1526
|
const results = await vectorDB.query({
|