@mastra/pg 0.11.0 → 0.11.1-alpha.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.
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { MastraError, ErrorCategory, ErrorDomain } from '@mastra/core/error';
1
2
  import { parseSqlIdentifier, parseFieldKey } from '@mastra/core/utils';
2
3
  import { MastraVector } from '@mastra/core/vector';
3
4
  import { Mutex } from 'async-mutex';
@@ -368,43 +369,57 @@ var PgVector = class extends MastraVector {
368
369
  schemaName,
369
370
  pgPoolOptions
370
371
  }) {
371
- if (!connectionString || connectionString.trim() === "") {
372
- throw new Error(
373
- "PgVector: connectionString must be provided and cannot be empty. Passing an empty string may cause fallback to local Postgres defaults."
374
- );
375
- }
376
- super();
377
- this.schema = schemaName;
378
- const basePool = new pg.Pool({
379
- connectionString,
380
- max: 20,
381
- // Maximum number of clients in the pool
382
- idleTimeoutMillis: 3e4,
383
- // Close idle connections after 30 seconds
384
- connectionTimeoutMillis: 2e3,
385
- // Fail fast if can't connect
386
- ...pgPoolOptions
387
- });
388
- const telemetry = this.__getTelemetry();
389
- this.pool = telemetry?.traceClass(basePool, {
390
- spanNamePrefix: "pg-vector",
391
- attributes: {
392
- "vector.type": "postgres"
372
+ try {
373
+ if (!connectionString || connectionString.trim() === "") {
374
+ throw new Error(
375
+ "PgVector: connectionString must be provided and cannot be empty. Passing an empty string may cause fallback to local Postgres defaults."
376
+ );
393
377
  }
394
- }) ?? basePool;
395
- void (async () => {
396
- const existingIndexes = await this.listIndexes();
397
- void existingIndexes.map(async (indexName) => {
398
- const info = await this.getIndexInfo({ indexName });
399
- const key = await this.getIndexCacheKey({
400
- indexName,
401
- metric: info.metric,
402
- dimension: info.dimension,
403
- type: info.type
404
- });
405
- this.createdIndexes.set(indexName, key);
378
+ super();
379
+ this.schema = schemaName;
380
+ const basePool = new pg.Pool({
381
+ connectionString,
382
+ max: 20,
383
+ // Maximum number of clients in the pool
384
+ idleTimeoutMillis: 3e4,
385
+ // Close idle connections after 30 seconds
386
+ connectionTimeoutMillis: 2e3,
387
+ // Fail fast if can't connect
388
+ ...pgPoolOptions
406
389
  });
407
- })();
390
+ const telemetry = this.__getTelemetry();
391
+ this.pool = telemetry?.traceClass(basePool, {
392
+ spanNamePrefix: "pg-vector",
393
+ attributes: {
394
+ "vector.type": "postgres"
395
+ }
396
+ }) ?? basePool;
397
+ void (async () => {
398
+ const existingIndexes = await this.listIndexes();
399
+ void existingIndexes.map(async (indexName) => {
400
+ const info = await this.getIndexInfo({ indexName });
401
+ const key = await this.getIndexCacheKey({
402
+ indexName,
403
+ metric: info.metric,
404
+ dimension: info.dimension,
405
+ type: info.type
406
+ });
407
+ this.createdIndexes.set(indexName, key);
408
+ });
409
+ })();
410
+ } catch (error) {
411
+ throw new MastraError(
412
+ {
413
+ id: "MASTRA_STORAGE_PG_VECTOR_INITIALIZATION_FAILED",
414
+ domain: ErrorDomain.MASTRA_VECTOR,
415
+ category: ErrorCategory.THIRD_PARTY,
416
+ details: {
417
+ schemaName: schemaName ?? ""
418
+ }
419
+ },
420
+ error
421
+ );
422
+ }
408
423
  }
409
424
  getMutexByName(indexName) {
410
425
  if (!this.mutexesByName.has(indexName)) this.mutexesByName.set(indexName, new Mutex());
@@ -443,11 +458,27 @@ var PgVector = class extends MastraVector {
443
458
  ef,
444
459
  probes
445
460
  }) {
446
- if (!Number.isInteger(topK) || topK <= 0) {
447
- throw new Error("topK must be a positive integer");
448
- }
449
- if (!Array.isArray(queryVector) || !queryVector.every((x) => typeof x === "number" && Number.isFinite(x))) {
450
- throw new Error("queryVector must be an array of finite numbers");
461
+ try {
462
+ if (!Number.isInteger(topK) || topK <= 0) {
463
+ throw new Error("topK must be a positive integer");
464
+ }
465
+ if (!Array.isArray(queryVector) || !queryVector.every((x) => typeof x === "number" && Number.isFinite(x))) {
466
+ throw new Error("queryVector must be an array of finite numbers");
467
+ }
468
+ } catch (error) {
469
+ const mastraError = new MastraError(
470
+ {
471
+ id: "MASTRA_STORAGE_PG_VECTOR_QUERY_INVALID_INPUT",
472
+ domain: ErrorDomain.MASTRA_VECTOR,
473
+ category: ErrorCategory.USER,
474
+ details: {
475
+ indexName
476
+ }
477
+ },
478
+ error
479
+ );
480
+ this.logger?.trackException(mastraError);
481
+ throw mastraError;
451
482
  }
452
483
  const client = await this.pool.connect();
453
484
  try {
@@ -486,6 +517,20 @@ var PgVector = class extends MastraVector {
486
517
  metadata,
487
518
  ...includeVector && embedding && { vector: JSON.parse(embedding) }
488
519
  }));
520
+ } catch (error) {
521
+ const mastraError = new MastraError(
522
+ {
523
+ id: "MASTRA_STORAGE_PG_VECTOR_QUERY_FAILED",
524
+ domain: ErrorDomain.MASTRA_VECTOR,
525
+ category: ErrorCategory.THIRD_PARTY,
526
+ details: {
527
+ indexName
528
+ }
529
+ },
530
+ error
531
+ );
532
+ this.logger?.trackException(mastraError);
533
+ throw mastraError;
489
534
  } finally {
490
535
  client.release();
491
536
  }
@@ -516,12 +561,37 @@ var PgVector = class extends MastraVector {
516
561
  const match = error.message.match(/expected (\d+) dimensions, not (\d+)/);
517
562
  if (match) {
518
563
  const [, expected, actual] = match;
519
- throw new Error(
520
- `Vector dimension mismatch: Index "${indexName}" expects ${expected} dimensions but got ${actual} dimensions. Either use a matching embedding model or delete and recreate the index with the new dimension.`
564
+ const mastraError2 = new MastraError(
565
+ {
566
+ id: "MASTRA_STORAGE_PG_VECTOR_UPSERT_INVALID_INPUT",
567
+ domain: ErrorDomain.MASTRA_VECTOR,
568
+ category: ErrorCategory.USER,
569
+ text: `Vector dimension mismatch: Index "${indexName}" expects ${expected} dimensions but got ${actual} dimensions. Either use a matching embedding model or delete and recreate the index with the new dimension.`,
570
+ details: {
571
+ indexName,
572
+ expected: expected ?? "",
573
+ actual: actual ?? ""
574
+ }
575
+ },
576
+ error
521
577
  );
578
+ this.logger?.trackException(mastraError2);
579
+ throw mastraError2;
522
580
  }
523
581
  }
524
- throw error;
582
+ const mastraError = new MastraError(
583
+ {
584
+ id: "MASTRA_STORAGE_PG_VECTOR_UPSERT_FAILED",
585
+ domain: ErrorDomain.MASTRA_VECTOR,
586
+ category: ErrorCategory.THIRD_PARTY,
587
+ details: {
588
+ indexName
589
+ }
590
+ },
591
+ error
592
+ );
593
+ this.logger?.trackException(mastraError);
594
+ throw mastraError;
525
595
  } finally {
526
596
  client.release();
527
597
  }
@@ -589,11 +659,27 @@ var PgVector = class extends MastraVector {
589
659
  buildIndex = true
590
660
  }) {
591
661
  const { tableName } = this.getTableName(indexName);
592
- if (!indexName.match(/^[a-zA-Z_][a-zA-Z0-9_]*$/)) {
593
- throw new Error("Invalid index name format");
594
- }
595
- if (!Number.isInteger(dimension) || dimension <= 0) {
596
- throw new Error("Dimension must be a positive integer");
662
+ try {
663
+ if (!indexName.match(/^[a-zA-Z_][a-zA-Z0-9_]*$/)) {
664
+ throw new Error("Invalid index name format");
665
+ }
666
+ if (!Number.isInteger(dimension) || dimension <= 0) {
667
+ throw new Error("Dimension must be a positive integer");
668
+ }
669
+ } catch (error) {
670
+ const mastraError = new MastraError(
671
+ {
672
+ id: "MASTRA_STORAGE_PG_VECTOR_CREATE_INDEX_INVALID_INPUT",
673
+ domain: ErrorDomain.MASTRA_VECTOR,
674
+ category: ErrorCategory.USER,
675
+ details: {
676
+ indexName
677
+ }
678
+ },
679
+ error
680
+ );
681
+ this.logger?.trackException(mastraError);
682
+ throw mastraError;
597
683
  }
598
684
  const indexCacheKey = await this.getIndexCacheKey({ indexName, dimension, type: indexConfig.type, metric });
599
685
  if (this.cachedIndexExists(indexName, indexCacheKey)) {
@@ -626,12 +712,40 @@ var PgVector = class extends MastraVector {
626
712
  } finally {
627
713
  client.release();
628
714
  }
715
+ }).catch((error) => {
716
+ const mastraError = new MastraError(
717
+ {
718
+ id: "MASTRA_STORAGE_PG_VECTOR_CREATE_INDEX_FAILED",
719
+ domain: ErrorDomain.MASTRA_VECTOR,
720
+ category: ErrorCategory.THIRD_PARTY,
721
+ details: {
722
+ indexName
723
+ }
724
+ },
725
+ error
726
+ );
727
+ this.logger?.trackException(mastraError);
728
+ throw mastraError;
629
729
  });
630
730
  }
631
731
  async buildIndex({ indexName, metric = "cosine", indexConfig }) {
632
732
  const client = await this.pool.connect();
633
733
  try {
634
734
  await this.setupIndex({ indexName, metric, indexConfig }, client);
735
+ } catch (error) {
736
+ const mastraError = new MastraError(
737
+ {
738
+ id: "MASTRA_STORAGE_PG_VECTOR_BUILD_INDEX_FAILED",
739
+ domain: ErrorDomain.MASTRA_VECTOR,
740
+ category: ErrorCategory.THIRD_PARTY,
741
+ details: {
742
+ indexName
743
+ }
744
+ },
745
+ error
746
+ );
747
+ this.logger?.trackException(mastraError);
748
+ throw mastraError;
635
749
  } finally {
636
750
  client.release();
637
751
  }
@@ -728,6 +842,17 @@ var PgVector = class extends MastraVector {
728
842
  `;
729
843
  const vectorTables = await client.query(vectorTablesQuery, [this.schema || "public"]);
730
844
  return vectorTables.rows.map((row) => row.table_name);
845
+ } catch (e) {
846
+ const mastraError = new MastraError(
847
+ {
848
+ id: "MASTRA_STORAGE_PG_VECTOR_LIST_INDEXES_FAILED",
849
+ domain: ErrorDomain.MASTRA_VECTOR,
850
+ category: ErrorCategory.THIRD_PARTY
851
+ },
852
+ e
853
+ );
854
+ this.logger?.trackException(mastraError);
855
+ throw mastraError;
731
856
  } finally {
732
857
  client.release();
733
858
  }
@@ -807,7 +932,19 @@ var PgVector = class extends MastraVector {
807
932
  };
808
933
  } catch (e) {
809
934
  await client.query("ROLLBACK");
810
- throw new Error(`Failed to describe vector table: ${e.message}`);
935
+ const mastraError = new MastraError(
936
+ {
937
+ id: "MASTRA_STORAGE_PG_VECTOR_DESCRIBE_INDEX_FAILED",
938
+ domain: ErrorDomain.MASTRA_VECTOR,
939
+ category: ErrorCategory.THIRD_PARTY,
940
+ details: {
941
+ indexName
942
+ }
943
+ },
944
+ e
945
+ );
946
+ this.logger?.trackException(mastraError);
947
+ throw mastraError;
811
948
  } finally {
812
949
  client.release();
813
950
  }
@@ -820,7 +957,19 @@ var PgVector = class extends MastraVector {
820
957
  this.createdIndexes.delete(indexName);
821
958
  } catch (error) {
822
959
  await client.query("ROLLBACK");
823
- throw new Error(`Failed to delete vector table: ${error.message}`);
960
+ const mastraError = new MastraError(
961
+ {
962
+ id: "MASTRA_STORAGE_PG_VECTOR_DELETE_INDEX_FAILED",
963
+ domain: ErrorDomain.MASTRA_VECTOR,
964
+ category: ErrorCategory.THIRD_PARTY,
965
+ details: {
966
+ indexName
967
+ }
968
+ },
969
+ error
970
+ );
971
+ this.logger?.trackException(mastraError);
972
+ throw mastraError;
824
973
  } finally {
825
974
  client.release();
826
975
  }
@@ -832,7 +981,19 @@ var PgVector = class extends MastraVector {
832
981
  await client.query(`TRUNCATE ${tableName}`);
833
982
  } catch (e) {
834
983
  await client.query("ROLLBACK");
835
- throw new Error(`Failed to truncate vector table: ${e.message}`);
984
+ const mastraError = new MastraError(
985
+ {
986
+ id: "MASTRA_STORAGE_PG_VECTOR_TRUNCATE_INDEX_FAILED",
987
+ domain: ErrorDomain.MASTRA_VECTOR,
988
+ category: ErrorCategory.THIRD_PARTY,
989
+ details: {
990
+ indexName
991
+ }
992
+ },
993
+ e
994
+ );
995
+ this.logger?.trackException(mastraError);
996
+ throw mastraError;
836
997
  } finally {
837
998
  client.release();
838
999
  }
@@ -851,11 +1012,12 @@ var PgVector = class extends MastraVector {
851
1012
  * @throws Will throw an error if no updates are provided or if the update operation fails.
852
1013
  */
853
1014
  async updateVector({ indexName, id, update }) {
854
- if (!update.vector && !update.metadata) {
855
- throw new Error("No updates provided");
856
- }
857
- const client = await this.pool.connect();
1015
+ let client;
858
1016
  try {
1017
+ if (!update.vector && !update.metadata) {
1018
+ throw new Error("No updates provided");
1019
+ }
1020
+ client = await this.pool.connect();
859
1021
  let updateParts = [];
860
1022
  let values = [id];
861
1023
  let valueIndex = 2;
@@ -879,9 +1041,22 @@ var PgVector = class extends MastraVector {
879
1041
  `;
880
1042
  await client.query(query, values);
881
1043
  } catch (error) {
882
- throw new Error(`Failed to update vector by id: ${id} for index: ${indexName}: ${error.message}`);
1044
+ const mastraError = new MastraError(
1045
+ {
1046
+ id: "MASTRA_STORAGE_PG_VECTOR_UPDATE_VECTOR_FAILED",
1047
+ domain: ErrorDomain.MASTRA_VECTOR,
1048
+ category: ErrorCategory.THIRD_PARTY,
1049
+ details: {
1050
+ indexName,
1051
+ id
1052
+ }
1053
+ },
1054
+ error
1055
+ );
1056
+ this.logger?.trackException(mastraError);
1057
+ throw mastraError;
883
1058
  } finally {
884
- client.release();
1059
+ client?.release();
885
1060
  }
886
1061
  }
887
1062
  /**
@@ -892,8 +1067,9 @@ var PgVector = class extends MastraVector {
892
1067
  * @throws Will throw an error if the deletion operation fails.
893
1068
  */
894
1069
  async deleteVector({ indexName, id }) {
895
- const client = await this.pool.connect();
1070
+ let client;
896
1071
  try {
1072
+ client = await this.pool.connect();
897
1073
  const { tableName } = this.getTableName(indexName);
898
1074
  const query = `
899
1075
  DELETE FROM ${tableName}
@@ -901,9 +1077,22 @@ var PgVector = class extends MastraVector {
901
1077
  `;
902
1078
  await client.query(query, [id]);
903
1079
  } catch (error) {
904
- throw new Error(`Failed to delete vector by id: ${id} for index: ${indexName}: ${error.message}`);
1080
+ const mastraError = new MastraError(
1081
+ {
1082
+ id: "MASTRA_STORAGE_PG_VECTOR_DELETE_VECTOR_FAILED",
1083
+ domain: ErrorDomain.MASTRA_VECTOR,
1084
+ category: ErrorCategory.THIRD_PARTY,
1085
+ details: {
1086
+ indexName,
1087
+ id
1088
+ }
1089
+ },
1090
+ error
1091
+ );
1092
+ this.logger?.trackException(mastraError);
1093
+ throw mastraError;
905
1094
  } finally {
906
- client.release();
1095
+ client?.release();
907
1096
  }
908
1097
  }
909
1098
  };
@@ -914,35 +1103,46 @@ var PostgresStore = class extends MastraStorage {
914
1103
  setupSchemaPromise = null;
915
1104
  schemaSetupComplete = void 0;
916
1105
  constructor(config) {
917
- if ("connectionString" in config) {
918
- if (!config.connectionString || typeof config.connectionString !== "string" || config.connectionString.trim() === "") {
919
- throw new Error(
920
- "PostgresStore: connectionString must be provided and cannot be empty. Passing an empty string may cause fallback to local Postgres defaults."
921
- );
922
- }
923
- } else {
924
- const required = ["host", "database", "user", "password"];
925
- for (const key of required) {
926
- if (!(key in config) || typeof config[key] !== "string" || config[key].trim() === "") {
1106
+ try {
1107
+ if ("connectionString" in config) {
1108
+ if (!config.connectionString || typeof config.connectionString !== "string" || config.connectionString.trim() === "") {
927
1109
  throw new Error(
928
- `PostgresStore: ${key} must be provided and cannot be empty. Passing an empty string may cause fallback to local Postgres defaults.`
1110
+ "PostgresStore: connectionString must be provided and cannot be empty. Passing an empty string may cause fallback to local Postgres defaults."
929
1111
  );
930
1112
  }
1113
+ } else {
1114
+ const required = ["host", "database", "user", "password"];
1115
+ for (const key of required) {
1116
+ if (!(key in config) || typeof config[key] !== "string" || config[key].trim() === "") {
1117
+ throw new Error(
1118
+ `PostgresStore: ${key} must be provided and cannot be empty. Passing an empty string may cause fallback to local Postgres defaults.`
1119
+ );
1120
+ }
1121
+ }
931
1122
  }
1123
+ super({ name: "PostgresStore" });
1124
+ this.pgp = pgPromise();
1125
+ this.schema = config.schemaName;
1126
+ this.db = this.pgp(
1127
+ `connectionString` in config ? { connectionString: config.connectionString } : {
1128
+ host: config.host,
1129
+ port: config.port,
1130
+ database: config.database,
1131
+ user: config.user,
1132
+ password: config.password,
1133
+ ssl: config.ssl
1134
+ }
1135
+ );
1136
+ } catch (e) {
1137
+ throw new MastraError(
1138
+ {
1139
+ id: "MASTRA_STORAGE_PG_STORE_INITIALIZATION_FAILED",
1140
+ domain: ErrorDomain.STORAGE,
1141
+ category: ErrorCategory.USER
1142
+ },
1143
+ e
1144
+ );
932
1145
  }
933
- super({ name: "PostgresStore" });
934
- this.pgp = pgPromise();
935
- this.schema = config.schemaName;
936
- this.db = this.pgp(
937
- `connectionString` in config ? { connectionString: config.connectionString } : {
938
- host: config.host,
939
- port: config.port,
940
- database: config.database,
941
- user: config.user,
942
- password: config.password,
943
- ssl: config.ssl
944
- }
945
- );
946
1146
  }
947
1147
  get supports() {
948
1148
  return {
@@ -1004,9 +1204,19 @@ var PostgresStore = class extends MastraStorage {
1004
1204
  }
1005
1205
  await this.db.query("COMMIT");
1006
1206
  } catch (error) {
1007
- console.error(`Error inserting into ${tableName}:`, error);
1008
1207
  await this.db.query("ROLLBACK");
1009
- throw error;
1208
+ throw new MastraError(
1209
+ {
1210
+ id: "MASTRA_STORAGE_PG_STORE_BATCH_INSERT_FAILED",
1211
+ domain: ErrorDomain.STORAGE,
1212
+ category: ErrorCategory.THIRD_PARTY,
1213
+ details: {
1214
+ tableName,
1215
+ numberOfRecords: records.length
1216
+ }
1217
+ },
1218
+ error
1219
+ );
1010
1220
  }
1011
1221
  }
1012
1222
  /**
@@ -1063,8 +1273,24 @@ var PostgresStore = class extends MastraStorage {
1063
1273
  }
1064
1274
  const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
1065
1275
  const countQuery = `SELECT COUNT(*) FROM ${this.getTableName(TABLE_TRACES)} ${whereClause}`;
1066
- const countResult = await this.db.one(countQuery, queryParams);
1067
- const total = parseInt(countResult.count, 10);
1276
+ let total = 0;
1277
+ try {
1278
+ const countResult = await this.db.one(countQuery, queryParams);
1279
+ total = parseInt(countResult.count, 10);
1280
+ } catch (error) {
1281
+ throw new MastraError(
1282
+ {
1283
+ id: "MASTRA_STORAGE_PG_STORE_GET_TRACES_PAGINATED_FAILED_TO_RETRIEVE_TOTAL_COUNT",
1284
+ domain: ErrorDomain.STORAGE,
1285
+ category: ErrorCategory.THIRD_PARTY,
1286
+ details: {
1287
+ name: args.name ?? "",
1288
+ scope: args.scope ?? ""
1289
+ }
1290
+ },
1291
+ error
1292
+ );
1293
+ }
1068
1294
  if (total === 0) {
1069
1295
  return {
1070
1296
  traces: [],
@@ -1078,30 +1304,45 @@ var PostgresStore = class extends MastraStorage {
1078
1304
  TABLE_TRACES
1079
1305
  )} ${whereClause} ORDER BY "createdAt" DESC LIMIT $${paramIndex++} OFFSET $${paramIndex++}`;
1080
1306
  const finalQueryParams = [...queryParams, perPage, currentOffset];
1081
- const rows = await this.db.manyOrNone(dataQuery, finalQueryParams);
1082
- const traces = rows.map((row) => ({
1083
- id: row.id,
1084
- parentSpanId: row.parentSpanId,
1085
- traceId: row.traceId,
1086
- name: row.name,
1087
- scope: row.scope,
1088
- kind: row.kind,
1089
- status: row.status,
1090
- events: row.events,
1091
- links: row.links,
1092
- attributes: row.attributes,
1093
- startTime: row.startTime,
1094
- endTime: row.endTime,
1095
- other: row.other,
1096
- createdAt: row.createdAt
1097
- }));
1098
- return {
1099
- traces,
1100
- total,
1101
- page,
1102
- perPage,
1103
- hasMore: currentOffset + traces.length < total
1104
- };
1307
+ try {
1308
+ const rows = await this.db.manyOrNone(dataQuery, finalQueryParams);
1309
+ const traces = rows.map((row) => ({
1310
+ id: row.id,
1311
+ parentSpanId: row.parentSpanId,
1312
+ traceId: row.traceId,
1313
+ name: row.name,
1314
+ scope: row.scope,
1315
+ kind: row.kind,
1316
+ status: row.status,
1317
+ events: row.events,
1318
+ links: row.links,
1319
+ attributes: row.attributes,
1320
+ startTime: row.startTime,
1321
+ endTime: row.endTime,
1322
+ other: row.other,
1323
+ createdAt: row.createdAt
1324
+ }));
1325
+ return {
1326
+ traces,
1327
+ total,
1328
+ page,
1329
+ perPage,
1330
+ hasMore: currentOffset + traces.length < total
1331
+ };
1332
+ } catch (error) {
1333
+ throw new MastraError(
1334
+ {
1335
+ id: "MASTRA_STORAGE_PG_STORE_GET_TRACES_PAGINATED_FAILED_TO_RETRIEVE_TRACES",
1336
+ domain: ErrorDomain.STORAGE,
1337
+ category: ErrorCategory.THIRD_PARTY,
1338
+ details: {
1339
+ name: args.name ?? "",
1340
+ scope: args.scope ?? ""
1341
+ }
1342
+ },
1343
+ error
1344
+ );
1345
+ }
1105
1346
  }
1106
1347
  async setupSchema() {
1107
1348
  if (!this.schema || this.schemaSetupComplete) {
@@ -1176,8 +1417,17 @@ var PostgresStore = class extends MastraStorage {
1176
1417
  `;
1177
1418
  await this.db.none(sql);
1178
1419
  } catch (error) {
1179
- console.error(`Error creating table ${tableName}:`, error);
1180
- throw error;
1420
+ throw new MastraError(
1421
+ {
1422
+ id: "MASTRA_STORAGE_PG_STORE_CREATE_TABLE_FAILED",
1423
+ domain: ErrorDomain.STORAGE,
1424
+ category: ErrorCategory.THIRD_PARTY,
1425
+ details: {
1426
+ tableName
1427
+ }
1428
+ },
1429
+ error
1430
+ );
1181
1431
  }
1182
1432
  }
1183
1433
  getDefaultValue(type) {
@@ -1216,18 +1466,34 @@ var PostgresStore = class extends MastraStorage {
1216
1466
  }
1217
1467
  }
1218
1468
  } catch (error) {
1219
- this.logger?.error?.(
1220
- `Error altering table ${tableName}: ${error instanceof Error ? error.message : String(error)}`
1469
+ throw new MastraError(
1470
+ {
1471
+ id: "MASTRA_STORAGE_PG_STORE_ALTER_TABLE_FAILED",
1472
+ domain: ErrorDomain.STORAGE,
1473
+ category: ErrorCategory.THIRD_PARTY,
1474
+ details: {
1475
+ tableName
1476
+ }
1477
+ },
1478
+ error
1221
1479
  );
1222
- throw new Error(`Failed to alter table ${tableName}: ${error}`);
1223
1480
  }
1224
1481
  }
1225
1482
  async clearTable({ tableName }) {
1226
1483
  try {
1227
1484
  await this.db.none(`TRUNCATE TABLE ${this.getTableName(tableName)} CASCADE`);
1228
1485
  } catch (error) {
1229
- console.error(`Error clearing table ${tableName}:`, error);
1230
- throw error;
1486
+ throw new MastraError(
1487
+ {
1488
+ id: "MASTRA_STORAGE_PG_STORE_CLEAR_TABLE_FAILED",
1489
+ domain: ErrorDomain.STORAGE,
1490
+ category: ErrorCategory.THIRD_PARTY,
1491
+ details: {
1492
+ tableName
1493
+ }
1494
+ },
1495
+ error
1496
+ );
1231
1497
  }
1232
1498
  }
1233
1499
  async insert({ tableName, record }) {
@@ -1240,8 +1506,17 @@ var PostgresStore = class extends MastraStorage {
1240
1506
  values
1241
1507
  );
1242
1508
  } catch (error) {
1243
- console.error(`Error inserting into ${tableName}:`, error);
1244
- throw error;
1509
+ throw new MastraError(
1510
+ {
1511
+ id: "MASTRA_STORAGE_PG_STORE_INSERT_FAILED",
1512
+ domain: ErrorDomain.STORAGE,
1513
+ category: ErrorCategory.THIRD_PARTY,
1514
+ details: {
1515
+ tableName
1516
+ }
1517
+ },
1518
+ error
1519
+ );
1245
1520
  }
1246
1521
  }
1247
1522
  async load({ tableName, keys }) {
@@ -1265,8 +1540,17 @@ var PostgresStore = class extends MastraStorage {
1265
1540
  }
1266
1541
  return result;
1267
1542
  } catch (error) {
1268
- console.error(`Error loading from ${tableName}:`, error);
1269
- throw error;
1543
+ throw new MastraError(
1544
+ {
1545
+ id: "MASTRA_STORAGE_PG_STORE_LOAD_FAILED",
1546
+ domain: ErrorDomain.STORAGE,
1547
+ category: ErrorCategory.THIRD_PARTY,
1548
+ details: {
1549
+ tableName
1550
+ }
1551
+ },
1552
+ error
1553
+ );
1270
1554
  }
1271
1555
  }
1272
1556
  async getThreadById({ threadId }) {
@@ -1293,8 +1577,17 @@ var PostgresStore = class extends MastraStorage {
1293
1577
  updatedAt: thread.updatedAt
1294
1578
  };
1295
1579
  } catch (error) {
1296
- console.error(`Error getting thread ${threadId}:`, error);
1297
- throw error;
1580
+ throw new MastraError(
1581
+ {
1582
+ id: "MASTRA_STORAGE_PG_STORE_GET_THREAD_BY_ID_FAILED",
1583
+ domain: ErrorDomain.STORAGE,
1584
+ category: ErrorCategory.THIRD_PARTY,
1585
+ details: {
1586
+ threadId
1587
+ }
1588
+ },
1589
+ error
1590
+ );
1298
1591
  }
1299
1592
  }
1300
1593
  /**
@@ -1354,7 +1647,20 @@ var PostgresStore = class extends MastraStorage {
1354
1647
  hasMore: currentOffset + threads.length < total
1355
1648
  };
1356
1649
  } catch (error) {
1357
- this.logger.error(`Error getting threads for resource ${resourceId}:`, error);
1650
+ const mastraError = new MastraError(
1651
+ {
1652
+ id: "MASTRA_STORAGE_PG_STORE_GET_THREADS_BY_RESOURCE_ID_PAGINATED_FAILED",
1653
+ domain: ErrorDomain.STORAGE,
1654
+ category: ErrorCategory.THIRD_PARTY,
1655
+ details: {
1656
+ resourceId,
1657
+ page
1658
+ }
1659
+ },
1660
+ error
1661
+ );
1662
+ this.logger?.error?.(mastraError.toString());
1663
+ this.logger?.trackException(mastraError);
1358
1664
  return { threads: [], total: 0, page, perPage: perPageInput || 100, hasMore: false };
1359
1665
  }
1360
1666
  }
@@ -1386,8 +1692,17 @@ var PostgresStore = class extends MastraStorage {
1386
1692
  );
1387
1693
  return thread;
1388
1694
  } catch (error) {
1389
- console.error("Error saving thread:", error);
1390
- throw error;
1695
+ throw new MastraError(
1696
+ {
1697
+ id: "MASTRA_STORAGE_PG_STORE_SAVE_THREAD_FAILED",
1698
+ domain: ErrorDomain.STORAGE,
1699
+ category: ErrorCategory.THIRD_PARTY,
1700
+ details: {
1701
+ threadId: thread.id
1702
+ }
1703
+ },
1704
+ error
1705
+ );
1391
1706
  }
1392
1707
  }
1393
1708
  async updateThread({
@@ -1395,20 +1710,29 @@ var PostgresStore = class extends MastraStorage {
1395
1710
  title,
1396
1711
  metadata
1397
1712
  }) {
1713
+ const existingThread = await this.getThreadById({ threadId: id });
1714
+ if (!existingThread) {
1715
+ throw new MastraError({
1716
+ id: "MASTRA_STORAGE_PG_STORE_UPDATE_THREAD_FAILED",
1717
+ domain: ErrorDomain.STORAGE,
1718
+ category: ErrorCategory.USER,
1719
+ text: `Thread ${id} not found`,
1720
+ details: {
1721
+ threadId: id,
1722
+ title
1723
+ }
1724
+ });
1725
+ }
1726
+ const mergedMetadata = {
1727
+ ...existingThread.metadata,
1728
+ ...metadata
1729
+ };
1398
1730
  try {
1399
- const existingThread = await this.getThreadById({ threadId: id });
1400
- if (!existingThread) {
1401
- throw new Error(`Thread ${id} not found`);
1402
- }
1403
- const mergedMetadata = {
1404
- ...existingThread.metadata,
1405
- ...metadata
1406
- };
1407
1731
  const thread = await this.db.one(
1408
1732
  `UPDATE ${this.getTableName(TABLE_THREADS)}
1409
1733
  SET title = $1,
1410
- metadata = $2,
1411
- "updatedAt" = $3
1734
+ metadata = $2,
1735
+ "updatedAt" = $3
1412
1736
  WHERE id = $4
1413
1737
  RETURNING *`,
1414
1738
  [title, mergedMetadata, (/* @__PURE__ */ new Date()).toISOString(), id]
@@ -1420,8 +1744,18 @@ var PostgresStore = class extends MastraStorage {
1420
1744
  updatedAt: thread.updatedAt
1421
1745
  };
1422
1746
  } catch (error) {
1423
- console.error("Error updating thread:", error);
1424
- throw error;
1747
+ throw new MastraError(
1748
+ {
1749
+ id: "MASTRA_STORAGE_PG_STORE_UPDATE_THREAD_FAILED",
1750
+ domain: ErrorDomain.STORAGE,
1751
+ category: ErrorCategory.THIRD_PARTY,
1752
+ details: {
1753
+ threadId: id,
1754
+ title
1755
+ }
1756
+ },
1757
+ error
1758
+ );
1425
1759
  }
1426
1760
  }
1427
1761
  async deleteThread({ threadId }) {
@@ -1431,26 +1765,34 @@ var PostgresStore = class extends MastraStorage {
1431
1765
  await t.none(`DELETE FROM ${this.getTableName(TABLE_THREADS)} WHERE id = $1`, [threadId]);
1432
1766
  });
1433
1767
  } catch (error) {
1434
- console.error("Error deleting thread:", error);
1435
- throw error;
1768
+ throw new MastraError(
1769
+ {
1770
+ id: "MASTRA_STORAGE_PG_STORE_DELETE_THREAD_FAILED",
1771
+ domain: ErrorDomain.STORAGE,
1772
+ category: ErrorCategory.THIRD_PARTY,
1773
+ details: {
1774
+ threadId
1775
+ }
1776
+ },
1777
+ error
1778
+ );
1436
1779
  }
1437
1780
  }
1438
- async getMessages(args) {
1439
- const { threadId, format, selectBy } = args;
1440
- const selectStatement = `SELECT id, content, role, type, "createdAt", thread_id AS "threadId"`;
1441
- const orderByStatement = `ORDER BY "createdAt" DESC`;
1442
- try {
1443
- let rows = [];
1444
- const include = selectBy?.include || [];
1445
- if (include.length) {
1446
- const unionQueries = [];
1447
- const params = [];
1448
- let paramIdx = 1;
1449
- for (const inc of include) {
1450
- const { id, withPreviousMessages = 0, withNextMessages = 0 } = inc;
1451
- const searchId = inc.threadId || threadId;
1452
- unionQueries.push(
1453
- `
1781
+ async _getIncludedMessages({
1782
+ threadId,
1783
+ selectBy,
1784
+ orderByStatement
1785
+ }) {
1786
+ const include = selectBy?.include;
1787
+ if (!include) return null;
1788
+ const unionQueries = [];
1789
+ const params = [];
1790
+ let paramIdx = 1;
1791
+ for (const inc of include) {
1792
+ const { id, withPreviousMessages = 0, withNextMessages = 0 } = inc;
1793
+ const searchId = inc.threadId || threadId;
1794
+ unionQueries.push(
1795
+ `
1454
1796
  SELECT * FROM (
1455
1797
  WITH ordered_messages AS (
1456
1798
  SELECT
@@ -1482,34 +1824,45 @@ var PostgresStore = class extends MastraStorage {
1482
1824
  )
1483
1825
  ) AS query_${paramIdx}
1484
1826
  `
1485
- // Keep ASC for final sorting after fetching context
1486
- );
1487
- params.push(searchId, id, withPreviousMessages, withNextMessages);
1488
- paramIdx += 4;
1489
- }
1490
- const finalQuery = unionQueries.join(" UNION ALL ") + ' ORDER BY "createdAt" ASC';
1491
- const includedRows = await this.db.manyOrNone(finalQuery, params);
1492
- const seen = /* @__PURE__ */ new Set();
1493
- const dedupedRows = includedRows.filter((row) => {
1494
- if (seen.has(row.id)) return false;
1495
- seen.add(row.id);
1496
- return true;
1497
- });
1498
- rows = dedupedRows;
1499
- } else {
1500
- const limit = typeof selectBy?.last === `number` ? selectBy.last : 40;
1501
- if (limit === 0 && selectBy?.last !== false) ; else {
1502
- let query = `${selectStatement} FROM ${this.getTableName(
1503
- TABLE_MESSAGES
1504
- )} WHERE thread_id = $1 ${orderByStatement}`;
1505
- const queryParams = [threadId];
1506
- if (limit !== void 0 && selectBy?.last !== false) {
1507
- query += ` LIMIT $2`;
1508
- queryParams.push(limit);
1509
- }
1510
- rows = await this.db.manyOrNone(query, queryParams);
1827
+ // Keep ASC for final sorting after fetching context
1828
+ );
1829
+ params.push(searchId, id, withPreviousMessages, withNextMessages);
1830
+ paramIdx += 4;
1831
+ }
1832
+ const finalQuery = unionQueries.join(" UNION ALL ") + ' ORDER BY "createdAt" ASC';
1833
+ const includedRows = await this.db.manyOrNone(finalQuery, params);
1834
+ const seen = /* @__PURE__ */ new Set();
1835
+ const dedupedRows = includedRows.filter((row) => {
1836
+ if (seen.has(row.id)) return false;
1837
+ seen.add(row.id);
1838
+ return true;
1839
+ });
1840
+ return dedupedRows;
1841
+ }
1842
+ async getMessages(args) {
1843
+ const { threadId, format, selectBy } = args;
1844
+ const selectStatement = `SELECT id, content, role, type, "createdAt", thread_id AS "threadId"`;
1845
+ const orderByStatement = `ORDER BY "createdAt" DESC`;
1846
+ const limit = this.resolveMessageLimit({ last: selectBy?.last, defaultLimit: 40 });
1847
+ try {
1848
+ let rows = [];
1849
+ const include = selectBy?.include || [];
1850
+ if (include?.length) {
1851
+ const includeMessages = await this._getIncludedMessages({ threadId, selectBy, orderByStatement });
1852
+ if (includeMessages) {
1853
+ rows.push(...includeMessages);
1511
1854
  }
1512
1855
  }
1856
+ const excludeIds = rows.map((m) => m.id);
1857
+ const excludeIdsParam = excludeIds.map((_, idx) => `$${idx + 2}`).join(", ");
1858
+ let query = `${selectStatement} FROM ${this.getTableName(TABLE_MESSAGES)} WHERE thread_id = $1
1859
+ ${excludeIds.length ? `AND id NOT IN (${excludeIdsParam})` : ""}
1860
+ ${orderByStatement}
1861
+ LIMIT $${excludeIds.length + 2}
1862
+ `;
1863
+ const queryParams = [threadId, ...excludeIds, limit];
1864
+ const remainingRows = await this.db.manyOrNone(query, queryParams);
1865
+ rows.push(...remainingRows);
1513
1866
  const fetchedMessages = (rows || []).map((message) => {
1514
1867
  if (typeof message.content === "string") {
1515
1868
  try {
@@ -1527,7 +1880,19 @@ var PostgresStore = class extends MastraStorage {
1527
1880
  (m) => ({ ...m, content: m.content || { format: 2, parts: [{ type: "text", text: "" }] } })
1528
1881
  ) : sortedMessages;
1529
1882
  } catch (error) {
1530
- this.logger.error("Error getting messages:", error);
1883
+ const mastraError = new MastraError(
1884
+ {
1885
+ id: "MASTRA_STORAGE_PG_STORE_GET_MESSAGES_FAILED",
1886
+ domain: ErrorDomain.STORAGE,
1887
+ category: ErrorCategory.THIRD_PARTY,
1888
+ details: {
1889
+ threadId
1890
+ }
1891
+ },
1892
+ error
1893
+ );
1894
+ this.logger?.error?.(mastraError.toString());
1895
+ this.logger?.trackException(mastraError);
1531
1896
  return [];
1532
1897
  }
1533
1898
  }
@@ -1538,6 +1903,13 @@ var PostgresStore = class extends MastraStorage {
1538
1903
  const toDate = dateRange?.end;
1539
1904
  const selectStatement = `SELECT id, content, role, type, "createdAt", thread_id AS "threadId"`;
1540
1905
  const orderByStatement = `ORDER BY "createdAt" DESC`;
1906
+ const messages = [];
1907
+ if (selectBy?.include?.length) {
1908
+ const includeMessages = await this._getIncludedMessages({ threadId, selectBy, orderByStatement });
1909
+ if (includeMessages) {
1910
+ messages.push(...includeMessages);
1911
+ }
1912
+ }
1541
1913
  try {
1542
1914
  const perPage = perPageInput !== void 0 ? perPageInput : 40;
1543
1915
  const currentOffset = page * perPage;
@@ -1569,7 +1941,8 @@ var PostgresStore = class extends MastraStorage {
1569
1941
  TABLE_MESSAGES
1570
1942
  )} ${whereClause} ${orderByStatement} LIMIT $${paramIndex++} OFFSET $${paramIndex++}`;
1571
1943
  const rows = await this.db.manyOrNone(dataQuery, [...queryParams, perPage, currentOffset]);
1572
- const list = new MessageList().add(rows || [], "memory");
1944
+ messages.push(...rows || []);
1945
+ const list = new MessageList().add(messages, "memory");
1573
1946
  const messagesToReturn = format === `v2` ? list.get.all.v2() : list.get.all.v1();
1574
1947
  return {
1575
1948
  messages: messagesToReturn,
@@ -1579,7 +1952,20 @@ var PostgresStore = class extends MastraStorage {
1579
1952
  hasMore: currentOffset + rows.length < total
1580
1953
  };
1581
1954
  } catch (error) {
1582
- this.logger.error("Error getting messages:", error);
1955
+ const mastraError = new MastraError(
1956
+ {
1957
+ id: "MASTRA_STORAGE_PG_STORE_GET_MESSAGES_PAGINATED_FAILED",
1958
+ domain: ErrorDomain.STORAGE,
1959
+ category: ErrorCategory.THIRD_PARTY,
1960
+ details: {
1961
+ threadId,
1962
+ page
1963
+ }
1964
+ },
1965
+ error
1966
+ );
1967
+ this.logger?.error?.(mastraError.toString());
1968
+ this.logger?.trackException(mastraError);
1583
1969
  return { messages: [], total: 0, page, perPage: perPageInput || 40, hasMore: false };
1584
1970
  }
1585
1971
  }
@@ -1588,15 +1974,28 @@ var PostgresStore = class extends MastraStorage {
1588
1974
  format
1589
1975
  }) {
1590
1976
  if (messages.length === 0) return messages;
1977
+ const threadId = messages[0]?.threadId;
1978
+ if (!threadId) {
1979
+ throw new MastraError({
1980
+ id: "MASTRA_STORAGE_PG_STORE_SAVE_MESSAGES_FAILED",
1981
+ domain: ErrorDomain.STORAGE,
1982
+ category: ErrorCategory.THIRD_PARTY,
1983
+ text: `Thread ID is required`
1984
+ });
1985
+ }
1986
+ const thread = await this.getThreadById({ threadId });
1987
+ if (!thread) {
1988
+ throw new MastraError({
1989
+ id: "MASTRA_STORAGE_PG_STORE_SAVE_MESSAGES_FAILED",
1990
+ domain: ErrorDomain.STORAGE,
1991
+ category: ErrorCategory.THIRD_PARTY,
1992
+ text: `Thread ${threadId} not found`,
1993
+ details: {
1994
+ threadId
1995
+ }
1996
+ });
1997
+ }
1591
1998
  try {
1592
- const threadId = messages[0]?.threadId;
1593
- if (!threadId) {
1594
- throw new Error("Thread ID is required");
1595
- }
1596
- const thread = await this.getThreadById({ threadId });
1597
- if (!thread) {
1598
- throw new Error(`Thread ${threadId} not found`);
1599
- }
1600
1999
  await this.db.tx(async (t) => {
1601
2000
  const messageInserts = messages.map((message) => {
1602
2001
  if (!message.threadId) {
@@ -1635,8 +2034,17 @@ var PostgresStore = class extends MastraStorage {
1635
2034
  if (format === `v2`) return list.get.all.v2();
1636
2035
  return list.get.all.v1();
1637
2036
  } catch (error) {
1638
- console.error("Error saving messages:", error);
1639
- throw error;
2037
+ throw new MastraError(
2038
+ {
2039
+ id: "MASTRA_STORAGE_PG_STORE_SAVE_MESSAGES_FAILED",
2040
+ domain: ErrorDomain.STORAGE,
2041
+ category: ErrorCategory.THIRD_PARTY,
2042
+ details: {
2043
+ threadId
2044
+ }
2045
+ },
2046
+ error
2047
+ );
1640
2048
  }
1641
2049
  }
1642
2050
  async persistWorkflowSnapshot({
@@ -1660,8 +2068,18 @@ var PostgresStore = class extends MastraStorage {
1660
2068
  [workflowName, runId, JSON.stringify(snapshot), now, now]
1661
2069
  );
1662
2070
  } catch (error) {
1663
- console.error("Error persisting workflow snapshot:", error);
1664
- throw error;
2071
+ throw new MastraError(
2072
+ {
2073
+ id: "MASTRA_STORAGE_PG_STORE_PERSIST_WORKFLOW_SNAPSHOT_FAILED",
2074
+ domain: ErrorDomain.STORAGE,
2075
+ category: ErrorCategory.THIRD_PARTY,
2076
+ details: {
2077
+ workflowName,
2078
+ runId
2079
+ }
2080
+ },
2081
+ error
2082
+ );
1665
2083
  }
1666
2084
  }
1667
2085
  async loadWorkflowSnapshot({
@@ -1681,8 +2099,18 @@ var PostgresStore = class extends MastraStorage {
1681
2099
  }
1682
2100
  return result.snapshot;
1683
2101
  } catch (error) {
1684
- console.error("Error loading workflow snapshot:", error);
1685
- throw error;
2102
+ throw new MastraError(
2103
+ {
2104
+ id: "MASTRA_STORAGE_PG_STORE_LOAD_WORKFLOW_SNAPSHOT_FAILED",
2105
+ domain: ErrorDomain.STORAGE,
2106
+ category: ErrorCategory.THIRD_PARTY,
2107
+ details: {
2108
+ workflowName,
2109
+ runId
2110
+ }
2111
+ },
2112
+ error
2113
+ );
1686
2114
  }
1687
2115
  }
1688
2116
  async hasColumn(table, column) {
@@ -1770,8 +2198,17 @@ var PostgresStore = class extends MastraStorage {
1770
2198
  });
1771
2199
  return { runs, total: total || runs.length };
1772
2200
  } catch (error) {
1773
- console.error("Error getting workflow runs:", error);
1774
- throw error;
2201
+ throw new MastraError(
2202
+ {
2203
+ id: "MASTRA_STORAGE_PG_STORE_GET_WORKFLOW_RUNS_FAILED",
2204
+ domain: ErrorDomain.STORAGE,
2205
+ category: ErrorCategory.THIRD_PARTY,
2206
+ details: {
2207
+ workflowName: workflowName || "all"
2208
+ }
2209
+ },
2210
+ error
2211
+ );
1775
2212
  }
1776
2213
  }
1777
2214
  async getWorkflowRunById({
@@ -1804,8 +2241,18 @@ var PostgresStore = class extends MastraStorage {
1804
2241
  }
1805
2242
  return this.parseWorkflowRun(result);
1806
2243
  } catch (error) {
1807
- console.error("Error getting workflow run by ID:", error);
1808
- throw error;
2244
+ throw new MastraError(
2245
+ {
2246
+ id: "MASTRA_STORAGE_PG_STORE_GET_WORKFLOW_RUN_BY_ID_FAILED",
2247
+ domain: ErrorDomain.STORAGE,
2248
+ category: ErrorCategory.THIRD_PARTY,
2249
+ details: {
2250
+ runId,
2251
+ workflowName: workflowName || ""
2252
+ }
2253
+ },
2254
+ error
2255
+ );
1809
2256
  }
1810
2257
  }
1811
2258
  async close() {
@@ -1837,29 +2284,144 @@ var PostgresStore = class extends MastraStorage {
1837
2284
  }
1838
2285
  const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
1839
2286
  const countQuery = `SELECT COUNT(*) FROM ${this.getTableName(TABLE_EVALS)} ${whereClause}`;
1840
- const countResult = await this.db.one(countQuery, queryParams);
1841
- const total = parseInt(countResult.count, 10);
1842
- const currentOffset = page * perPage;
1843
- if (total === 0) {
2287
+ try {
2288
+ const countResult = await this.db.one(countQuery, queryParams);
2289
+ const total = parseInt(countResult.count, 10);
2290
+ const currentOffset = page * perPage;
2291
+ if (total === 0) {
2292
+ return {
2293
+ evals: [],
2294
+ total: 0,
2295
+ page,
2296
+ perPage,
2297
+ hasMore: false
2298
+ };
2299
+ }
2300
+ const dataQuery = `SELECT * FROM ${this.getTableName(
2301
+ TABLE_EVALS
2302
+ )} ${whereClause} ORDER BY created_at DESC LIMIT $${paramIndex++} OFFSET $${paramIndex++}`;
2303
+ const rows = await this.db.manyOrNone(dataQuery, [...queryParams, perPage, currentOffset]);
1844
2304
  return {
1845
- evals: [],
1846
- total: 0,
2305
+ evals: rows?.map((row) => this.transformEvalRow(row)) ?? [],
2306
+ total,
1847
2307
  page,
1848
2308
  perPage,
1849
- hasMore: false
2309
+ hasMore: currentOffset + (rows?.length ?? 0) < total
1850
2310
  };
2311
+ } catch (error) {
2312
+ const mastraError = new MastraError(
2313
+ {
2314
+ id: "MASTRA_STORAGE_PG_STORE_GET_EVALS_FAILED",
2315
+ domain: ErrorDomain.STORAGE,
2316
+ category: ErrorCategory.THIRD_PARTY,
2317
+ details: {
2318
+ agentName: agentName || "all",
2319
+ type: type || "all",
2320
+ page,
2321
+ perPage
2322
+ }
2323
+ },
2324
+ error
2325
+ );
2326
+ this.logger?.error?.(mastraError.toString());
2327
+ this.logger?.trackException(mastraError);
2328
+ throw mastraError;
1851
2329
  }
1852
- const dataQuery = `SELECT * FROM ${this.getTableName(
1853
- TABLE_EVALS
1854
- )} ${whereClause} ORDER BY created_at DESC LIMIT $${paramIndex++} OFFSET $${paramIndex++}`;
1855
- const rows = await this.db.manyOrNone(dataQuery, [...queryParams, perPage, currentOffset]);
1856
- return {
1857
- evals: rows?.map((row) => this.transformEvalRow(row)) ?? [],
1858
- total,
1859
- page,
1860
- perPage,
1861
- hasMore: currentOffset + (rows?.length ?? 0) < total
1862
- };
2330
+ }
2331
+ async updateMessages({
2332
+ messages
2333
+ }) {
2334
+ if (messages.length === 0) {
2335
+ return [];
2336
+ }
2337
+ const messageIds = messages.map((m) => m.id);
2338
+ const selectQuery = `SELECT id, content, role, type, "createdAt", thread_id AS "threadId", "resourceId" FROM ${this.getTableName(
2339
+ TABLE_MESSAGES
2340
+ )} WHERE id IN ($1:list)`;
2341
+ const existingMessagesDb = await this.db.manyOrNone(selectQuery, [messageIds]);
2342
+ if (existingMessagesDb.length === 0) {
2343
+ return [];
2344
+ }
2345
+ const existingMessages = existingMessagesDb.map((msg) => {
2346
+ if (typeof msg.content === "string") {
2347
+ try {
2348
+ msg.content = JSON.parse(msg.content);
2349
+ } catch {
2350
+ }
2351
+ }
2352
+ return msg;
2353
+ });
2354
+ const threadIdsToUpdate = /* @__PURE__ */ new Set();
2355
+ await this.db.tx(async (t) => {
2356
+ const queries = [];
2357
+ const columnMapping = {
2358
+ threadId: "thread_id"
2359
+ };
2360
+ for (const existingMessage of existingMessages) {
2361
+ const updatePayload = messages.find((m) => m.id === existingMessage.id);
2362
+ if (!updatePayload) continue;
2363
+ const { id, ...fieldsToUpdate } = updatePayload;
2364
+ if (Object.keys(fieldsToUpdate).length === 0) continue;
2365
+ threadIdsToUpdate.add(existingMessage.threadId);
2366
+ if (updatePayload.threadId && updatePayload.threadId !== existingMessage.threadId) {
2367
+ threadIdsToUpdate.add(updatePayload.threadId);
2368
+ }
2369
+ const setClauses = [];
2370
+ const values = [];
2371
+ let paramIndex = 1;
2372
+ const updatableFields = { ...fieldsToUpdate };
2373
+ if (updatableFields.content) {
2374
+ const newContent = {
2375
+ ...existingMessage.content,
2376
+ ...updatableFields.content,
2377
+ // Deep merge metadata if it exists on both
2378
+ ...existingMessage.content?.metadata && updatableFields.content.metadata ? {
2379
+ metadata: {
2380
+ ...existingMessage.content.metadata,
2381
+ ...updatableFields.content.metadata
2382
+ }
2383
+ } : {}
2384
+ };
2385
+ setClauses.push(`content = $${paramIndex++}`);
2386
+ values.push(newContent);
2387
+ delete updatableFields.content;
2388
+ }
2389
+ for (const key in updatableFields) {
2390
+ if (Object.prototype.hasOwnProperty.call(updatableFields, key)) {
2391
+ const dbColumn = columnMapping[key] || key;
2392
+ setClauses.push(`"${dbColumn}" = $${paramIndex++}`);
2393
+ values.push(updatableFields[key]);
2394
+ }
2395
+ }
2396
+ if (setClauses.length > 0) {
2397
+ values.push(id);
2398
+ const sql = `UPDATE ${this.getTableName(
2399
+ TABLE_MESSAGES
2400
+ )} SET ${setClauses.join(", ")} WHERE id = $${paramIndex}`;
2401
+ queries.push(t.none(sql, values));
2402
+ }
2403
+ }
2404
+ if (threadIdsToUpdate.size > 0) {
2405
+ queries.push(
2406
+ t.none(`UPDATE ${this.getTableName(TABLE_THREADS)} SET "updatedAt" = NOW() WHERE id IN ($1:list)`, [
2407
+ Array.from(threadIdsToUpdate)
2408
+ ])
2409
+ );
2410
+ }
2411
+ if (queries.length > 0) {
2412
+ await t.batch(queries);
2413
+ }
2414
+ });
2415
+ const updatedMessages = await this.db.manyOrNone(selectQuery, [messageIds]);
2416
+ return (updatedMessages || []).map((message) => {
2417
+ if (typeof message.content === "string") {
2418
+ try {
2419
+ message.content = JSON.parse(message.content);
2420
+ } catch {
2421
+ }
2422
+ }
2423
+ return message;
2424
+ });
1863
2425
  }
1864
2426
  };
1865
2427