@mastra/libsql 0.10.4-alpha.0 → 0.10.4-alpha.2
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/.turbo/turbo-build.log +7 -7
- package/CHANGELOG.md +28 -0
- package/dist/_tsup-dts-rollup.d.cts +33 -6
- package/dist/_tsup-dts-rollup.d.ts +33 -6
- package/dist/index.cjs +555 -155
- package/dist/index.js +545 -145
- package/package.json +4 -4
- package/src/storage/index.test.ts +1 -30
- package/src/storage/index.ts +453 -137
- package/src/vector/filter.test.ts +22 -84
- package/src/vector/filter.ts +19 -5
- package/src/vector/index.test.ts +1 -11
- package/src/vector/index.ts +130 -18
- package/src/vector/sql-builder.ts +5 -5
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest';
|
|
2
2
|
|
|
3
|
+
import type { LibSQLVectorFilter } from './filter';
|
|
3
4
|
import { LibSQLFilterTranslator } from './filter';
|
|
4
5
|
|
|
5
6
|
describe('LibSQLFilterTranslator', () => {
|
|
@@ -17,14 +18,8 @@ describe('LibSQLFilterTranslator', () => {
|
|
|
17
18
|
});
|
|
18
19
|
});
|
|
19
20
|
|
|
20
|
-
it('translates array to $in', () => {
|
|
21
|
-
expect(translator.translate({ field: ['a', 'b'] })).toEqual({
|
|
22
|
-
field: { $in: ['a', 'b'] },
|
|
23
|
-
});
|
|
24
|
-
});
|
|
25
|
-
|
|
26
21
|
it('preserves comparison operators', () => {
|
|
27
|
-
const filter = {
|
|
22
|
+
const filter: LibSQLVectorFilter = {
|
|
28
23
|
field1: { $eq: 'value' },
|
|
29
24
|
field2: { $ne: 'value' },
|
|
30
25
|
field3: { $gt: 5 },
|
|
@@ -55,7 +50,7 @@ describe('LibSQLFilterTranslator', () => {
|
|
|
55
50
|
nested: {
|
|
56
51
|
field: 'value',
|
|
57
52
|
},
|
|
58
|
-
}),
|
|
53
|
+
} as any),
|
|
59
54
|
).toEqual({
|
|
60
55
|
'nested.field': { $eq: 'value' },
|
|
61
56
|
});
|
|
@@ -65,7 +60,8 @@ describe('LibSQLFilterTranslator', () => {
|
|
|
65
60
|
// Array Operations
|
|
66
61
|
describe('array operations', () => {
|
|
67
62
|
it('translates array to $in', () => {
|
|
68
|
-
|
|
63
|
+
const filter: LibSQLVectorFilter = { field: ['a', 'b'] };
|
|
64
|
+
expect(translator.translate(filter)).toEqual({
|
|
69
65
|
field: { $in: ['a', 'b'] },
|
|
70
66
|
});
|
|
71
67
|
});
|
|
@@ -82,7 +78,7 @@ describe('LibSQLFilterTranslator', () => {
|
|
|
82
78
|
it('handles empty arrays', () => {
|
|
83
79
|
expect(
|
|
84
80
|
translator.translate({
|
|
85
|
-
field: [],
|
|
81
|
+
field: [] as any,
|
|
86
82
|
}),
|
|
87
83
|
).toEqual({
|
|
88
84
|
field: { $in: [] },
|
|
@@ -128,7 +124,7 @@ describe('LibSQLFilterTranslator', () => {
|
|
|
128
124
|
});
|
|
129
125
|
|
|
130
126
|
// Array Operator Normalization
|
|
131
|
-
describe('
|
|
127
|
+
describe('Array operator normalization', () => {
|
|
132
128
|
it('normalizes single values for $all', () => {
|
|
133
129
|
expect(
|
|
134
130
|
translator.translate({
|
|
@@ -173,7 +169,7 @@ describe('LibSQLFilterTranslator', () => {
|
|
|
173
169
|
// Logical Operators
|
|
174
170
|
describe('Logical Operators', () => {
|
|
175
171
|
it('handles logical operators', () => {
|
|
176
|
-
const filter = {
|
|
172
|
+
const filter: LibSQLVectorFilter = {
|
|
177
173
|
$and: [{ field1: { $eq: 'value1' } }, { field2: { $eq: 'value2' } }],
|
|
178
174
|
$or: [{ field3: { $eq: 'value3' } }, { field4: { $eq: 'value4' } }],
|
|
179
175
|
};
|
|
@@ -457,16 +453,6 @@ describe('LibSQLFilterTranslator', () => {
|
|
|
457
453
|
field: { $eq: '' },
|
|
458
454
|
});
|
|
459
455
|
});
|
|
460
|
-
|
|
461
|
-
it('handles empty arrays', () => {
|
|
462
|
-
expect(
|
|
463
|
-
translator.translate({
|
|
464
|
-
field: [],
|
|
465
|
-
}),
|
|
466
|
-
).toEqual({
|
|
467
|
-
field: { $in: [] },
|
|
468
|
-
});
|
|
469
|
-
});
|
|
470
456
|
});
|
|
471
457
|
|
|
472
458
|
// Complex Filter Structures
|
|
@@ -540,53 +526,10 @@ describe('LibSQLFilterTranslator', () => {
|
|
|
540
526
|
});
|
|
541
527
|
});
|
|
542
528
|
|
|
543
|
-
// Array Operator Normalization
|
|
544
|
-
describe('Array Operator Normalization', () => {
|
|
545
|
-
it('normalizes single values for $all', () => {
|
|
546
|
-
expect(
|
|
547
|
-
translator.translate({
|
|
548
|
-
field: { $all: 'value' },
|
|
549
|
-
}),
|
|
550
|
-
).toEqual({
|
|
551
|
-
field: { $all: ['value'] },
|
|
552
|
-
});
|
|
553
|
-
});
|
|
554
|
-
|
|
555
|
-
it('normalizes single values for $in', () => {
|
|
556
|
-
expect(
|
|
557
|
-
translator.translate({
|
|
558
|
-
field: { $in: 'value' },
|
|
559
|
-
}),
|
|
560
|
-
).toEqual({
|
|
561
|
-
field: { $in: ['value'] },
|
|
562
|
-
});
|
|
563
|
-
});
|
|
564
|
-
|
|
565
|
-
it('normalizes single values for $nin', () => {
|
|
566
|
-
expect(
|
|
567
|
-
translator.translate({
|
|
568
|
-
field: { $nin: 'value' },
|
|
569
|
-
}),
|
|
570
|
-
).toEqual({
|
|
571
|
-
field: { $nin: ['value'] },
|
|
572
|
-
});
|
|
573
|
-
});
|
|
574
|
-
|
|
575
|
-
it('preserves arrays for array operators', () => {
|
|
576
|
-
expect(
|
|
577
|
-
translator.translate({
|
|
578
|
-
field: { $all: ['value1', 'value2'] },
|
|
579
|
-
}),
|
|
580
|
-
).toEqual({
|
|
581
|
-
field: { $all: ['value1', 'value2'] },
|
|
582
|
-
});
|
|
583
|
-
});
|
|
584
|
-
});
|
|
585
|
-
|
|
586
529
|
// Operator Support Validation
|
|
587
530
|
describe('Operator Support Validation', () => {
|
|
588
531
|
it('ensure all operator filters are supported', () => {
|
|
589
|
-
const supportedFilters = [
|
|
532
|
+
const supportedFilters: LibSQLVectorFilter[] = [
|
|
590
533
|
// Basic comparison operators
|
|
591
534
|
{ field: { $eq: 'value' } },
|
|
592
535
|
{ field: { $ne: 'value' } },
|
|
@@ -612,12 +555,7 @@ describe('LibSQLFilterTranslator', () => {
|
|
|
612
555
|
{ $or: [{ field1: 'value1' }, { field2: 'value2' }] },
|
|
613
556
|
{ $nor: [{ field1: 'value1' }, { field2: 'value2' }] },
|
|
614
557
|
|
|
615
|
-
{ $and: {
|
|
616
|
-
{ $or: { field: 'value' } },
|
|
617
|
-
{ $nor: { field: 'value' } },
|
|
618
|
-
{ $not: { field: 'value' } },
|
|
619
|
-
|
|
620
|
-
{ $or: [{ $and: { field1: 'value1' } }, { $not: { field2: 'value2' } }] },
|
|
558
|
+
{ $or: [{ $and: [{ field1: 'value1' }] }, { $not: { field2: 'value2' } }] },
|
|
621
559
|
|
|
622
560
|
{ field: { $not: { $eq: 'value' } } },
|
|
623
561
|
{ field: { $not: { $in: ['value1', 'value2'] } } },
|
|
@@ -634,7 +572,7 @@ describe('LibSQLFilterTranslator', () => {
|
|
|
634
572
|
|
|
635
573
|
it('throws error for $not if not an object', () => {
|
|
636
574
|
expect(() => translator.translate({ $not: 'value' })).toThrow();
|
|
637
|
-
expect(() => translator.translate({ $not: [{ field: 'value' }] })).toThrow();
|
|
575
|
+
expect(() => translator.translate({ $not: [{ field: 'value' }] } as any)).toThrow();
|
|
638
576
|
});
|
|
639
577
|
it('throws error for $not if empty', () => {
|
|
640
578
|
expect(() => translator.translate({ $not: {} })).toThrow();
|
|
@@ -646,21 +584,21 @@ describe('LibSQLFilterTranslator', () => {
|
|
|
646
584
|
expect(() =>
|
|
647
585
|
translator.translate({
|
|
648
586
|
field: { $and: [{ $eq: 'value1' }, { $eq: 'value2' }] },
|
|
649
|
-
}),
|
|
587
|
+
} as any),
|
|
650
588
|
).toThrow();
|
|
651
589
|
|
|
652
590
|
// $or cannot be used in field conditions
|
|
653
591
|
expect(() =>
|
|
654
592
|
translator.translate({
|
|
655
593
|
field: { $or: [{ $eq: 'value1' }, { $eq: 'value2' }] },
|
|
656
|
-
}),
|
|
594
|
+
} as any),
|
|
657
595
|
).toThrow();
|
|
658
596
|
|
|
659
597
|
// $nor cannot be used in field conditions
|
|
660
598
|
expect(() =>
|
|
661
599
|
translator.translate({
|
|
662
600
|
field: { $nor: [{ $eq: 'value1' }, { $eq: 'value2' }] },
|
|
663
|
-
}),
|
|
601
|
+
} as any),
|
|
664
602
|
).toThrow();
|
|
665
603
|
});
|
|
666
604
|
|
|
@@ -709,7 +647,7 @@ describe('LibSQLFilterTranslator', () => {
|
|
|
709
647
|
field: {
|
|
710
648
|
$gt: {
|
|
711
649
|
$or: [{ subfield: 'value1' }, { subfield: 'value2' }],
|
|
712
|
-
},
|
|
650
|
+
} as any,
|
|
713
651
|
},
|
|
714
652
|
}),
|
|
715
653
|
).toThrow();
|
|
@@ -723,17 +661,17 @@ describe('LibSQLFilterTranslator', () => {
|
|
|
723
661
|
$and: [{ subfield: 'value1' }, { subfield: 'value2' }],
|
|
724
662
|
},
|
|
725
663
|
],
|
|
726
|
-
},
|
|
664
|
+
} as any,
|
|
727
665
|
}),
|
|
728
666
|
).toThrow();
|
|
729
667
|
});
|
|
730
668
|
|
|
731
669
|
it('validates $not operator structure', () => {
|
|
732
670
|
// $not must be an object
|
|
733
|
-
expect(() => translator.translate({ field: { $not: 'value' } })).toThrow();
|
|
671
|
+
expect(() => translator.translate({ field: { $not: 'value' } } as any)).toThrow();
|
|
734
672
|
expect(() => translator.translate({ field: { $not: ['value'] } })).toThrow();
|
|
735
673
|
expect(() => translator.translate({ $not: 'value' })).toThrow();
|
|
736
|
-
expect(() => translator.translate({ $not: ['value'] })).toThrow();
|
|
674
|
+
expect(() => translator.translate({ $not: ['value'] } as any)).toThrow();
|
|
737
675
|
});
|
|
738
676
|
|
|
739
677
|
it('validates $not operator nesting', () => {
|
|
@@ -793,7 +731,7 @@ describe('LibSQLFilterTranslator', () => {
|
|
|
793
731
|
const invalidFilters = [{ $gt: 100 }, { $in: ['value1', 'value2'] }, { $eq: true }];
|
|
794
732
|
|
|
795
733
|
invalidFilters.forEach(filter => {
|
|
796
|
-
expect(() => translator.translate(filter)).toThrow(/Invalid top-level operator/);
|
|
734
|
+
expect(() => translator.translate(filter as any)).toThrow(/Invalid top-level operator/);
|
|
797
735
|
});
|
|
798
736
|
});
|
|
799
737
|
it('allows logical operators at top level', () => {
|
|
@@ -815,13 +753,13 @@ describe('LibSQLFilterTranslator', () => {
|
|
|
815
753
|
// Should throw for non-object values
|
|
816
754
|
expect(() =>
|
|
817
755
|
translator.translate({
|
|
818
|
-
field: { $elemMatch: 'value' },
|
|
756
|
+
field: { $elemMatch: 'value' } as any,
|
|
819
757
|
}),
|
|
820
758
|
).toThrow('$elemMatch requires an object with conditions');
|
|
821
759
|
|
|
822
760
|
expect(() =>
|
|
823
761
|
translator.translate({
|
|
824
|
-
field: { $elemMatch: ['value'] },
|
|
762
|
+
field: { $elemMatch: ['value'] } as any,
|
|
825
763
|
}),
|
|
826
764
|
).toThrow('$elemMatch requires an object with conditions');
|
|
827
765
|
});
|
|
@@ -962,7 +900,7 @@ describe('LibSQLFilterTranslator', () => {
|
|
|
962
900
|
// Unsupported Operations
|
|
963
901
|
describe('unsupported operators', () => {
|
|
964
902
|
it('throws on unsupported operators', () => {
|
|
965
|
-
expect(() => translator.translate({ field: { $regex: 'value' } })).toThrow();
|
|
903
|
+
expect(() => translator.translate({ field: { $regex: 'value' } } as any)).toThrow();
|
|
966
904
|
});
|
|
967
905
|
});
|
|
968
906
|
});
|
package/src/vector/filter.ts
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
import { BaseFilterTranslator } from '@mastra/core/vector/filter';
|
|
2
|
-
import type {
|
|
2
|
+
import type { VectorFilter, OperatorSupport, OperatorValueMap, VectorFieldValue } from '@mastra/core/vector/filter';
|
|
3
|
+
|
|
4
|
+
type LibSQLOperatorValueMap = Omit<
|
|
5
|
+
OperatorValueMap,
|
|
6
|
+
'$regex' | '$options' | '$in' | '$all' | '$nin' | '$eq' | '$ne'
|
|
7
|
+
> & {
|
|
8
|
+
$size: number;
|
|
9
|
+
$contains: VectorFieldValue | Record<string, unknown>;
|
|
10
|
+
$all: VectorFieldValue;
|
|
11
|
+
$in: VectorFieldValue;
|
|
12
|
+
$nin: VectorFieldValue;
|
|
13
|
+
$eq: VectorFieldValue;
|
|
14
|
+
$ne: VectorFieldValue;
|
|
15
|
+
};
|
|
16
|
+
export type LibSQLVectorFilter = VectorFilter<keyof LibSQLOperatorValueMap, LibSQLOperatorValueMap>;
|
|
3
17
|
|
|
4
18
|
/**
|
|
5
19
|
* Translates MongoDB-style filters to LibSQL compatible filters.
|
|
@@ -11,7 +25,7 @@ import type { FieldCondition, VectorFilter, OperatorSupport } from '@mastra/core
|
|
|
11
25
|
* - Can take either a single condition or an array of conditions
|
|
12
26
|
*
|
|
13
27
|
*/
|
|
14
|
-
export class LibSQLFilterTranslator extends BaseFilterTranslator {
|
|
28
|
+
export class LibSQLFilterTranslator extends BaseFilterTranslator<LibSQLVectorFilter> {
|
|
15
29
|
protected override getSupportedOperators(): OperatorSupport {
|
|
16
30
|
return {
|
|
17
31
|
...BaseFilterTranslator.DEFAULT_OPERATORS,
|
|
@@ -20,7 +34,7 @@ export class LibSQLFilterTranslator extends BaseFilterTranslator {
|
|
|
20
34
|
};
|
|
21
35
|
}
|
|
22
36
|
|
|
23
|
-
translate(filter?:
|
|
37
|
+
translate(filter?: LibSQLVectorFilter): LibSQLVectorFilter {
|
|
24
38
|
if (this.isEmpty(filter)) {
|
|
25
39
|
return filter;
|
|
26
40
|
}
|
|
@@ -28,7 +42,7 @@ export class LibSQLFilterTranslator extends BaseFilterTranslator {
|
|
|
28
42
|
return this.translateNode(filter);
|
|
29
43
|
}
|
|
30
44
|
|
|
31
|
-
private translateNode(node:
|
|
45
|
+
private translateNode(node: LibSQLVectorFilter, currentPath: string = ''): any {
|
|
32
46
|
if (this.isRegex(node)) {
|
|
33
47
|
throw new Error('Direct regex pattern format is not supported in LibSQL');
|
|
34
48
|
}
|
|
@@ -74,7 +88,7 @@ export class LibSQLFilterTranslator extends BaseFilterTranslator {
|
|
|
74
88
|
|
|
75
89
|
if (this.isLogicalOperator(key)) {
|
|
76
90
|
result[key] = Array.isArray(value)
|
|
77
|
-
? value.map((filter:
|
|
91
|
+
? value.map((filter: LibSQLVectorFilter) => this.translateNode(filter))
|
|
78
92
|
: this.translateNode(value);
|
|
79
93
|
} else if (this.isOperator(key)) {
|
|
80
94
|
if (this.isArrayOperator(key) && !Array.isArray(value) && key !== '$elemMatch') {
|
package/src/vector/index.test.ts
CHANGED
|
@@ -1130,7 +1130,7 @@ describe('LibSQLVector', () => {
|
|
|
1130
1130
|
vectorDB.query({
|
|
1131
1131
|
indexName,
|
|
1132
1132
|
queryVector: [1, 0, 0],
|
|
1133
|
-
filter: { price: { $invalid: 100 } },
|
|
1133
|
+
filter: { price: { $invalid: 100 } } as any,
|
|
1134
1134
|
}),
|
|
1135
1135
|
).rejects.toThrow('Unsupported operator: $invalid');
|
|
1136
1136
|
});
|
|
@@ -1360,16 +1360,6 @@ describe('LibSQLVector', () => {
|
|
|
1360
1360
|
});
|
|
1361
1361
|
});
|
|
1362
1362
|
|
|
1363
|
-
it('should throw error for invalid operator', async () => {
|
|
1364
|
-
await expect(
|
|
1365
|
-
vectorDB.query({
|
|
1366
|
-
indexName,
|
|
1367
|
-
queryVector: [1, 0, 0],
|
|
1368
|
-
filter: { price: { $invalid: 100 } },
|
|
1369
|
-
}),
|
|
1370
|
-
).rejects.toThrow('Unsupported operator: $invalid');
|
|
1371
|
-
});
|
|
1372
|
-
|
|
1373
1363
|
it('should handle multiple logical operators at root level', async () => {
|
|
1374
1364
|
const results = await vectorDB.query({
|
|
1375
1365
|
indexName,
|
package/src/vector/index.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createClient } from '@libsql/client';
|
|
2
2
|
import type { Client as TursoClient, InValue } from '@libsql/client';
|
|
3
3
|
|
|
4
|
+
import { ErrorCategory, ErrorDomain, MastraError } from '@mastra/core/error';
|
|
4
5
|
import { parseSqlIdentifier } from '@mastra/core/utils';
|
|
5
6
|
import { MastraVector } from '@mastra/core/vector';
|
|
6
7
|
import type {
|
|
@@ -14,11 +15,11 @@ import type {
|
|
|
14
15
|
DeleteVectorParams,
|
|
15
16
|
UpdateVectorParams,
|
|
16
17
|
} from '@mastra/core/vector';
|
|
17
|
-
import type {
|
|
18
|
+
import type { LibSQLVectorFilter } from './filter';
|
|
18
19
|
import { LibSQLFilterTranslator } from './filter';
|
|
19
20
|
import { buildFilterQuery } from './sql-builder';
|
|
20
21
|
|
|
21
|
-
interface LibSQLQueryVectorParams extends QueryVectorParams {
|
|
22
|
+
interface LibSQLQueryVectorParams extends QueryVectorParams<LibSQLVectorFilter> {
|
|
22
23
|
minScore?: number;
|
|
23
24
|
}
|
|
24
25
|
|
|
@@ -40,7 +41,7 @@ export interface LibSQLVectorConfig {
|
|
|
40
41
|
initialBackoffMs?: number;
|
|
41
42
|
}
|
|
42
43
|
|
|
43
|
-
export class LibSQLVector extends MastraVector {
|
|
44
|
+
export class LibSQLVector extends MastraVector<LibSQLVectorFilter> {
|
|
44
45
|
private turso: TursoClient;
|
|
45
46
|
private readonly maxRetries: number;
|
|
46
47
|
private readonly initialBackoffMs: number;
|
|
@@ -108,7 +109,7 @@ export class LibSQLVector extends MastraVector {
|
|
|
108
109
|
throw new Error('LibSQLVector: Max retries reached, but no error was re-thrown from the loop.');
|
|
109
110
|
}
|
|
110
111
|
|
|
111
|
-
transformFilter(filter?:
|
|
112
|
+
transformFilter(filter?: LibSQLVectorFilter) {
|
|
112
113
|
const translator = new LibSQLFilterTranslator();
|
|
113
114
|
return translator.translate(filter);
|
|
114
115
|
}
|
|
@@ -128,7 +129,18 @@ export class LibSQLVector extends MastraVector {
|
|
|
128
129
|
if (!Array.isArray(queryVector) || !queryVector.every(x => typeof x === 'number' && Number.isFinite(x))) {
|
|
129
130
|
throw new Error('queryVector must be an array of finite numbers');
|
|
130
131
|
}
|
|
132
|
+
} catch (error) {
|
|
133
|
+
throw new MastraError(
|
|
134
|
+
{
|
|
135
|
+
id: 'LIBSQL_VECTOR_QUERY_INVALID_ARGS',
|
|
136
|
+
domain: ErrorDomain.STORAGE,
|
|
137
|
+
category: ErrorCategory.USER,
|
|
138
|
+
},
|
|
139
|
+
error,
|
|
140
|
+
);
|
|
141
|
+
}
|
|
131
142
|
|
|
143
|
+
try {
|
|
132
144
|
const parsedIndexName = parseSqlIdentifier(indexName, 'index name');
|
|
133
145
|
|
|
134
146
|
const vectorStr = `[${queryVector.join(',')}]`;
|
|
@@ -165,13 +177,31 @@ export class LibSQLVector extends MastraVector {
|
|
|
165
177
|
metadata: JSON.parse((metadata as string) ?? '{}'),
|
|
166
178
|
...(includeVector && embedding && { vector: JSON.parse(embedding as string) }),
|
|
167
179
|
}));
|
|
168
|
-
}
|
|
169
|
-
|
|
180
|
+
} catch (error) {
|
|
181
|
+
throw new MastraError(
|
|
182
|
+
{
|
|
183
|
+
id: 'LIBSQL_VECTOR_QUERY_FAILED',
|
|
184
|
+
domain: ErrorDomain.STORAGE,
|
|
185
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
186
|
+
},
|
|
187
|
+
error,
|
|
188
|
+
);
|
|
170
189
|
}
|
|
171
190
|
}
|
|
172
191
|
|
|
173
192
|
public upsert(args: UpsertVectorParams): Promise<string[]> {
|
|
174
|
-
|
|
193
|
+
try {
|
|
194
|
+
return this.executeWriteOperationWithRetry(() => this.doUpsert(args), true);
|
|
195
|
+
} catch (error) {
|
|
196
|
+
throw new MastraError(
|
|
197
|
+
{
|
|
198
|
+
id: 'LIBSQL_VECTOR_UPSERT_FAILED',
|
|
199
|
+
domain: ErrorDomain.STORAGE,
|
|
200
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
201
|
+
},
|
|
202
|
+
error,
|
|
203
|
+
);
|
|
204
|
+
}
|
|
175
205
|
}
|
|
176
206
|
|
|
177
207
|
private async doUpsert({ indexName, vectors, metadata, ids }: UpsertVectorParams): Promise<string[]> {
|
|
@@ -218,7 +248,19 @@ export class LibSQLVector extends MastraVector {
|
|
|
218
248
|
}
|
|
219
249
|
|
|
220
250
|
public createIndex(args: CreateIndexParams): Promise<void> {
|
|
221
|
-
|
|
251
|
+
try {
|
|
252
|
+
return this.executeWriteOperationWithRetry(() => this.doCreateIndex(args));
|
|
253
|
+
} catch (error) {
|
|
254
|
+
throw new MastraError(
|
|
255
|
+
{
|
|
256
|
+
id: 'LIBSQL_VECTOR_CREATE_INDEX_FAILED',
|
|
257
|
+
domain: ErrorDomain.STORAGE,
|
|
258
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
259
|
+
details: { indexName: args.indexName, dimension: args.dimension },
|
|
260
|
+
},
|
|
261
|
+
error,
|
|
262
|
+
);
|
|
263
|
+
}
|
|
222
264
|
}
|
|
223
265
|
|
|
224
266
|
private async doCreateIndex({ indexName, dimension }: CreateIndexParams): Promise<void> {
|
|
@@ -247,7 +289,19 @@ export class LibSQLVector extends MastraVector {
|
|
|
247
289
|
}
|
|
248
290
|
|
|
249
291
|
public deleteIndex(args: DeleteIndexParams): Promise<void> {
|
|
250
|
-
|
|
292
|
+
try {
|
|
293
|
+
return this.executeWriteOperationWithRetry(() => this.doDeleteIndex(args));
|
|
294
|
+
} catch (error) {
|
|
295
|
+
throw new MastraError(
|
|
296
|
+
{
|
|
297
|
+
id: 'LIBSQL_VECTOR_DELETE_INDEX_FAILED',
|
|
298
|
+
domain: ErrorDomain.STORAGE,
|
|
299
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
300
|
+
details: { indexName: args.indexName },
|
|
301
|
+
},
|
|
302
|
+
error,
|
|
303
|
+
);
|
|
304
|
+
}
|
|
251
305
|
}
|
|
252
306
|
|
|
253
307
|
private async doDeleteIndex({ indexName }: DeleteIndexParams): Promise<void> {
|
|
@@ -271,7 +325,14 @@ export class LibSQLVector extends MastraVector {
|
|
|
271
325
|
});
|
|
272
326
|
return result.rows.map(row => row.name as string);
|
|
273
327
|
} catch (error: any) {
|
|
274
|
-
throw new
|
|
328
|
+
throw new MastraError(
|
|
329
|
+
{
|
|
330
|
+
id: 'LIBSQL_VECTOR_LIST_INDEXES_FAILED',
|
|
331
|
+
domain: ErrorDomain.STORAGE,
|
|
332
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
333
|
+
},
|
|
334
|
+
error,
|
|
335
|
+
);
|
|
275
336
|
}
|
|
276
337
|
}
|
|
277
338
|
|
|
@@ -322,7 +383,15 @@ export class LibSQLVector extends MastraVector {
|
|
|
322
383
|
metric,
|
|
323
384
|
};
|
|
324
385
|
} catch (e: any) {
|
|
325
|
-
throw new
|
|
386
|
+
throw new MastraError(
|
|
387
|
+
{
|
|
388
|
+
id: 'LIBSQL_VECTOR_DESCRIBE_INDEX_FAILED',
|
|
389
|
+
domain: ErrorDomain.STORAGE,
|
|
390
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
391
|
+
details: { indexName },
|
|
392
|
+
},
|
|
393
|
+
e,
|
|
394
|
+
);
|
|
326
395
|
}
|
|
327
396
|
}
|
|
328
397
|
|
|
@@ -357,7 +426,13 @@ export class LibSQLVector extends MastraVector {
|
|
|
357
426
|
}
|
|
358
427
|
|
|
359
428
|
if (updates.length === 0) {
|
|
360
|
-
throw new
|
|
429
|
+
throw new MastraError({
|
|
430
|
+
id: 'LIBSQL_VECTOR_UPDATE_VECTOR_INVALID_ARGS',
|
|
431
|
+
domain: ErrorDomain.STORAGE,
|
|
432
|
+
category: ErrorCategory.USER,
|
|
433
|
+
details: { indexName, id },
|
|
434
|
+
text: 'No updates provided',
|
|
435
|
+
});
|
|
361
436
|
}
|
|
362
437
|
args.push(id);
|
|
363
438
|
const query = `
|
|
@@ -365,10 +440,23 @@ export class LibSQLVector extends MastraVector {
|
|
|
365
440
|
SET ${updates.join(', ')}
|
|
366
441
|
WHERE vector_id = ?;
|
|
367
442
|
`;
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
443
|
+
|
|
444
|
+
try {
|
|
445
|
+
await this.turso.execute({
|
|
446
|
+
sql: query,
|
|
447
|
+
args,
|
|
448
|
+
});
|
|
449
|
+
} catch (error) {
|
|
450
|
+
throw new MastraError(
|
|
451
|
+
{
|
|
452
|
+
id: 'LIBSQL_VECTOR_UPDATE_VECTOR_FAILED',
|
|
453
|
+
domain: ErrorDomain.STORAGE,
|
|
454
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
455
|
+
details: { indexName, id },
|
|
456
|
+
},
|
|
457
|
+
error,
|
|
458
|
+
);
|
|
459
|
+
}
|
|
372
460
|
}
|
|
373
461
|
|
|
374
462
|
/**
|
|
@@ -379,7 +467,19 @@ export class LibSQLVector extends MastraVector {
|
|
|
379
467
|
* @throws Will throw an error if the deletion operation fails.
|
|
380
468
|
*/
|
|
381
469
|
public deleteVector(args: DeleteVectorParams): Promise<void> {
|
|
382
|
-
|
|
470
|
+
try {
|
|
471
|
+
return this.executeWriteOperationWithRetry(() => this.doDeleteVector(args));
|
|
472
|
+
} catch (error) {
|
|
473
|
+
throw new MastraError(
|
|
474
|
+
{
|
|
475
|
+
id: 'LIBSQL_VECTOR_DELETE_VECTOR_FAILED',
|
|
476
|
+
domain: ErrorDomain.STORAGE,
|
|
477
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
478
|
+
details: { indexName: args.indexName, id: args.id },
|
|
479
|
+
},
|
|
480
|
+
error,
|
|
481
|
+
);
|
|
482
|
+
}
|
|
383
483
|
}
|
|
384
484
|
|
|
385
485
|
private async doDeleteVector({ indexName, id }: DeleteVectorParams): Promise<void> {
|
|
@@ -391,7 +491,19 @@ export class LibSQLVector extends MastraVector {
|
|
|
391
491
|
}
|
|
392
492
|
|
|
393
493
|
public truncateIndex(args: DeleteIndexParams): Promise<void> {
|
|
394
|
-
|
|
494
|
+
try {
|
|
495
|
+
return this.executeWriteOperationWithRetry(() => this._doTruncateIndex(args));
|
|
496
|
+
} catch (error) {
|
|
497
|
+
throw new MastraError(
|
|
498
|
+
{
|
|
499
|
+
id: 'LIBSQL_VECTOR_TRUNCATE_INDEX_FAILED',
|
|
500
|
+
domain: ErrorDomain.STORAGE,
|
|
501
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
502
|
+
details: { indexName: args.indexName },
|
|
503
|
+
},
|
|
504
|
+
error,
|
|
505
|
+
);
|
|
506
|
+
}
|
|
395
507
|
}
|
|
396
508
|
|
|
397
509
|
private async _doTruncateIndex({ indexName }: DeleteIndexParams): Promise<void> {
|
|
@@ -6,8 +6,8 @@ import type {
|
|
|
6
6
|
ArrayOperator,
|
|
7
7
|
ElementOperator,
|
|
8
8
|
LogicalOperator,
|
|
9
|
-
VectorFilter,
|
|
10
9
|
} from '@mastra/core/vector/filter';
|
|
10
|
+
import type { LibSQLVectorFilter } from './filter';
|
|
11
11
|
|
|
12
12
|
type OperatorType =
|
|
13
13
|
| BasicOperator
|
|
@@ -372,7 +372,7 @@ function escapeLikePattern(str: string): string {
|
|
|
372
372
|
return str.replace(/([%_\\])/g, '\\$1');
|
|
373
373
|
}
|
|
374
374
|
|
|
375
|
-
export function buildFilterQuery(filter:
|
|
375
|
+
export function buildFilterQuery(filter: LibSQLVectorFilter): FilterResult {
|
|
376
376
|
if (!filter) {
|
|
377
377
|
return { sql: '', values: [] };
|
|
378
378
|
}
|
|
@@ -428,11 +428,11 @@ function buildCondition(key: string, value: any, parentPath: string): FilterResu
|
|
|
428
428
|
|
|
429
429
|
function handleLogicalOperator(
|
|
430
430
|
key: '$and' | '$or' | '$not' | '$nor',
|
|
431
|
-
value:
|
|
431
|
+
value: LibSQLVectorFilter[] | LibSQLVectorFilter,
|
|
432
432
|
parentPath: string,
|
|
433
433
|
): FilterResult {
|
|
434
434
|
// Handle empty conditions
|
|
435
|
-
if (!value || value.length === 0) {
|
|
435
|
+
if (!value || (Array.isArray(value) && value.length === 0)) {
|
|
436
436
|
switch (key) {
|
|
437
437
|
case '$and':
|
|
438
438
|
case '$nor':
|
|
@@ -460,7 +460,7 @@ function handleLogicalOperator(
|
|
|
460
460
|
const joinOperator = key === '$or' || key === '$nor' ? 'OR' : 'AND';
|
|
461
461
|
const conditions = Array.isArray(value)
|
|
462
462
|
? value.map(f => {
|
|
463
|
-
const entries = Object.entries(f);
|
|
463
|
+
const entries = !!f ? Object.entries(f) : [];
|
|
464
464
|
return entries.map(([k, v]) => buildCondition(k, v, key));
|
|
465
465
|
})
|
|
466
466
|
: [buildCondition(key, value, parentPath)];
|