@mastra/astra 0.11.4 → 0.11.7-alpha.0

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 CHANGED
@@ -1,5 +1,32 @@
1
1
  # @mastra/astra
2
2
 
3
+ ## 0.11.7-alpha.0
4
+
5
+ ### Patch Changes
6
+
7
+ - [#7343](https://github.com/mastra-ai/mastra/pull/7343) [`de3cbc6`](https://github.com/mastra-ai/mastra/commit/de3cbc61079211431bd30487982ea3653517278e) Thanks [@LekoArts](https://github.com/LekoArts)! - Update the `package.json` file to include additional fields like `repository`, `homepage` or `files`.
8
+
9
+ - Updated dependencies [[`85ef90b`](https://github.com/mastra-ai/mastra/commit/85ef90bb2cd4ae4df855c7ac175f7d392c55c1bf), [`de3cbc6`](https://github.com/mastra-ai/mastra/commit/de3cbc61079211431bd30487982ea3653517278e)]:
10
+ - @mastra/core@0.15.3-alpha.5
11
+
12
+ ## 0.11.6
13
+
14
+ ### Patch Changes
15
+
16
+ - [`c6113ed`](https://github.com/mastra-ai/mastra/commit/c6113ed7f9df297e130d94436ceee310273d6430) Thanks [@wardpeet](https://github.com/wardpeet)! - Fix peerdpes for @mastra/core
17
+
18
+ - Updated dependencies []:
19
+ - @mastra/core@0.15.2
20
+
21
+ ## 0.11.5
22
+
23
+ ### Patch Changes
24
+
25
+ - [`95b2aa9`](https://github.com/mastra-ai/mastra/commit/95b2aa908230919e67efcac0d69005a2d5745298) Thanks [@wardpeet](https://github.com/wardpeet)! - Fix peerdeps @mastra/core
26
+
27
+ - Updated dependencies []:
28
+ - @mastra/core@0.15.1
29
+
3
30
  ## 0.11.4
4
31
 
5
32
  ### Patch Changes
package/package.json CHANGED
@@ -1,10 +1,14 @@
1
1
  {
2
2
  "name": "@mastra/astra",
3
- "version": "0.11.4",
3
+ "version": "0.11.7-alpha.0",
4
4
  "description": "Astra DB provider for Mastra - includes vector store capabilities",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
8
+ "files": [
9
+ "dist",
10
+ "CHANGELOG.md"
11
+ ],
8
12
  "exports": {
9
13
  ".": {
10
14
  "import": {
@@ -18,7 +22,7 @@
18
22
  },
19
23
  "./package.json": "./package.json"
20
24
  },
21
- "license": "MIT",
25
+ "license": "Apache-2.0",
22
26
  "dependencies": {
23
27
  "@datastax/astra-db-ts": "^1.5.0"
24
28
  },
@@ -29,12 +33,21 @@
29
33
  "tsup": "^8.5.0",
30
34
  "typescript": "^5.8.3",
31
35
  "vitest": "^3.2.4",
32
- "@internal/lint": "0.0.30",
33
- "@mastra/core": "0.14.0",
34
- "@internal/types-builder": "0.0.5"
36
+ "@internal/lint": "0.0.34",
37
+ "@mastra/core": "0.15.3-alpha.5",
38
+ "@internal/types-builder": "0.0.9"
35
39
  },
36
40
  "peerDependencies": {
37
- "@mastra/core": ">=0.10.7-0 <0.15.0-0"
41
+ "@mastra/core": ">=0.10.7-0 <0.16.0-0"
42
+ },
43
+ "homepage": "https://mastra.ai",
44
+ "repository": {
45
+ "type": "git",
46
+ "url": "git+https://github.com/mastra-ai/mastra.git",
47
+ "directory": "stores/astra"
48
+ },
49
+ "bugs": {
50
+ "url": "https://github.com/mastra-ai/mastra/issues"
38
51
  },
39
52
  "scripts": {
40
53
  "build": "tsup --silent --config tsup.config.ts",
@@ -1,4 +0,0 @@
1
-
2
- > @mastra/astra@0.11.4-alpha.0 build /home/runner/work/mastra/mastra/stores/astra
3
- > tsup --silent --config tsup.config.ts
4
-
package/eslint.config.js DELETED
@@ -1,6 +0,0 @@
1
- import { createConfig } from '@internal/lint/eslint';
2
-
3
- const config = await createConfig();
4
-
5
- /** @type {import("eslint").Linter.Config[]} */
6
- export default [...config];
package/src/index.ts DELETED
@@ -1,2 +0,0 @@
1
- export * from './vector';
2
- export { ASTRA_PROMPT } from './vector/prompt';
@@ -1,353 +0,0 @@
1
- import { describe, it, expect, beforeEach } from 'vitest';
2
-
3
- import type { AstraVectorFilter } from './filter';
4
- import { AstraFilterTranslator } from './filter';
5
-
6
- describe('AstraFilterTranslator', () => {
7
- let translator: AstraFilterTranslator;
8
-
9
- beforeEach(() => {
10
- translator = new AstraFilterTranslator();
11
- });
12
-
13
- // Basic Filter Operations
14
- describe('basic operations', () => {
15
- it('handles simple equality', () => {
16
- const filter: AstraVectorFilter = { field: 'value' };
17
- expect(translator.translate(filter)).toEqual(filter);
18
- });
19
-
20
- it('handles comparison operators', () => {
21
- const filter: AstraVectorFilter = {
22
- age: { $gt: 25 },
23
- score: { $lte: 100 },
24
- };
25
- expect(translator.translate(filter)).toEqual(filter);
26
- });
27
-
28
- it('handles valid multiple operators on same field', () => {
29
- const filter: AstraVectorFilter = {
30
- price: { $gt: 100, $lt: 200 },
31
- quantity: { $gte: 10, $lte: 20 },
32
- };
33
- expect(translator.translate(filter)).toEqual(filter);
34
- });
35
-
36
- it('handles null values correctly', () => {
37
- const filter: AstraVectorFilter = {
38
- field: null,
39
- other: { $eq: null },
40
- };
41
- expect(translator.translate(filter)).toEqual(filter);
42
- });
43
-
44
- it('throws on unsupported combinations', () => {
45
- const filter: AstraVectorFilter = {
46
- field: { $gt: 100, $lt: 200 },
47
- };
48
- expect(translator.translate(filter)).toEqual(filter);
49
- });
50
- });
51
-
52
- // Array Operations
53
- describe('array operations', () => {
54
- it('handles array operators', () => {
55
- const filter: AstraVectorFilter = {
56
- tags: { $all: ['tag1', 'tag2'] },
57
- categories: { $in: ['A', 'B'] },
58
- };
59
- expect(translator.translate(filter)).toEqual(filter);
60
- });
61
- it('handles empty array values', () => {
62
- const filter: AstraVectorFilter = {
63
- tags: { $in: [] },
64
- categories: { $all: [] },
65
- };
66
- expect(translator.translate(filter)).toEqual(filter);
67
- });
68
-
69
- it('handles nested array operators', () => {
70
- const filter: AstraVectorFilter = {
71
- $and: [{ tags: { $all: ['tag1', 'tag2'] } }, { 'nested.array': { $in: [1, 2, 3] } }],
72
- };
73
- expect(translator.translate(filter)).toEqual(filter);
74
- });
75
- });
76
-
77
- // Logical Operators
78
- describe('logical operators', () => {
79
- it('handles logical operators', () => {
80
- const filter: AstraVectorFilter = {
81
- $or: [{ status: 'active' }, { age: { $gt: 25 } }],
82
- };
83
- expect(translator.translate(filter)).toEqual(filter);
84
- });
85
-
86
- it('handles nested logical operators', () => {
87
- const filter: AstraVectorFilter = {
88
- $and: [
89
- { status: 'active' },
90
- { $or: [{ category: { $in: ['A', 'B'] } }, { $and: [{ price: { $gt: 100 } }, { stock: { $lt: 50 } }] }] },
91
- ],
92
- };
93
- expect(translator.translate(filter)).toEqual(filter);
94
- });
95
-
96
- it('handles empty conditions in logical operators', () => {
97
- const filter: AstraVectorFilter = {
98
- $and: [],
99
- $or: [{}],
100
- field: 'value',
101
- };
102
- expect(translator.translate(filter)).toEqual(filter);
103
- });
104
-
105
- it('allows multiple logical operators at root level with complex conditions', () => {
106
- expect(() =>
107
- translator.translate({
108
- $and: [{ field1: { $gt: 10 } }],
109
- $or: [{ field2: { $lt: 20 } }],
110
- field4: { $not: { $eq: 'value' } },
111
- }),
112
- ).not.toThrow();
113
- });
114
-
115
- it('allows logical operators at root level', () => {
116
- expect(() =>
117
- translator.translate({
118
- $and: [{ field1: 'value1' }, { field2: 'value2' }],
119
- $or: [{ field3: 'value3' }, { field4: 'value4' }],
120
- }),
121
- ).not.toThrow();
122
- });
123
-
124
- it('allows logical operators nested within other logical operators', () => {
125
- expect(() =>
126
- translator.translate({
127
- $and: [
128
- {
129
- $or: [{ field1: 'value1' }, { field2: 'value2' }],
130
- },
131
- {
132
- $and: [{ field3: 'value3' }, { field4: 'value4' }],
133
- },
134
- ],
135
- }),
136
- ).not.toThrow();
137
- });
138
- });
139
-
140
- // Logical Operator Validation
141
- describe('logical operator validation', () => {
142
- it('throws error for direct operators in logical operator arrays', () => {
143
- expect(() =>
144
- translator.translate({
145
- $and: [{ $eq: 'value' }, { $gt: 100 }],
146
- }),
147
- ).toThrow(/Logical operators must contain field conditions/);
148
-
149
- expect(() =>
150
- translator.translate({
151
- $or: [{ $in: ['value1', 'value2'] as any }],
152
- }),
153
- ).toThrow(/Logical operators must contain field conditions/);
154
- });
155
-
156
- it('throws error for deeply nested logical operators in non-logical contexts', () => {
157
- expect(() =>
158
- translator.translate({
159
- field: {
160
- $gt: {
161
- $or: [{ subfield: 'value1' }, { subfield: 'value2' }],
162
- } as any,
163
- },
164
- }),
165
- ).toThrow();
166
-
167
- expect(() =>
168
- translator.translate({
169
- field: {
170
- $in: [
171
- {
172
- $and: [{ subfield: 'value1' }, { subfield: 'value2' }],
173
- } as any,
174
- ],
175
- },
176
- }),
177
- ).toThrow();
178
- });
179
-
180
- it('throws error for logical operators nested in non-logical contexts', () => {
181
- expect(() =>
182
- translator.translate({
183
- field: {
184
- $gt: {
185
- $or: [{ subfield: 'value1' }, { subfield: 'value2' }],
186
- } as any,
187
- },
188
- }),
189
- ).toThrow();
190
-
191
- expect(() =>
192
- translator.translate({
193
- field: {
194
- $not: {
195
- $and: [{ subfield: 'value1' }, { subfield: 'value2' }],
196
- },
197
- },
198
- }),
199
- ).not.toThrow(); // $not is allowed to contain logical operators
200
- });
201
-
202
- it('throws error for $not if not an object', () => {
203
- expect(() => translator.translate({ $not: 'value' })).toThrow();
204
- expect(() => translator.translate({ $not: [{ field: 'value' }] } as any)).toThrow();
205
- });
206
-
207
- it('throws error for $not if empty', () => {
208
- expect(() => translator.translate({ $not: {} })).toThrow();
209
- });
210
- });
211
-
212
- // Nested Objects and Fields
213
- describe('nested objects and fields', () => {
214
- it('handles nested objects', () => {
215
- const filter: AstraVectorFilter = {
216
- 'user.profile.age': { $gt: 25 },
217
- 'user.status': 'active',
218
- };
219
- expect(translator.translate(filter)).toEqual(filter);
220
- });
221
-
222
- it('handles deeply nested field paths', () => {
223
- const filter: AstraVectorFilter = {
224
- 'user.profile.address.city': { $eq: 'New York' },
225
- 'deep.nested.field': { $gt: 100 },
226
- };
227
- expect(translator.translate(filter)).toEqual(filter);
228
- });
229
-
230
- it('preserves nested empty objects', () => {
231
- const filter: AstraVectorFilter = {
232
- status: 'active',
233
- metadata: {},
234
- 'user.profile': {},
235
- 'usersettings.theme': null,
236
- };
237
- expect(translator.translate(filter)).toEqual(filter);
238
- });
239
-
240
- it('handles mix of operators and empty objects', () => {
241
- const filter: AstraVectorFilter = {
242
- tags: { $in: ['a', 'b'] },
243
- metadata: {},
244
- 'nested.field': { $eq: 'value' },
245
- 'nested.empty': {},
246
- };
247
- expect(translator.translate(filter)).toEqual(filter);
248
- });
249
-
250
- it('handles deeply nested operators', () => {
251
- const filter: AstraVectorFilter = {
252
- 'user.profile.preferences.theme': { $in: ['dark', 'light'] },
253
- };
254
- expect(translator.translate(filter)).toEqual(filter);
255
- });
256
- });
257
-
258
- // Special Cases
259
- describe('special cases', () => {
260
- it('handles empty filters', () => {
261
- expect(translator.translate({})).toEqual({});
262
- expect(translator.translate(null)).toEqual(null);
263
- expect(translator.translate(undefined)).toEqual(undefined);
264
- });
265
-
266
- it('normalizes dates', () => {
267
- const date = new Date('2024-01-01');
268
- const filter: AstraVectorFilter = { timestamp: { $gt: date } };
269
- expect(translator.translate(filter)).toEqual({
270
- timestamp: { $gt: date.toISOString() },
271
- });
272
- });
273
-
274
- it('allows $not in field-level conditions', () => {
275
- expect(() =>
276
- translator.translate({
277
- field1: { $not: { $eq: 'value1' } },
278
- field2: { $not: { $in: ['value2', 'value3'] } },
279
- field3: { $not: { $regex: 'pattern' } },
280
- }),
281
- ).not.toThrow();
282
- });
283
- });
284
-
285
- describe('operator validation', () => {
286
- it('ensure all operator filters are supported', () => {
287
- const supportedFilters: AstraVectorFilter[] = [
288
- // Basic comparison operators
289
- { field: { $eq: 'value' } },
290
- { field: { $ne: 'value' } },
291
- { field: { $gt: 'value' } },
292
- { field: { $gte: 'value' } },
293
- { field: { $lt: 'value' } },
294
- { field: { $lte: 'value' } },
295
-
296
- // Array operators
297
- { field: { $in: ['value'] } },
298
- { field: { $nin: ['value'] } },
299
- { field: { $all: ['value'] } },
300
-
301
- // Existence
302
- { field: { $exists: true } },
303
-
304
- { $and: [{ field1: 'value1' }, { field2: 'value2' }] },
305
- { $or: [{ field1: 'value1' }, { field2: 'value2' }] },
306
-
307
- { $not: { field: 'value' } },
308
-
309
- { $or: [{ $and: [{ field1: 'value1' }] }, { $not: { field2: 'value2' } }] },
310
-
311
- { field: { $not: { $eq: 'value' } } },
312
- { field: { $not: { $in: ['value1', 'value2'] } } },
313
- { field: { $not: { $gt: 100 } } },
314
- { field: { $not: { $lt: 50 } } },
315
-
316
- { field: { $size: 1 } },
317
- ];
318
-
319
- supportedFilters.forEach(filter => {
320
- expect(() => translator.translate(filter)).not.toThrow();
321
- });
322
- });
323
-
324
- it('throws on unsupported operators', () => {
325
- expect(() => translator.translate({ field: { $regex: 'value' } as any })).toThrow('Unsupported operator: $regex');
326
- const filter: any = { field: /pattern/i };
327
- expect(() => translator.translate(filter)).toThrow();
328
- expect(() => translator.translate({ $nor: [{ field: 'value' }] } as any)).toThrow('Unsupported operator: $nor');
329
- expect(() => translator.translate({ field: { $elemMatch: { $gt: 5 } } } as any)).toThrow(
330
- 'Unsupported operator: $elemMatch',
331
- );
332
- });
333
- it('throws error for non-logical operators at top level', () => {
334
- const invalidFilters: any = [{ $gt: 100 }, { $in: ['value1', 'value2'] }, { $exists: true }];
335
-
336
- invalidFilters.forEach(filter => {
337
- expect(() => translator.translate(filter)).toThrow(/Invalid top-level operator/);
338
- });
339
- });
340
-
341
- it('allows logical operators at top level', () => {
342
- const validFilters: AstraVectorFilter[] = [
343
- { $and: [{ field: 'value' }] },
344
- { $or: [{ field: 'value' }] },
345
- { $not: { field: 'value' } },
346
- ];
347
-
348
- validFilters.forEach(filter => {
349
- expect(() => translator.translate(filter)).not.toThrow();
350
- });
351
- });
352
- });
353
- });
@@ -1,83 +0,0 @@
1
- import { BaseFilterTranslator } from '@mastra/core/vector/filter';
2
- import type {
3
- VectorFilter,
4
- OperatorSupport,
5
- QueryOperator,
6
- OperatorValueMap,
7
- LogicalOperatorValueMap,
8
- BlacklistedRootOperators,
9
- } from '@mastra/core/vector/filter';
10
-
11
- type AstraOperatorValueMap = Omit<OperatorValueMap, '$elemMatch' | '$regex' | '$options'> & {
12
- $size: number; // Astra-specific
13
- };
14
-
15
- type AstraLogicalOperatorValueMap = Omit<LogicalOperatorValueMap, '$nor'>;
16
-
17
- type AstraBlacklisted = BlacklistedRootOperators | '$nor' | '$size';
18
-
19
- export type AstraVectorFilter = VectorFilter<
20
- keyof AstraOperatorValueMap,
21
- AstraOperatorValueMap,
22
- AstraLogicalOperatorValueMap,
23
- AstraBlacklisted
24
- >;
25
-
26
- /**
27
- * Translator for Astra DB filter queries.
28
- * Maintains MongoDB-compatible syntax while ensuring proper validation
29
- * and normalization of values.
30
- */
31
- export class AstraFilterTranslator extends BaseFilterTranslator<AstraVectorFilter> {
32
- protected override getSupportedOperators(): OperatorSupport {
33
- return {
34
- ...BaseFilterTranslator.DEFAULT_OPERATORS,
35
- array: ['$all', '$in', '$nin'],
36
- logical: ['$and', '$or', '$not'],
37
- regex: [],
38
- custom: ['$size'],
39
- };
40
- }
41
-
42
- translate(filter?: AstraVectorFilter): AstraVectorFilter {
43
- if (this.isEmpty(filter)) return filter;
44
- this.validateFilter(filter);
45
-
46
- return this.translateNode(filter);
47
- }
48
-
49
- private translateNode(node: AstraVectorFilter): any {
50
- // Handle primitive values and arrays
51
- if (this.isRegex(node)) {
52
- throw new Error('Regex is not supported in Astra DB');
53
- }
54
- if (this.isPrimitive(node) || Array.isArray(node)) {
55
- return node;
56
- }
57
-
58
- const entries = Object.entries(node as Record<string, any>);
59
- const translatedEntries = entries.map(([key, value]) => {
60
- // Handle operators
61
- if (this.isOperator(key)) {
62
- return [key, this.translateOperatorValue(key, value)];
63
- }
64
-
65
- // Handle nested paths and objects
66
- return [key, this.translateNode(value)];
67
- });
68
-
69
- return Object.fromEntries(translatedEntries);
70
- }
71
-
72
- private translateOperatorValue(operator: QueryOperator, value: any): any {
73
- if (this.isBasicOperator(operator) || this.isNumericOperator(operator)) {
74
- return this.normalizeComparisonValue(value);
75
- }
76
-
77
- if (this.isArrayOperator(operator) && Array.isArray(value)) {
78
- return this.normalizeArrayValues(value);
79
- }
80
-
81
- return this.translateNode(value);
82
- }
83
- }