@mastra/pg 0.10.2-alpha.0 → 0.10.2-alpha.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/.turbo/turbo-build.log +7 -7
- package/CHANGELOG.md +20 -0
- package/dist/_tsup-dts-rollup.d.cts +33 -40
- package/dist/_tsup-dts-rollup.d.ts +33 -40
- package/dist/index.cjs +286 -225
- package/dist/index.js +286 -225
- package/package.json +4 -4
- package/src/storage/index.test.ts +308 -191
- package/src/storage/index.ts +348 -345
package/dist/index.js
CHANGED
|
@@ -936,6 +936,11 @@ var PostgresStore = class extends MastraStorage {
|
|
|
936
936
|
}
|
|
937
937
|
);
|
|
938
938
|
}
|
|
939
|
+
get supports() {
|
|
940
|
+
return {
|
|
941
|
+
selectByIncludeResourceScope: true
|
|
942
|
+
};
|
|
943
|
+
}
|
|
939
944
|
getTableName(indexName) {
|
|
940
945
|
const parsedIndexName = parseSqlIdentifier(indexName, "table name");
|
|
941
946
|
const parsedSchemaName = this.schema ? parseSqlIdentifier(this.schema, "schema name") : void 0;
|
|
@@ -992,18 +997,23 @@ var PostgresStore = class extends MastraStorage {
|
|
|
992
997
|
throw error;
|
|
993
998
|
}
|
|
994
999
|
}
|
|
1000
|
+
/**
|
|
1001
|
+
* @deprecated use getTracesPaginated instead
|
|
1002
|
+
*/
|
|
995
1003
|
async getTraces(args) {
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
} = args;
|
|
1004
|
+
if (args.fromDate || args.toDate) {
|
|
1005
|
+
args.dateRange = {
|
|
1006
|
+
start: args.fromDate,
|
|
1007
|
+
end: args.toDate
|
|
1008
|
+
};
|
|
1009
|
+
}
|
|
1010
|
+
const result = await this.getTracesPaginated(args);
|
|
1011
|
+
return result.traces;
|
|
1012
|
+
}
|
|
1013
|
+
async getTracesPaginated(args) {
|
|
1014
|
+
const { name, scope, page = 0, perPage: perPageInput, attributes, filters, dateRange } = args;
|
|
1015
|
+
const fromDate = dateRange?.start;
|
|
1016
|
+
const toDate = dateRange?.end;
|
|
1007
1017
|
const perPage = perPageInput !== void 0 ? perPageInput : 100;
|
|
1008
1018
|
const currentOffset = page * perPage;
|
|
1009
1019
|
const queryParams = [];
|
|
@@ -1043,7 +1053,7 @@ var PostgresStore = class extends MastraStorage {
|
|
|
1043
1053
|
const countQuery = `SELECT COUNT(*) FROM ${this.getTableName(TABLE_TRACES)} ${whereClause}`;
|
|
1044
1054
|
const countResult = await this.db.one(countQuery, queryParams);
|
|
1045
1055
|
const total = parseInt(countResult.count, 10);
|
|
1046
|
-
if (total === 0
|
|
1056
|
+
if (total === 0) {
|
|
1047
1057
|
return {
|
|
1048
1058
|
traces: [],
|
|
1049
1059
|
total: 0,
|
|
@@ -1051,10 +1061,10 @@ var PostgresStore = class extends MastraStorage {
|
|
|
1051
1061
|
perPage,
|
|
1052
1062
|
hasMore: false
|
|
1053
1063
|
};
|
|
1054
|
-
} else if (total === 0) {
|
|
1055
|
-
return [];
|
|
1056
1064
|
}
|
|
1057
|
-
const dataQuery = `SELECT * FROM ${this.getTableName(
|
|
1065
|
+
const dataQuery = `SELECT * FROM ${this.getTableName(
|
|
1066
|
+
TABLE_TRACES
|
|
1067
|
+
)} ${whereClause} ORDER BY "createdAt" DESC LIMIT $${paramIndex++} OFFSET $${paramIndex++}`;
|
|
1058
1068
|
const finalQueryParams = [...queryParams, perPage, currentOffset];
|
|
1059
1069
|
const rows = await this.db.manyOrNone(dataQuery, finalQueryParams);
|
|
1060
1070
|
const traces = rows.map((row) => ({
|
|
@@ -1073,17 +1083,13 @@ var PostgresStore = class extends MastraStorage {
|
|
|
1073
1083
|
other: row.other,
|
|
1074
1084
|
createdAt: row.createdAt
|
|
1075
1085
|
}));
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
};
|
|
1084
|
-
} else {
|
|
1085
|
-
return traces;
|
|
1086
|
-
}
|
|
1086
|
+
return {
|
|
1087
|
+
traces,
|
|
1088
|
+
total,
|
|
1089
|
+
page,
|
|
1090
|
+
perPage,
|
|
1091
|
+
hasMore: currentOffset + traces.length < total
|
|
1092
|
+
};
|
|
1087
1093
|
}
|
|
1088
1094
|
async setupSchema() {
|
|
1089
1095
|
if (!this.schema || this.schemaSetupComplete) {
|
|
@@ -1162,6 +1168,48 @@ var PostgresStore = class extends MastraStorage {
|
|
|
1162
1168
|
throw error;
|
|
1163
1169
|
}
|
|
1164
1170
|
}
|
|
1171
|
+
getDefaultValue(type) {
|
|
1172
|
+
switch (type) {
|
|
1173
|
+
case "timestamp":
|
|
1174
|
+
return "DEFAULT NOW()";
|
|
1175
|
+
case "jsonb":
|
|
1176
|
+
return "DEFAULT '{}'::jsonb";
|
|
1177
|
+
default:
|
|
1178
|
+
return super.getDefaultValue(type);
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
/**
|
|
1182
|
+
* Alters table schema to add columns if they don't exist
|
|
1183
|
+
* @param tableName Name of the table
|
|
1184
|
+
* @param schema Schema of the table
|
|
1185
|
+
* @param ifNotExists Array of column names to add if they don't exist
|
|
1186
|
+
*/
|
|
1187
|
+
async alterTable({
|
|
1188
|
+
tableName,
|
|
1189
|
+
schema,
|
|
1190
|
+
ifNotExists
|
|
1191
|
+
}) {
|
|
1192
|
+
const fullTableName = this.getTableName(tableName);
|
|
1193
|
+
try {
|
|
1194
|
+
for (const columnName of ifNotExists) {
|
|
1195
|
+
if (schema[columnName]) {
|
|
1196
|
+
const columnDef = schema[columnName];
|
|
1197
|
+
const sqlType = this.getSqlType(columnDef.type);
|
|
1198
|
+
const nullable = columnDef.nullable === false ? "NOT NULL" : "";
|
|
1199
|
+
const defaultValue = columnDef.nullable === false ? this.getDefaultValue(columnDef.type) : "";
|
|
1200
|
+
const parsedColumnName = parseSqlIdentifier(columnName, "column name");
|
|
1201
|
+
const alterSql = `ALTER TABLE ${fullTableName} ADD COLUMN IF NOT EXISTS "${parsedColumnName}" ${sqlType} ${nullable} ${defaultValue}`.trim();
|
|
1202
|
+
await this.db.none(alterSql);
|
|
1203
|
+
this.logger?.debug?.(`Ensured column ${parsedColumnName} exists in table ${fullTableName}`);
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
} catch (error) {
|
|
1207
|
+
this.logger?.error?.(
|
|
1208
|
+
`Error altering table ${tableName}: ${error instanceof Error ? error.message : String(error)}`
|
|
1209
|
+
);
|
|
1210
|
+
throw new Error(`Failed to alter table ${tableName}: ${error}`);
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1165
1213
|
async clearTable({ tableName }) {
|
|
1166
1214
|
try {
|
|
1167
1215
|
await this.db.none(`TRUNCATE TABLE ${this.getTableName(tableName)} CASCADE`);
|
|
@@ -1237,58 +1285,65 @@ var PostgresStore = class extends MastraStorage {
|
|
|
1237
1285
|
throw error;
|
|
1238
1286
|
}
|
|
1239
1287
|
}
|
|
1288
|
+
/**
|
|
1289
|
+
* @deprecated use getThreadsByResourceIdPaginated instead
|
|
1290
|
+
*/
|
|
1240
1291
|
async getThreadsByResourceId(args) {
|
|
1241
|
-
const { resourceId
|
|
1292
|
+
const { resourceId } = args;
|
|
1242
1293
|
try {
|
|
1243
1294
|
const baseQuery = `FROM ${this.getTableName(TABLE_THREADS)} WHERE "resourceId" = $1`;
|
|
1244
1295
|
const queryParams = [resourceId];
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1296
|
+
const dataQuery = `SELECT id, "resourceId", title, metadata, "createdAt", "updatedAt" ${baseQuery} ORDER BY "createdAt" DESC`;
|
|
1297
|
+
const rows = await this.db.manyOrNone(dataQuery, queryParams);
|
|
1298
|
+
return (rows || []).map((thread) => ({
|
|
1299
|
+
...thread,
|
|
1300
|
+
metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
|
|
1301
|
+
createdAt: thread.createdAt,
|
|
1302
|
+
updatedAt: thread.updatedAt
|
|
1303
|
+
}));
|
|
1304
|
+
} catch (error) {
|
|
1305
|
+
this.logger.error(`Error getting threads for resource ${resourceId}:`, error);
|
|
1306
|
+
return [];
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
async getThreadsByResourceIdPaginated(args) {
|
|
1310
|
+
const { resourceId, page = 0, perPage: perPageInput } = args;
|
|
1311
|
+
try {
|
|
1312
|
+
const baseQuery = `FROM ${this.getTableName(TABLE_THREADS)} WHERE "resourceId" = $1`;
|
|
1313
|
+
const queryParams = [resourceId];
|
|
1314
|
+
const perPage = perPageInput !== void 0 ? perPageInput : 100;
|
|
1315
|
+
const currentOffset = page * perPage;
|
|
1316
|
+
const countQuery = `SELECT COUNT(*) ${baseQuery}`;
|
|
1317
|
+
const countResult = await this.db.one(countQuery, queryParams);
|
|
1318
|
+
const total = parseInt(countResult.count, 10);
|
|
1319
|
+
if (total === 0) {
|
|
1269
1320
|
return {
|
|
1270
|
-
threads,
|
|
1271
|
-
total,
|
|
1321
|
+
threads: [],
|
|
1322
|
+
total: 0,
|
|
1272
1323
|
page,
|
|
1273
1324
|
perPage,
|
|
1274
|
-
hasMore:
|
|
1325
|
+
hasMore: false
|
|
1275
1326
|
};
|
|
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
1327
|
}
|
|
1328
|
+
const dataQuery = `SELECT id, "resourceId", title, metadata, "createdAt", "updatedAt" ${baseQuery} ORDER BY "createdAt" DESC LIMIT $2 OFFSET $3`;
|
|
1329
|
+
const rows = await this.db.manyOrNone(dataQuery, [...queryParams, perPage, currentOffset]);
|
|
1330
|
+
const threads = (rows || []).map((thread) => ({
|
|
1331
|
+
...thread,
|
|
1332
|
+
metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
|
|
1333
|
+
createdAt: thread.createdAt,
|
|
1334
|
+
// Assuming already Date objects or ISO strings
|
|
1335
|
+
updatedAt: thread.updatedAt
|
|
1336
|
+
}));
|
|
1337
|
+
return {
|
|
1338
|
+
threads,
|
|
1339
|
+
total,
|
|
1340
|
+
page,
|
|
1341
|
+
perPage,
|
|
1342
|
+
hasMore: currentOffset + threads.length < total
|
|
1343
|
+
};
|
|
1286
1344
|
} catch (error) {
|
|
1287
1345
|
this.logger.error(`Error getting threads for resource ${resourceId}:`, error);
|
|
1288
|
-
|
|
1289
|
-
return { threads: [], total: 0, page, perPage: perPageInput || 100, hasMore: false };
|
|
1290
|
-
}
|
|
1291
|
-
return [];
|
|
1346
|
+
return { threads: [], total: 0, page, perPage: perPageInput || 100, hasMore: false };
|
|
1292
1347
|
}
|
|
1293
1348
|
}
|
|
1294
1349
|
async saveThread({ thread }) {
|
|
@@ -1369,144 +1424,156 @@ var PostgresStore = class extends MastraStorage {
|
|
|
1369
1424
|
}
|
|
1370
1425
|
}
|
|
1371
1426
|
async getMessages(args) {
|
|
1372
|
-
const { threadId, format,
|
|
1427
|
+
const { threadId, format, selectBy } = args;
|
|
1373
1428
|
const selectStatement = `SELECT id, content, role, type, "createdAt", thread_id AS "threadId"`;
|
|
1374
1429
|
const orderByStatement = `ORDER BY "createdAt" DESC`;
|
|
1375
1430
|
try {
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
const
|
|
1380
|
-
const
|
|
1381
|
-
let
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
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(
|
|
1431
|
+
let rows = [];
|
|
1432
|
+
const include = selectBy?.include || [];
|
|
1433
|
+
if (include.length) {
|
|
1434
|
+
const unionQueries = [];
|
|
1435
|
+
const params = [];
|
|
1436
|
+
let paramIdx = 1;
|
|
1437
|
+
for (const inc of include) {
|
|
1438
|
+
const { id, withPreviousMessages = 0, withNextMessages = 0 } = inc;
|
|
1439
|
+
const searchId = inc.threadId || threadId;
|
|
1440
|
+
unionQueries.push(
|
|
1433
1441
|
`
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
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)
|
|
1442
|
+
SELECT * FROM (
|
|
1443
|
+
WITH ordered_messages AS (
|
|
1444
|
+
SELECT
|
|
1445
|
+
*,
|
|
1446
|
+
ROW_NUMBER() OVER (${orderByStatement}) as row_num
|
|
1447
|
+
FROM ${this.getTableName(TABLE_MESSAGES)}
|
|
1448
|
+
WHERE thread_id = $${paramIdx}
|
|
1459
1449
|
)
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1450
|
+
SELECT
|
|
1451
|
+
m.id,
|
|
1452
|
+
m.content,
|
|
1453
|
+
m.role,
|
|
1454
|
+
m.type,
|
|
1455
|
+
m."createdAt",
|
|
1456
|
+
m.thread_id AS "threadId",
|
|
1457
|
+
m."resourceId"
|
|
1458
|
+
FROM ordered_messages m
|
|
1459
|
+
WHERE m.id = $${paramIdx + 1}
|
|
1460
|
+
OR EXISTS (
|
|
1461
|
+
SELECT 1 FROM ordered_messages target
|
|
1462
|
+
WHERE target.id = $${paramIdx + 1}
|
|
1463
|
+
AND (
|
|
1464
|
+
-- Get previous messages based on the max withPreviousMessages
|
|
1465
|
+
(m.row_num <= target.row_num + $${paramIdx + 2} AND m.row_num > target.row_num)
|
|
1466
|
+
OR
|
|
1467
|
+
-- Get next messages based on the max withNextMessages
|
|
1468
|
+
(m.row_num >= target.row_num - $${paramIdx + 3} AND m.row_num < target.row_num)
|
|
1469
|
+
)
|
|
1470
|
+
)
|
|
1471
|
+
)
|
|
1472
|
+
`
|
|
1463
1473
|
// 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
1474
|
);
|
|
1473
|
-
|
|
1474
|
-
|
|
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);
|
|
1483
|
-
}
|
|
1475
|
+
params.push(searchId, id, withPreviousMessages, withNextMessages);
|
|
1476
|
+
paramIdx += 4;
|
|
1484
1477
|
}
|
|
1485
|
-
const
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
const sortedMessages = fetchedMessages.sort(
|
|
1496
|
-
(a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime()
|
|
1478
|
+
const finalQuery = unionQueries.join(" UNION ALL ") + ' ORDER BY "createdAt" ASC';
|
|
1479
|
+
const includedRows = await this.db.manyOrNone(finalQuery, params);
|
|
1480
|
+
const dedupedRows = Object.values(
|
|
1481
|
+
includedRows.reduce(
|
|
1482
|
+
(acc, row) => {
|
|
1483
|
+
acc[row.id] = row;
|
|
1484
|
+
return acc;
|
|
1485
|
+
},
|
|
1486
|
+
{}
|
|
1487
|
+
)
|
|
1497
1488
|
);
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1489
|
+
rows = dedupedRows;
|
|
1490
|
+
} else {
|
|
1491
|
+
const limit = typeof selectBy?.last === `number` ? selectBy.last : 40;
|
|
1492
|
+
if (limit === 0 && selectBy?.last !== false) ; else {
|
|
1493
|
+
let query = `${selectStatement} FROM ${this.getTableName(
|
|
1494
|
+
TABLE_MESSAGES
|
|
1495
|
+
)} WHERE thread_id = $1 ${orderByStatement}`;
|
|
1496
|
+
const queryParams = [threadId];
|
|
1497
|
+
if (limit !== void 0 && selectBy?.last !== false) {
|
|
1498
|
+
query += ` LIMIT $2`;
|
|
1499
|
+
queryParams.push(limit);
|
|
1500
|
+
}
|
|
1501
|
+
rows = await this.db.manyOrNone(query, queryParams);
|
|
1502
|
+
}
|
|
1501
1503
|
}
|
|
1504
|
+
const fetchedMessages = (rows || []).map((message) => {
|
|
1505
|
+
if (typeof message.content === "string") {
|
|
1506
|
+
try {
|
|
1507
|
+
message.content = JSON.parse(message.content);
|
|
1508
|
+
} catch {
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
if (message.type === "v2") delete message.type;
|
|
1512
|
+
return message;
|
|
1513
|
+
});
|
|
1514
|
+
const sortedMessages = fetchedMessages.sort(
|
|
1515
|
+
(a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime()
|
|
1516
|
+
);
|
|
1517
|
+
return format === "v2" ? sortedMessages.map(
|
|
1518
|
+
(m) => ({ ...m, content: m.content || { format: 2, parts: [{ type: "text", text: "" }] } })
|
|
1519
|
+
) : sortedMessages;
|
|
1502
1520
|
} catch (error) {
|
|
1503
1521
|
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
1522
|
return [];
|
|
1508
1523
|
}
|
|
1509
1524
|
}
|
|
1525
|
+
async getMessagesPaginated(args) {
|
|
1526
|
+
const { threadId, format, selectBy } = args;
|
|
1527
|
+
const { page = 0, perPage: perPageInput, dateRange } = selectBy?.pagination || {};
|
|
1528
|
+
const fromDate = dateRange?.start;
|
|
1529
|
+
const toDate = dateRange?.end;
|
|
1530
|
+
const selectStatement = `SELECT id, content, role, type, "createdAt", thread_id AS "threadId"`;
|
|
1531
|
+
const orderByStatement = `ORDER BY "createdAt" DESC`;
|
|
1532
|
+
try {
|
|
1533
|
+
const perPage = perPageInput !== void 0 ? perPageInput : 40;
|
|
1534
|
+
const currentOffset = page * perPage;
|
|
1535
|
+
const conditions = [`thread_id = $1`];
|
|
1536
|
+
const queryParams = [threadId];
|
|
1537
|
+
let paramIndex = 2;
|
|
1538
|
+
if (fromDate) {
|
|
1539
|
+
conditions.push(`"createdAt" >= $${paramIndex++}`);
|
|
1540
|
+
queryParams.push(fromDate);
|
|
1541
|
+
}
|
|
1542
|
+
if (toDate) {
|
|
1543
|
+
conditions.push(`"createdAt" <= $${paramIndex++}`);
|
|
1544
|
+
queryParams.push(toDate);
|
|
1545
|
+
}
|
|
1546
|
+
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
1547
|
+
const countQuery = `SELECT COUNT(*) FROM ${this.getTableName(TABLE_MESSAGES)} ${whereClause}`;
|
|
1548
|
+
const countResult = await this.db.one(countQuery, queryParams);
|
|
1549
|
+
const total = parseInt(countResult.count, 10);
|
|
1550
|
+
if (total === 0) {
|
|
1551
|
+
return {
|
|
1552
|
+
messages: [],
|
|
1553
|
+
total: 0,
|
|
1554
|
+
page,
|
|
1555
|
+
perPage,
|
|
1556
|
+
hasMore: false
|
|
1557
|
+
};
|
|
1558
|
+
}
|
|
1559
|
+
const dataQuery = `${selectStatement} FROM ${this.getTableName(
|
|
1560
|
+
TABLE_MESSAGES
|
|
1561
|
+
)} ${whereClause} ${orderByStatement} LIMIT $${paramIndex++} OFFSET $${paramIndex++}`;
|
|
1562
|
+
const rows = await this.db.manyOrNone(dataQuery, [...queryParams, perPage, currentOffset]);
|
|
1563
|
+
const list = new MessageList().add(rows || [], "memory");
|
|
1564
|
+
const messagesToReturn = format === `v2` ? list.get.all.v2() : list.get.all.v1();
|
|
1565
|
+
return {
|
|
1566
|
+
messages: messagesToReturn,
|
|
1567
|
+
total,
|
|
1568
|
+
page,
|
|
1569
|
+
perPage,
|
|
1570
|
+
hasMore: currentOffset + rows.length < total
|
|
1571
|
+
};
|
|
1572
|
+
} catch (error) {
|
|
1573
|
+
this.logger.error("Error getting messages:", error);
|
|
1574
|
+
return { messages: [], total: 0, page, perPage: perPageInput || 40, hasMore: false };
|
|
1575
|
+
}
|
|
1576
|
+
}
|
|
1510
1577
|
async saveMessages({
|
|
1511
1578
|
messages,
|
|
1512
1579
|
format
|
|
@@ -1523,16 +1590,27 @@ var PostgresStore = class extends MastraStorage {
|
|
|
1523
1590
|
}
|
|
1524
1591
|
await this.db.tx(async (t) => {
|
|
1525
1592
|
for (const message of messages) {
|
|
1593
|
+
if (!message.threadId) {
|
|
1594
|
+
throw new Error(
|
|
1595
|
+
`Expected to find a threadId for message, but couldn't find one. An unexpected error has occurred.`
|
|
1596
|
+
);
|
|
1597
|
+
}
|
|
1598
|
+
if (!message.resourceId) {
|
|
1599
|
+
throw new Error(
|
|
1600
|
+
`Expected to find a resourceId for message, but couldn't find one. An unexpected error has occurred.`
|
|
1601
|
+
);
|
|
1602
|
+
}
|
|
1526
1603
|
await t.none(
|
|
1527
|
-
`INSERT INTO ${this.getTableName(TABLE_MESSAGES)} (id, thread_id, content, "createdAt", role, type)
|
|
1528
|
-
VALUES ($1, $2, $3, $4, $5, $6)`,
|
|
1604
|
+
`INSERT INTO ${this.getTableName(TABLE_MESSAGES)} (id, thread_id, content, "createdAt", role, type, "resourceId")
|
|
1605
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7)`,
|
|
1529
1606
|
[
|
|
1530
1607
|
message.id,
|
|
1531
|
-
threadId,
|
|
1608
|
+
message.threadId,
|
|
1532
1609
|
typeof message.content === "string" ? message.content : JSON.stringify(message.content),
|
|
1533
1610
|
message.createdAt || (/* @__PURE__ */ new Date()).toISOString(),
|
|
1534
1611
|
message.role,
|
|
1535
|
-
message.type || "v2"
|
|
1612
|
+
message.type || "v2",
|
|
1613
|
+
message.resourceId
|
|
1536
1614
|
]
|
|
1537
1615
|
);
|
|
1538
1616
|
}
|
|
@@ -1717,8 +1795,10 @@ var PostgresStore = class extends MastraStorage {
|
|
|
1717
1795
|
async close() {
|
|
1718
1796
|
this.pgp.end();
|
|
1719
1797
|
}
|
|
1720
|
-
async getEvals(options) {
|
|
1721
|
-
const { agentName, type, page, perPage
|
|
1798
|
+
async getEvals(options = {}) {
|
|
1799
|
+
const { agentName, type, page = 0, perPage = 100, dateRange } = options;
|
|
1800
|
+
const fromDate = dateRange?.start;
|
|
1801
|
+
const toDate = dateRange?.end;
|
|
1722
1802
|
const conditions = [];
|
|
1723
1803
|
const queryParams = [];
|
|
1724
1804
|
let paramIndex = 1;
|
|
@@ -1743,45 +1823,26 @@ var PostgresStore = class extends MastraStorage {
|
|
|
1743
1823
|
const countQuery = `SELECT COUNT(*) FROM ${this.getTableName(TABLE_EVALS)} ${whereClause}`;
|
|
1744
1824
|
const countResult = await this.db.one(countQuery, queryParams);
|
|
1745
1825
|
const total = parseInt(countResult.count, 10);
|
|
1746
|
-
|
|
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
|
-
}
|
|
1826
|
+
const currentOffset = page * perPage;
|
|
1768
1827
|
if (total === 0) {
|
|
1769
1828
|
return {
|
|
1770
1829
|
evals: [],
|
|
1771
1830
|
total: 0,
|
|
1772
|
-
page
|
|
1773
|
-
perPage
|
|
1831
|
+
page,
|
|
1832
|
+
perPage,
|
|
1774
1833
|
hasMore: false
|
|
1775
1834
|
};
|
|
1776
1835
|
}
|
|
1777
|
-
const dataQuery = `SELECT * FROM ${this.getTableName(
|
|
1778
|
-
|
|
1836
|
+
const dataQuery = `SELECT * FROM ${this.getTableName(
|
|
1837
|
+
TABLE_EVALS
|
|
1838
|
+
)} ${whereClause} ORDER BY created_at DESC LIMIT $${paramIndex++} OFFSET $${paramIndex++}`;
|
|
1839
|
+
const rows = await this.db.manyOrNone(dataQuery, [...queryParams, perPage, currentOffset]);
|
|
1779
1840
|
return {
|
|
1780
1841
|
evals: rows?.map((row) => this.transformEvalRow(row)) ?? [],
|
|
1781
1842
|
total,
|
|
1782
|
-
page
|
|
1783
|
-
perPage
|
|
1784
|
-
hasMore
|
|
1843
|
+
page,
|
|
1844
|
+
perPage,
|
|
1845
|
+
hasMore: currentOffset + (rows?.length ?? 0) < total
|
|
1785
1846
|
};
|
|
1786
1847
|
}
|
|
1787
1848
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mastra/pg",
|
|
3
|
-
"version": "0.10.2-alpha.
|
|
3
|
+
"version": "0.10.2-alpha.2",
|
|
4
4
|
"description": "Postgres provider for Mastra - includes both vector and db storage capabilities",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -32,10 +32,10 @@
|
|
|
32
32
|
"eslint": "^9.28.0",
|
|
33
33
|
"tsup": "^8.5.0",
|
|
34
34
|
"typescript": "^5.8.2",
|
|
35
|
-
"vitest": "^3.
|
|
35
|
+
"vitest": "^3.2.2",
|
|
36
36
|
"@internal/lint": "0.0.10",
|
|
37
|
-
"@
|
|
38
|
-
"@
|
|
37
|
+
"@mastra/core": "0.10.4-alpha.2",
|
|
38
|
+
"@internal/storage-test-utils": "0.0.6"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
41
41
|
"@mastra/core": "^0.10.2-alpha.0"
|