@mastra/chroma 0.0.0-vector-query-sources-20250516172905 → 0.0.0-vector-query-tool-provider-options-20250828222356
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 +361 -4
- package/LICENSE.md +12 -4
- package/README.md +47 -21
- package/dist/index.cjs +280 -157
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +277 -154
- package/dist/index.js.map +1 -0
- package/dist/vector/filter.d.ts +19 -0
- package/dist/vector/filter.d.ts.map +1 -0
- package/dist/vector/index.d.ts +70 -0
- package/dist/vector/index.d.ts.map +1 -0
- package/dist/vector/prompt.d.ts +6 -0
- package/dist/vector/prompt.d.ts.map +1 -0
- package/package.json +18 -13
- package/src/vector/filter.test.ts +27 -19
- package/src/vector/filter.ts +28 -5
- package/src/vector/index.test.ts +142 -129
- package/src/vector/index.ts +306 -200
- package/tsconfig.build.json +9 -0
- package/tsconfig.json +1 -1
- package/tsup.config.ts +17 -0
- package/dist/_tsup-dts-rollup.d.cts +0 -126
- package/dist/_tsup-dts-rollup.d.ts +0 -126
- package/dist/index.d.cts +0 -2
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { MastraVector } from '@mastra/core/vector';
|
|
2
|
+
import type { QueryResult, IndexStats, CreateIndexParams, UpsertVectorParams, QueryVectorParams, DescribeIndexParams, DeleteIndexParams, DeleteVectorParams, UpdateVectorParams } from '@mastra/core/vector';
|
|
3
|
+
import type { ChromaClientArgs, Where, WhereDocument, Collection, Metadata } from 'chromadb';
|
|
4
|
+
import type { ChromaVectorFilter } from './filter.js';
|
|
5
|
+
interface ChromaUpsertVectorParams extends UpsertVectorParams {
|
|
6
|
+
documents?: string[];
|
|
7
|
+
}
|
|
8
|
+
interface ChromaQueryVectorParams extends QueryVectorParams<ChromaVectorFilter> {
|
|
9
|
+
documentFilter?: WhereDocument | null;
|
|
10
|
+
}
|
|
11
|
+
interface ChromaGetRecordsParams {
|
|
12
|
+
indexName: string;
|
|
13
|
+
ids?: string[];
|
|
14
|
+
filter?: ChromaVectorFilter;
|
|
15
|
+
documentFilter?: WhereDocument | null;
|
|
16
|
+
includeVector?: boolean;
|
|
17
|
+
limit?: number;
|
|
18
|
+
offset?: number;
|
|
19
|
+
}
|
|
20
|
+
type ChromaVectorArgs = ChromaClientArgs & {
|
|
21
|
+
apiKey?: string;
|
|
22
|
+
};
|
|
23
|
+
export declare class ChromaVector extends MastraVector<ChromaVectorFilter> {
|
|
24
|
+
private client;
|
|
25
|
+
private collections;
|
|
26
|
+
constructor(chromaClientArgs?: ChromaVectorArgs);
|
|
27
|
+
getCollection({ indexName, forceUpdate }: {
|
|
28
|
+
indexName: string;
|
|
29
|
+
forceUpdate?: boolean;
|
|
30
|
+
}): Promise<Collection>;
|
|
31
|
+
private validateVectorDimensions;
|
|
32
|
+
upsert({ indexName, vectors, metadata, ids, documents }: ChromaUpsertVectorParams): Promise<string[]>;
|
|
33
|
+
createIndex({ indexName, dimension, metric }: CreateIndexParams): Promise<void>;
|
|
34
|
+
transformFilter(filter?: ChromaVectorFilter): Where | undefined;
|
|
35
|
+
query<T extends Metadata = Metadata>({ indexName, queryVector, topK, filter, includeVector, documentFilter, }: ChromaQueryVectorParams): Promise<QueryResult[]>;
|
|
36
|
+
get<T extends Metadata = Metadata>({ indexName, ids, filter, includeVector, documentFilter, offset, limit, }: ChromaGetRecordsParams): Promise<{
|
|
37
|
+
id: string;
|
|
38
|
+
document: string | null | undefined;
|
|
39
|
+
embedding: number[] | undefined;
|
|
40
|
+
metadata: T | null | undefined;
|
|
41
|
+
uri: string | null | undefined;
|
|
42
|
+
}[]>;
|
|
43
|
+
listIndexes(): Promise<string[]>;
|
|
44
|
+
/**
|
|
45
|
+
* Retrieves statistics about a vector index.
|
|
46
|
+
*
|
|
47
|
+
* @param {string} indexName - The name of the index to describe
|
|
48
|
+
* @returns A promise that resolves to the index statistics including dimension, count and metric
|
|
49
|
+
*/
|
|
50
|
+
describeIndex({ indexName }: DescribeIndexParams): Promise<IndexStats>;
|
|
51
|
+
deleteIndex({ indexName }: DeleteIndexParams): Promise<void>;
|
|
52
|
+
forkIndex({ indexName, newIndexName }: {
|
|
53
|
+
indexName: string;
|
|
54
|
+
newIndexName: string;
|
|
55
|
+
}): Promise<void>;
|
|
56
|
+
/**
|
|
57
|
+
* Updates a vector by its ID with the provided vector and/or metadata.
|
|
58
|
+
* @param indexName - The name of the index containing the vector.
|
|
59
|
+
* @param id - The ID of the vector to update.
|
|
60
|
+
* @param update - An object containing the vector and/or metadata to update.
|
|
61
|
+
* @param update.vector - An optional array of numbers representing the new vector.
|
|
62
|
+
* @param update.metadata - An optional record containing the new metadata.
|
|
63
|
+
* @returns A promise that resolves when the update is complete.
|
|
64
|
+
* @throws Will throw an error if no updates are provided or if the update operation fails.
|
|
65
|
+
*/
|
|
66
|
+
updateVector({ indexName, id, update }: UpdateVectorParams): Promise<void>;
|
|
67
|
+
deleteVector({ indexName, id }: DeleteVectorParams): Promise<void>;
|
|
68
|
+
}
|
|
69
|
+
export {};
|
|
70
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/vector/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vector store specific prompt that details supported operators and examples.
|
|
3
|
+
* This prompt helps users construct valid filters for Chroma Vector.
|
|
4
|
+
*/
|
|
5
|
+
export declare const CHROMA_PROMPT = "When querying Chroma, you can ONLY use the operators listed below. Any other operators will be rejected.\nImportant: Don't explain how to construct the filter - use the specified operators and fields to search the content and return relevant results.\nIf a user tries to give an explicit operator that is not supported, reject the filter entirely and let them know that the operator is not supported.\n\nBasic Comparison Operators:\n- $eq: Exact match (default when using field: value)\n Example: { \"category\": \"electronics\" }\n- $ne: Not equal\n Example: { \"category\": { \"$ne\": \"electronics\" } }\n- $gt: Greater than\n Example: { \"price\": { \"$gt\": 100 } }\n- $gte: Greater than or equal\n Example: { \"price\": { \"$gte\": 100 } }\n- $lt: Less than\n Example: { \"price\": { \"$lt\": 100 } }\n- $lte: Less than or equal\n Example: { \"price\": { \"$lte\": 100 } }\n\nArray Operators:\n- $in: Match any value in array\n Example: { \"category\": { \"$in\": [\"electronics\", \"books\"] } }\n- $nin: Does not match any value in array\n Example: { \"category\": { \"$nin\": [\"electronics\", \"books\"] } }\n\nLogical Operators:\n- $and: Logical AND\n Example: { \"$and\": [{ \"price\": { \"$gt\": 100 } }, { \"category\": \"electronics\" }] }\n- $or: Logical OR\n Example: { \"$or\": [{ \"price\": { \"$lt\": 50 } }, { \"category\": \"books\" }] }\n\nRestrictions:\n- Regex patterns are not supported\n- Element operators are not supported\n- Only $and and $or logical operators are supported\n- Nested fields are supported using dot notation\n- Multiple conditions on the same field are supported with both implicit and explicit $and\n- Empty arrays in $in/$nin will return no results\n- If multiple top-level fields exist, they're wrapped in $and\n- Only logical operators ($and, $or) can be used at the top level\n- All other operators must be used within a field condition\n Valid: { \"field\": { \"$gt\": 100 } }\n Valid: { \"$and\": [...] }\n Invalid: { \"$gt\": 100 }\n Invalid: { \"$in\": [...] }\n- Logical operators must contain field conditions, not direct operators\n Valid: { \"$and\": [{ \"field\": { \"$gt\": 100 } }] }\n Invalid: { \"$and\": [{ \"$gt\": 100 }] }\n- Logical operators ($and, $or):\n - Can only be used at top level or nested within other logical operators\n - Can not be used on a field level, or be nested inside a field\n - Can not be used inside an operator\n - Valid: { \"$and\": [{ \"field\": { \"$gt\": 100 } }] }\n - Valid: { \"$or\": [{ \"$and\": [{ \"field\": { \"$gt\": 100 } }] }] }\n - Invalid: { \"field\": { \"$and\": [{ \"$gt\": 100 }] } }\n - Invalid: { \"field\": { \"$or\": [{ \"$gt\": 100 }] } }\n - Invalid: { \"field\": { \"$gt\": { \"$and\": [{...}] } } }\n\nExample Complex Query:\n{\n \"$and\": [\n { \"category\": { \"$in\": [\"electronics\", \"computers\"] } },\n { \"price\": { \"$gte\": 100, \"$lte\": 1000 } },\n { \"$or\": [\n { \"inStock\": true },\n { \"preorder\": true }\n ]}\n ]\n}";
|
|
6
|
+
//# sourceMappingURL=prompt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../../src/vector/prompt.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,aAAa,q8FAmExB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mastra/chroma",
|
|
3
|
-
"version": "0.0.0-vector-query-
|
|
3
|
+
"version": "0.0.0-vector-query-tool-provider-options-20250828222356",
|
|
4
4
|
"description": "Chroma vector store provider for Mastra",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"default": "./dist/index.js"
|
|
13
13
|
},
|
|
14
14
|
"require": {
|
|
15
|
-
"types": "./dist/index.d.
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
16
|
"default": "./dist/index.cjs"
|
|
17
17
|
}
|
|
18
18
|
},
|
|
@@ -20,21 +20,26 @@
|
|
|
20
20
|
},
|
|
21
21
|
"license": "MIT",
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"chromadb": "^
|
|
24
|
-
"@mastra/core": "0.0.0-vector-query-sources-20250516172905"
|
|
23
|
+
"chromadb": "^3.0.11"
|
|
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-vector-query-
|
|
26
|
+
"@microsoft/api-extractor": "^7.52.8",
|
|
27
|
+
"@types/node": "^20.19.0",
|
|
28
|
+
"eslint": "^9.30.1",
|
|
29
|
+
"tsup": "^8.5.0",
|
|
30
|
+
"typescript": "^5.8.3",
|
|
31
|
+
"vitest": "^3.2.4",
|
|
32
|
+
"@internal/lint": "0.0.0-vector-query-tool-provider-options-20250828222356",
|
|
33
|
+
"@internal/storage-test-utils": "0.0.30",
|
|
34
|
+
"@internal/types-builder": "0.0.0-vector-query-tool-provider-options-20250828222356",
|
|
35
|
+
"@mastra/core": "0.0.0-vector-query-tool-provider-options-20250828222356"
|
|
36
|
+
},
|
|
37
|
+
"peerDependencies": {
|
|
38
|
+
"@mastra/core": "0.0.0-vector-query-tool-provider-options-20250828222356"
|
|
34
39
|
},
|
|
35
40
|
"scripts": {
|
|
36
|
-
"build": "tsup
|
|
37
|
-
"build:watch": "
|
|
41
|
+
"build": "tsup --silent --config tsup.config.ts",
|
|
42
|
+
"build:watch": "tsup --watch --silent --config tsup.config.ts",
|
|
38
43
|
"test": "vitest run",
|
|
39
44
|
"lint": "eslint ."
|
|
40
45
|
}
|
|
@@ -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
|
},
|
|
@@ -350,6 +355,7 @@ describe('ChromaFilterTranslator', () => {
|
|
|
350
355
|
},
|
|
351
356
|
];
|
|
352
357
|
|
|
358
|
+
// @ts-expect-error
|
|
353
359
|
invalidFilters.forEach(filter => {
|
|
354
360
|
expect(() => translator.translate(filter)).toThrow(/Unsupported operator/);
|
|
355
361
|
});
|
|
@@ -374,7 +380,7 @@ describe('ChromaFilterTranslator', () => {
|
|
|
374
380
|
});
|
|
375
381
|
|
|
376
382
|
it('throws error for unsupported operators', () => {
|
|
377
|
-
const unsupportedFilters = [
|
|
383
|
+
const unsupportedFilters: any = [
|
|
378
384
|
{ field: { $regex: 'pattern' } },
|
|
379
385
|
{ field: { $contains: 'value' } },
|
|
380
386
|
{ field: { $exists: true } },
|
|
@@ -385,6 +391,7 @@ describe('ChromaFilterTranslator', () => {
|
|
|
385
391
|
{ field: { $all: [{ $eq: 'value' }] } },
|
|
386
392
|
];
|
|
387
393
|
|
|
394
|
+
// @ts-expect-error
|
|
388
395
|
unsupportedFilters.forEach(filter => {
|
|
389
396
|
expect(() => translator.translate(filter)).toThrow(/Unsupported operator/);
|
|
390
397
|
});
|
|
@@ -395,8 +402,9 @@ describe('ChromaFilterTranslator', () => {
|
|
|
395
402
|
expect(() => translator.translate(filter)).toThrow();
|
|
396
403
|
});
|
|
397
404
|
it('throws error for non-logical operators at top level', () => {
|
|
398
|
-
const invalidFilters = [{ $gt: 100 }, { $in: ['value1', 'value2'] }, { $eq: true }];
|
|
405
|
+
const invalidFilters: any = [{ $gt: 100 }, { $in: ['value1', 'value2'] }, { $eq: true }];
|
|
399
406
|
|
|
407
|
+
// @ts-expect-error
|
|
400
408
|
invalidFilters.forEach(filter => {
|
|
401
409
|
expect(() => translator.translate(filter)).toThrow(/Invalid top-level operator/);
|
|
402
410
|
});
|
package/src/vector/filter.ts
CHANGED
|
@@ -1,12 +1,32 @@
|
|
|
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
|
+
>;
|
|
3
23
|
|
|
4
24
|
/**
|
|
5
25
|
* Translator for Chroma filter queries.
|
|
6
26
|
* Maintains MongoDB-compatible syntax while ensuring proper validation
|
|
7
27
|
* and normalization of values.
|
|
8
28
|
*/
|
|
9
|
-
export class ChromaFilterTranslator extends BaseFilterTranslator {
|
|
29
|
+
export class ChromaFilterTranslator extends BaseFilterTranslator<ChromaVectorFilter> {
|
|
10
30
|
protected override getSupportedOperators(): OperatorSupport {
|
|
11
31
|
return {
|
|
12
32
|
...BaseFilterTranslator.DEFAULT_OPERATORS,
|
|
@@ -18,17 +38,17 @@ export class ChromaFilterTranslator extends BaseFilterTranslator {
|
|
|
18
38
|
};
|
|
19
39
|
}
|
|
20
40
|
|
|
21
|
-
translate(filter?:
|
|
41
|
+
translate(filter?: ChromaVectorFilter): ChromaVectorFilter {
|
|
22
42
|
if (this.isEmpty(filter)) return filter;
|
|
23
43
|
this.validateFilter(filter);
|
|
24
44
|
|
|
25
45
|
return this.translateNode(filter);
|
|
26
46
|
}
|
|
27
47
|
|
|
28
|
-
private translateNode(node:
|
|
48
|
+
private translateNode(node: ChromaVectorFilter, currentPath: string = ''): any {
|
|
29
49
|
// Handle primitive values and arrays
|
|
30
50
|
if (this.isRegex(node)) {
|
|
31
|
-
throw new Error('Regex is
|
|
51
|
+
throw new Error('Regex is supported in Chroma via the `documentFilter` argument');
|
|
32
52
|
}
|
|
33
53
|
if (this.isPrimitive(node)) return this.normalizeComparisonValue(node);
|
|
34
54
|
if (Array.isArray(node)) return { $in: this.normalizeArrayValues(node) };
|
|
@@ -39,6 +59,9 @@ export class ChromaFilterTranslator extends BaseFilterTranslator {
|
|
|
39
59
|
if (entries.length === 1 && firstEntry && this.isOperator(firstEntry[0])) {
|
|
40
60
|
const [operator, value] = firstEntry;
|
|
41
61
|
const translated = this.translateOperator(operator, value);
|
|
62
|
+
if (this.isLogicalOperator(operator) && Array.isArray(translated) && translated.length === 1) {
|
|
63
|
+
return translated[0];
|
|
64
|
+
}
|
|
42
65
|
return this.isLogicalOperator(operator) ? { [operator]: translated } : translated;
|
|
43
66
|
}
|
|
44
67
|
|