@mastra/lance 0.3.10 → 0.3.11

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/dist/index.js CHANGED
@@ -1427,6 +1427,8 @@ var StoreScoresLance = class extends ScoresStorage {
1427
1427
  filteredScore[key] = JSON.stringify(filteredScore[key]);
1428
1428
  }
1429
1429
  }
1430
+ filteredScore.createdAt = /* @__PURE__ */ new Date();
1431
+ filteredScore.updatedAt = /* @__PURE__ */ new Date();
1430
1432
  filteredScore.id = id;
1431
1433
  await table.add([filteredScore], { mode: "append" });
1432
1434
  return { score };
@@ -3192,7 +3194,44 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
3192
3194
  );
3193
3195
  }
3194
3196
  }
3195
- async updateVector({ indexName, id, update }) {
3197
+ async updateVector(params) {
3198
+ const { indexName, update } = params;
3199
+ if ("id" in params && "filter" in params && params.id && params.filter) {
3200
+ throw new MastraError({
3201
+ id: "STORAGE_LANCE_VECTOR_UPDATE_VECTOR_INVALID_ARGS",
3202
+ domain: ErrorDomain.STORAGE,
3203
+ category: ErrorCategory.USER,
3204
+ text: "id and filter are mutually exclusive",
3205
+ details: { indexName }
3206
+ });
3207
+ }
3208
+ if (!("id" in params || "filter" in params) || !params.id && !params.filter) {
3209
+ throw new MastraError({
3210
+ id: "STORAGE_LANCE_VECTOR_UPDATE_VECTOR_INVALID_ARGS",
3211
+ domain: ErrorDomain.STORAGE,
3212
+ category: ErrorCategory.USER,
3213
+ text: "Either id or filter must be provided",
3214
+ details: { indexName }
3215
+ });
3216
+ }
3217
+ if ("filter" in params && params.filter && Object.keys(params.filter).length === 0) {
3218
+ throw new MastraError({
3219
+ id: "STORAGE_LANCE_VECTOR_UPDATE_VECTOR_INVALID_ARGS",
3220
+ domain: ErrorDomain.STORAGE,
3221
+ category: ErrorCategory.USER,
3222
+ text: "Cannot update with empty filter",
3223
+ details: { indexName }
3224
+ });
3225
+ }
3226
+ if (!update.vector && !update.metadata) {
3227
+ throw new MastraError({
3228
+ id: "STORAGE_LANCE_VECTOR_UPDATE_VECTOR_INVALID_ARGS",
3229
+ domain: ErrorDomain.STORAGE,
3230
+ category: ErrorCategory.USER,
3231
+ text: "No updates provided",
3232
+ details: { indexName }
3233
+ });
3234
+ }
3196
3235
  try {
3197
3236
  if (!this.lanceClient) {
3198
3237
  throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
@@ -3200,21 +3239,6 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
3200
3239
  if (!indexName) {
3201
3240
  throw new Error("indexName is required");
3202
3241
  }
3203
- if (!id) {
3204
- throw new Error("id is required");
3205
- }
3206
- } catch (err) {
3207
- throw new MastraError(
3208
- {
3209
- id: "STORAGE_LANCE_VECTOR_UPDATE_VECTOR_FAILED_INVALID_ARGS",
3210
- domain: ErrorDomain.STORAGE,
3211
- category: ErrorCategory.USER,
3212
- details: { indexName, id }
3213
- },
3214
- err
3215
- );
3216
- }
3217
- try {
3218
3242
  const tables = await this.lanceClient.tableNames();
3219
3243
  for (const tableName of tables) {
3220
3244
  this.logger.debug("Checking table:" + tableName);
@@ -3224,39 +3248,66 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
3224
3248
  const hasColumn = schema.fields.some((field) => field.name === indexName);
3225
3249
  if (hasColumn) {
3226
3250
  this.logger.debug(`Found column ${indexName} in table ${tableName}`);
3227
- const existingRecord = await table.query().where(`id = '${id}'`).select(schema.fields.map((field) => field.name)).limit(1).toArray();
3228
- if (existingRecord.length === 0) {
3229
- throw new Error(`Record with id '${id}' not found in table ${tableName}`);
3251
+ let whereClause;
3252
+ if ("id" in params && params.id) {
3253
+ whereClause = `id = '${params.id}'`;
3254
+ } else if ("filter" in params && params.filter) {
3255
+ const translator = new LanceFilterTranslator();
3256
+ const processFilterKeys = (filter) => {
3257
+ const processedFilter = {};
3258
+ Object.entries(filter).forEach(([key, value]) => {
3259
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
3260
+ Object.entries(value).forEach(([nestedKey, nestedValue]) => {
3261
+ processedFilter[`metadata_${key}_${nestedKey}`] = nestedValue;
3262
+ });
3263
+ } else {
3264
+ processedFilter[`metadata_${key}`] = value;
3265
+ }
3266
+ });
3267
+ return processedFilter;
3268
+ };
3269
+ const prefixedFilter = processFilterKeys(params.filter);
3270
+ whereClause = translator.translate(prefixedFilter) || "";
3271
+ if (!whereClause) {
3272
+ throw new Error("Failed to translate filter to SQL");
3273
+ }
3274
+ } else {
3275
+ throw new Error("Either id or filter must be provided");
3230
3276
  }
3231
- const rowData = {
3232
- id
3233
- };
3234
- Object.entries(existingRecord[0]).forEach(([key, value]) => {
3235
- if (key !== "id" && key !== "_distance") {
3236
- if (key === indexName) {
3237
- if (!update.vector) {
3238
- if (Array.isArray(value)) {
3239
- rowData[key] = [...value];
3240
- } else if (typeof value === "object" && value !== null) {
3241
- rowData[key] = Array.from(value);
3277
+ const existingRecords = await table.query().where(whereClause).select(schema.fields.map((field) => field.name)).toArray();
3278
+ if (existingRecords.length === 0) {
3279
+ this.logger.info(`No records found matching criteria in table ${tableName}`);
3280
+ return;
3281
+ }
3282
+ const updatedRecords = existingRecords.map((record) => {
3283
+ const rowData = {};
3284
+ Object.entries(record).forEach(([key, value]) => {
3285
+ if (key !== "_distance") {
3286
+ if (key === indexName) {
3287
+ if (update.vector) {
3288
+ rowData[key] = update.vector;
3242
3289
  } else {
3243
- rowData[key] = value;
3290
+ if (Array.isArray(value)) {
3291
+ rowData[key] = [...value];
3292
+ } else if (typeof value === "object" && value !== null) {
3293
+ rowData[key] = Array.from(value);
3294
+ } else {
3295
+ rowData[key] = value;
3296
+ }
3244
3297
  }
3298
+ } else {
3299
+ rowData[key] = value;
3245
3300
  }
3246
- } else {
3247
- rowData[key] = value;
3248
3301
  }
3302
+ });
3303
+ if (update.metadata) {
3304
+ Object.entries(update.metadata).forEach(([key, value]) => {
3305
+ rowData[`metadata_${key}`] = value;
3306
+ });
3249
3307
  }
3308
+ return rowData;
3250
3309
  });
3251
- if (update.vector) {
3252
- rowData[indexName] = update.vector;
3253
- }
3254
- if (update.metadata) {
3255
- Object.entries(update.metadata).forEach(([key, value]) => {
3256
- rowData[`metadata_${key}`] = value;
3257
- });
3258
- }
3259
- await table.add([rowData], { mode: "overwrite" });
3310
+ await table.add(updatedRecords, { mode: "overwrite" });
3260
3311
  return;
3261
3312
  }
3262
3313
  } catch (err) {
@@ -3266,12 +3317,19 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
3266
3317
  }
3267
3318
  throw new Error(`No table found with column/index '${indexName}'`);
3268
3319
  } catch (error) {
3320
+ if (error instanceof MastraError) throw error;
3269
3321
  throw new MastraError(
3270
3322
  {
3271
3323
  id: "STORAGE_LANCE_VECTOR_UPDATE_VECTOR_FAILED",
3272
3324
  domain: ErrorDomain.STORAGE,
3273
3325
  category: ErrorCategory.THIRD_PARTY,
3274
- details: { indexName, id, hasVector: !!update.vector, hasMetadata: !!update.metadata }
3326
+ details: {
3327
+ indexName,
3328
+ ..."id" in params && params.id && { id: params.id },
3329
+ ..."filter" in params && params.filter && { filter: JSON.stringify(params.filter) },
3330
+ hasVector: !!update.vector,
3331
+ hasMetadata: !!update.metadata
3332
+ }
3275
3333
  },
3276
3334
  error
3277
3335
  );
@@ -3294,7 +3352,10 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
3294
3352
  id: "STORAGE_LANCE_VECTOR_DELETE_VECTOR_FAILED_INVALID_ARGS",
3295
3353
  domain: ErrorDomain.STORAGE,
3296
3354
  category: ErrorCategory.USER,
3297
- details: { indexName, id }
3355
+ details: {
3356
+ indexName,
3357
+ ...id && { id }
3358
+ }
3298
3359
  },
3299
3360
  err
3300
3361
  );
@@ -3324,7 +3385,10 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
3324
3385
  id: "STORAGE_LANCE_VECTOR_DELETE_VECTOR_FAILED",
3325
3386
  domain: ErrorDomain.STORAGE,
3326
3387
  category: ErrorCategory.THIRD_PARTY,
3327
- details: { indexName, id }
3388
+ details: {
3389
+ indexName,
3390
+ ...id && { id }
3391
+ }
3328
3392
  },
3329
3393
  error
3330
3394
  );
@@ -3355,6 +3419,109 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
3355
3419
  });
3356
3420
  return result;
3357
3421
  }
3422
+ async deleteVectors({ indexName, filter, ids }) {
3423
+ if (ids && filter) {
3424
+ throw new MastraError({
3425
+ id: "STORAGE_LANCE_VECTOR_DELETE_VECTORS_INVALID_ARGS",
3426
+ domain: ErrorDomain.STORAGE,
3427
+ category: ErrorCategory.USER,
3428
+ text: "ids and filter are mutually exclusive",
3429
+ details: { indexName }
3430
+ });
3431
+ }
3432
+ if (!ids && !filter) {
3433
+ throw new MastraError({
3434
+ id: "STORAGE_LANCE_VECTOR_DELETE_VECTORS_INVALID_ARGS",
3435
+ domain: ErrorDomain.STORAGE,
3436
+ category: ErrorCategory.USER,
3437
+ text: "Either filter or ids must be provided",
3438
+ details: { indexName }
3439
+ });
3440
+ }
3441
+ if (ids && ids.length === 0) {
3442
+ throw new MastraError({
3443
+ id: "STORAGE_LANCE_VECTOR_DELETE_VECTORS_INVALID_ARGS",
3444
+ domain: ErrorDomain.STORAGE,
3445
+ category: ErrorCategory.USER,
3446
+ text: "Cannot delete with empty ids array",
3447
+ details: { indexName }
3448
+ });
3449
+ }
3450
+ if (filter && Object.keys(filter).length === 0) {
3451
+ throw new MastraError({
3452
+ id: "STORAGE_LANCE_VECTOR_DELETE_VECTORS_INVALID_ARGS",
3453
+ domain: ErrorDomain.STORAGE,
3454
+ category: ErrorCategory.USER,
3455
+ text: "Cannot delete with empty filter",
3456
+ details: { indexName }
3457
+ });
3458
+ }
3459
+ try {
3460
+ if (!this.lanceClient) {
3461
+ throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
3462
+ }
3463
+ if (!indexName) {
3464
+ throw new Error("indexName is required");
3465
+ }
3466
+ const tables = await this.lanceClient.tableNames();
3467
+ for (const tableName of tables) {
3468
+ this.logger.debug("Checking table:" + tableName);
3469
+ const table = await this.lanceClient.openTable(tableName);
3470
+ try {
3471
+ const schema = await table.schema();
3472
+ const hasColumn = schema.fields.some((field) => field.name === indexName);
3473
+ if (hasColumn) {
3474
+ this.logger.debug(`Found column ${indexName} in table ${tableName}`);
3475
+ if (ids) {
3476
+ const idsConditions = ids.map((id) => `id = '${id}'`).join(" OR ");
3477
+ await table.delete(idsConditions);
3478
+ } else if (filter) {
3479
+ const translator = new LanceFilterTranslator();
3480
+ const processFilterKeys = (filter2) => {
3481
+ const processedFilter = {};
3482
+ Object.entries(filter2).forEach(([key, value]) => {
3483
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
3484
+ Object.entries(value).forEach(([nestedKey, nestedValue]) => {
3485
+ processedFilter[`metadata_${key}_${nestedKey}`] = nestedValue;
3486
+ });
3487
+ } else {
3488
+ processedFilter[`metadata_${key}`] = value;
3489
+ }
3490
+ });
3491
+ return processedFilter;
3492
+ };
3493
+ const prefixedFilter = processFilterKeys(filter);
3494
+ const whereClause = translator.translate(prefixedFilter);
3495
+ if (!whereClause) {
3496
+ throw new Error("Failed to translate filter to SQL");
3497
+ }
3498
+ await table.delete(whereClause);
3499
+ }
3500
+ return;
3501
+ }
3502
+ } catch (err) {
3503
+ this.logger.error(`Error checking schema for table ${tableName}:` + err);
3504
+ continue;
3505
+ }
3506
+ }
3507
+ throw new Error(`No table found with column/index '${indexName}'`);
3508
+ } catch (error) {
3509
+ if (error instanceof MastraError) throw error;
3510
+ throw new MastraError(
3511
+ {
3512
+ id: "STORAGE_LANCE_VECTOR_DELETE_VECTORS_FAILED",
3513
+ domain: ErrorDomain.STORAGE,
3514
+ category: ErrorCategory.THIRD_PARTY,
3515
+ details: {
3516
+ indexName,
3517
+ ...filter && { filter: JSON.stringify(filter) },
3518
+ ...ids && { idsCount: ids.length }
3519
+ }
3520
+ },
3521
+ error
3522
+ );
3523
+ }
3524
+ }
3358
3525
  };
3359
3526
 
3360
3527
  export { LanceStorage, LanceVectorStore };