@mastra/libsql 0.13.0 → 0.13.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/vector/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,KAAK,EACV,UAAU,EACV,WAAW,EACX,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACnB,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EACnB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAInD,UAAU,uBAAwB,SAAQ,iBAAiB,CAAC,kBAAkB,CAAC;IAC7E,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,qBAAa,YAAa,SAAQ,YAAY,CAAC,kBAAkB,CAAC;IAChE,OAAO,CAAC,KAAK,CAAc;IAC3B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;gBAE9B,EACV,aAAa,EACb,SAAS,EACT,OAAO,EACP,YAAY,EACZ,UAAc,EACd,gBAAsB,GACvB,EAAE,kBAAkB;YAwBP,8BAA8B;IAgC5C,eAAe,CAAC,MAAM,CAAC,EAAE,kBAAkB;IAKrC,KAAK,CAAC,EACV,SAAS,EACT,WAAW,EACX,IAAS,EACT,MAAM,EACN,aAAqB,EACrB,QAAY,GACb,EAAE,uBAAuB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAoE5C,MAAM,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;YAe5C,QAAQ;IA2Cf,WAAW,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;YAgB5C,aAAa;IAyBpB,WAAW,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;YAgB5C,aAAa;IAQrB,WAAW,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAwBtC;;;;;OAKG;IACG,aAAa,CAAC,EAAE,SAAS,EAAE,EAAE,mBAAmB,GAAG,OAAO,CAAC,UAAU,CAAC;IAqD5E;;;;;;;;;;OAUG;IACI,YAAY,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;YAI9C,cAAc;IAiD5B;;;;;;OAMG;IACI,YAAY,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;YAgB9C,cAAc;IAQrB,aAAa,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;YAgB9C,gBAAgB;CAM/B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/vector/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,KAAK,EACV,UAAU,EACV,WAAW,EACX,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACnB,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EACnB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAInD,UAAU,uBAAwB,SAAQ,iBAAiB,CAAC,kBAAkB,CAAC;IAC7E,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,qBAAa,YAAa,SAAQ,YAAY,CAAC,kBAAkB,CAAC;IAChE,OAAO,CAAC,KAAK,CAAc;IAC3B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;gBAE9B,EACV,aAAa,EACb,SAAS,EACT,OAAO,EACP,YAAY,EACZ,UAAc,EACd,gBAAsB,GACvB,EAAE,kBAAkB;YAwBP,8BAA8B;IAgC5C,eAAe,CAAC,MAAM,CAAC,EAAE,kBAAkB;IAKrC,KAAK,CAAC,EACV,SAAS,EACT,WAAW,EACX,IAAS,EACT,MAAM,EACN,aAAqB,EACrB,QAAa,GACd,EAAE,uBAAuB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAoE5C,MAAM,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;YAe5C,QAAQ;IA2Cf,WAAW,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;YAgB5C,aAAa;IAyBpB,WAAW,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;YAgB5C,aAAa;IAQrB,WAAW,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAwBtC;;;;;OAKG;IACG,aAAa,CAAC,EAAE,SAAS,EAAE,EAAE,mBAAmB,GAAG,OAAO,CAAC,UAAU,CAAC;IAqD5E;;;;;;;;;;OAUG;IACI,YAAY,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;YAI9C,cAAc;IAiD5B;;;;;;OAMG;IACI,YAAY,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;YAgB9C,cAAc;IAQrB,aAAa,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;YAgB9C,gBAAgB;CAM/B"}
@@ -1 +1 @@
1
- {"version":3,"file":"sql-builder.d.ts","sourceRoot":"","sources":["../../src/vector/sql-builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAS9C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AA2VnD,UAAU,YAAY;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,OAAO,EAAE,CAAC;CACnB;AAeD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,kBAAkB,GAAG,YAAY,CAkBzE"}
1
+ {"version":3,"file":"sql-builder.d.ts","sourceRoot":"","sources":["../../src/vector/sql-builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAS9C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AA8VnD,UAAU,YAAY;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,OAAO,EAAE,CAAC;CACnB;AA6BD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,kBAAkB,GAAG,YAAY,CAkBzE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mastra/libsql",
3
- "version": "0.13.0",
3
+ "version": "0.13.1",
4
4
  "description": "Libsql provider for Mastra - includes both vector and db storage capabilities",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -29,10 +29,10 @@
29
29
  "tsup": "^8.5.0",
30
30
  "typescript": "^5.8.3",
31
31
  "vitest": "^3.2.4",
32
- "@internal/storage-test-utils": "0.0.23",
33
- "@internal/lint": "0.0.27",
34
- "@mastra/core": "0.13.0",
35
- "@internal/types-builder": "0.0.2"
32
+ "@internal/lint": "0.0.28",
33
+ "@internal/storage-test-utils": "0.0.24",
34
+ "@mastra/core": "0.13.1",
35
+ "@internal/types-builder": "0.0.3"
36
36
  },
37
37
  "peerDependencies": {
38
38
  "@mastra/core": ">=0.13.0-0 <0.14.0-0"
@@ -1,3 +1,4 @@
1
+ import { createVectorTestSuite } from '@internal/storage-test-utils';
1
2
  import { describe, it, expect, beforeAll, afterAll, beforeEach, afterEach } from 'vitest';
2
3
 
3
4
  import { LibSQLVector } from './index.js';
@@ -254,7 +255,7 @@ describe('LibSQLVector', () => {
254
255
  const metadata = [
255
256
  { type: 'a', value: 1 },
256
257
  { type: 'b', value: 2 },
257
- { type: 'a', value: 3 },
258
+ { type: 'c', value: 3 },
258
259
  ];
259
260
  await vectorDB.upsert({ indexName, vectors, metadata });
260
261
  });
@@ -1670,3 +1671,23 @@ describe('LibSQLVector', () => {
1670
1671
  });
1671
1672
  });
1672
1673
  });
1674
+
1675
+ // Use the shared test suite with factory pattern
1676
+ const libSQLVectorDB = new LibSQLVector({
1677
+ connectionUrl: 'file::memory:?cache=shared',
1678
+ });
1679
+
1680
+ createVectorTestSuite({
1681
+ vector: libSQLVectorDB,
1682
+ createIndex: async (indexName: string) => {
1683
+ await libSQLVectorDB.createIndex({ indexName, dimension: 4, metric: 'cosine' });
1684
+ },
1685
+ deleteIndex: async (indexName: string) => {
1686
+ try {
1687
+ await libSQLVectorDB.deleteIndex({ indexName });
1688
+ } catch (error) {
1689
+ console.error(`Error deleting index ${indexName}:`, error);
1690
+ }
1691
+ },
1692
+ waitForIndexing: () => new Promise(resolve => setTimeout(resolve, 100)),
1693
+ });
@@ -120,7 +120,7 @@ export class LibSQLVector extends MastraVector<LibSQLVectorFilter> {
120
120
  topK = 10,
121
121
  filter,
122
122
  includeVector = false,
123
- minScore = 0,
123
+ minScore = -1, // Default to -1 to include all results (cosine similarity ranges from -1 to 1)
124
124
  }: LibSQLQueryVectorParams): Promise<QueryResult[]> {
125
125
  try {
126
126
  if (!Number.isInteger(topK) || topK <= 0) {
@@ -29,11 +29,11 @@ type OperatorFn = (key: string, value?: any) => FilterOperator;
29
29
  // Helper functions to create operators
30
30
  const createBasicOperator = (symbol: string) => {
31
31
  return (key: string, value: any): FilterOperator => {
32
- const jsonPathKey = parseJsonPathKey(key);
32
+ const jsonPath = getJsonPath(key);
33
33
  return {
34
34
  sql: `CASE
35
- WHEN ? IS NULL THEN json_extract(metadata, '$."${jsonPathKey}"') IS ${symbol === '=' ? '' : 'NOT'} NULL
36
- ELSE json_extract(metadata, '$."${jsonPathKey}"') ${symbol} ?
35
+ WHEN ? IS NULL THEN json_extract(metadata, ${jsonPath}) IS ${symbol === '=' ? '' : 'NOT'} NULL
36
+ ELSE json_extract(metadata, ${jsonPath}) ${symbol} ?
37
37
  END`,
38
38
  needsValue: true,
39
39
  transformValue: () => {
@@ -45,19 +45,21 @@ const createBasicOperator = (symbol: string) => {
45
45
  };
46
46
  const createNumericOperator = (symbol: string) => {
47
47
  return (key: string): FilterOperator => {
48
- const jsonPathKey = parseJsonPathKey(key);
48
+ const jsonPath = getJsonPath(key);
49
49
  return {
50
- sql: `CAST(json_extract(metadata, '$."${jsonPathKey}"') AS NUMERIC) ${symbol} ?`,
50
+ sql: `CAST(json_extract(metadata, ${jsonPath}) AS NUMERIC) ${symbol} ?`,
51
51
  needsValue: true,
52
52
  };
53
53
  };
54
54
  };
55
55
 
56
- const validateJsonArray = (key: string) =>
57
- `json_valid(json_extract(metadata, '$."${key}"'))
58
- AND json_type(json_extract(metadata, '$."${key}"')) = 'array'`;
56
+ const validateJsonArray = (key: string) => {
57
+ const jsonPath = getJsonPath(key);
58
+ return `json_valid(json_extract(metadata, ${jsonPath}))
59
+ AND json_type(json_extract(metadata, ${jsonPath})) = 'array'`;
60
+ };
59
61
 
60
- const pattern = /json_extract\(metadata, '\$\."[^"]*"(\."[^"]*")*'\)/g;
62
+ const pattern = /json_extract\(metadata, '\$\.(?:"[^"]*"(?:\."[^"]*")*|[^']+)'\)/g;
61
63
 
62
64
  function buildElemMatchConditions(value: any) {
63
65
  const conditions = Object.entries(value).map(([field, fieldValue]) => {
@@ -71,13 +73,14 @@ function buildElemMatchConditions(value: any) {
71
73
  // Nested field with operators (count: { $gt: 20 })
72
74
  const { sql, values } = buildCondition(field, fieldValue, '');
73
75
  // Replace the field path with elem.value path
74
- const elemSql = sql.replace(pattern, `json_extract(elem.value, '$."${field}"')`);
76
+ const jsonPath = parseJsonPathKey(field);
77
+ const elemSql = sql.replace(pattern, `json_extract(elem.value, '$.${jsonPath}')`);
75
78
  return { sql: elemSql, values };
76
79
  } else {
77
- const parsedFieldKey = parseFieldKey(field);
80
+ const jsonPath = parseJsonPathKey(field);
78
81
  // Simple field equality (warehouse: 'A')
79
82
  return {
80
- sql: `json_extract(elem.value, '$."${parsedFieldKey}"') = ?`,
83
+ sql: `json_extract(elem.value, '$.${jsonPath}') = ?`,
81
84
  values: [fieldValue],
82
85
  };
83
86
  }
@@ -97,7 +100,7 @@ const FILTER_OPERATORS: Record<OperatorType, OperatorFn> = {
97
100
 
98
101
  // Array Operators
99
102
  $in: (key: string, value: any) => {
100
- const jsonPathKey = parseJsonPathKey(key);
103
+ const jsonPath = getJsonPath(key);
101
104
  const arr = Array.isArray(value) ? value : [value];
102
105
  if (arr.length === 0) {
103
106
  return { sql: '1 = 0', needsValue: true, transformValue: () => [] };
@@ -106,12 +109,12 @@ const FILTER_OPERATORS: Record<OperatorType, OperatorFn> = {
106
109
  return {
107
110
  sql: `(
108
111
  CASE
109
- WHEN ${validateJsonArray(jsonPathKey)} THEN
112
+ WHEN ${validateJsonArray(key)} THEN
110
113
  EXISTS (
111
- SELECT 1 FROM json_each(json_extract(metadata, '$."${jsonPathKey}"')) as elem
114
+ SELECT 1 FROM json_each(json_extract(metadata, ${jsonPath})) as elem
112
115
  WHERE elem.value IN (SELECT value FROM json_each(?))
113
116
  )
114
- ELSE json_extract(metadata, '$."${jsonPathKey}"') IN (${paramPlaceholders})
117
+ ELSE json_extract(metadata, ${jsonPath}) IN (${paramPlaceholders})
115
118
  END
116
119
  )`,
117
120
  needsValue: true,
@@ -120,7 +123,7 @@ const FILTER_OPERATORS: Record<OperatorType, OperatorFn> = {
120
123
  },
121
124
 
122
125
  $nin: (key: string, value: any) => {
123
- const jsonPathKey = parseJsonPathKey(key);
126
+ const jsonPath = getJsonPath(key);
124
127
  const arr = Array.isArray(value) ? value : [value];
125
128
  if (arr.length === 0) {
126
129
  return { sql: '1 = 1', needsValue: true, transformValue: () => [] };
@@ -129,12 +132,12 @@ const FILTER_OPERATORS: Record<OperatorType, OperatorFn> = {
129
132
  return {
130
133
  sql: `(
131
134
  CASE
132
- WHEN ${validateJsonArray(jsonPathKey)} THEN
135
+ WHEN ${validateJsonArray(key)} THEN
133
136
  NOT EXISTS (
134
- SELECT 1 FROM json_each(json_extract(metadata, '$."${jsonPathKey}"')) as elem
137
+ SELECT 1 FROM json_each(json_extract(metadata, ${jsonPath})) as elem
135
138
  WHERE elem.value IN (SELECT value FROM json_each(?))
136
139
  )
137
- ELSE json_extract(metadata, '$."${jsonPathKey}"') NOT IN (${paramPlaceholders})
140
+ ELSE json_extract(metadata, ${jsonPath}) NOT IN (${paramPlaceholders})
138
141
  END
139
142
  )`,
140
143
  needsValue: true,
@@ -142,7 +145,7 @@ const FILTER_OPERATORS: Record<OperatorType, OperatorFn> = {
142
145
  };
143
146
  },
144
147
  $all: (key: string, value: any) => {
145
- const jsonPathKey = parseJsonPathKey(key);
148
+ const jsonPath = getJsonPath(key);
146
149
  let sql: string;
147
150
  const arrayValue = Array.isArray(value) ? value : [value];
148
151
 
@@ -152,13 +155,13 @@ const FILTER_OPERATORS: Record<OperatorType, OperatorFn> = {
152
155
  } else {
153
156
  sql = `(
154
157
  CASE
155
- WHEN ${validateJsonArray(jsonPathKey)} THEN
158
+ WHEN ${validateJsonArray(key)} THEN
156
159
  NOT EXISTS (
157
160
  SELECT value
158
161
  FROM json_each(?)
159
162
  WHERE value NOT IN (
160
163
  SELECT value
161
- FROM json_each(json_extract(metadata, '$."${jsonPathKey}"'))
164
+ FROM json_each(json_extract(metadata, ${jsonPath}))
162
165
  )
163
166
  )
164
167
  ELSE FALSE
@@ -178,7 +181,7 @@ const FILTER_OPERATORS: Record<OperatorType, OperatorFn> = {
178
181
  };
179
182
  },
180
183
  $elemMatch: (key: string, value: any) => {
181
- const jsonPathKey = parseJsonPathKey(key);
184
+ const jsonPath = getJsonPath(key);
182
185
  if (typeof value !== 'object' || Array.isArray(value)) {
183
186
  throw new Error('$elemMatch requires an object with conditions');
184
187
  }
@@ -189,10 +192,10 @@ const FILTER_OPERATORS: Record<OperatorType, OperatorFn> = {
189
192
  return {
190
193
  sql: `(
191
194
  CASE
192
- WHEN ${validateJsonArray(jsonPathKey)} THEN
195
+ WHEN ${validateJsonArray(key)} THEN
193
196
  EXISTS (
194
197
  SELECT 1
195
- FROM json_each(json_extract(metadata, '$."${jsonPathKey}"')) as elem
198
+ FROM json_each(json_extract(metadata, ${jsonPath})) as elem
196
199
  WHERE ${conditions.map(c => c.sql).join(' AND ')}
197
200
  )
198
201
  ELSE FALSE
@@ -205,9 +208,9 @@ const FILTER_OPERATORS: Record<OperatorType, OperatorFn> = {
205
208
 
206
209
  // Element Operators
207
210
  $exists: (key: string) => {
208
- const jsonPathKey = parseJsonPathKey(key);
211
+ const jsonPath = getJsonPath(key);
209
212
  return {
210
- sql: `json_extract(metadata, '$."${jsonPathKey}"') IS NOT NULL`,
213
+ sql: `json_extract(metadata, ${jsonPath}) IS NOT NULL`,
211
214
  needsValue: false,
212
215
  };
213
216
  },
@@ -227,12 +230,12 @@ const FILTER_OPERATORS: Record<OperatorType, OperatorFn> = {
227
230
  needsValue: false,
228
231
  }),
229
232
  $size: (key: string, paramIndex: number) => {
230
- const jsonPathKey = parseJsonPathKey(key);
233
+ const jsonPath = getJsonPath(key);
231
234
  return {
232
235
  sql: `(
233
236
  CASE
234
- WHEN json_type(json_extract(metadata, '$."${jsonPathKey}"')) = 'array' THEN
235
- json_array_length(json_extract(metadata, '$."${jsonPathKey}"')) = $${paramIndex}
237
+ WHEN json_type(json_extract(metadata, ${jsonPath})) = 'array' THEN
238
+ json_array_length(json_extract(metadata, ${jsonPath})) = $${paramIndex}
236
239
  ELSE FALSE
237
240
  END
238
241
  )`,
@@ -365,7 +368,21 @@ function isFilterResult(obj: any): obj is FilterResult {
365
368
 
366
369
  const parseJsonPathKey = (key: string) => {
367
370
  const parsedKey = parseFieldKey(key);
368
- return parsedKey.replace(/\./g, '"."');
371
+ // Only add quotes around path segments if they contain dots
372
+ if (parsedKey.includes('.')) {
373
+ return parsedKey
374
+ .split('.')
375
+ .map(segment => `"${segment}"`)
376
+ .join('.');
377
+ }
378
+ return parsedKey;
379
+ };
380
+
381
+ // Helper to generate the correct JSON path format for LibSQL
382
+ const getJsonPath = (key: string) => {
383
+ const jsonPathKey = parseJsonPathKey(key);
384
+ // Always use quotes for consistency
385
+ return `'$.${jsonPathKey}'`;
369
386
  };
370
387
 
371
388
  function escapeLikePattern(str: string): string {
@@ -400,8 +417,9 @@ function buildCondition(key: string, value: any, parentPath: string): FilterResu
400
417
 
401
418
  // If condition is not a FilterCondition object, assume it's an equality check
402
419
  if (!value || typeof value !== 'object') {
420
+ const jsonPath = getJsonPath(key);
403
421
  return {
404
- sql: `json_extract(metadata, '$."${key.replace(/\./g, '"."')}"') = ?`,
422
+ sql: `json_extract(metadata, ${jsonPath}) = ?`,
405
423
  values: [value],
406
424
  };
407
425
  }