@mastra/pg 0.10.1 → 0.10.2-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
@@ -941,6 +941,7 @@ var PostgresStore = class extends MastraStorage {
941
941
  const parsedSchemaName = this.schema ? parseSqlIdentifier(this.schema, "schema name") : void 0;
942
942
  return parsedSchemaName ? `${parsedSchemaName}."${parsedIndexName}"` : `"${parsedIndexName}"`;
943
943
  }
944
+ /** @deprecated use getEvals instead */
944
945
  async getEvalsByAgentName(agentName, type) {
945
946
  try {
946
947
  const baseQuery = `SELECT * FROM ${this.getTableName(TABLE_EVALS)} WHERE agent_name = $1`;
@@ -991,76 +992,72 @@ var PostgresStore = class extends MastraStorage {
991
992
  throw error;
992
993
  }
993
994
  }
994
- async getTraces({
995
- name,
996
- scope,
997
- page,
998
- perPage,
999
- attributes,
1000
- filters,
1001
- fromDate,
1002
- toDate
1003
- }) {
1004
- let idx = 1;
1005
- const limit = perPage;
1006
- const offset = page * perPage;
1007
- const args = [];
995
+ async getTraces(args) {
996
+ const {
997
+ name,
998
+ scope,
999
+ page,
1000
+ perPage: perPageInput,
1001
+ attributes,
1002
+ filters,
1003
+ fromDate,
1004
+ toDate,
1005
+ returnPaginationResults
1006
+ } = args;
1007
+ const perPage = perPageInput !== void 0 ? perPageInput : 100;
1008
+ const currentOffset = page * perPage;
1009
+ const queryParams = [];
1008
1010
  const conditions = [];
1011
+ let paramIndex = 1;
1009
1012
  if (name) {
1010
- conditions.push(`name LIKE CONCAT($${idx++}, '%')`);
1013
+ conditions.push(`name LIKE $${paramIndex++}`);
1014
+ queryParams.push(`${name}%`);
1011
1015
  }
1012
1016
  if (scope) {
1013
- conditions.push(`scope = $${idx++}`);
1017
+ conditions.push(`scope = $${paramIndex++}`);
1018
+ queryParams.push(scope);
1014
1019
  }
1015
1020
  if (attributes) {
1016
- Object.keys(attributes).forEach((key) => {
1021
+ Object.entries(attributes).forEach(([key, value]) => {
1017
1022
  const parsedKey = parseSqlIdentifier(key, "attribute key");
1018
- conditions.push(`attributes->>'${parsedKey}' = $${idx++}`);
1023
+ conditions.push(`attributes->>'${parsedKey}' = $${paramIndex++}`);
1024
+ queryParams.push(value);
1019
1025
  });
1020
1026
  }
1021
1027
  if (filters) {
1022
- Object.entries(filters).forEach(([key]) => {
1028
+ Object.entries(filters).forEach(([key, value]) => {
1023
1029
  const parsedKey = parseSqlIdentifier(key, "filter key");
1024
- conditions.push(`${parsedKey} = $${idx++}`);
1030
+ conditions.push(`"${parsedKey}" = $${paramIndex++}`);
1031
+ queryParams.push(value);
1025
1032
  });
1026
1033
  }
1027
1034
  if (fromDate) {
1028
- conditions.push(`createdAt >= $${idx++}`);
1035
+ conditions.push(`"createdAt" >= $${paramIndex++}`);
1036
+ queryParams.push(fromDate);
1029
1037
  }
1030
1038
  if (toDate) {
1031
- conditions.push(`createdAt <= $${idx++}`);
1039
+ conditions.push(`"createdAt" <= $${paramIndex++}`);
1040
+ queryParams.push(toDate);
1032
1041
  }
1033
1042
  const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
1034
- if (name) {
1035
- args.push(name);
1036
- }
1037
- if (scope) {
1038
- args.push(scope);
1039
- }
1040
- if (attributes) {
1041
- for (const [_key, value] of Object.entries(attributes)) {
1042
- args.push(value);
1043
- }
1044
- }
1045
- if (filters) {
1046
- for (const [, value] of Object.entries(filters)) {
1047
- args.push(value);
1048
- }
1049
- }
1050
- if (fromDate) {
1051
- args.push(fromDate.toISOString());
1052
- }
1053
- if (toDate) {
1054
- args.push(toDate.toISOString());
1055
- }
1056
- const result = await this.db.manyOrNone(
1057
- `SELECT * FROM ${this.getTableName(TABLE_TRACES)} ${whereClause} ORDER BY "createdAt" DESC LIMIT ${limit} OFFSET ${offset}`,
1058
- args
1059
- );
1060
- if (!result) {
1043
+ const countQuery = `SELECT COUNT(*) FROM ${this.getTableName(TABLE_TRACES)} ${whereClause}`;
1044
+ const countResult = await this.db.one(countQuery, queryParams);
1045
+ const total = parseInt(countResult.count, 10);
1046
+ if (total === 0 && returnPaginationResults) {
1047
+ return {
1048
+ traces: [],
1049
+ total: 0,
1050
+ page,
1051
+ perPage,
1052
+ hasMore: false
1053
+ };
1054
+ } else if (total === 0) {
1061
1055
  return [];
1062
1056
  }
1063
- return result.map((row) => ({
1057
+ const dataQuery = `SELECT * FROM ${this.getTableName(TABLE_TRACES)} ${whereClause} ORDER BY "createdAt" DESC LIMIT $${paramIndex++} OFFSET $${paramIndex++}`;
1058
+ const finalQueryParams = [...queryParams, perPage, currentOffset];
1059
+ const rows = await this.db.manyOrNone(dataQuery, finalQueryParams);
1060
+ const traces = rows.map((row) => ({
1064
1061
  id: row.id,
1065
1062
  parentSpanId: row.parentSpanId,
1066
1063
  traceId: row.traceId,
@@ -1076,6 +1073,17 @@ var PostgresStore = class extends MastraStorage {
1076
1073
  other: row.other,
1077
1074
  createdAt: row.createdAt
1078
1075
  }));
1076
+ if (returnPaginationResults) {
1077
+ return {
1078
+ traces,
1079
+ total,
1080
+ page,
1081
+ perPage,
1082
+ hasMore: currentOffset + traces.length < total
1083
+ };
1084
+ } else {
1085
+ return traces;
1086
+ }
1079
1087
  }
1080
1088
  async setupSchema() {
1081
1089
  if (!this.schema || this.schemaSetupComplete) {
@@ -1229,29 +1237,58 @@ var PostgresStore = class extends MastraStorage {
1229
1237
  throw error;
1230
1238
  }
1231
1239
  }
1232
- async getThreadsByResourceId({ resourceId }) {
1240
+ async getThreadsByResourceId(args) {
1241
+ const { resourceId, page, perPage: perPageInput } = args;
1233
1242
  try {
1234
- const threads = await this.db.manyOrNone(
1235
- `SELECT
1236
- id,
1237
- "resourceId",
1238
- title,
1239
- metadata,
1240
- "createdAt",
1241
- "updatedAt"
1242
- FROM ${this.getTableName(TABLE_THREADS)}
1243
- WHERE "resourceId" = $1`,
1244
- [resourceId]
1245
- );
1246
- return threads.map((thread) => ({
1247
- ...thread,
1248
- metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
1249
- createdAt: thread.createdAt,
1250
- updatedAt: thread.updatedAt
1251
- }));
1243
+ const baseQuery = `FROM ${this.getTableName(TABLE_THREADS)} WHERE "resourceId" = $1`;
1244
+ const queryParams = [resourceId];
1245
+ if (page !== void 0) {
1246
+ const perPage = perPageInput !== void 0 ? perPageInput : 100;
1247
+ const currentOffset = page * perPage;
1248
+ const countQuery = `SELECT COUNT(*) ${baseQuery}`;
1249
+ const countResult = await this.db.one(countQuery, queryParams);
1250
+ const total = parseInt(countResult.count, 10);
1251
+ if (total === 0) {
1252
+ return {
1253
+ threads: [],
1254
+ total: 0,
1255
+ page,
1256
+ perPage,
1257
+ hasMore: false
1258
+ };
1259
+ }
1260
+ const dataQuery = `SELECT id, "resourceId", title, metadata, "createdAt", "updatedAt" ${baseQuery} ORDER BY "createdAt" DESC LIMIT $2 OFFSET $3`;
1261
+ const rows = await this.db.manyOrNone(dataQuery, [...queryParams, perPage, currentOffset]);
1262
+ const threads = (rows || []).map((thread) => ({
1263
+ ...thread,
1264
+ metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
1265
+ createdAt: thread.createdAt,
1266
+ // Assuming already Date objects or ISO strings
1267
+ updatedAt: thread.updatedAt
1268
+ }));
1269
+ return {
1270
+ threads,
1271
+ total,
1272
+ page,
1273
+ perPage,
1274
+ hasMore: currentOffset + threads.length < total
1275
+ };
1276
+ } else {
1277
+ const dataQuery = `SELECT id, "resourceId", title, metadata, "createdAt", "updatedAt" ${baseQuery} ORDER BY "createdAt" DESC`;
1278
+ const rows = await this.db.manyOrNone(dataQuery, queryParams);
1279
+ return (rows || []).map((thread) => ({
1280
+ ...thread,
1281
+ metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
1282
+ createdAt: thread.createdAt,
1283
+ updatedAt: thread.updatedAt
1284
+ }));
1285
+ }
1252
1286
  } catch (error) {
1253
- console.error(`Error getting threads for resource ${resourceId}:`, error);
1254
- throw error;
1287
+ this.logger.error(`Error getting threads for resource ${resourceId}:`, error);
1288
+ if (page !== void 0) {
1289
+ return { threads: [], total: 0, page, perPage: perPageInput || 100, hasMore: false };
1290
+ }
1291
+ return [];
1255
1292
  }
1256
1293
  }
1257
1294
  async saveThread({ thread }) {
@@ -1331,84 +1368,143 @@ var PostgresStore = class extends MastraStorage {
1331
1368
  throw error;
1332
1369
  }
1333
1370
  }
1334
- async getMessages({ threadId, selectBy }) {
1371
+ async getMessages(args) {
1372
+ const { threadId, format, page, perPage: perPageInput, fromDate, toDate, selectBy } = args;
1373
+ const selectStatement = `SELECT id, content, role, type, "createdAt", thread_id AS "threadId"`;
1374
+ const orderByStatement = `ORDER BY "createdAt" DESC`;
1335
1375
  try {
1336
- const messages = [];
1337
- const limit = typeof selectBy?.last === `number` ? selectBy.last : 40;
1338
- const include = selectBy?.include || [];
1339
- if (include.length) {
1340
- const includeResult = await this.db.manyOrNone(
1341
- `
1342
- WITH ordered_messages AS (
1343
- SELECT
1344
- *,
1345
- ROW_NUMBER() OVER (ORDER BY "createdAt" DESC) as row_num
1346
- FROM ${this.getTableName(TABLE_MESSAGES)}
1347
- WHERE thread_id = $1
1348
- )
1349
- SELECT
1350
- m.id,
1351
- m.content,
1352
- m.role,
1353
- m.type,
1354
- m."createdAt",
1355
- m.thread_id AS "threadId"
1356
- FROM ordered_messages m
1357
- WHERE m.id = ANY($2)
1358
- OR EXISTS (
1359
- SELECT 1 FROM ordered_messages target
1360
- WHERE target.id = ANY($2)
1361
- AND (
1362
- -- Get previous messages based on the max withPreviousMessages
1363
- (m.row_num <= target.row_num + $3 AND m.row_num > target.row_num)
1364
- OR
1365
- -- Get next messages based on the max withNextMessages
1366
- (m.row_num >= target.row_num - $4 AND m.row_num < target.row_num)
1376
+ if (page !== void 0) {
1377
+ const perPage = perPageInput !== void 0 ? perPageInput : 40;
1378
+ const currentOffset = page * perPage;
1379
+ const conditions = [`thread_id = $1`];
1380
+ const queryParams = [threadId];
1381
+ let paramIndex = 2;
1382
+ if (fromDate) {
1383
+ conditions.push(`"createdAt" >= $${paramIndex++}`);
1384
+ queryParams.push(fromDate);
1385
+ }
1386
+ if (toDate) {
1387
+ conditions.push(`"createdAt" <= $${paramIndex++}`);
1388
+ queryParams.push(toDate);
1389
+ }
1390
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
1391
+ const countQuery = `SELECT COUNT(*) FROM ${this.getTableName(TABLE_MESSAGES)} ${whereClause}`;
1392
+ const countResult = await this.db.one(countQuery, queryParams);
1393
+ const total = parseInt(countResult.count, 10);
1394
+ if (total === 0) {
1395
+ return {
1396
+ messages: [],
1397
+ total: 0,
1398
+ page,
1399
+ perPage,
1400
+ hasMore: false
1401
+ };
1402
+ }
1403
+ const dataQuery = `${selectStatement} FROM ${this.getTableName(TABLE_MESSAGES)} ${whereClause} ${orderByStatement} LIMIT $${paramIndex++} OFFSET $${paramIndex++}`;
1404
+ const rows = await this.db.manyOrNone(dataQuery, [...queryParams, perPage, currentOffset]);
1405
+ const fetchedMessages = (rows || []).map((message) => {
1406
+ if (typeof message.content === "string") {
1407
+ try {
1408
+ message.content = JSON.parse(message.content);
1409
+ } catch {
1410
+ }
1411
+ }
1412
+ if (message.type === "v2") delete message.type;
1413
+ return message;
1414
+ });
1415
+ const messagesToReturn = format === "v2" ? fetchedMessages.map(
1416
+ (m) => ({
1417
+ ...m,
1418
+ content: m.content || { format: 2, parts: [{ type: "text", text: "" }] }
1419
+ })
1420
+ ) : fetchedMessages;
1421
+ return {
1422
+ messages: messagesToReturn,
1423
+ total,
1424
+ page,
1425
+ perPage,
1426
+ hasMore: currentOffset + fetchedMessages.length < total
1427
+ };
1428
+ } else {
1429
+ let rows = [];
1430
+ const include = selectBy?.include || [];
1431
+ if (include.length) {
1432
+ rows = await this.db.manyOrNone(
1433
+ `
1434
+ WITH ordered_messages AS (
1435
+ SELECT
1436
+ *,
1437
+ ROW_NUMBER() OVER (${orderByStatement}) as row_num
1438
+ FROM ${this.getTableName(TABLE_MESSAGES)}
1439
+ WHERE thread_id = $1
1367
1440
  )
1368
- )
1369
- ORDER BY m."createdAt" DESC
1370
- `,
1371
- [
1372
- threadId,
1373
- include.map((i) => i.id),
1374
- Math.max(...include.map((i) => i.withPreviousMessages || 0)),
1375
- Math.max(...include.map((i) => i.withNextMessages || 0))
1376
- ]
1377
- );
1378
- messages.push(...includeResult);
1379
- }
1380
- const result = await this.db.manyOrNone(
1381
- `
1382
- SELECT
1383
- id,
1384
- content,
1385
- role,
1386
- type,
1387
- "createdAt",
1388
- thread_id AS "threadId"
1389
- FROM ${this.getTableName(TABLE_MESSAGES)}
1390
- WHERE thread_id = $1
1391
- AND id != ALL($2)
1392
- ORDER BY "createdAt" DESC
1393
- LIMIT $3
1394
- `,
1395
- [threadId, messages.map((m) => m.id), limit]
1396
- );
1397
- messages.push(...result);
1398
- messages.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
1399
- messages.forEach((message) => {
1400
- if (typeof message.content === "string") {
1401
- try {
1402
- message.content = JSON.parse(message.content);
1403
- } catch {
1441
+ SELECT
1442
+ m.id,
1443
+ m.content,
1444
+ m.role,
1445
+ m.type,
1446
+ m."createdAt",
1447
+ m.thread_id AS "threadId"
1448
+ FROM ordered_messages m
1449
+ WHERE m.id = ANY($2)
1450
+ OR EXISTS (
1451
+ SELECT 1 FROM ordered_messages target
1452
+ WHERE target.id = ANY($2)
1453
+ AND (
1454
+ -- Get previous messages based on the max withPreviousMessages
1455
+ (m.row_num <= target.row_num + $3 AND m.row_num > target.row_num)
1456
+ OR
1457
+ -- Get next messages based on the max withNextMessages
1458
+ (m.row_num >= target.row_num - $4 AND m.row_num < target.row_num)
1459
+ )
1460
+ )
1461
+ ORDER BY m."createdAt" ASC
1462
+ `,
1463
+ // Keep ASC for final sorting after fetching context
1464
+ [
1465
+ threadId,
1466
+ include.map((i) => i.id),
1467
+ Math.max(0, ...include.map((i) => i.withPreviousMessages || 0)),
1468
+ // Ensure non-negative
1469
+ Math.max(0, ...include.map((i) => i.withNextMessages || 0))
1470
+ // Ensure non-negative
1471
+ ]
1472
+ );
1473
+ } else {
1474
+ const limit = typeof selectBy?.last === `number` ? selectBy.last : 40;
1475
+ if (limit === 0 && selectBy?.last !== false) ; else {
1476
+ let query = `${selectStatement} FROM ${this.getTableName(TABLE_MESSAGES)} WHERE thread_id = $1 ${orderByStatement}`;
1477
+ const queryParams = [threadId];
1478
+ if (limit !== void 0 && selectBy?.last !== false) {
1479
+ query += ` LIMIT $2`;
1480
+ queryParams.push(limit);
1481
+ }
1482
+ rows = await this.db.manyOrNone(query, queryParams);
1404
1483
  }
1405
1484
  }
1406
- if (message.type === `v2`) delete message.type;
1407
- });
1408
- return messages;
1485
+ const fetchedMessages = (rows || []).map((message) => {
1486
+ if (typeof message.content === "string") {
1487
+ try {
1488
+ message.content = JSON.parse(message.content);
1489
+ } catch {
1490
+ }
1491
+ }
1492
+ if (message.type === "v2") delete message.type;
1493
+ return message;
1494
+ });
1495
+ const sortedMessages = fetchedMessages.sort(
1496
+ (a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime()
1497
+ );
1498
+ return format === "v2" ? sortedMessages.map(
1499
+ (m) => ({ ...m, content: m.content || { format: 2, parts: [{ type: "text", text: "" }] } })
1500
+ ) : sortedMessages;
1501
+ }
1409
1502
  } catch (error) {
1410
- console.error("Error getting messages:", error);
1411
- throw error;
1503
+ this.logger.error("Error getting messages:", error);
1504
+ if (page !== void 0) {
1505
+ return { messages: [], total: 0, page, perPage: perPageInput || 40, hasMore: false };
1506
+ }
1507
+ return [];
1412
1508
  }
1413
1509
  }
1414
1510
  async saveMessages({
@@ -1621,6 +1717,73 @@ var PostgresStore = class extends MastraStorage {
1621
1717
  async close() {
1622
1718
  this.pgp.end();
1623
1719
  }
1720
+ async getEvals(options) {
1721
+ const { agentName, type, page, perPage, limit, offset, fromDate, toDate } = options || {};
1722
+ const conditions = [];
1723
+ const queryParams = [];
1724
+ let paramIndex = 1;
1725
+ if (agentName) {
1726
+ conditions.push(`agent_name = $${paramIndex++}`);
1727
+ queryParams.push(agentName);
1728
+ }
1729
+ if (type === "test") {
1730
+ conditions.push(`(test_info IS NOT NULL AND test_info->>'testPath' IS NOT NULL)`);
1731
+ } else if (type === "live") {
1732
+ conditions.push(`(test_info IS NULL OR test_info->>'testPath' IS NULL)`);
1733
+ }
1734
+ if (fromDate) {
1735
+ conditions.push(`created_at >= $${paramIndex++}`);
1736
+ queryParams.push(fromDate);
1737
+ }
1738
+ if (toDate) {
1739
+ conditions.push(`created_at <= $${paramIndex++}`);
1740
+ queryParams.push(toDate);
1741
+ }
1742
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
1743
+ const countQuery = `SELECT COUNT(*) FROM ${this.getTableName(TABLE_EVALS)} ${whereClause}`;
1744
+ const countResult = await this.db.one(countQuery, queryParams);
1745
+ const total = parseInt(countResult.count, 10);
1746
+ let currentLimit;
1747
+ let currentOffset;
1748
+ let currentPage = page;
1749
+ let currentPerPage = perPage;
1750
+ let hasMore = false;
1751
+ if (limit !== void 0 && offset !== void 0) {
1752
+ currentLimit = limit;
1753
+ currentOffset = offset;
1754
+ currentPage = void 0;
1755
+ currentPerPage = void 0;
1756
+ hasMore = currentOffset + currentLimit < total;
1757
+ } else if (page !== void 0 && perPage !== void 0) {
1758
+ currentLimit = perPage;
1759
+ currentOffset = page * perPage;
1760
+ hasMore = currentOffset + currentLimit < total;
1761
+ } else {
1762
+ currentLimit = perPage || 100;
1763
+ currentOffset = (page || 0) * currentLimit;
1764
+ if (page === void 0) currentPage = 0;
1765
+ if (currentPerPage === void 0) currentPerPage = currentLimit;
1766
+ hasMore = currentOffset + currentLimit < total;
1767
+ }
1768
+ if (total === 0) {
1769
+ return {
1770
+ evals: [],
1771
+ total: 0,
1772
+ page: currentPage,
1773
+ perPage: currentPerPage,
1774
+ hasMore: false
1775
+ };
1776
+ }
1777
+ const dataQuery = `SELECT * FROM ${this.getTableName(TABLE_EVALS)} ${whereClause} ORDER BY created_at DESC LIMIT $${paramIndex++} OFFSET $${paramIndex++}`;
1778
+ const rows = await this.db.manyOrNone(dataQuery, [...queryParams, currentLimit, currentOffset]);
1779
+ return {
1780
+ evals: rows?.map((row) => this.transformEvalRow(row)) ?? [],
1781
+ total,
1782
+ page: currentPage,
1783
+ perPage: currentPerPage,
1784
+ hasMore
1785
+ };
1786
+ }
1624
1787
  };
1625
1788
 
1626
1789
  // src/vector/prompt.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mastra/pg",
3
- "version": "0.10.1",
3
+ "version": "0.10.2-alpha.0",
4
4
  "description": "Postgres provider for Mastra - includes both vector and db storage capabilities",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -21,20 +21,21 @@
21
21
  "license": "MIT",
22
22
  "dependencies": {
23
23
  "async-mutex": "^0.5.0",
24
- "pg": "^8.13.3",
25
- "pg-promise": "^11.11.0",
24
+ "pg": "^8.16.0",
25
+ "pg-promise": "^11.13.0",
26
26
  "xxhash-wasm": "^1.1.0"
27
27
  },
28
28
  "devDependencies": {
29
- "@microsoft/api-extractor": "^7.52.5",
30
- "@types/node": "^20.17.27",
31
- "@types/pg": "^8.11.11",
32
- "eslint": "^9.23.0",
33
- "tsup": "^8.4.0",
29
+ "@microsoft/api-extractor": "^7.52.8",
30
+ "@types/node": "^20.17.57",
31
+ "@types/pg": "^8.15.4",
32
+ "eslint": "^9.28.0",
33
+ "tsup": "^8.5.0",
34
34
  "typescript": "^5.8.2",
35
35
  "vitest": "^3.1.2",
36
- "@internal/lint": "0.0.8",
37
- "@mastra/core": "0.10.2"
36
+ "@internal/lint": "0.0.10",
37
+ "@internal/storage-test-utils": "0.0.6",
38
+ "@mastra/core": "0.10.4-alpha.0"
38
39
  },
39
40
  "peerDependencies": {
40
41
  "@mastra/core": "^0.10.2-alpha.0"