@mastra/libsql 0.16.2 → 0.16.3-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/dist/index.js CHANGED
@@ -90,12 +90,20 @@ var createBasicOperator = (symbol) => {
90
90
  };
91
91
  };
92
92
  var createNumericOperator = (symbol) => {
93
- return (key) => {
93
+ return (key, value) => {
94
94
  const jsonPath = getJsonPath(key);
95
- return {
96
- sql: `CAST(json_extract(metadata, ${jsonPath}) AS NUMERIC) ${symbol} ?`,
97
- needsValue: true
98
- };
95
+ const isNumeric = typeof value === "number" || typeof value === "string" && !isNaN(Number(value)) && value.trim() !== "";
96
+ if (isNumeric) {
97
+ return {
98
+ sql: `CAST(json_extract(metadata, ${jsonPath}) AS NUMERIC) ${symbol} ?`,
99
+ needsValue: true
100
+ };
101
+ } else {
102
+ return {
103
+ sql: `CAST(json_extract(metadata, ${jsonPath}) AS TEXT) ${symbol} ?`,
104
+ needsValue: true
105
+ };
106
+ }
99
107
  };
100
108
  };
101
109
  var validateJsonArray = (key) => {
@@ -823,8 +831,27 @@ var LibSQLVector = class extends MastraVector {
823
831
  updateVector(args) {
824
832
  return this.executeWriteOperationWithRetry(() => this.doUpdateVector(args));
825
833
  }
826
- async doUpdateVector({ indexName, id, update }) {
834
+ async doUpdateVector(params) {
835
+ const { indexName, update } = params;
827
836
  const parsedIndexName = parseSqlIdentifier(indexName, "index name");
837
+ if ("id" in params && params.id && "filter" in params && params.filter) {
838
+ throw new MastraError({
839
+ id: "LIBSQL_VECTOR_UPDATE_MUTUALLY_EXCLUSIVE_PARAMS",
840
+ domain: ErrorDomain.STORAGE,
841
+ category: ErrorCategory.USER,
842
+ details: { indexName },
843
+ text: "id and filter are mutually exclusive - provide only one"
844
+ });
845
+ }
846
+ if (!update.vector && !update.metadata) {
847
+ throw new MastraError({
848
+ id: "LIBSQL_VECTOR_UPDATE_VECTOR_INVALID_ARGS",
849
+ domain: ErrorDomain.STORAGE,
850
+ category: ErrorCategory.USER,
851
+ details: { indexName },
852
+ text: "No updates provided"
853
+ });
854
+ }
828
855
  const updates = [];
829
856
  const args = [];
830
857
  if (update.vector) {
@@ -836,32 +863,81 @@ var LibSQLVector = class extends MastraVector {
836
863
  args.push(JSON.stringify(update.metadata));
837
864
  }
838
865
  if (updates.length === 0) {
866
+ return;
867
+ }
868
+ let whereClause;
869
+ let whereValues;
870
+ if ("id" in params && params.id) {
871
+ whereClause = "vector_id = ?";
872
+ whereValues = [params.id];
873
+ } else if ("filter" in params && params.filter) {
874
+ const filter = params.filter;
875
+ if (!filter || Object.keys(filter).length === 0) {
876
+ throw new MastraError({
877
+ id: "LIBSQL_VECTOR_UPDATE_EMPTY_FILTER",
878
+ domain: ErrorDomain.STORAGE,
879
+ category: ErrorCategory.USER,
880
+ details: { indexName },
881
+ text: "Cannot update with empty filter"
882
+ });
883
+ }
884
+ const translatedFilter = this.transformFilter(filter);
885
+ const { sql: filterSql, values: filterValues } = buildFilterQuery(translatedFilter);
886
+ if (!filterSql || filterSql.trim() === "") {
887
+ throw new MastraError({
888
+ id: "LIBSQL_VECTOR_UPDATE_INVALID_FILTER",
889
+ domain: ErrorDomain.STORAGE,
890
+ category: ErrorCategory.USER,
891
+ details: { indexName },
892
+ text: "Filter produced empty WHERE clause"
893
+ });
894
+ }
895
+ const normalizedCondition = filterSql.replace(/^\s*WHERE\s+/i, "").trim().toLowerCase();
896
+ const matchAllPatterns = ["true", "1 = 1", "1=1"];
897
+ if (matchAllPatterns.includes(normalizedCondition)) {
898
+ throw new MastraError({
899
+ id: "LIBSQL_VECTOR_UPDATE_MATCH_ALL_FILTER",
900
+ domain: ErrorDomain.STORAGE,
901
+ category: ErrorCategory.USER,
902
+ details: { indexName, filterSql: normalizedCondition },
903
+ text: "Filter matches all vectors. Provide a specific filter to update targeted vectors."
904
+ });
905
+ }
906
+ whereClause = filterSql.replace(/^WHERE\s+/i, "");
907
+ whereValues = filterValues;
908
+ } else {
839
909
  throw new MastraError({
840
- id: "LIBSQL_VECTOR_UPDATE_VECTOR_INVALID_ARGS",
910
+ id: "LIBSQL_VECTOR_UPDATE_MISSING_PARAMS",
841
911
  domain: ErrorDomain.STORAGE,
842
912
  category: ErrorCategory.USER,
843
- details: { indexName, id },
844
- text: "No updates provided"
913
+ details: { indexName },
914
+ text: "Either id or filter must be provided"
845
915
  });
846
916
  }
847
- args.push(id);
848
917
  const query = `
849
- UPDATE ${parsedIndexName}
850
- SET ${updates.join(", ")}
851
- WHERE vector_id = ?;
852
- `;
918
+ UPDATE ${parsedIndexName}
919
+ SET ${updates.join(", ")}
920
+ WHERE ${whereClause};
921
+ `;
853
922
  try {
854
923
  await this.turso.execute({
855
924
  sql: query,
856
- args
925
+ args: [...args, ...whereValues]
857
926
  });
858
927
  } catch (error) {
928
+ const errorDetails = { indexName };
929
+ if ("id" in params && params.id) {
930
+ errorDetails.id = params.id;
931
+ }
932
+ if ("filter" in params && params.filter) {
933
+ errorDetails.filter = JSON.stringify(params.filter);
934
+ }
859
935
  throw new MastraError(
860
936
  {
861
937
  id: "LIBSQL_VECTOR_UPDATE_VECTOR_FAILED",
862
938
  domain: ErrorDomain.STORAGE,
863
939
  category: ErrorCategory.THIRD_PARTY,
864
- details: { indexName, id }
940
+ details: errorDetails
865
941
  },
866
942
  error
867
943
  );
@@ -883,7 +959,10 @@ var LibSQLVector = class extends MastraVector {
883
959
  id: "LIBSQL_VECTOR_DELETE_VECTOR_FAILED",
884
960
  domain: ErrorDomain.STORAGE,
885
961
  category: ErrorCategory.THIRD_PARTY,
886
- details: { indexName: args.indexName, id: args.id }
962
+ details: {
963
+ indexName: args.indexName,
964
+ ...args.id && { id: args.id }
965
+ }
887
966
  },
888
967
  error
889
968
  );
@@ -896,6 +975,100 @@ var LibSQLVector = class extends MastraVector {
896
975
  args: [id]
897
976
  });
898
977
  }
978
+ deleteVectors(args) {
979
+ return this.executeWriteOperationWithRetry(() => this.doDeleteVectors(args));
980
+ }
981
+ async doDeleteVectors({ indexName, filter, ids }) {
982
+ const parsedIndexName = parseSqlIdentifier(indexName, "index name");
983
+ if (!filter && !ids) {
984
+ throw new MastraError({
985
+ id: "LIBSQL_VECTOR_DELETE_MISSING_PARAMS",
986
+ domain: ErrorDomain.STORAGE,
987
+ category: ErrorCategory.USER,
988
+ details: { indexName },
989
+ text: "Either filter or ids must be provided"
990
+ });
991
+ }
992
+ if (filter && ids) {
993
+ throw new MastraError({
994
+ id: "LIBSQL_VECTOR_DELETE_CONFLICTING_PARAMS",
995
+ domain: ErrorDomain.STORAGE,
996
+ category: ErrorCategory.USER,
997
+ details: { indexName },
998
+ text: "Cannot provide both filter and ids - they are mutually exclusive"
999
+ });
1000
+ }
1001
+ let query;
1002
+ let values;
1003
+ if (ids) {
1004
+ if (ids.length === 0) {
1005
+ throw new MastraError({
1006
+ id: "LIBSQL_VECTOR_DELETE_EMPTY_IDS",
1007
+ domain: ErrorDomain.STORAGE,
1008
+ category: ErrorCategory.USER,
1009
+ details: { indexName },
1010
+ text: "Cannot delete with empty ids array"
1011
+ });
1012
+ }
1013
+ const placeholders = ids.map(() => "?").join(", ");
1014
+ query = `DELETE FROM ${parsedIndexName} WHERE vector_id IN (${placeholders})`;
1015
+ values = ids;
1016
+ } else {
1017
+ if (!filter || Object.keys(filter).length === 0) {
1018
+ throw new MastraError({
1019
+ id: "LIBSQL_VECTOR_DELETE_EMPTY_FILTER",
1020
+ domain: ErrorDomain.STORAGE,
1021
+ category: ErrorCategory.USER,
1022
+ details: { indexName },
1023
+ text: "Cannot delete with empty filter. Use deleteIndex to delete all vectors."
1024
+ });
1025
+ }
1026
+ const translatedFilter = this.transformFilter(filter);
1027
+ const { sql: filterSql, values: filterValues } = buildFilterQuery(translatedFilter);
1028
+ if (!filterSql || filterSql.trim() === "") {
1029
+ throw new MastraError({
1030
+ id: "LIBSQL_VECTOR_DELETE_INVALID_FILTER",
1031
+ domain: ErrorDomain.STORAGE,
1032
+ category: ErrorCategory.USER,
1033
+ details: { indexName },
1034
+ text: "Filter produced empty WHERE clause"
1035
+ });
1036
+ }
1037
+ const normalizedCondition = filterSql.replace(/^\s*WHERE\s+/i, "").trim().toLowerCase();
1038
+ const matchAllPatterns = ["true", "1 = 1", "1=1"];
1039
+ if (matchAllPatterns.includes(normalizedCondition)) {
1040
+ throw new MastraError({
1041
+ id: "LIBSQL_VECTOR_DELETE_MATCH_ALL_FILTER",
1042
+ domain: ErrorDomain.STORAGE,
1043
+ category: ErrorCategory.USER,
1044
+ details: { indexName, filterSql: normalizedCondition },
1045
+ text: "Filter matches all vectors. Use deleteIndex to delete all vectors from an index."
1046
+ });
1047
+ }
1048
+ query = `DELETE FROM ${parsedIndexName} ${filterSql}`;
1049
+ values = filterValues;
1050
+ }
1051
+ try {
1052
+ await this.turso.execute({
1053
+ sql: query,
1054
+ args: values
1055
+ });
1056
+ } catch (error) {
1057
+ throw new MastraError(
1058
+ {
1059
+ id: "LIBSQL_VECTOR_DELETE_VECTORS_FAILED",
1060
+ domain: ErrorDomain.STORAGE,
1061
+ category: ErrorCategory.THIRD_PARTY,
1062
+ details: {
1063
+ indexName,
1064
+ ...filter && { filter: JSON.stringify(filter) },
1065
+ ...ids && { idsCount: ids.length }
1066
+ }
1067
+ },
1068
+ error
1069
+ );
1070
+ }
1071
+ }
899
1072
  truncateIndex(args) {
900
1073
  try {
901
1074
  return this.executeWriteOperationWithRetry(() => this._doTruncateIndex(args));
@@ -1254,7 +1427,11 @@ var MemoryLibSQL = class extends MemoryStorage {
1254
1427
  args: [...queryParams, ...excludeIds, perPage, currentOffset]
1255
1428
  });
1256
1429
  messages.push(...(dataResult.rows || []).map((row) => this.parseRow(row)));
1257
- const messagesToReturn = format === "v1" ? new MessageList().add(messages, "memory").get.all.v1() : new MessageList().add(messages, "memory").get.all.v2();
1430
+ const list = new MessageList().add(messages, "memory");
1431
+ let messagesToReturn = format === "v1" ? list.get.all.v1() : list.get.all.v2();
1432
+ messagesToReturn = messagesToReturn.sort(
1433
+ (a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime()
1434
+ );
1258
1435
  return {
1259
1436
  messages: messagesToReturn,
1260
1437
  total,