@mastra/lance 1.0.0-beta.0 → 1.0.0-beta.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/dist/index.js CHANGED
@@ -1553,11 +1553,13 @@ var StoreWorkflowsLance = class extends WorkflowsStorage {
1553
1553
  } else {
1554
1554
  createdAt = now;
1555
1555
  }
1556
+ const { status, value, ...rest } = snapshot;
1556
1557
  const record = {
1557
1558
  workflow_name: workflowName,
1558
1559
  run_id: runId,
1559
1560
  resourceId,
1560
- snapshot: JSON.stringify(snapshot),
1561
+ snapshot: JSON.stringify({ status, value, ...rest }),
1562
+ // this is to ensure status is always just before value, for when querying the db by status
1561
1563
  createdAt,
1562
1564
  updatedAt: now
1563
1565
  };
@@ -1627,6 +1629,10 @@ var StoreWorkflowsLance = class extends WorkflowsStorage {
1627
1629
  if (args?.workflowName) {
1628
1630
  conditions.push(`workflow_name = '${args.workflowName.replace(/'/g, "''")}'`);
1629
1631
  }
1632
+ if (args?.status) {
1633
+ const escapedStatus = args.status.replace(/\\/g, "\\\\").replace(/'/g, "''").replace(/%/g, "\\%").replace(/_/g, "\\_");
1634
+ conditions.push(`\`snapshot\` LIKE '%"status":"${escapedStatus}","value"%'`);
1635
+ }
1630
1636
  if (args?.resourceId) {
1631
1637
  conditions.push(`\`resourceId\` = '${args.resourceId}'`);
1632
1638
  }
@@ -2837,7 +2843,44 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
2837
2843
  );
2838
2844
  }
2839
2845
  }
2840
- async updateVector({ indexName, id, update }) {
2846
+ async updateVector(params) {
2847
+ const { indexName, update } = params;
2848
+ if ("id" in params && "filter" in params && params.id && params.filter) {
2849
+ throw new MastraError({
2850
+ id: "STORAGE_LANCE_VECTOR_UPDATE_VECTOR_INVALID_ARGS",
2851
+ domain: ErrorDomain.STORAGE,
2852
+ category: ErrorCategory.USER,
2853
+ text: "id and filter are mutually exclusive",
2854
+ details: { indexName }
2855
+ });
2856
+ }
2857
+ if (!("id" in params || "filter" in params) || !params.id && !params.filter) {
2858
+ throw new MastraError({
2859
+ id: "STORAGE_LANCE_VECTOR_UPDATE_VECTOR_INVALID_ARGS",
2860
+ domain: ErrorDomain.STORAGE,
2861
+ category: ErrorCategory.USER,
2862
+ text: "Either id or filter must be provided",
2863
+ details: { indexName }
2864
+ });
2865
+ }
2866
+ if ("filter" in params && params.filter && Object.keys(params.filter).length === 0) {
2867
+ throw new MastraError({
2868
+ id: "STORAGE_LANCE_VECTOR_UPDATE_VECTOR_INVALID_ARGS",
2869
+ domain: ErrorDomain.STORAGE,
2870
+ category: ErrorCategory.USER,
2871
+ text: "Cannot update with empty filter",
2872
+ details: { indexName }
2873
+ });
2874
+ }
2875
+ if (!update.vector && !update.metadata) {
2876
+ throw new MastraError({
2877
+ id: "STORAGE_LANCE_VECTOR_UPDATE_VECTOR_INVALID_ARGS",
2878
+ domain: ErrorDomain.STORAGE,
2879
+ category: ErrorCategory.USER,
2880
+ text: "No updates provided",
2881
+ details: { indexName }
2882
+ });
2883
+ }
2841
2884
  try {
2842
2885
  if (!this.lanceClient) {
2843
2886
  throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
@@ -2845,21 +2888,6 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
2845
2888
  if (!indexName) {
2846
2889
  throw new Error("indexName is required");
2847
2890
  }
2848
- if (!id) {
2849
- throw new Error("id is required");
2850
- }
2851
- } catch (err) {
2852
- throw new MastraError(
2853
- {
2854
- id: "STORAGE_LANCE_VECTOR_UPDATE_VECTOR_FAILED_INVALID_ARGS",
2855
- domain: ErrorDomain.STORAGE,
2856
- category: ErrorCategory.USER,
2857
- details: { indexName, id }
2858
- },
2859
- err
2860
- );
2861
- }
2862
- try {
2863
2891
  const tables = await this.lanceClient.tableNames();
2864
2892
  for (const tableName of tables) {
2865
2893
  this.logger.debug("Checking table:" + tableName);
@@ -2869,39 +2897,66 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
2869
2897
  const hasColumn = schema.fields.some((field) => field.name === indexName);
2870
2898
  if (hasColumn) {
2871
2899
  this.logger.debug(`Found column ${indexName} in table ${tableName}`);
2872
- const existingRecord = await table.query().where(`id = '${id}'`).select(schema.fields.map((field) => field.name)).limit(1).toArray();
2873
- if (existingRecord.length === 0) {
2874
- throw new Error(`Record with id '${id}' not found in table ${tableName}`);
2900
+ let whereClause;
2901
+ if ("id" in params && params.id) {
2902
+ whereClause = `id = '${params.id}'`;
2903
+ } else if ("filter" in params && params.filter) {
2904
+ const translator = new LanceFilterTranslator();
2905
+ const processFilterKeys = (filter) => {
2906
+ const processedFilter = {};
2907
+ Object.entries(filter).forEach(([key, value]) => {
2908
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
2909
+ Object.entries(value).forEach(([nestedKey, nestedValue]) => {
2910
+ processedFilter[`metadata_${key}_${nestedKey}`] = nestedValue;
2911
+ });
2912
+ } else {
2913
+ processedFilter[`metadata_${key}`] = value;
2914
+ }
2915
+ });
2916
+ return processedFilter;
2917
+ };
2918
+ const prefixedFilter = processFilterKeys(params.filter);
2919
+ whereClause = translator.translate(prefixedFilter) || "";
2920
+ if (!whereClause) {
2921
+ throw new Error("Failed to translate filter to SQL");
2922
+ }
2923
+ } else {
2924
+ throw new Error("Either id or filter must be provided");
2875
2925
  }
2876
- const rowData = {
2877
- id
2878
- };
2879
- Object.entries(existingRecord[0]).forEach(([key, value]) => {
2880
- if (key !== "id" && key !== "_distance") {
2881
- if (key === indexName) {
2882
- if (!update.vector) {
2883
- if (Array.isArray(value)) {
2884
- rowData[key] = [...value];
2885
- } else if (typeof value === "object" && value !== null) {
2886
- rowData[key] = Array.from(value);
2926
+ const existingRecords = await table.query().where(whereClause).select(schema.fields.map((field) => field.name)).toArray();
2927
+ if (existingRecords.length === 0) {
2928
+ this.logger.info(`No records found matching criteria in table ${tableName}`);
2929
+ return;
2930
+ }
2931
+ const updatedRecords = existingRecords.map((record) => {
2932
+ const rowData = {};
2933
+ Object.entries(record).forEach(([key, value]) => {
2934
+ if (key !== "_distance") {
2935
+ if (key === indexName) {
2936
+ if (update.vector) {
2937
+ rowData[key] = update.vector;
2887
2938
  } else {
2888
- rowData[key] = value;
2939
+ if (Array.isArray(value)) {
2940
+ rowData[key] = [...value];
2941
+ } else if (typeof value === "object" && value !== null) {
2942
+ rowData[key] = Array.from(value);
2943
+ } else {
2944
+ rowData[key] = value;
2945
+ }
2889
2946
  }
2947
+ } else {
2948
+ rowData[key] = value;
2890
2949
  }
2891
- } else {
2892
- rowData[key] = value;
2893
2950
  }
2951
+ });
2952
+ if (update.metadata) {
2953
+ Object.entries(update.metadata).forEach(([key, value]) => {
2954
+ rowData[`metadata_${key}`] = value;
2955
+ });
2894
2956
  }
2957
+ return rowData;
2895
2958
  });
2896
- if (update.vector) {
2897
- rowData[indexName] = update.vector;
2898
- }
2899
- if (update.metadata) {
2900
- Object.entries(update.metadata).forEach(([key, value]) => {
2901
- rowData[`metadata_${key}`] = value;
2902
- });
2903
- }
2904
- await table.add([rowData], { mode: "overwrite" });
2959
+ await table.add(updatedRecords, { mode: "overwrite" });
2905
2960
  return;
2906
2961
  }
2907
2962
  } catch (err) {
@@ -2911,12 +2966,19 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
2911
2966
  }
2912
2967
  throw new Error(`No table found with column/index '${indexName}'`);
2913
2968
  } catch (error) {
2969
+ if (error instanceof MastraError) throw error;
2914
2970
  throw new MastraError(
2915
2971
  {
2916
2972
  id: "STORAGE_LANCE_VECTOR_UPDATE_VECTOR_FAILED",
2917
2973
  domain: ErrorDomain.STORAGE,
2918
2974
  category: ErrorCategory.THIRD_PARTY,
2919
- details: { indexName, id, hasVector: !!update.vector, hasMetadata: !!update.metadata }
2975
+ details: {
2976
+ indexName,
2977
+ ..."id" in params && params.id && { id: params.id },
2978
+ ..."filter" in params && params.filter && { filter: JSON.stringify(params.filter) },
2979
+ hasVector: !!update.vector,
2980
+ hasMetadata: !!update.metadata
2981
+ }
2920
2982
  },
2921
2983
  error
2922
2984
  );
@@ -2939,7 +3001,10 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
2939
3001
  id: "STORAGE_LANCE_VECTOR_DELETE_VECTOR_FAILED_INVALID_ARGS",
2940
3002
  domain: ErrorDomain.STORAGE,
2941
3003
  category: ErrorCategory.USER,
2942
- details: { indexName, id }
3004
+ details: {
3005
+ indexName,
3006
+ ...id && { id }
3007
+ }
2943
3008
  },
2944
3009
  err
2945
3010
  );
@@ -2969,7 +3034,10 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
2969
3034
  id: "STORAGE_LANCE_VECTOR_DELETE_VECTOR_FAILED",
2970
3035
  domain: ErrorDomain.STORAGE,
2971
3036
  category: ErrorCategory.THIRD_PARTY,
2972
- details: { indexName, id }
3037
+ details: {
3038
+ indexName,
3039
+ ...id && { id }
3040
+ }
2973
3041
  },
2974
3042
  error
2975
3043
  );
@@ -3000,6 +3068,109 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
3000
3068
  });
3001
3069
  return result;
3002
3070
  }
3071
+ async deleteVectors({ indexName, filter, ids }) {
3072
+ if (ids && filter) {
3073
+ throw new MastraError({
3074
+ id: "STORAGE_LANCE_VECTOR_DELETE_VECTORS_INVALID_ARGS",
3075
+ domain: ErrorDomain.STORAGE,
3076
+ category: ErrorCategory.USER,
3077
+ text: "ids and filter are mutually exclusive",
3078
+ details: { indexName }
3079
+ });
3080
+ }
3081
+ if (!ids && !filter) {
3082
+ throw new MastraError({
3083
+ id: "STORAGE_LANCE_VECTOR_DELETE_VECTORS_INVALID_ARGS",
3084
+ domain: ErrorDomain.STORAGE,
3085
+ category: ErrorCategory.USER,
3086
+ text: "Either filter or ids must be provided",
3087
+ details: { indexName }
3088
+ });
3089
+ }
3090
+ if (ids && ids.length === 0) {
3091
+ throw new MastraError({
3092
+ id: "STORAGE_LANCE_VECTOR_DELETE_VECTORS_INVALID_ARGS",
3093
+ domain: ErrorDomain.STORAGE,
3094
+ category: ErrorCategory.USER,
3095
+ text: "Cannot delete with empty ids array",
3096
+ details: { indexName }
3097
+ });
3098
+ }
3099
+ if (filter && Object.keys(filter).length === 0) {
3100
+ throw new MastraError({
3101
+ id: "STORAGE_LANCE_VECTOR_DELETE_VECTORS_INVALID_ARGS",
3102
+ domain: ErrorDomain.STORAGE,
3103
+ category: ErrorCategory.USER,
3104
+ text: "Cannot delete with empty filter",
3105
+ details: { indexName }
3106
+ });
3107
+ }
3108
+ try {
3109
+ if (!this.lanceClient) {
3110
+ throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
3111
+ }
3112
+ if (!indexName) {
3113
+ throw new Error("indexName is required");
3114
+ }
3115
+ const tables = await this.lanceClient.tableNames();
3116
+ for (const tableName of tables) {
3117
+ this.logger.debug("Checking table:" + tableName);
3118
+ const table = await this.lanceClient.openTable(tableName);
3119
+ try {
3120
+ const schema = await table.schema();
3121
+ const hasColumn = schema.fields.some((field) => field.name === indexName);
3122
+ if (hasColumn) {
3123
+ this.logger.debug(`Found column ${indexName} in table ${tableName}`);
3124
+ if (ids) {
3125
+ const idsConditions = ids.map((id) => `id = '${id}'`).join(" OR ");
3126
+ await table.delete(idsConditions);
3127
+ } else if (filter) {
3128
+ const translator = new LanceFilterTranslator();
3129
+ const processFilterKeys = (filter2) => {
3130
+ const processedFilter = {};
3131
+ Object.entries(filter2).forEach(([key, value]) => {
3132
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
3133
+ Object.entries(value).forEach(([nestedKey, nestedValue]) => {
3134
+ processedFilter[`metadata_${key}_${nestedKey}`] = nestedValue;
3135
+ });
3136
+ } else {
3137
+ processedFilter[`metadata_${key}`] = value;
3138
+ }
3139
+ });
3140
+ return processedFilter;
3141
+ };
3142
+ const prefixedFilter = processFilterKeys(filter);
3143
+ const whereClause = translator.translate(prefixedFilter);
3144
+ if (!whereClause) {
3145
+ throw new Error("Failed to translate filter to SQL");
3146
+ }
3147
+ await table.delete(whereClause);
3148
+ }
3149
+ return;
3150
+ }
3151
+ } catch (err) {
3152
+ this.logger.error(`Error checking schema for table ${tableName}:` + err);
3153
+ continue;
3154
+ }
3155
+ }
3156
+ throw new Error(`No table found with column/index '${indexName}'`);
3157
+ } catch (error) {
3158
+ if (error instanceof MastraError) throw error;
3159
+ throw new MastraError(
3160
+ {
3161
+ id: "STORAGE_LANCE_VECTOR_DELETE_VECTORS_FAILED",
3162
+ domain: ErrorDomain.STORAGE,
3163
+ category: ErrorCategory.THIRD_PARTY,
3164
+ details: {
3165
+ indexName,
3166
+ ...filter && { filter: JSON.stringify(filter) },
3167
+ ...ids && { idsCount: ids.length }
3168
+ }
3169
+ },
3170
+ error
3171
+ );
3172
+ }
3173
+ }
3003
3174
  };
3004
3175
 
3005
3176
  export { LanceStorage, LanceVectorStore };