@mastra/cloudflare-d1 0.0.0-vnextWorkflows-20250422081019 → 0.0.0-workflow-deno-20250616115451
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/_tsup-dts-rollup.d.cts +113 -43
- package/dist/_tsup-dts-rollup.d.ts +113 -43
- package/dist/index.cjs +514 -123
- package/dist/index.d.cts +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +514 -123
- package/package.json +17 -13
package/dist/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
import { MessageList } from '@mastra/core/agent';
|
|
1
2
|
import { MastraStorage, TABLE_THREADS, TABLE_MESSAGES, TABLE_WORKFLOW_SNAPSHOT, TABLE_TRACES, TABLE_EVALS } from '@mastra/core/storage';
|
|
2
3
|
import Cloudflare from 'cloudflare';
|
|
4
|
+
import { parseSqlIdentifier } from '@mastra/core/utils';
|
|
3
5
|
|
|
4
6
|
// src/storage/index.ts
|
|
5
|
-
|
|
6
|
-
// src/storage/sql-builder.ts
|
|
7
7
|
var SqlBuilder = class {
|
|
8
8
|
sql = "";
|
|
9
9
|
params = [];
|
|
@@ -13,12 +13,15 @@ var SqlBuilder = class {
|
|
|
13
13
|
if (!columns || Array.isArray(columns) && columns.length === 0) {
|
|
14
14
|
this.sql = "SELECT *";
|
|
15
15
|
} else {
|
|
16
|
-
|
|
16
|
+
const cols = Array.isArray(columns) ? columns : [columns];
|
|
17
|
+
const parsedCols = cols.map((col) => parseSelectIdentifier(col));
|
|
18
|
+
this.sql = `SELECT ${parsedCols.join(", ")}`;
|
|
17
19
|
}
|
|
18
20
|
return this;
|
|
19
21
|
}
|
|
20
22
|
from(table) {
|
|
21
|
-
|
|
23
|
+
const parsedTableName = parseSqlIdentifier(table, "table name");
|
|
24
|
+
this.sql += ` FROM ${parsedTableName}`;
|
|
22
25
|
return this;
|
|
23
26
|
}
|
|
24
27
|
/**
|
|
@@ -55,7 +58,11 @@ var SqlBuilder = class {
|
|
|
55
58
|
return this;
|
|
56
59
|
}
|
|
57
60
|
orderBy(column, direction = "ASC") {
|
|
58
|
-
|
|
61
|
+
const parsedColumn = parseSqlIdentifier(column, "column name");
|
|
62
|
+
if (!["ASC", "DESC"].includes(direction)) {
|
|
63
|
+
throw new Error(`Invalid sort direction: ${direction}`);
|
|
64
|
+
}
|
|
65
|
+
this.sql += ` ORDER BY ${parsedColumn} ${direction}`;
|
|
59
66
|
return this;
|
|
60
67
|
}
|
|
61
68
|
limit(count) {
|
|
@@ -68,6 +75,10 @@ var SqlBuilder = class {
|
|
|
68
75
|
this.params.push(count);
|
|
69
76
|
return this;
|
|
70
77
|
}
|
|
78
|
+
count() {
|
|
79
|
+
this.sql += "SELECT COUNT(*) AS count";
|
|
80
|
+
return this;
|
|
81
|
+
}
|
|
71
82
|
/**
|
|
72
83
|
* Insert a row, or update specific columns on conflict (upsert).
|
|
73
84
|
* @param table Table name
|
|
@@ -77,27 +88,33 @@ var SqlBuilder = class {
|
|
|
77
88
|
* @param updateMap Object mapping columns to update to their new value (e.g. { name: 'excluded.name' })
|
|
78
89
|
*/
|
|
79
90
|
insert(table, columns, values, conflictColumns, updateMap) {
|
|
80
|
-
const
|
|
91
|
+
const parsedTableName = parseSqlIdentifier(table, "table name");
|
|
92
|
+
const parsedColumns = columns.map((col) => parseSqlIdentifier(col, "column name"));
|
|
93
|
+
const placeholders = parsedColumns.map(() => "?").join(", ");
|
|
81
94
|
if (conflictColumns && updateMap) {
|
|
95
|
+
const parsedConflictColumns = conflictColumns.map((col) => parseSqlIdentifier(col, "column name"));
|
|
82
96
|
const updateClause = Object.entries(updateMap).map(([col, expr]) => `${col} = ${expr}`).join(", ");
|
|
83
|
-
this.sql = `INSERT INTO ${
|
|
97
|
+
this.sql = `INSERT INTO ${parsedTableName} (${parsedColumns.join(", ")}) VALUES (${placeholders}) ON CONFLICT(${parsedConflictColumns.join(", ")}) DO UPDATE SET ${updateClause}`;
|
|
84
98
|
this.params.push(...values);
|
|
85
99
|
return this;
|
|
86
100
|
}
|
|
87
|
-
this.sql = `INSERT INTO ${
|
|
101
|
+
this.sql = `INSERT INTO ${parsedTableName} (${parsedColumns.join(", ")}) VALUES (${placeholders})`;
|
|
88
102
|
this.params.push(...values);
|
|
89
103
|
return this;
|
|
90
104
|
}
|
|
91
105
|
// Update operations
|
|
92
106
|
update(table, columns, values) {
|
|
93
|
-
const
|
|
94
|
-
|
|
107
|
+
const parsedTableName = parseSqlIdentifier(table, "table name");
|
|
108
|
+
const parsedColumns = columns.map((col) => parseSqlIdentifier(col, "column name"));
|
|
109
|
+
const setClause = parsedColumns.map((col) => `${col} = ?`).join(", ");
|
|
110
|
+
this.sql = `UPDATE ${parsedTableName} SET ${setClause}`;
|
|
95
111
|
this.params.push(...values);
|
|
96
112
|
return this;
|
|
97
113
|
}
|
|
98
114
|
// Delete operations
|
|
99
115
|
delete(table) {
|
|
100
|
-
|
|
116
|
+
const parsedTableName = parseSqlIdentifier(table, "table name");
|
|
117
|
+
this.sql = `DELETE FROM ${parsedTableName}`;
|
|
101
118
|
return this;
|
|
102
119
|
}
|
|
103
120
|
/**
|
|
@@ -108,9 +125,16 @@ var SqlBuilder = class {
|
|
|
108
125
|
* @returns The builder instance
|
|
109
126
|
*/
|
|
110
127
|
createTable(table, columnDefinitions, tableConstraints) {
|
|
111
|
-
const
|
|
128
|
+
const parsedTableName = parseSqlIdentifier(table, "table name");
|
|
129
|
+
const parsedColumnDefinitions = columnDefinitions.map((def) => {
|
|
130
|
+
const colName = def.split(/\s+/)[0];
|
|
131
|
+
if (!colName) throw new Error("Empty column name in definition");
|
|
132
|
+
parseSqlIdentifier(colName, "column name");
|
|
133
|
+
return def;
|
|
134
|
+
});
|
|
135
|
+
const columns = parsedColumnDefinitions.join(", ");
|
|
112
136
|
const constraints = tableConstraints && tableConstraints.length > 0 ? ", " + tableConstraints.join(", ") : "";
|
|
113
|
-
this.sql = `CREATE TABLE IF NOT EXISTS ${
|
|
137
|
+
this.sql = `CREATE TABLE IF NOT EXISTS ${parsedTableName} (${columns}${constraints})`;
|
|
114
138
|
return this;
|
|
115
139
|
}
|
|
116
140
|
/**
|
|
@@ -133,13 +157,10 @@ var SqlBuilder = class {
|
|
|
133
157
|
* @returns The builder instance
|
|
134
158
|
*/
|
|
135
159
|
createIndex(indexName, tableName, columnName, indexType = "") {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
raw(sql, ...params) {
|
|
141
|
-
this.sql = sql;
|
|
142
|
-
this.params.push(...params);
|
|
160
|
+
const parsedIndexName = parseSqlIdentifier(indexName, "index name");
|
|
161
|
+
const parsedTableName = parseSqlIdentifier(tableName, "table name");
|
|
162
|
+
const parsedColumnName = parseSqlIdentifier(columnName, "column name");
|
|
163
|
+
this.sql = `CREATE ${indexType ? indexType + " " : ""}INDEX IF NOT EXISTS ${parsedIndexName} ON ${parsedTableName}(${parsedColumnName})`;
|
|
143
164
|
return this;
|
|
144
165
|
}
|
|
145
166
|
/**
|
|
@@ -149,11 +170,12 @@ var SqlBuilder = class {
|
|
|
149
170
|
* @param exact If true, will not add % wildcards
|
|
150
171
|
*/
|
|
151
172
|
like(column, value, exact = false) {
|
|
173
|
+
const parsedColumnName = parseSqlIdentifier(column, "column name");
|
|
152
174
|
const likeValue = exact ? value : `%${value}%`;
|
|
153
175
|
if (this.whereAdded) {
|
|
154
|
-
this.sql += ` AND ${
|
|
176
|
+
this.sql += ` AND ${parsedColumnName} LIKE ?`;
|
|
155
177
|
} else {
|
|
156
|
-
this.sql += ` WHERE ${
|
|
178
|
+
this.sql += ` WHERE ${parsedColumnName} LIKE ?`;
|
|
157
179
|
this.whereAdded = true;
|
|
158
180
|
}
|
|
159
181
|
this.params.push(likeValue);
|
|
@@ -166,11 +188,13 @@ var SqlBuilder = class {
|
|
|
166
188
|
* @param value The value to match
|
|
167
189
|
*/
|
|
168
190
|
jsonLike(column, key, value) {
|
|
169
|
-
const
|
|
191
|
+
const parsedColumnName = parseSqlIdentifier(column, "column name");
|
|
192
|
+
const parsedKey = parseSqlIdentifier(key, "key name");
|
|
193
|
+
const jsonPattern = `%"${parsedKey}":"${value}"%`;
|
|
170
194
|
if (this.whereAdded) {
|
|
171
|
-
this.sql += ` AND ${
|
|
195
|
+
this.sql += ` AND ${parsedColumnName} LIKE ?`;
|
|
172
196
|
} else {
|
|
173
|
-
this.sql += ` WHERE ${
|
|
197
|
+
this.sql += ` WHERE ${parsedColumnName} LIKE ?`;
|
|
174
198
|
this.whereAdded = true;
|
|
175
199
|
}
|
|
176
200
|
this.params.push(jsonPattern);
|
|
@@ -200,6 +224,15 @@ var SqlBuilder = class {
|
|
|
200
224
|
function createSqlBuilder() {
|
|
201
225
|
return new SqlBuilder();
|
|
202
226
|
}
|
|
227
|
+
var SQL_IDENTIFIER_PATTERN = /^[a-zA-Z0-9_]+(\s+AS\s+[a-zA-Z0-9_]+)?$/;
|
|
228
|
+
function parseSelectIdentifier(column) {
|
|
229
|
+
if (column !== "*" && !SQL_IDENTIFIER_PATTERN.test(column)) {
|
|
230
|
+
throw new Error(
|
|
231
|
+
`Invalid column name: "${column}". Must be "*" or a valid identifier (letters, numbers, underscores), optionally with "AS alias".`
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
return column;
|
|
235
|
+
}
|
|
203
236
|
|
|
204
237
|
// src/storage/index.ts
|
|
205
238
|
function isArrayOfRecords(value) {
|
|
@@ -218,6 +251,9 @@ var D1Store = class extends MastraStorage {
|
|
|
218
251
|
*/
|
|
219
252
|
constructor(config) {
|
|
220
253
|
super({ name: "D1" });
|
|
254
|
+
if (config.tablePrefix && !/^[a-zA-Z0-9_]*$/.test(config.tablePrefix)) {
|
|
255
|
+
throw new Error("Invalid tablePrefix: only letters, numbers, and underscores are allowed.");
|
|
256
|
+
}
|
|
221
257
|
this.tablePrefix = config.tablePrefix || "";
|
|
222
258
|
if ("binding" in config) {
|
|
223
259
|
if (!config.binding) {
|
|
@@ -244,30 +280,6 @@ var D1Store = class extends MastraStorage {
|
|
|
244
280
|
formatSqlParams(params) {
|
|
245
281
|
return params.map((p) => p === void 0 || p === null ? null : p);
|
|
246
282
|
}
|
|
247
|
-
// Helper method to create SQL indexes for better query performance
|
|
248
|
-
async createIndexIfNotExists(tableName, columnName, indexType = "") {
|
|
249
|
-
const fullTableName = this.getTableName(tableName);
|
|
250
|
-
const indexName = `idx_${tableName}_${columnName}`;
|
|
251
|
-
try {
|
|
252
|
-
const checkQuery = createSqlBuilder().checkIndexExists(indexName, fullTableName);
|
|
253
|
-
const { sql: checkSql, params: checkParams } = checkQuery.build();
|
|
254
|
-
const indexExists = await this.executeQuery({
|
|
255
|
-
sql: checkSql,
|
|
256
|
-
params: checkParams,
|
|
257
|
-
first: true
|
|
258
|
-
});
|
|
259
|
-
if (!indexExists) {
|
|
260
|
-
const createQuery = createSqlBuilder().createIndex(indexName, fullTableName, columnName, indexType);
|
|
261
|
-
const { sql: createSql, params: createParams } = createQuery.build();
|
|
262
|
-
await this.executeQuery({ sql: createSql, params: createParams });
|
|
263
|
-
this.logger.debug(`Created index ${indexName} on ${fullTableName}(${columnName})`);
|
|
264
|
-
}
|
|
265
|
-
} catch (error) {
|
|
266
|
-
this.logger.error(`Error creating index on ${fullTableName}(${columnName}):`, {
|
|
267
|
-
message: error instanceof Error ? error.message : String(error)
|
|
268
|
-
});
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
283
|
async executeWorkersBindingQuery({
|
|
272
284
|
sql,
|
|
273
285
|
params = [],
|
|
@@ -371,34 +383,25 @@ var D1Store = class extends MastraStorage {
|
|
|
371
383
|
throw new Error(`D1 query error: ${error.message}`);
|
|
372
384
|
}
|
|
373
385
|
}
|
|
374
|
-
// Helper to
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
return
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
386
|
+
// Helper to get existing table columns
|
|
387
|
+
async getTableColumns(tableName) {
|
|
388
|
+
try {
|
|
389
|
+
const sql = `PRAGMA table_info(${tableName})`;
|
|
390
|
+
const result = await this.executeQuery({ sql, params: [] });
|
|
391
|
+
if (!result || !Array.isArray(result)) {
|
|
392
|
+
return [];
|
|
393
|
+
}
|
|
394
|
+
return result.map((row) => ({
|
|
395
|
+
name: row.name,
|
|
396
|
+
type: row.type
|
|
397
|
+
}));
|
|
398
|
+
} catch (error) {
|
|
399
|
+
this.logger.error(`Error getting table columns for ${tableName}:`, {
|
|
400
|
+
message: error instanceof Error ? error.message : String(error)
|
|
401
|
+
});
|
|
402
|
+
return [];
|
|
391
403
|
}
|
|
392
404
|
}
|
|
393
|
-
ensureDate(date) {
|
|
394
|
-
if (!date) return void 0;
|
|
395
|
-
return date instanceof Date ? date : new Date(date);
|
|
396
|
-
}
|
|
397
|
-
serializeDate(date) {
|
|
398
|
-
if (!date) return void 0;
|
|
399
|
-
const dateObj = this.ensureDate(date);
|
|
400
|
-
return dateObj?.toISOString();
|
|
401
|
-
}
|
|
402
405
|
// Helper to serialize objects to JSON strings
|
|
403
406
|
serializeValue(value) {
|
|
404
407
|
if (value === null || value === void 0) return null;
|
|
@@ -432,6 +435,18 @@ var D1Store = class extends MastraStorage {
|
|
|
432
435
|
}
|
|
433
436
|
return value;
|
|
434
437
|
}
|
|
438
|
+
getSqlType(type) {
|
|
439
|
+
switch (type) {
|
|
440
|
+
case "bigint":
|
|
441
|
+
return "INTEGER";
|
|
442
|
+
// SQLite uses INTEGER for all integer sizes
|
|
443
|
+
case "jsonb":
|
|
444
|
+
return "TEXT";
|
|
445
|
+
// Store JSON as TEXT in SQLite
|
|
446
|
+
default:
|
|
447
|
+
return super.getSqlType(type);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
435
450
|
async createTable({
|
|
436
451
|
tableName,
|
|
437
452
|
schema
|
|
@@ -459,6 +474,39 @@ var D1Store = class extends MastraStorage {
|
|
|
459
474
|
throw new Error(`Failed to create table ${fullTableName}: ${error}`);
|
|
460
475
|
}
|
|
461
476
|
}
|
|
477
|
+
/**
|
|
478
|
+
* Alters table schema to add columns if they don't exist
|
|
479
|
+
* @param tableName Name of the table
|
|
480
|
+
* @param schema Schema of the table
|
|
481
|
+
* @param ifNotExists Array of column names to add if they don't exist
|
|
482
|
+
*/
|
|
483
|
+
async alterTable({
|
|
484
|
+
tableName,
|
|
485
|
+
schema,
|
|
486
|
+
ifNotExists
|
|
487
|
+
}) {
|
|
488
|
+
const fullTableName = this.getTableName(tableName);
|
|
489
|
+
try {
|
|
490
|
+
const existingColumns = await this.getTableColumns(fullTableName);
|
|
491
|
+
const existingColumnNames = new Set(existingColumns.map((col) => col.name.toLowerCase()));
|
|
492
|
+
for (const columnName of ifNotExists) {
|
|
493
|
+
if (!existingColumnNames.has(columnName.toLowerCase()) && schema[columnName]) {
|
|
494
|
+
const columnDef = schema[columnName];
|
|
495
|
+
const sqlType = this.getSqlType(columnDef.type);
|
|
496
|
+
const nullable = columnDef.nullable === false ? "NOT NULL" : "";
|
|
497
|
+
const defaultValue = columnDef.nullable === false ? this.getDefaultValue(columnDef.type) : "";
|
|
498
|
+
const alterSql = `ALTER TABLE ${fullTableName} ADD COLUMN ${columnName} ${sqlType} ${nullable} ${defaultValue}`.trim();
|
|
499
|
+
await this.executeQuery({ sql: alterSql, params: [] });
|
|
500
|
+
this.logger.debug(`Added column ${columnName} to table ${fullTableName}`);
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
} catch (error) {
|
|
504
|
+
this.logger.error(`Error altering table ${fullTableName}:`, {
|
|
505
|
+
message: error instanceof Error ? error.message : String(error)
|
|
506
|
+
});
|
|
507
|
+
throw new Error(`Failed to alter table ${fullTableName}: ${error}`);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
462
510
|
async clearTable({ tableName }) {
|
|
463
511
|
const fullTableName = this.getTableName(tableName);
|
|
464
512
|
try {
|
|
@@ -490,7 +538,8 @@ var D1Store = class extends MastraStorage {
|
|
|
490
538
|
try {
|
|
491
539
|
await this.executeQuery({ sql, params });
|
|
492
540
|
} catch (error) {
|
|
493
|
-
|
|
541
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
542
|
+
this.logger.error(`Error inserting into ${fullTableName}:`, { message });
|
|
494
543
|
throw new Error(`Failed to insert into ${fullTableName}: ${error}`);
|
|
495
544
|
}
|
|
496
545
|
}
|
|
@@ -543,6 +592,9 @@ var D1Store = class extends MastraStorage {
|
|
|
543
592
|
return null;
|
|
544
593
|
}
|
|
545
594
|
}
|
|
595
|
+
/**
|
|
596
|
+
* @deprecated use getThreadsByResourceIdPaginated instead
|
|
597
|
+
*/
|
|
546
598
|
async getThreadsByResourceId({ resourceId }) {
|
|
547
599
|
const fullTableName = this.getTableName(TABLE_THREADS);
|
|
548
600
|
try {
|
|
@@ -562,6 +614,29 @@ var D1Store = class extends MastraStorage {
|
|
|
562
614
|
return [];
|
|
563
615
|
}
|
|
564
616
|
}
|
|
617
|
+
async getThreadsByResourceIdPaginated(args) {
|
|
618
|
+
const { resourceId, page, perPage } = args;
|
|
619
|
+
const fullTableName = this.getTableName(TABLE_THREADS);
|
|
620
|
+
const mapRowToStorageThreadType = (row) => ({
|
|
621
|
+
...row,
|
|
622
|
+
createdAt: this.ensureDate(row.createdAt),
|
|
623
|
+
updatedAt: this.ensureDate(row.updatedAt),
|
|
624
|
+
metadata: typeof row.metadata === "string" ? JSON.parse(row.metadata || "{}") : row.metadata || {}
|
|
625
|
+
});
|
|
626
|
+
const countQuery = createSqlBuilder().count().from(fullTableName).where("resourceId = ?", resourceId);
|
|
627
|
+
const countResult = await this.executeQuery(countQuery.build());
|
|
628
|
+
const total = Number(countResult?.[0]?.count ?? 0);
|
|
629
|
+
const selectQuery = createSqlBuilder().select("*").from(fullTableName).where("resourceId = ?", resourceId).orderBy("createdAt", "DESC").limit(perPage).offset(page * perPage);
|
|
630
|
+
const results = await this.executeQuery(selectQuery.build());
|
|
631
|
+
const threads = results.map(mapRowToStorageThreadType);
|
|
632
|
+
return {
|
|
633
|
+
threads,
|
|
634
|
+
total,
|
|
635
|
+
page,
|
|
636
|
+
perPage,
|
|
637
|
+
hasMore: page * perPage + threads.length < total
|
|
638
|
+
};
|
|
639
|
+
}
|
|
565
640
|
async saveThread({ thread }) {
|
|
566
641
|
const fullTableName = this.getTableName(TABLE_THREADS);
|
|
567
642
|
const threadToSave = {
|
|
@@ -588,7 +663,8 @@ var D1Store = class extends MastraStorage {
|
|
|
588
663
|
await this.executeQuery({ sql, params });
|
|
589
664
|
return thread;
|
|
590
665
|
} catch (error) {
|
|
591
|
-
|
|
666
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
667
|
+
this.logger.error(`Error saving thread to ${fullTableName}:`, { message });
|
|
592
668
|
throw error;
|
|
593
669
|
}
|
|
594
670
|
}
|
|
@@ -622,7 +698,8 @@ var D1Store = class extends MastraStorage {
|
|
|
622
698
|
updatedAt: /* @__PURE__ */ new Date()
|
|
623
699
|
};
|
|
624
700
|
} catch (error) {
|
|
625
|
-
|
|
701
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
702
|
+
this.logger.error("Error updating thread:", { message });
|
|
626
703
|
throw error;
|
|
627
704
|
}
|
|
628
705
|
}
|
|
@@ -643,11 +720,12 @@ var D1Store = class extends MastraStorage {
|
|
|
643
720
|
throw new Error(`Failed to delete thread ${threadId}: ${error}`);
|
|
644
721
|
}
|
|
645
722
|
}
|
|
646
|
-
|
|
647
|
-
|
|
723
|
+
async saveMessages(args) {
|
|
724
|
+
const { messages, format = "v1" } = args;
|
|
648
725
|
if (messages.length === 0) return [];
|
|
649
726
|
try {
|
|
650
727
|
const now = /* @__PURE__ */ new Date();
|
|
728
|
+
const threadId = messages[0]?.threadId;
|
|
651
729
|
for (const [i, message] of messages.entries()) {
|
|
652
730
|
if (!message.id) throw new Error(`Message at index ${i} missing id`);
|
|
653
731
|
if (!message.threadId) throw new Error(`Message at index ${i} missing threadId`);
|
|
@@ -666,36 +744,42 @@ var D1Store = class extends MastraStorage {
|
|
|
666
744
|
content: typeof message.content === "string" ? message.content : JSON.stringify(message.content),
|
|
667
745
|
createdAt: createdAt.toISOString(),
|
|
668
746
|
role: message.role,
|
|
669
|
-
type: message.type
|
|
747
|
+
type: message.type || "v2",
|
|
748
|
+
resourceId: message.resourceId
|
|
670
749
|
};
|
|
671
750
|
});
|
|
672
|
-
await
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
751
|
+
await Promise.all([
|
|
752
|
+
this.batchInsert({
|
|
753
|
+
tableName: TABLE_MESSAGES,
|
|
754
|
+
records: messagesToInsert
|
|
755
|
+
}),
|
|
756
|
+
// Update thread's updatedAt timestamp
|
|
757
|
+
this.executeQuery({
|
|
758
|
+
sql: `UPDATE ${this.getTableName(TABLE_THREADS)} SET updatedAt = ? WHERE id = ?`,
|
|
759
|
+
params: [now.toISOString(), threadId]
|
|
760
|
+
})
|
|
761
|
+
]);
|
|
676
762
|
this.logger.debug(`Saved ${messages.length} messages`);
|
|
677
|
-
|
|
763
|
+
const list = new MessageList().add(messages, "memory");
|
|
764
|
+
if (format === `v2`) return list.get.all.v2();
|
|
765
|
+
return list.get.all.v1();
|
|
678
766
|
} catch (error) {
|
|
679
767
|
this.logger.error("Error saving messages:", { message: error instanceof Error ? error.message : String(error) });
|
|
680
768
|
throw error;
|
|
681
769
|
}
|
|
682
770
|
}
|
|
683
|
-
async
|
|
684
|
-
const
|
|
685
|
-
|
|
686
|
-
const
|
|
687
|
-
const
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
const prevMax = Math.max(...include.map((i) => i.withPreviousMessages || 0));
|
|
691
|
-
const nextMax = Math.max(...include.map((i) => i.withNextMessages || 0));
|
|
692
|
-
const includeIds = include.map((i) => i.id);
|
|
693
|
-
const sql2 = `
|
|
771
|
+
async _getIncludedMessages(threadId, selectBy) {
|
|
772
|
+
const include = selectBy?.include;
|
|
773
|
+
if (!include) return null;
|
|
774
|
+
const prevMax = Math.max(...include.map((i) => i.withPreviousMessages || 0));
|
|
775
|
+
const nextMax = Math.max(...include.map((i) => i.withNextMessages || 0));
|
|
776
|
+
const includeIds = include.map((i) => i.id);
|
|
777
|
+
const sql = `
|
|
694
778
|
WITH ordered_messages AS (
|
|
695
779
|
SELECT
|
|
696
780
|
*,
|
|
697
781
|
ROW_NUMBER() OVER (ORDER BY createdAt DESC) AS row_num
|
|
698
|
-
FROM ${
|
|
782
|
+
FROM ${this.getTableName(TABLE_MESSAGES)}
|
|
699
783
|
WHERE thread_id = ?
|
|
700
784
|
)
|
|
701
785
|
SELECT
|
|
@@ -704,7 +788,7 @@ var D1Store = class extends MastraStorage {
|
|
|
704
788
|
m.role,
|
|
705
789
|
m.type,
|
|
706
790
|
m.createdAt,
|
|
707
|
-
m.thread_id AS
|
|
791
|
+
m.thread_id AS threadId
|
|
708
792
|
FROM ordered_messages m
|
|
709
793
|
WHERE m.id IN (${includeIds.map(() => "?").join(",")})
|
|
710
794
|
OR EXISTS (
|
|
@@ -718,20 +802,38 @@ var D1Store = class extends MastraStorage {
|
|
|
718
802
|
)
|
|
719
803
|
ORDER BY m.createdAt DESC
|
|
720
804
|
`;
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
805
|
+
const params = [
|
|
806
|
+
threadId,
|
|
807
|
+
...includeIds,
|
|
808
|
+
// for m.id IN (...)
|
|
809
|
+
...includeIds,
|
|
810
|
+
// for target.id IN (...)
|
|
811
|
+
prevMax,
|
|
812
|
+
nextMax
|
|
813
|
+
];
|
|
814
|
+
const messages = await this.executeQuery({ sql, params });
|
|
815
|
+
return messages;
|
|
816
|
+
}
|
|
817
|
+
async getMessages({
|
|
818
|
+
threadId,
|
|
819
|
+
selectBy,
|
|
820
|
+
format
|
|
821
|
+
}) {
|
|
822
|
+
const fullTableName = this.getTableName(TABLE_MESSAGES);
|
|
823
|
+
const limit = typeof selectBy?.last === "number" ? selectBy.last : 40;
|
|
824
|
+
const include = selectBy?.include || [];
|
|
825
|
+
const messages = [];
|
|
826
|
+
try {
|
|
827
|
+
if (include.length) {
|
|
828
|
+
const includeResult = await this._getIncludedMessages(threadId, selectBy);
|
|
731
829
|
if (Array.isArray(includeResult)) messages.push(...includeResult);
|
|
732
830
|
}
|
|
733
831
|
const excludeIds = messages.map((m) => m.id);
|
|
734
|
-
|
|
832
|
+
const query = createSqlBuilder().select(["id", "content", "role", "type", "createdAt", "thread_id AS threadId"]).from(fullTableName).where("thread_id = ?", threadId);
|
|
833
|
+
if (excludeIds.length > 0) {
|
|
834
|
+
query.andWhere(`id NOT IN (${excludeIds.map(() => "?").join(",")})`, ...excludeIds);
|
|
835
|
+
}
|
|
836
|
+
query.orderBy("createdAt", "DESC").limit(limit);
|
|
735
837
|
const { sql, params } = query.build();
|
|
736
838
|
const result = await this.executeQuery({ sql, params });
|
|
737
839
|
if (Array.isArray(result)) messages.push(...result);
|
|
@@ -745,12 +847,15 @@ var D1Store = class extends MastraStorage {
|
|
|
745
847
|
const processedMessages = messages.map((message) => {
|
|
746
848
|
const processedMsg = {};
|
|
747
849
|
for (const [key, value] of Object.entries(message)) {
|
|
850
|
+
if (key === `type` && value === `v2`) continue;
|
|
748
851
|
processedMsg[key] = this.deserializeValue(value);
|
|
749
852
|
}
|
|
750
853
|
return processedMsg;
|
|
751
854
|
});
|
|
752
855
|
this.logger.debug(`Retrieved ${messages.length} messages for thread ${threadId}`);
|
|
753
|
-
|
|
856
|
+
const list = new MessageList().add(processedMessages, "memory");
|
|
857
|
+
if (format === `v2`) return list.get.all.v2();
|
|
858
|
+
return list.get.all.v1();
|
|
754
859
|
} catch (error) {
|
|
755
860
|
this.logger.error("Error retrieving messages for thread", {
|
|
756
861
|
threadId,
|
|
@@ -759,6 +864,47 @@ var D1Store = class extends MastraStorage {
|
|
|
759
864
|
return [];
|
|
760
865
|
}
|
|
761
866
|
}
|
|
867
|
+
async getMessagesPaginated({
|
|
868
|
+
threadId,
|
|
869
|
+
selectBy,
|
|
870
|
+
format
|
|
871
|
+
}) {
|
|
872
|
+
const { dateRange, page = 0, perPage = 40 } = selectBy?.pagination || {};
|
|
873
|
+
const { start: fromDate, end: toDate } = dateRange || {};
|
|
874
|
+
const fullTableName = this.getTableName(TABLE_MESSAGES);
|
|
875
|
+
const messages = [];
|
|
876
|
+
if (selectBy?.include?.length) {
|
|
877
|
+
const includeResult = await this._getIncludedMessages(threadId, selectBy);
|
|
878
|
+
if (Array.isArray(includeResult)) messages.push(...includeResult);
|
|
879
|
+
}
|
|
880
|
+
const countQuery = createSqlBuilder().count().from(fullTableName).where("thread_id = ?", threadId);
|
|
881
|
+
if (fromDate) {
|
|
882
|
+
countQuery.andWhere("createdAt >= ?", this.serializeDate(fromDate));
|
|
883
|
+
}
|
|
884
|
+
if (toDate) {
|
|
885
|
+
countQuery.andWhere("createdAt <= ?", this.serializeDate(toDate));
|
|
886
|
+
}
|
|
887
|
+
const countResult = await this.executeQuery(countQuery.build());
|
|
888
|
+
const total = Number(countResult[0]?.count ?? 0);
|
|
889
|
+
const query = createSqlBuilder().select(["id", "content", "role", "type", "createdAt", "thread_id AS threadId"]).from(fullTableName).where("thread_id = ?", threadId);
|
|
890
|
+
if (fromDate) {
|
|
891
|
+
query.andWhere("createdAt >= ?", this.serializeDate(fromDate));
|
|
892
|
+
}
|
|
893
|
+
if (toDate) {
|
|
894
|
+
query.andWhere("createdAt <= ?", this.serializeDate(toDate));
|
|
895
|
+
}
|
|
896
|
+
query.orderBy("createdAt", "DESC").limit(perPage).offset(page * perPage);
|
|
897
|
+
const results = await this.executeQuery(query.build());
|
|
898
|
+
const list = new MessageList().add(results, "memory");
|
|
899
|
+
messages.push(...format === `v2` ? list.get.all.v2() : list.get.all.v1());
|
|
900
|
+
return {
|
|
901
|
+
messages,
|
|
902
|
+
total,
|
|
903
|
+
page,
|
|
904
|
+
perPage,
|
|
905
|
+
hasMore: page * perPage + messages.length < total
|
|
906
|
+
};
|
|
907
|
+
}
|
|
762
908
|
async persistWorkflowSnapshot({
|
|
763
909
|
workflowName,
|
|
764
910
|
runId,
|
|
@@ -851,12 +997,17 @@ var D1Store = class extends MastraStorage {
|
|
|
851
997
|
throw new Error(`Failed to batch insert into ${tableName}: ${error}`);
|
|
852
998
|
}
|
|
853
999
|
}
|
|
1000
|
+
/**
|
|
1001
|
+
* @deprecated use getTracesPaginated instead
|
|
1002
|
+
*/
|
|
854
1003
|
async getTraces({
|
|
855
1004
|
name,
|
|
856
1005
|
scope,
|
|
857
1006
|
page,
|
|
858
1007
|
perPage,
|
|
859
|
-
attributes
|
|
1008
|
+
attributes,
|
|
1009
|
+
fromDate,
|
|
1010
|
+
toDate
|
|
860
1011
|
}) {
|
|
861
1012
|
const fullTableName = this.getTableName(TABLE_TRACES);
|
|
862
1013
|
try {
|
|
@@ -872,22 +1023,89 @@ var D1Store = class extends MastraStorage {
|
|
|
872
1023
|
query.jsonLike("attributes", key, value);
|
|
873
1024
|
}
|
|
874
1025
|
}
|
|
875
|
-
|
|
1026
|
+
if (fromDate) {
|
|
1027
|
+
query.andWhere("createdAt >= ?", fromDate instanceof Date ? fromDate.toISOString() : fromDate);
|
|
1028
|
+
}
|
|
1029
|
+
if (toDate) {
|
|
1030
|
+
query.andWhere("createdAt <= ?", toDate instanceof Date ? toDate.toISOString() : toDate);
|
|
1031
|
+
}
|
|
1032
|
+
query.orderBy("startTime", "DESC").limit(perPage).offset(page * perPage);
|
|
876
1033
|
const { sql, params } = query.build();
|
|
877
1034
|
const results = await this.executeQuery({ sql, params });
|
|
878
|
-
return isArrayOfRecords(results) ? results.map(
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
1035
|
+
return isArrayOfRecords(results) ? results.map(
|
|
1036
|
+
(trace) => ({
|
|
1037
|
+
...trace,
|
|
1038
|
+
attributes: this.deserializeValue(trace.attributes, "jsonb"),
|
|
1039
|
+
status: this.deserializeValue(trace.status, "jsonb"),
|
|
1040
|
+
events: this.deserializeValue(trace.events, "jsonb"),
|
|
1041
|
+
links: this.deserializeValue(trace.links, "jsonb"),
|
|
1042
|
+
other: this.deserializeValue(trace.other, "jsonb")
|
|
1043
|
+
})
|
|
1044
|
+
) : [];
|
|
886
1045
|
} catch (error) {
|
|
887
1046
|
this.logger.error("Error getting traces:", { message: error instanceof Error ? error.message : String(error) });
|
|
888
1047
|
return [];
|
|
889
1048
|
}
|
|
890
1049
|
}
|
|
1050
|
+
async getTracesPaginated(args) {
|
|
1051
|
+
const { name, scope, page, perPage, attributes, fromDate, toDate } = args;
|
|
1052
|
+
const fullTableName = this.getTableName(TABLE_TRACES);
|
|
1053
|
+
try {
|
|
1054
|
+
const dataQuery = createSqlBuilder().select("*").from(fullTableName).where("1=1");
|
|
1055
|
+
const countQuery = createSqlBuilder().count().from(fullTableName).where("1=1");
|
|
1056
|
+
if (name) {
|
|
1057
|
+
dataQuery.andWhere("name LIKE ?", `%${name}%`);
|
|
1058
|
+
countQuery.andWhere("name LIKE ?", `%${name}%`);
|
|
1059
|
+
}
|
|
1060
|
+
if (scope) {
|
|
1061
|
+
dataQuery.andWhere("scope = ?", scope);
|
|
1062
|
+
countQuery.andWhere("scope = ?", scope);
|
|
1063
|
+
}
|
|
1064
|
+
if (attributes && Object.keys(attributes).length > 0) {
|
|
1065
|
+
for (const [key, value] of Object.entries(attributes)) {
|
|
1066
|
+
dataQuery.jsonLike("attributes", key, value);
|
|
1067
|
+
countQuery.jsonLike("attributes", key, value);
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
if (fromDate) {
|
|
1071
|
+
const fromDateStr = fromDate instanceof Date ? fromDate.toISOString() : fromDate;
|
|
1072
|
+
dataQuery.andWhere("createdAt >= ?", fromDateStr);
|
|
1073
|
+
countQuery.andWhere("createdAt >= ?", fromDateStr);
|
|
1074
|
+
}
|
|
1075
|
+
if (toDate) {
|
|
1076
|
+
const toDateStr = toDate instanceof Date ? toDate.toISOString() : toDate;
|
|
1077
|
+
dataQuery.andWhere("createdAt <= ?", toDateStr);
|
|
1078
|
+
countQuery.andWhere("createdAt <= ?", toDateStr);
|
|
1079
|
+
}
|
|
1080
|
+
const countResult = await this.executeQuery(countQuery.build());
|
|
1081
|
+
const total = Number(countResult?.[0]?.count ?? 0);
|
|
1082
|
+
dataQuery.orderBy("startTime", "DESC").limit(perPage).offset(page * perPage);
|
|
1083
|
+
const results = await this.executeQuery(dataQuery.build());
|
|
1084
|
+
const traces = isArrayOfRecords(results) ? results.map(
|
|
1085
|
+
(trace) => ({
|
|
1086
|
+
...trace,
|
|
1087
|
+
attributes: this.deserializeValue(trace.attributes, "jsonb"),
|
|
1088
|
+
status: this.deserializeValue(trace.status, "jsonb"),
|
|
1089
|
+
events: this.deserializeValue(trace.events, "jsonb"),
|
|
1090
|
+
links: this.deserializeValue(trace.links, "jsonb"),
|
|
1091
|
+
other: this.deserializeValue(trace.other, "jsonb")
|
|
1092
|
+
})
|
|
1093
|
+
) : [];
|
|
1094
|
+
return {
|
|
1095
|
+
traces,
|
|
1096
|
+
total,
|
|
1097
|
+
page,
|
|
1098
|
+
perPage,
|
|
1099
|
+
hasMore: page * perPage + traces.length < total
|
|
1100
|
+
};
|
|
1101
|
+
} catch (error) {
|
|
1102
|
+
this.logger.error("Error getting traces:", { message: error instanceof Error ? error.message : String(error) });
|
|
1103
|
+
return { traces: [], total: 0, page, perPage, hasMore: false };
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
/**
|
|
1107
|
+
* @deprecated use getEvals instead
|
|
1108
|
+
*/
|
|
891
1109
|
async getEvalsByAgentName(agentName, type) {
|
|
892
1110
|
const fullTableName = this.getTableName(TABLE_EVALS);
|
|
893
1111
|
try {
|
|
@@ -923,8 +1141,181 @@ var D1Store = class extends MastraStorage {
|
|
|
923
1141
|
return [];
|
|
924
1142
|
}
|
|
925
1143
|
}
|
|
926
|
-
|
|
927
|
-
|
|
1144
|
+
async getEvals(options) {
|
|
1145
|
+
const { agentName, type, page = 0, perPage = 40, fromDate, toDate } = options || {};
|
|
1146
|
+
const fullTableName = this.getTableName(TABLE_EVALS);
|
|
1147
|
+
const conditions = [];
|
|
1148
|
+
const queryParams = [];
|
|
1149
|
+
if (agentName) {
|
|
1150
|
+
conditions.push(`agent_name = ?`);
|
|
1151
|
+
queryParams.push(agentName);
|
|
1152
|
+
}
|
|
1153
|
+
if (type === "test") {
|
|
1154
|
+
conditions.push(`(test_info IS NOT NULL AND json_extract(test_info, '$.testPath') IS NOT NULL)`);
|
|
1155
|
+
} else if (type === "live") {
|
|
1156
|
+
conditions.push(`(test_info IS NULL OR json_extract(test_info, '$.testPath') IS NULL)`);
|
|
1157
|
+
}
|
|
1158
|
+
if (fromDate) {
|
|
1159
|
+
conditions.push(`createdAt >= ?`);
|
|
1160
|
+
queryParams.push(this.serializeDate(fromDate));
|
|
1161
|
+
}
|
|
1162
|
+
if (toDate) {
|
|
1163
|
+
conditions.push(`createdAt <= ?`);
|
|
1164
|
+
queryParams.push(this.serializeDate(toDate));
|
|
1165
|
+
}
|
|
1166
|
+
const countQueryBuilder = createSqlBuilder().count().from(fullTableName);
|
|
1167
|
+
if (conditions.length > 0) {
|
|
1168
|
+
countQueryBuilder.where(conditions.join(" AND "), ...queryParams);
|
|
1169
|
+
}
|
|
1170
|
+
const { sql: countSql, params: countParams } = countQueryBuilder.build();
|
|
1171
|
+
const countResult = await this.executeQuery({ sql: countSql, params: countParams, first: true });
|
|
1172
|
+
const total = Number(countResult?.count || 0);
|
|
1173
|
+
const currentOffset = page * perPage;
|
|
1174
|
+
if (total === 0) {
|
|
1175
|
+
return {
|
|
1176
|
+
evals: [],
|
|
1177
|
+
total: 0,
|
|
1178
|
+
page,
|
|
1179
|
+
perPage,
|
|
1180
|
+
hasMore: false
|
|
1181
|
+
};
|
|
1182
|
+
}
|
|
1183
|
+
const dataQueryBuilder = createSqlBuilder().select("*").from(fullTableName);
|
|
1184
|
+
if (conditions.length > 0) {
|
|
1185
|
+
dataQueryBuilder.where(conditions.join(" AND "), ...queryParams);
|
|
1186
|
+
}
|
|
1187
|
+
dataQueryBuilder.orderBy("createdAt", "DESC").limit(perPage).offset(currentOffset);
|
|
1188
|
+
const { sql: dataSql, params: dataParams } = dataQueryBuilder.build();
|
|
1189
|
+
const rows = await this.executeQuery({ sql: dataSql, params: dataParams });
|
|
1190
|
+
const evals = (isArrayOfRecords(rows) ? rows : []).map((row) => {
|
|
1191
|
+
const result = this.deserializeValue(row.result);
|
|
1192
|
+
const testInfo = row.test_info ? this.deserializeValue(row.test_info) : void 0;
|
|
1193
|
+
if (!result || typeof result !== "object" || !("score" in result)) {
|
|
1194
|
+
throw new Error(`Invalid MetricResult format: ${JSON.stringify(result)}`);
|
|
1195
|
+
}
|
|
1196
|
+
return {
|
|
1197
|
+
input: row.input,
|
|
1198
|
+
output: row.output,
|
|
1199
|
+
result,
|
|
1200
|
+
agentName: row.agent_name,
|
|
1201
|
+
metricName: row.metric_name,
|
|
1202
|
+
instructions: row.instructions,
|
|
1203
|
+
testInfo,
|
|
1204
|
+
globalRunId: row.global_run_id,
|
|
1205
|
+
runId: row.run_id,
|
|
1206
|
+
createdAt: row.createdAt
|
|
1207
|
+
};
|
|
1208
|
+
});
|
|
1209
|
+
const hasMore = currentOffset + evals.length < total;
|
|
1210
|
+
return {
|
|
1211
|
+
evals,
|
|
1212
|
+
total,
|
|
1213
|
+
page,
|
|
1214
|
+
perPage,
|
|
1215
|
+
hasMore
|
|
1216
|
+
};
|
|
1217
|
+
}
|
|
1218
|
+
parseWorkflowRun(row) {
|
|
1219
|
+
let parsedSnapshot = row.snapshot;
|
|
1220
|
+
if (typeof parsedSnapshot === "string") {
|
|
1221
|
+
try {
|
|
1222
|
+
parsedSnapshot = JSON.parse(row.snapshot);
|
|
1223
|
+
} catch (e) {
|
|
1224
|
+
console.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
return {
|
|
1228
|
+
workflowName: row.workflow_name,
|
|
1229
|
+
runId: row.run_id,
|
|
1230
|
+
snapshot: parsedSnapshot,
|
|
1231
|
+
createdAt: this.ensureDate(row.createdAt),
|
|
1232
|
+
updatedAt: this.ensureDate(row.updatedAt),
|
|
1233
|
+
resourceId: row.resourceId
|
|
1234
|
+
};
|
|
1235
|
+
}
|
|
1236
|
+
async hasColumn(table, column) {
|
|
1237
|
+
const sql = `PRAGMA table_info(${table});`;
|
|
1238
|
+
const result = await this.executeQuery({ sql, params: [] });
|
|
1239
|
+
if (!result || !Array.isArray(result)) return false;
|
|
1240
|
+
return result.some((col) => col.name === column || col.name === column.toLowerCase());
|
|
1241
|
+
}
|
|
1242
|
+
async getWorkflowRuns({
|
|
1243
|
+
workflowName,
|
|
1244
|
+
fromDate,
|
|
1245
|
+
toDate,
|
|
1246
|
+
limit,
|
|
1247
|
+
offset,
|
|
1248
|
+
resourceId
|
|
1249
|
+
} = {}) {
|
|
1250
|
+
const fullTableName = this.getTableName(TABLE_WORKFLOW_SNAPSHOT);
|
|
1251
|
+
try {
|
|
1252
|
+
const builder = createSqlBuilder().select().from(fullTableName);
|
|
1253
|
+
const countBuilder = createSqlBuilder().count().from(fullTableName);
|
|
1254
|
+
if (workflowName) builder.whereAnd("workflow_name = ?", workflowName);
|
|
1255
|
+
if (resourceId) {
|
|
1256
|
+
const hasResourceId = await this.hasColumn(fullTableName, "resourceId");
|
|
1257
|
+
if (hasResourceId) {
|
|
1258
|
+
builder.whereAnd("resourceId = ?", resourceId);
|
|
1259
|
+
countBuilder.whereAnd("resourceId = ?", resourceId);
|
|
1260
|
+
} else {
|
|
1261
|
+
console.warn(`[${fullTableName}] resourceId column not found. Skipping resourceId filter.`);
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
if (fromDate) {
|
|
1265
|
+
builder.whereAnd("createdAt >= ?", fromDate instanceof Date ? fromDate.toISOString() : fromDate);
|
|
1266
|
+
countBuilder.whereAnd("createdAt >= ?", fromDate instanceof Date ? fromDate.toISOString() : fromDate);
|
|
1267
|
+
}
|
|
1268
|
+
if (toDate) {
|
|
1269
|
+
builder.whereAnd("createdAt <= ?", toDate instanceof Date ? toDate.toISOString() : toDate);
|
|
1270
|
+
countBuilder.whereAnd("createdAt <= ?", toDate instanceof Date ? toDate.toISOString() : toDate);
|
|
1271
|
+
}
|
|
1272
|
+
builder.orderBy("createdAt", "DESC");
|
|
1273
|
+
if (typeof limit === "number") builder.limit(limit);
|
|
1274
|
+
if (typeof offset === "number") builder.offset(offset);
|
|
1275
|
+
const { sql, params } = builder.build();
|
|
1276
|
+
let total = 0;
|
|
1277
|
+
if (limit !== void 0 && offset !== void 0) {
|
|
1278
|
+
const { sql: countSql, params: countParams } = countBuilder.build();
|
|
1279
|
+
const countResult = await this.executeQuery({ sql: countSql, params: countParams, first: true });
|
|
1280
|
+
total = Number(countResult?.count ?? 0);
|
|
1281
|
+
}
|
|
1282
|
+
const results = await this.executeQuery({ sql, params });
|
|
1283
|
+
const runs = (isArrayOfRecords(results) ? results : []).map((row) => this.parseWorkflowRun(row));
|
|
1284
|
+
return { runs, total: total || runs.length };
|
|
1285
|
+
} catch (error) {
|
|
1286
|
+
this.logger.error("Error getting workflow runs:", {
|
|
1287
|
+
message: error instanceof Error ? error.message : String(error)
|
|
1288
|
+
});
|
|
1289
|
+
throw error;
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
async getWorkflowRunById({
|
|
1293
|
+
runId,
|
|
1294
|
+
workflowName
|
|
1295
|
+
}) {
|
|
1296
|
+
const fullTableName = this.getTableName(TABLE_WORKFLOW_SNAPSHOT);
|
|
1297
|
+
try {
|
|
1298
|
+
const conditions = [];
|
|
1299
|
+
const params = [];
|
|
1300
|
+
if (runId) {
|
|
1301
|
+
conditions.push("run_id = ?");
|
|
1302
|
+
params.push(runId);
|
|
1303
|
+
}
|
|
1304
|
+
if (workflowName) {
|
|
1305
|
+
conditions.push("workflow_name = ?");
|
|
1306
|
+
params.push(workflowName);
|
|
1307
|
+
}
|
|
1308
|
+
const whereClause = conditions.length > 0 ? "WHERE " + conditions.join(" AND ") : "";
|
|
1309
|
+
const sql = `SELECT * FROM ${fullTableName} ${whereClause} ORDER BY createdAt DESC LIMIT 1`;
|
|
1310
|
+
const result = await this.executeQuery({ sql, params, first: true });
|
|
1311
|
+
if (!result) return null;
|
|
1312
|
+
return this.parseWorkflowRun(result);
|
|
1313
|
+
} catch (error) {
|
|
1314
|
+
this.logger.error("Error getting workflow run by ID:", {
|
|
1315
|
+
message: error instanceof Error ? error.message : String(error)
|
|
1316
|
+
});
|
|
1317
|
+
throw error;
|
|
1318
|
+
}
|
|
928
1319
|
}
|
|
929
1320
|
/**
|
|
930
1321
|
* Close the database connection
|