@mastra/cloudflare-d1 1.0.0-beta.1 → 1.0.0-beta.10
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/CHANGELOG.md +478 -0
- package/dist/docs/README.md +31 -0
- package/dist/docs/SKILL.md +32 -0
- package/dist/docs/SOURCE_MAP.json +6 -0
- package/dist/docs/storage/01-reference.md +110 -0
- package/dist/index.cjs +1079 -1116
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1077 -1117
- package/dist/index.js.map +1 -1
- package/dist/storage/{domains/operations → db}/index.d.ts +42 -6
- package/dist/storage/db/index.d.ts.map +1 -0
- package/dist/storage/domains/memory/index.d.ts +6 -5
- package/dist/storage/domains/memory/index.d.ts.map +1 -1
- package/dist/storage/domains/scores/index.d.ts +12 -34
- package/dist/storage/domains/scores/index.d.ts.map +1 -1
- package/dist/storage/domains/workflows/index.d.ts +14 -14
- package/dist/storage/domains/workflows/index.d.ts.map +1 -1
- package/dist/storage/index.d.ts +55 -177
- package/dist/storage/index.d.ts.map +1 -1
- package/package.json +9 -9
- package/dist/storage/domains/operations/index.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,11 +1,28 @@
|
|
|
1
1
|
import { MastraError, ErrorCategory, ErrorDomain } from '@mastra/core/error';
|
|
2
|
-
import {
|
|
2
|
+
import { MemoryStorage, TABLE_SCHEMAS, TABLE_THREADS, TABLE_MESSAGES, TABLE_RESOURCES, ensureDate, createStorageErrorId, normalizePerPage, calculatePagination, serializeDate, ScoresStorage, TABLE_SCORERS, WorkflowsStorage, TABLE_WORKFLOW_SNAPSHOT, MastraStorage, getSqlType, getDefaultValue, transformScoreRow as transformScoreRow$1 } from '@mastra/core/storage';
|
|
3
3
|
import Cloudflare from 'cloudflare';
|
|
4
4
|
import { MessageList } from '@mastra/core/agent';
|
|
5
|
+
import { MastraBase } from '@mastra/core/base';
|
|
5
6
|
import { parseSqlIdentifier } from '@mastra/core/utils';
|
|
6
7
|
import { saveScorePayloadSchema } from '@mastra/core/evals';
|
|
7
8
|
|
|
8
9
|
// src/storage/index.ts
|
|
10
|
+
|
|
11
|
+
// src/storage/domains/utils.ts
|
|
12
|
+
function isArrayOfRecords(value) {
|
|
13
|
+
return value && Array.isArray(value) && value.length > 0;
|
|
14
|
+
}
|
|
15
|
+
function deserializeValue(value, type) {
|
|
16
|
+
if (value === null || value === void 0) return null;
|
|
17
|
+
if (typeof value === "string" && (value.startsWith("{") || value.startsWith("["))) {
|
|
18
|
+
try {
|
|
19
|
+
return JSON.parse(value);
|
|
20
|
+
} catch {
|
|
21
|
+
return value;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return value;
|
|
25
|
+
}
|
|
9
26
|
var SqlBuilder = class {
|
|
10
27
|
sql = "";
|
|
11
28
|
params = [];
|
|
@@ -236,1127 +253,1201 @@ function parseSelectIdentifier(column) {
|
|
|
236
253
|
return column;
|
|
237
254
|
}
|
|
238
255
|
|
|
239
|
-
// src/storage/
|
|
240
|
-
function
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
try {
|
|
247
|
-
return JSON.parse(value);
|
|
248
|
-
} catch {
|
|
249
|
-
return value;
|
|
250
|
-
}
|
|
256
|
+
// src/storage/db/index.ts
|
|
257
|
+
function resolveD1Config(config) {
|
|
258
|
+
if ("client" in config) {
|
|
259
|
+
return {
|
|
260
|
+
client: config.client,
|
|
261
|
+
tablePrefix: config.tablePrefix
|
|
262
|
+
};
|
|
251
263
|
}
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
operations;
|
|
258
|
-
constructor({ operations }) {
|
|
259
|
-
super();
|
|
260
|
-
this.operations = operations;
|
|
264
|
+
if ("binding" in config) {
|
|
265
|
+
return {
|
|
266
|
+
binding: config.binding,
|
|
267
|
+
tablePrefix: config.tablePrefix
|
|
268
|
+
};
|
|
261
269
|
}
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
270
|
+
const cfClient = new Cloudflare({ apiToken: config.apiToken });
|
|
271
|
+
return {
|
|
272
|
+
client: {
|
|
273
|
+
query: ({ sql, params }) => {
|
|
274
|
+
return cfClient.d1.database.query(config.databaseId, {
|
|
275
|
+
account_id: config.accountId,
|
|
276
|
+
sql,
|
|
277
|
+
params
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
},
|
|
281
|
+
tablePrefix: config.tablePrefix
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
var D1DB = class extends MastraBase {
|
|
285
|
+
client;
|
|
286
|
+
binding;
|
|
287
|
+
tablePrefix;
|
|
288
|
+
constructor(config) {
|
|
289
|
+
super({
|
|
290
|
+
component: "STORAGE",
|
|
291
|
+
name: "D1_DB"
|
|
266
292
|
});
|
|
267
|
-
|
|
293
|
+
this.client = config.client;
|
|
294
|
+
this.binding = config.binding;
|
|
295
|
+
this.tablePrefix = config.tablePrefix || "";
|
|
296
|
+
}
|
|
297
|
+
async hasColumn(table, column) {
|
|
298
|
+
const fullTableName = table.startsWith(this.tablePrefix) ? table : `${this.tablePrefix}${table}`;
|
|
299
|
+
const sql = `PRAGMA table_info(${fullTableName});`;
|
|
300
|
+
const result = await this.executeQuery({ sql, params: [] });
|
|
301
|
+
if (!result || !Array.isArray(result)) return false;
|
|
302
|
+
return result.some((col) => col.name === column || col.name === column.toLowerCase());
|
|
303
|
+
}
|
|
304
|
+
getTableName(tableName) {
|
|
305
|
+
return `${this.tablePrefix}${tableName}`;
|
|
306
|
+
}
|
|
307
|
+
formatSqlParams(params) {
|
|
308
|
+
return params.map((p) => p === void 0 || p === null ? null : p);
|
|
309
|
+
}
|
|
310
|
+
async executeWorkersBindingQuery({
|
|
311
|
+
sql,
|
|
312
|
+
params = [],
|
|
313
|
+
first = false
|
|
314
|
+
}) {
|
|
315
|
+
if (!this.binding) {
|
|
316
|
+
throw new Error("Workers binding is not configured");
|
|
317
|
+
}
|
|
268
318
|
try {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
319
|
+
const statement = this.binding.prepare(sql);
|
|
320
|
+
const formattedParams = this.formatSqlParams(params);
|
|
321
|
+
let result;
|
|
322
|
+
if (formattedParams.length > 0) {
|
|
323
|
+
if (first) {
|
|
324
|
+
result = await statement.bind(...formattedParams).first();
|
|
325
|
+
if (!result) return null;
|
|
326
|
+
return result;
|
|
327
|
+
} else {
|
|
328
|
+
result = await statement.bind(...formattedParams).all();
|
|
329
|
+
const results = result.results || [];
|
|
330
|
+
return results;
|
|
331
|
+
}
|
|
332
|
+
} else {
|
|
333
|
+
if (first) {
|
|
334
|
+
result = await statement.first();
|
|
335
|
+
if (!result) return null;
|
|
336
|
+
return result;
|
|
337
|
+
} else {
|
|
338
|
+
result = await statement.all();
|
|
339
|
+
const results = result.results || [];
|
|
340
|
+
return results;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
275
343
|
} catch (error) {
|
|
276
|
-
|
|
344
|
+
throw new MastraError(
|
|
277
345
|
{
|
|
278
|
-
id: "
|
|
346
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "WORKERS_BINDING_QUERY", "FAILED"),
|
|
279
347
|
domain: ErrorDomain.STORAGE,
|
|
280
348
|
category: ErrorCategory.THIRD_PARTY,
|
|
281
|
-
|
|
282
|
-
details: { resourceId }
|
|
349
|
+
details: { sql }
|
|
283
350
|
},
|
|
284
351
|
error
|
|
285
352
|
);
|
|
286
|
-
this.logger?.error(mastraError.toString());
|
|
287
|
-
this.logger?.trackException(mastraError);
|
|
288
|
-
return null;
|
|
289
353
|
}
|
|
290
354
|
}
|
|
291
|
-
async
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
};
|
|
300
|
-
const processedRecord = await this.operations.processRecord(resourceToSave);
|
|
301
|
-
const columns = Object.keys(processedRecord);
|
|
302
|
-
const values = Object.values(processedRecord);
|
|
303
|
-
const updateMap = {
|
|
304
|
-
workingMemory: "excluded.workingMemory",
|
|
305
|
-
metadata: "excluded.metadata",
|
|
306
|
-
createdAt: "excluded.createdAt",
|
|
307
|
-
updatedAt: "excluded.updatedAt"
|
|
308
|
-
};
|
|
309
|
-
const query = createSqlBuilder().insert(fullTableName, columns, values, ["id"], updateMap);
|
|
310
|
-
const { sql, params } = query.build();
|
|
355
|
+
async executeRestQuery({
|
|
356
|
+
sql,
|
|
357
|
+
params = [],
|
|
358
|
+
first = false
|
|
359
|
+
}) {
|
|
360
|
+
if (!this.client) {
|
|
361
|
+
throw new Error("D1 client is not configured");
|
|
362
|
+
}
|
|
311
363
|
try {
|
|
312
|
-
|
|
313
|
-
|
|
364
|
+
const formattedParams = this.formatSqlParams(params);
|
|
365
|
+
const response = await this.client.query({
|
|
366
|
+
sql,
|
|
367
|
+
params: formattedParams
|
|
368
|
+
});
|
|
369
|
+
const result = response.result || [];
|
|
370
|
+
const results = result.flatMap((r) => r.results || []);
|
|
371
|
+
if (first) {
|
|
372
|
+
return results[0] || null;
|
|
373
|
+
}
|
|
374
|
+
return results;
|
|
314
375
|
} catch (error) {
|
|
315
376
|
throw new MastraError(
|
|
316
377
|
{
|
|
317
|
-
id: "
|
|
378
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "REST_QUERY", "FAILED"),
|
|
318
379
|
domain: ErrorDomain.STORAGE,
|
|
319
380
|
category: ErrorCategory.THIRD_PARTY,
|
|
320
|
-
|
|
321
|
-
details: { resourceId: resource.id }
|
|
381
|
+
details: { sql }
|
|
322
382
|
},
|
|
323
383
|
error
|
|
324
384
|
);
|
|
325
385
|
}
|
|
326
386
|
}
|
|
327
|
-
async
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
const newResource = {
|
|
335
|
-
id: resourceId,
|
|
336
|
-
workingMemory,
|
|
337
|
-
metadata: metadata || {},
|
|
338
|
-
createdAt: /* @__PURE__ */ new Date(),
|
|
339
|
-
updatedAt: /* @__PURE__ */ new Date()
|
|
340
|
-
};
|
|
341
|
-
return this.saveResource({ resource: newResource });
|
|
387
|
+
async executeQuery(options) {
|
|
388
|
+
if (this.binding) {
|
|
389
|
+
return this.executeWorkersBindingQuery(options);
|
|
390
|
+
} else if (this.client) {
|
|
391
|
+
return this.executeRestQuery(options);
|
|
392
|
+
} else {
|
|
393
|
+
throw new Error("Neither binding nor client is configured");
|
|
342
394
|
}
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
...existingResource,
|
|
346
|
-
workingMemory: workingMemory !== void 0 ? workingMemory : existingResource.workingMemory,
|
|
347
|
-
metadata: {
|
|
348
|
-
...existingResource.metadata,
|
|
349
|
-
...metadata
|
|
350
|
-
},
|
|
351
|
-
updatedAt
|
|
352
|
-
};
|
|
353
|
-
const fullTableName = this.operations.getTableName(TABLE_RESOURCES);
|
|
354
|
-
const columns = ["workingMemory", "metadata", "updatedAt"];
|
|
355
|
-
const values = [updatedResource.workingMemory, JSON.stringify(updatedResource.metadata), updatedAt.toISOString()];
|
|
356
|
-
const query = createSqlBuilder().update(fullTableName, columns, values).where("id = ?", resourceId);
|
|
357
|
-
const { sql, params } = query.build();
|
|
395
|
+
}
|
|
396
|
+
async getTableColumns(tableName) {
|
|
358
397
|
try {
|
|
359
|
-
|
|
360
|
-
|
|
398
|
+
const sql = `PRAGMA table_info(${tableName})`;
|
|
399
|
+
const result = await this.executeQuery({ sql });
|
|
400
|
+
if (!result || !Array.isArray(result)) {
|
|
401
|
+
return [];
|
|
402
|
+
}
|
|
403
|
+
return result.map((row) => ({
|
|
404
|
+
name: row.name,
|
|
405
|
+
type: row.type
|
|
406
|
+
}));
|
|
407
|
+
} catch (error) {
|
|
408
|
+
this.logger.warn(`Failed to get table columns for ${tableName}:`, error);
|
|
409
|
+
return [];
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
serializeValue(value) {
|
|
413
|
+
if (value === null || value === void 0) {
|
|
414
|
+
return null;
|
|
415
|
+
}
|
|
416
|
+
if (value instanceof Date) {
|
|
417
|
+
return value.toISOString();
|
|
418
|
+
}
|
|
419
|
+
if (typeof value === "object") {
|
|
420
|
+
return JSON.stringify(value);
|
|
421
|
+
}
|
|
422
|
+
return value;
|
|
423
|
+
}
|
|
424
|
+
getSqlType(type) {
|
|
425
|
+
switch (type) {
|
|
426
|
+
case "bigint":
|
|
427
|
+
return "INTEGER";
|
|
428
|
+
// SQLite uses INTEGER for all integer sizes
|
|
429
|
+
case "jsonb":
|
|
430
|
+
return "TEXT";
|
|
431
|
+
// Store JSON as TEXT in SQLite
|
|
432
|
+
case "boolean":
|
|
433
|
+
return "INTEGER";
|
|
434
|
+
// SQLite uses 0/1 for booleans
|
|
435
|
+
default:
|
|
436
|
+
return getSqlType(type);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
getDefaultValue(type) {
|
|
440
|
+
return getDefaultValue(type);
|
|
441
|
+
}
|
|
442
|
+
async createTable({
|
|
443
|
+
tableName,
|
|
444
|
+
schema
|
|
445
|
+
}) {
|
|
446
|
+
try {
|
|
447
|
+
const fullTableName = this.getTableName(tableName);
|
|
448
|
+
const columnDefinitions = Object.entries(schema).map(([colName, colDef]) => {
|
|
449
|
+
const type = this.getSqlType(colDef.type);
|
|
450
|
+
const nullable = colDef.nullable === false ? "NOT NULL" : "";
|
|
451
|
+
const primaryKey = colDef.primaryKey ? "PRIMARY KEY" : "";
|
|
452
|
+
return `${colName} ${type} ${nullable} ${primaryKey}`.trim();
|
|
453
|
+
});
|
|
454
|
+
const tableConstraints = [];
|
|
455
|
+
if (tableName === TABLE_WORKFLOW_SNAPSHOT) {
|
|
456
|
+
tableConstraints.push("UNIQUE (workflow_name, run_id)");
|
|
457
|
+
}
|
|
458
|
+
const query = createSqlBuilder().createTable(fullTableName, columnDefinitions, tableConstraints);
|
|
459
|
+
const { sql, params } = query.build();
|
|
460
|
+
await this.executeQuery({ sql, params });
|
|
461
|
+
this.logger.debug(`Created table ${fullTableName}`);
|
|
361
462
|
} catch (error) {
|
|
362
463
|
throw new MastraError(
|
|
363
464
|
{
|
|
364
|
-
id: "
|
|
465
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "CREATE_TABLE", "FAILED"),
|
|
365
466
|
domain: ErrorDomain.STORAGE,
|
|
366
467
|
category: ErrorCategory.THIRD_PARTY,
|
|
367
|
-
|
|
368
|
-
details: { resourceId }
|
|
468
|
+
details: { tableName }
|
|
369
469
|
},
|
|
370
470
|
error
|
|
371
471
|
);
|
|
372
472
|
}
|
|
373
473
|
}
|
|
374
|
-
async
|
|
375
|
-
const thread = await this.operations.load({
|
|
376
|
-
tableName: TABLE_THREADS,
|
|
377
|
-
keys: { id: threadId }
|
|
378
|
-
});
|
|
379
|
-
if (!thread) return null;
|
|
474
|
+
async clearTable({ tableName }) {
|
|
380
475
|
try {
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
};
|
|
476
|
+
const fullTableName = this.getTableName(tableName);
|
|
477
|
+
const query = createSqlBuilder().delete(fullTableName);
|
|
478
|
+
const { sql, params } = query.build();
|
|
479
|
+
await this.executeQuery({ sql, params });
|
|
480
|
+
this.logger.debug(`Cleared table ${fullTableName}`);
|
|
387
481
|
} catch (error) {
|
|
388
|
-
|
|
482
|
+
throw new MastraError(
|
|
389
483
|
{
|
|
390
|
-
id: "
|
|
484
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "CLEAR_TABLE", "FAILED"),
|
|
391
485
|
domain: ErrorDomain.STORAGE,
|
|
392
486
|
category: ErrorCategory.THIRD_PARTY,
|
|
393
|
-
|
|
394
|
-
details: { threadId }
|
|
487
|
+
details: { tableName }
|
|
395
488
|
},
|
|
396
489
|
error
|
|
397
490
|
);
|
|
398
|
-
this.logger?.error(mastraError.toString());
|
|
399
|
-
this.logger?.trackException(mastraError);
|
|
400
|
-
return null;
|
|
401
491
|
}
|
|
402
492
|
}
|
|
403
|
-
async
|
|
404
|
-
const { resourceId, page = 0, perPage: perPageInput, orderBy } = args;
|
|
405
|
-
const perPage = normalizePerPage(perPageInput, 100);
|
|
406
|
-
if (page < 0) {
|
|
407
|
-
throw new MastraError(
|
|
408
|
-
{
|
|
409
|
-
id: "STORAGE_CLOUDFLARE_D1_LIST_THREADS_BY_RESOURCE_ID_INVALID_PAGE",
|
|
410
|
-
domain: ErrorDomain.STORAGE,
|
|
411
|
-
category: ErrorCategory.USER,
|
|
412
|
-
details: { page }
|
|
413
|
-
},
|
|
414
|
-
new Error("page must be >= 0")
|
|
415
|
-
);
|
|
416
|
-
}
|
|
417
|
-
const { offset, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
|
|
418
|
-
const { field, direction } = this.parseOrderBy(orderBy);
|
|
419
|
-
const fullTableName = this.operations.getTableName(TABLE_THREADS);
|
|
420
|
-
const mapRowToStorageThreadType = (row) => ({
|
|
421
|
-
...row,
|
|
422
|
-
createdAt: ensureDate(row.createdAt),
|
|
423
|
-
updatedAt: ensureDate(row.updatedAt),
|
|
424
|
-
metadata: typeof row.metadata === "string" ? JSON.parse(row.metadata || "{}") : row.metadata || {}
|
|
425
|
-
});
|
|
493
|
+
async dropTable({ tableName }) {
|
|
426
494
|
try {
|
|
427
|
-
const
|
|
428
|
-
const
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
const selectQuery = createSqlBuilder().select("*").from(fullTableName).where("resourceId = ?", resourceId).orderBy(field, direction).limit(limitValue).offset(offset);
|
|
432
|
-
const results = await this.operations.executeQuery(selectQuery.build());
|
|
433
|
-
const threads = results.map(mapRowToStorageThreadType);
|
|
434
|
-
return {
|
|
435
|
-
threads,
|
|
436
|
-
total,
|
|
437
|
-
page,
|
|
438
|
-
perPage: perPageForResponse,
|
|
439
|
-
hasMore: perPageInput === false ? false : offset + perPage < total
|
|
440
|
-
};
|
|
495
|
+
const fullTableName = this.getTableName(tableName);
|
|
496
|
+
const sql = `DROP TABLE IF EXISTS ${fullTableName}`;
|
|
497
|
+
await this.executeQuery({ sql });
|
|
498
|
+
this.logger.debug(`Dropped table ${fullTableName}`);
|
|
441
499
|
} catch (error) {
|
|
442
|
-
|
|
500
|
+
throw new MastraError(
|
|
443
501
|
{
|
|
444
|
-
id: "
|
|
502
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "DROP_TABLE", "FAILED"),
|
|
445
503
|
domain: ErrorDomain.STORAGE,
|
|
446
504
|
category: ErrorCategory.THIRD_PARTY,
|
|
447
|
-
|
|
448
|
-
details: { resourceId }
|
|
505
|
+
details: { tableName }
|
|
449
506
|
},
|
|
450
507
|
error
|
|
451
508
|
);
|
|
452
|
-
this.logger?.error(mastraError.toString());
|
|
453
|
-
this.logger?.trackException(mastraError);
|
|
454
|
-
return {
|
|
455
|
-
threads: [],
|
|
456
|
-
total: 0,
|
|
457
|
-
page,
|
|
458
|
-
perPage: perPageForResponse,
|
|
459
|
-
hasMore: false
|
|
460
|
-
};
|
|
461
509
|
}
|
|
462
510
|
}
|
|
463
|
-
async
|
|
464
|
-
const fullTableName = this.operations.getTableName(TABLE_THREADS);
|
|
465
|
-
const threadToSave = {
|
|
466
|
-
id: thread.id,
|
|
467
|
-
resourceId: thread.resourceId,
|
|
468
|
-
title: thread.title,
|
|
469
|
-
metadata: thread.metadata ? JSON.stringify(thread.metadata) : null,
|
|
470
|
-
createdAt: thread.createdAt.toISOString(),
|
|
471
|
-
updatedAt: thread.updatedAt.toISOString()
|
|
472
|
-
};
|
|
473
|
-
const processedRecord = await this.operations.processRecord(threadToSave);
|
|
474
|
-
const columns = Object.keys(processedRecord);
|
|
475
|
-
const values = Object.values(processedRecord);
|
|
476
|
-
const updateMap = {
|
|
477
|
-
resourceId: "excluded.resourceId",
|
|
478
|
-
title: "excluded.title",
|
|
479
|
-
metadata: "excluded.metadata",
|
|
480
|
-
createdAt: "excluded.createdAt",
|
|
481
|
-
updatedAt: "excluded.updatedAt"
|
|
482
|
-
};
|
|
483
|
-
const query = createSqlBuilder().insert(fullTableName, columns, values, ["id"], updateMap);
|
|
484
|
-
const { sql, params } = query.build();
|
|
511
|
+
async alterTable(args) {
|
|
485
512
|
try {
|
|
486
|
-
|
|
487
|
-
|
|
513
|
+
const fullTableName = this.getTableName(args.tableName);
|
|
514
|
+
const existingColumns = await this.getTableColumns(fullTableName);
|
|
515
|
+
const existingColumnNames = new Set(existingColumns.map((col) => col.name));
|
|
516
|
+
for (const [columnName, column] of Object.entries(args.schema)) {
|
|
517
|
+
if (!existingColumnNames.has(columnName) && args.ifNotExists.includes(columnName)) {
|
|
518
|
+
const sqlType = this.getSqlType(column.type);
|
|
519
|
+
const defaultValue = this.getDefaultValue(column.type);
|
|
520
|
+
const sql = `ALTER TABLE ${fullTableName} ADD COLUMN ${columnName} ${sqlType} ${defaultValue}`;
|
|
521
|
+
await this.executeQuery({ sql });
|
|
522
|
+
this.logger.debug(`Added column ${columnName} to table ${fullTableName}`);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
488
525
|
} catch (error) {
|
|
489
526
|
throw new MastraError(
|
|
490
527
|
{
|
|
491
|
-
id: "
|
|
528
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "ALTER_TABLE", "FAILED"),
|
|
492
529
|
domain: ErrorDomain.STORAGE,
|
|
493
530
|
category: ErrorCategory.THIRD_PARTY,
|
|
494
|
-
|
|
495
|
-
details: { threadId: thread.id }
|
|
531
|
+
details: { tableName: args.tableName }
|
|
496
532
|
},
|
|
497
533
|
error
|
|
498
534
|
);
|
|
499
535
|
}
|
|
500
536
|
}
|
|
501
|
-
async
|
|
502
|
-
id,
|
|
503
|
-
title,
|
|
504
|
-
metadata
|
|
505
|
-
}) {
|
|
506
|
-
const thread = await this.getThreadById({ threadId: id });
|
|
537
|
+
async insert({ tableName, record }) {
|
|
507
538
|
try {
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
const
|
|
512
|
-
const
|
|
513
|
-
...typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
|
|
514
|
-
...metadata
|
|
515
|
-
};
|
|
516
|
-
const updatedAt = /* @__PURE__ */ new Date();
|
|
517
|
-
const columns = ["title", "metadata", "updatedAt"];
|
|
518
|
-
const values = [title, JSON.stringify(mergedMetadata), updatedAt.toISOString()];
|
|
519
|
-
const query = createSqlBuilder().update(fullTableName, columns, values).where("id = ?", id);
|
|
539
|
+
const fullTableName = this.getTableName(tableName);
|
|
540
|
+
const processedRecord = await this.processRecord(record);
|
|
541
|
+
const columns = Object.keys(processedRecord);
|
|
542
|
+
const values = Object.values(processedRecord);
|
|
543
|
+
const query = createSqlBuilder().insert(fullTableName, columns, values);
|
|
520
544
|
const { sql, params } = query.build();
|
|
521
|
-
await this.
|
|
522
|
-
return {
|
|
523
|
-
...thread,
|
|
524
|
-
title,
|
|
525
|
-
metadata: {
|
|
526
|
-
...typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
|
|
527
|
-
...metadata
|
|
528
|
-
},
|
|
529
|
-
updatedAt
|
|
530
|
-
};
|
|
545
|
+
await this.executeQuery({ sql, params });
|
|
531
546
|
} catch (error) {
|
|
532
547
|
throw new MastraError(
|
|
533
548
|
{
|
|
534
|
-
id: "
|
|
549
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "INSERT", "FAILED"),
|
|
535
550
|
domain: ErrorDomain.STORAGE,
|
|
536
551
|
category: ErrorCategory.THIRD_PARTY,
|
|
537
|
-
|
|
538
|
-
details: { threadId: id }
|
|
552
|
+
details: { tableName }
|
|
539
553
|
},
|
|
540
554
|
error
|
|
541
555
|
);
|
|
542
556
|
}
|
|
543
557
|
}
|
|
544
|
-
async
|
|
545
|
-
const fullTableName = this.operations.getTableName(TABLE_THREADS);
|
|
558
|
+
async batchInsert({ tableName, records }) {
|
|
546
559
|
try {
|
|
547
|
-
|
|
548
|
-
const
|
|
549
|
-
await
|
|
550
|
-
const
|
|
551
|
-
const
|
|
552
|
-
|
|
553
|
-
|
|
560
|
+
if (records.length === 0) return;
|
|
561
|
+
const fullTableName = this.getTableName(tableName);
|
|
562
|
+
const processedRecords = await Promise.all(records.map((record) => this.processRecord(record)));
|
|
563
|
+
const columns = Object.keys(processedRecords[0] || {});
|
|
564
|
+
for (const record of processedRecords) {
|
|
565
|
+
const values = Object.values(record);
|
|
566
|
+
const query = createSqlBuilder().insert(fullTableName, columns, values);
|
|
567
|
+
const { sql, params } = query.build();
|
|
568
|
+
await this.executeQuery({ sql, params });
|
|
569
|
+
}
|
|
554
570
|
} catch (error) {
|
|
555
571
|
throw new MastraError(
|
|
556
572
|
{
|
|
557
|
-
id: "
|
|
573
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "BATCH_INSERT", "FAILED"),
|
|
558
574
|
domain: ErrorDomain.STORAGE,
|
|
559
575
|
category: ErrorCategory.THIRD_PARTY,
|
|
560
|
-
|
|
561
|
-
details: { threadId }
|
|
576
|
+
details: { tableName }
|
|
562
577
|
},
|
|
563
578
|
error
|
|
564
579
|
);
|
|
565
580
|
}
|
|
566
581
|
}
|
|
567
|
-
async
|
|
568
|
-
const { messages } = args;
|
|
569
|
-
if (messages.length === 0) return { messages: [] };
|
|
582
|
+
async load({ tableName, keys }) {
|
|
570
583
|
try {
|
|
571
|
-
const
|
|
572
|
-
const
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
if (
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
}
|
|
581
|
-
if (!message.role) {
|
|
582
|
-
throw new Error(`Message at index ${i} missing role`);
|
|
583
|
-
}
|
|
584
|
-
if (!message.resourceId) {
|
|
585
|
-
throw new Error(`Message at index ${i} missing resourceId`);
|
|
586
|
-
}
|
|
587
|
-
const thread = await this.getThreadById({ threadId: message.threadId });
|
|
588
|
-
if (!thread) {
|
|
589
|
-
throw new Error(`Thread ${message.threadId} not found`);
|
|
584
|
+
const fullTableName = this.getTableName(tableName);
|
|
585
|
+
const query = createSqlBuilder().select("*").from(fullTableName);
|
|
586
|
+
let firstKey = true;
|
|
587
|
+
for (const [key, value] of Object.entries(keys)) {
|
|
588
|
+
if (firstKey) {
|
|
589
|
+
query.where(`${key} = ?`, value);
|
|
590
|
+
firstKey = false;
|
|
591
|
+
} else {
|
|
592
|
+
query.andWhere(`${key} = ?`, value);
|
|
590
593
|
}
|
|
591
594
|
}
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
await Promise.all([
|
|
605
|
-
this.operations.batchUpsert({
|
|
606
|
-
tableName: TABLE_MESSAGES,
|
|
607
|
-
records: messagesToInsert
|
|
608
|
-
}),
|
|
609
|
-
// Update thread's updatedAt timestamp
|
|
610
|
-
this.operations.executeQuery({
|
|
611
|
-
sql: `UPDATE ${this.operations.getTableName(TABLE_THREADS)} SET updatedAt = ? WHERE id = ?`,
|
|
612
|
-
params: [now.toISOString(), threadId]
|
|
613
|
-
})
|
|
614
|
-
]);
|
|
615
|
-
this.logger.debug(`Saved ${messages.length} messages`);
|
|
616
|
-
const list = new MessageList().add(messages, "memory");
|
|
617
|
-
return { messages: list.get.all.db() };
|
|
595
|
+
query.orderBy("createdAt", "DESC");
|
|
596
|
+
query.limit(1);
|
|
597
|
+
const { sql, params } = query.build();
|
|
598
|
+
const result = await this.executeQuery({ sql, params, first: true });
|
|
599
|
+
if (!result) {
|
|
600
|
+
return null;
|
|
601
|
+
}
|
|
602
|
+
const deserializedResult = {};
|
|
603
|
+
for (const [key, value] of Object.entries(result)) {
|
|
604
|
+
deserializedResult[key] = deserializeValue(value);
|
|
605
|
+
}
|
|
606
|
+
return deserializedResult;
|
|
618
607
|
} catch (error) {
|
|
619
608
|
throw new MastraError(
|
|
620
609
|
{
|
|
621
|
-
id: "
|
|
610
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "LOAD", "FAILED"),
|
|
622
611
|
domain: ErrorDomain.STORAGE,
|
|
623
612
|
category: ErrorCategory.THIRD_PARTY,
|
|
624
|
-
|
|
613
|
+
details: { tableName }
|
|
625
614
|
},
|
|
626
615
|
error
|
|
627
616
|
);
|
|
628
617
|
}
|
|
629
618
|
}
|
|
630
|
-
async
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
const params = [];
|
|
635
|
-
let paramIdx = 1;
|
|
636
|
-
for (const inc of include) {
|
|
637
|
-
const { id, withPreviousMessages = 0, withNextMessages = 0 } = inc;
|
|
638
|
-
const searchId = inc.threadId || threadId;
|
|
639
|
-
unionQueries.push(`
|
|
640
|
-
SELECT * FROM (
|
|
641
|
-
WITH ordered_messages AS (
|
|
642
|
-
SELECT
|
|
643
|
-
*,
|
|
644
|
-
ROW_NUMBER() OVER (ORDER BY createdAt ASC) AS row_num
|
|
645
|
-
FROM ${this.operations.getTableName(TABLE_MESSAGES)}
|
|
646
|
-
WHERE thread_id = ?
|
|
647
|
-
)
|
|
648
|
-
SELECT
|
|
649
|
-
m.id,
|
|
650
|
-
m.content,
|
|
651
|
-
m.role,
|
|
652
|
-
m.type,
|
|
653
|
-
m.createdAt,
|
|
654
|
-
m.thread_id AS threadId,
|
|
655
|
-
m.resourceId
|
|
656
|
-
FROM ordered_messages m
|
|
657
|
-
WHERE m.id = ?
|
|
658
|
-
OR EXISTS (
|
|
659
|
-
SELECT 1 FROM ordered_messages target
|
|
660
|
-
WHERE target.id = ?
|
|
661
|
-
AND (
|
|
662
|
-
(m.row_num <= target.row_num + ? AND m.row_num > target.row_num)
|
|
663
|
-
OR
|
|
664
|
-
(m.row_num >= target.row_num - ? AND m.row_num < target.row_num)
|
|
665
|
-
)
|
|
666
|
-
)
|
|
667
|
-
) AS query_${paramIdx}
|
|
668
|
-
`);
|
|
669
|
-
params.push(searchId, id, id, withNextMessages, withPreviousMessages);
|
|
670
|
-
paramIdx++;
|
|
671
|
-
}
|
|
672
|
-
const finalQuery = unionQueries.join(" UNION ALL ") + " ORDER BY createdAt ASC";
|
|
673
|
-
const messages = await this.operations.executeQuery({ sql: finalQuery, params });
|
|
674
|
-
if (!Array.isArray(messages)) {
|
|
675
|
-
return [];
|
|
619
|
+
async processRecord(record) {
|
|
620
|
+
const processed = {};
|
|
621
|
+
for (const [key, value] of Object.entries(record)) {
|
|
622
|
+
processed[key] = this.serializeValue(value);
|
|
676
623
|
}
|
|
677
|
-
|
|
678
|
-
const processedMsg = {};
|
|
679
|
-
for (const [key, value] of Object.entries(message)) {
|
|
680
|
-
if (key === `type` && value === `v2`) continue;
|
|
681
|
-
processedMsg[key] = deserializeValue(value);
|
|
682
|
-
}
|
|
683
|
-
return processedMsg;
|
|
684
|
-
});
|
|
685
|
-
return processedMessages;
|
|
624
|
+
return processed;
|
|
686
625
|
}
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
626
|
+
/**
|
|
627
|
+
* Upsert multiple records in a batch operation
|
|
628
|
+
* @param tableName The table to insert into
|
|
629
|
+
* @param records The records to insert
|
|
630
|
+
*/
|
|
631
|
+
async batchUpsert({ tableName, records }) {
|
|
632
|
+
if (records.length === 0) return;
|
|
633
|
+
const fullTableName = this.getTableName(tableName);
|
|
691
634
|
try {
|
|
692
|
-
const
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
635
|
+
const batchSize = 50;
|
|
636
|
+
for (let i = 0; i < records.length; i += batchSize) {
|
|
637
|
+
const batch = records.slice(i, i + batchSize);
|
|
638
|
+
const recordsToInsert = batch;
|
|
639
|
+
if (recordsToInsert.length > 0) {
|
|
640
|
+
const firstRecord = recordsToInsert[0];
|
|
641
|
+
const columns = Object.keys(firstRecord || {});
|
|
642
|
+
for (const record of recordsToInsert) {
|
|
643
|
+
const values = columns.map((col) => {
|
|
644
|
+
if (!record) return null;
|
|
645
|
+
const value = typeof col === "string" ? record[col] : null;
|
|
646
|
+
return this.serializeValue(value);
|
|
647
|
+
});
|
|
648
|
+
const recordToUpsert = columns.reduce(
|
|
649
|
+
(acc, col) => {
|
|
650
|
+
if (col !== "createdAt") acc[col] = `excluded.${col}`;
|
|
651
|
+
return acc;
|
|
652
|
+
},
|
|
653
|
+
{}
|
|
654
|
+
);
|
|
655
|
+
const query = createSqlBuilder().insert(fullTableName, columns, values, ["id"], recordToUpsert);
|
|
656
|
+
const { sql, params } = query.build();
|
|
657
|
+
await this.executeQuery({ sql, params });
|
|
658
|
+
}
|
|
702
659
|
}
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
660
|
+
this.logger.debug(
|
|
661
|
+
`Processed batch ${Math.floor(i / batchSize) + 1} of ${Math.ceil(records.length / batchSize)}`
|
|
662
|
+
);
|
|
663
|
+
}
|
|
664
|
+
this.logger.debug(`Successfully batch upserted ${records.length} records into ${tableName}`);
|
|
708
665
|
} catch (error) {
|
|
709
|
-
|
|
666
|
+
throw new MastraError(
|
|
710
667
|
{
|
|
711
|
-
id: "
|
|
668
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "BATCH_UPSERT", "FAILED"),
|
|
712
669
|
domain: ErrorDomain.STORAGE,
|
|
713
670
|
category: ErrorCategory.THIRD_PARTY,
|
|
714
|
-
text: `Failed to
|
|
715
|
-
details: {
|
|
671
|
+
text: `Failed to batch upsert into ${tableName}: ${error instanceof Error ? error.message : String(error)}`,
|
|
672
|
+
details: { tableName }
|
|
716
673
|
},
|
|
717
674
|
error
|
|
718
675
|
);
|
|
719
|
-
this.logger?.error(mastraError.toString());
|
|
720
|
-
this.logger?.trackException(mastraError);
|
|
721
|
-
throw mastraError;
|
|
722
676
|
}
|
|
723
677
|
}
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
678
|
+
};
|
|
679
|
+
|
|
680
|
+
// src/storage/domains/memory/index.ts
|
|
681
|
+
var MemoryStorageD1 = class extends MemoryStorage {
|
|
682
|
+
#db;
|
|
683
|
+
constructor(config) {
|
|
684
|
+
super();
|
|
685
|
+
this.#db = new D1DB(resolveD1Config(config));
|
|
686
|
+
}
|
|
687
|
+
async init() {
|
|
688
|
+
await this.#db.createTable({ tableName: TABLE_THREADS, schema: TABLE_SCHEMAS[TABLE_THREADS] });
|
|
689
|
+
await this.#db.createTable({ tableName: TABLE_MESSAGES, schema: TABLE_SCHEMAS[TABLE_MESSAGES] });
|
|
690
|
+
await this.#db.createTable({ tableName: TABLE_RESOURCES, schema: TABLE_SCHEMAS[TABLE_RESOURCES] });
|
|
691
|
+
await this.#db.alterTable({
|
|
692
|
+
tableName: TABLE_MESSAGES,
|
|
693
|
+
schema: TABLE_SCHEMAS[TABLE_MESSAGES],
|
|
694
|
+
ifNotExists: ["resourceId"]
|
|
695
|
+
});
|
|
696
|
+
}
|
|
697
|
+
async dangerouslyClearAll() {
|
|
698
|
+
await this.#db.clearTable({ tableName: TABLE_MESSAGES });
|
|
699
|
+
await this.#db.clearTable({ tableName: TABLE_THREADS });
|
|
700
|
+
await this.#db.clearTable({ tableName: TABLE_RESOURCES });
|
|
701
|
+
}
|
|
702
|
+
async getResourceById({ resourceId }) {
|
|
703
|
+
const resource = await this.#db.load({
|
|
704
|
+
tableName: TABLE_RESOURCES,
|
|
705
|
+
keys: { id: resourceId }
|
|
706
|
+
});
|
|
707
|
+
if (!resource) return null;
|
|
708
|
+
try {
|
|
709
|
+
return {
|
|
710
|
+
...resource,
|
|
711
|
+
createdAt: ensureDate(resource.createdAt),
|
|
712
|
+
updatedAt: ensureDate(resource.updatedAt),
|
|
713
|
+
metadata: typeof resource.metadata === "string" ? JSON.parse(resource.metadata || "{}") : resource.metadata
|
|
714
|
+
};
|
|
715
|
+
} catch (error) {
|
|
716
|
+
const mastraError = new MastraError(
|
|
728
717
|
{
|
|
729
|
-
id: "
|
|
718
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "GET_RESOURCE_BY_ID", "FAILED"),
|
|
730
719
|
domain: ErrorDomain.STORAGE,
|
|
731
720
|
category: ErrorCategory.THIRD_PARTY,
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
new Error("threadId must be a non-empty string")
|
|
735
|
-
);
|
|
736
|
-
}
|
|
737
|
-
if (page < 0) {
|
|
738
|
-
throw new MastraError(
|
|
739
|
-
{
|
|
740
|
-
id: "STORAGE_CLOUDFLARE_D1_LIST_MESSAGES_INVALID_PAGE",
|
|
741
|
-
domain: ErrorDomain.STORAGE,
|
|
742
|
-
category: ErrorCategory.USER,
|
|
743
|
-
details: { page }
|
|
721
|
+
text: `Error processing resource ${resourceId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
722
|
+
details: { resourceId }
|
|
744
723
|
},
|
|
745
|
-
|
|
724
|
+
error
|
|
746
725
|
);
|
|
726
|
+
this.logger?.error(mastraError.toString());
|
|
727
|
+
this.logger?.trackException(mastraError);
|
|
728
|
+
return null;
|
|
747
729
|
}
|
|
748
|
-
|
|
749
|
-
|
|
730
|
+
}
|
|
731
|
+
async saveResource({ resource }) {
|
|
732
|
+
const fullTableName = this.#db.getTableName(TABLE_RESOURCES);
|
|
733
|
+
const resourceToSave = {
|
|
734
|
+
id: resource.id,
|
|
735
|
+
workingMemory: resource.workingMemory,
|
|
736
|
+
metadata: resource.metadata ? JSON.stringify(resource.metadata) : null,
|
|
737
|
+
createdAt: resource.createdAt,
|
|
738
|
+
updatedAt: resource.updatedAt
|
|
739
|
+
};
|
|
740
|
+
const processedRecord = await this.#db.processRecord(resourceToSave);
|
|
741
|
+
const columns = Object.keys(processedRecord);
|
|
742
|
+
const values = Object.values(processedRecord);
|
|
743
|
+
const updateMap = {
|
|
744
|
+
workingMemory: "excluded.workingMemory",
|
|
745
|
+
metadata: "excluded.metadata",
|
|
746
|
+
createdAt: "excluded.createdAt",
|
|
747
|
+
updatedAt: "excluded.updatedAt"
|
|
748
|
+
};
|
|
749
|
+
const query = createSqlBuilder().insert(fullTableName, columns, values, ["id"], updateMap);
|
|
750
|
+
const { sql, params } = query.build();
|
|
750
751
|
try {
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
SELECT id, content, role, type, createdAt, thread_id AS threadId, resourceId
|
|
754
|
-
FROM ${fullTableName}
|
|
755
|
-
WHERE thread_id = ?
|
|
756
|
-
`;
|
|
757
|
-
const queryParams = [threadId];
|
|
758
|
-
if (resourceId) {
|
|
759
|
-
query += ` AND resourceId = ?`;
|
|
760
|
-
queryParams.push(resourceId);
|
|
761
|
-
}
|
|
762
|
-
const dateRange = filter?.dateRange;
|
|
763
|
-
if (dateRange?.start) {
|
|
764
|
-
const startDate = dateRange.start instanceof Date ? serializeDate(dateRange.start) : serializeDate(new Date(dateRange.start));
|
|
765
|
-
query += ` AND createdAt >= ?`;
|
|
766
|
-
queryParams.push(startDate);
|
|
767
|
-
}
|
|
768
|
-
if (dateRange?.end) {
|
|
769
|
-
const endDate = dateRange.end instanceof Date ? serializeDate(dateRange.end) : serializeDate(new Date(dateRange.end));
|
|
770
|
-
query += ` AND createdAt <= ?`;
|
|
771
|
-
queryParams.push(endDate);
|
|
772
|
-
}
|
|
773
|
-
const { field, direction } = this.parseOrderBy(orderBy, "ASC");
|
|
774
|
-
query += ` ORDER BY "${field}" ${direction}`;
|
|
775
|
-
if (perPage !== Number.MAX_SAFE_INTEGER) {
|
|
776
|
-
query += ` LIMIT ? OFFSET ?`;
|
|
777
|
-
queryParams.push(perPage, offset);
|
|
778
|
-
}
|
|
779
|
-
const results = await this.operations.executeQuery({ sql: query, params: queryParams });
|
|
780
|
-
const paginatedMessages = (isArrayOfRecords(results) ? results : []).map((message) => {
|
|
781
|
-
const processedMsg = {};
|
|
782
|
-
for (const [key, value] of Object.entries(message)) {
|
|
783
|
-
if (key === `type` && value === `v2`) continue;
|
|
784
|
-
processedMsg[key] = deserializeValue(value);
|
|
785
|
-
}
|
|
786
|
-
return processedMsg;
|
|
787
|
-
});
|
|
788
|
-
const paginatedCount = paginatedMessages.length;
|
|
789
|
-
let countQuery = `SELECT count() as count FROM ${fullTableName} WHERE thread_id = ?`;
|
|
790
|
-
const countParams = [threadId];
|
|
791
|
-
if (resourceId) {
|
|
792
|
-
countQuery += ` AND resourceId = ?`;
|
|
793
|
-
countParams.push(resourceId);
|
|
794
|
-
}
|
|
795
|
-
if (dateRange?.start) {
|
|
796
|
-
const startDate = dateRange.start instanceof Date ? serializeDate(dateRange.start) : serializeDate(new Date(dateRange.start));
|
|
797
|
-
countQuery += ` AND createdAt >= ?`;
|
|
798
|
-
countParams.push(startDate);
|
|
799
|
-
}
|
|
800
|
-
if (dateRange?.end) {
|
|
801
|
-
const endDate = dateRange.end instanceof Date ? serializeDate(dateRange.end) : serializeDate(new Date(dateRange.end));
|
|
802
|
-
countQuery += ` AND createdAt <= ?`;
|
|
803
|
-
countParams.push(endDate);
|
|
804
|
-
}
|
|
805
|
-
const countResult = await this.operations.executeQuery({ sql: countQuery, params: countParams });
|
|
806
|
-
const total = Number(countResult[0]?.count ?? 0);
|
|
807
|
-
if (total === 0 && paginatedCount === 0 && (!include || include.length === 0)) {
|
|
808
|
-
return {
|
|
809
|
-
messages: [],
|
|
810
|
-
total: 0,
|
|
811
|
-
page,
|
|
812
|
-
perPage: perPageForResponse,
|
|
813
|
-
hasMore: false
|
|
814
|
-
};
|
|
815
|
-
}
|
|
816
|
-
const messageIds = new Set(paginatedMessages.map((m) => m.id));
|
|
817
|
-
let includeMessages = [];
|
|
818
|
-
if (include && include.length > 0) {
|
|
819
|
-
const includeResult = await this._getIncludedMessages(threadId, include);
|
|
820
|
-
if (Array.isArray(includeResult)) {
|
|
821
|
-
includeMessages = includeResult;
|
|
822
|
-
for (const includeMsg of includeMessages) {
|
|
823
|
-
if (!messageIds.has(includeMsg.id)) {
|
|
824
|
-
paginatedMessages.push(includeMsg);
|
|
825
|
-
messageIds.add(includeMsg.id);
|
|
826
|
-
}
|
|
827
|
-
}
|
|
828
|
-
}
|
|
829
|
-
}
|
|
830
|
-
const list = new MessageList().add(paginatedMessages, "memory");
|
|
831
|
-
let finalMessages = list.get.all.db();
|
|
832
|
-
finalMessages = finalMessages.sort((a, b) => {
|
|
833
|
-
const isDateField = field === "createdAt" || field === "updatedAt";
|
|
834
|
-
const aValue = isDateField ? new Date(a[field]).getTime() : a[field];
|
|
835
|
-
const bValue = isDateField ? new Date(b[field]).getTime() : b[field];
|
|
836
|
-
if (aValue === bValue) {
|
|
837
|
-
return a.id.localeCompare(b.id);
|
|
838
|
-
}
|
|
839
|
-
if (typeof aValue === "number" && typeof bValue === "number") {
|
|
840
|
-
return direction === "ASC" ? aValue - bValue : bValue - aValue;
|
|
841
|
-
}
|
|
842
|
-
return direction === "ASC" ? String(aValue).localeCompare(String(bValue)) : String(bValue).localeCompare(String(aValue));
|
|
843
|
-
});
|
|
844
|
-
const returnedThreadMessageIds = new Set(finalMessages.filter((m) => m.threadId === threadId).map((m) => m.id));
|
|
845
|
-
const allThreadMessagesReturned = returnedThreadMessageIds.size >= total;
|
|
846
|
-
const hasMore = perPageInput === false ? false : allThreadMessagesReturned ? false : offset + paginatedCount < total;
|
|
847
|
-
return {
|
|
848
|
-
messages: finalMessages,
|
|
849
|
-
total,
|
|
850
|
-
page,
|
|
851
|
-
perPage: perPageForResponse,
|
|
852
|
-
hasMore
|
|
853
|
-
};
|
|
752
|
+
await this.#db.executeQuery({ sql, params });
|
|
753
|
+
return resource;
|
|
854
754
|
} catch (error) {
|
|
855
|
-
|
|
755
|
+
throw new MastraError(
|
|
856
756
|
{
|
|
857
|
-
id: "
|
|
757
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "SAVE_RESOURCE", "FAILED"),
|
|
858
758
|
domain: ErrorDomain.STORAGE,
|
|
859
759
|
category: ErrorCategory.THIRD_PARTY,
|
|
860
|
-
text: `Failed to
|
|
861
|
-
details: {
|
|
862
|
-
threadId,
|
|
863
|
-
resourceId: resourceId ?? ""
|
|
864
|
-
}
|
|
760
|
+
text: `Failed to save resource to ${fullTableName}: ${error instanceof Error ? error.message : String(error)}`,
|
|
761
|
+
details: { resourceId: resource.id }
|
|
865
762
|
},
|
|
866
763
|
error
|
|
867
764
|
);
|
|
868
|
-
this.logger?.error?.(mastraError.toString());
|
|
869
|
-
this.logger?.trackException?.(mastraError);
|
|
870
|
-
return {
|
|
871
|
-
messages: [],
|
|
872
|
-
total: 0,
|
|
873
|
-
page,
|
|
874
|
-
perPage: perPageForResponse,
|
|
875
|
-
hasMore: false
|
|
876
|
-
};
|
|
877
765
|
}
|
|
878
766
|
}
|
|
879
|
-
async
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
767
|
+
async updateResource({
|
|
768
|
+
resourceId,
|
|
769
|
+
workingMemory,
|
|
770
|
+
metadata
|
|
771
|
+
}) {
|
|
772
|
+
const existingResource = await this.getResourceById({ resourceId });
|
|
773
|
+
if (!existingResource) {
|
|
774
|
+
const newResource = {
|
|
775
|
+
id: resourceId,
|
|
776
|
+
workingMemory,
|
|
777
|
+
metadata: metadata || {},
|
|
778
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
779
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
780
|
+
};
|
|
781
|
+
return this.saveResource({ resource: newResource });
|
|
884
782
|
}
|
|
885
|
-
const
|
|
886
|
-
const
|
|
887
|
-
|
|
783
|
+
const updatedAt = /* @__PURE__ */ new Date();
|
|
784
|
+
const updatedResource = {
|
|
785
|
+
...existingResource,
|
|
786
|
+
workingMemory: workingMemory !== void 0 ? workingMemory : existingResource.workingMemory,
|
|
787
|
+
metadata: {
|
|
788
|
+
...existingResource.metadata,
|
|
789
|
+
...metadata
|
|
790
|
+
},
|
|
791
|
+
updatedAt
|
|
792
|
+
};
|
|
793
|
+
const fullTableName = this.#db.getTableName(TABLE_RESOURCES);
|
|
794
|
+
const columns = ["workingMemory", "metadata", "updatedAt"];
|
|
795
|
+
const values = [updatedResource.workingMemory, JSON.stringify(updatedResource.metadata), updatedAt.toISOString()];
|
|
796
|
+
const query = createSqlBuilder().update(fullTableName, columns, values).where("id = ?", resourceId);
|
|
797
|
+
const { sql, params } = query.build();
|
|
888
798
|
try {
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
const existingMessages = await this.operations.executeQuery({ sql: selectQuery, params: messageIds });
|
|
892
|
-
if (existingMessages.length === 0) {
|
|
893
|
-
return [];
|
|
894
|
-
}
|
|
895
|
-
const parsedExistingMessages = existingMessages.map((msg) => {
|
|
896
|
-
if (typeof msg.content === "string") {
|
|
897
|
-
try {
|
|
898
|
-
msg.content = JSON.parse(msg.content);
|
|
899
|
-
} catch {
|
|
900
|
-
}
|
|
901
|
-
}
|
|
902
|
-
return msg;
|
|
903
|
-
});
|
|
904
|
-
const threadIdsToUpdate = /* @__PURE__ */ new Set();
|
|
905
|
-
const updateQueries = [];
|
|
906
|
-
for (const existingMessage of parsedExistingMessages) {
|
|
907
|
-
const updatePayload = messages.find((m) => m.id === existingMessage.id);
|
|
908
|
-
if (!updatePayload) continue;
|
|
909
|
-
const { id, ...fieldsToUpdate } = updatePayload;
|
|
910
|
-
if (Object.keys(fieldsToUpdate).length === 0) continue;
|
|
911
|
-
threadIdsToUpdate.add(existingMessage.threadId);
|
|
912
|
-
if ("threadId" in updatePayload && updatePayload.threadId && updatePayload.threadId !== existingMessage.threadId) {
|
|
913
|
-
threadIdsToUpdate.add(updatePayload.threadId);
|
|
914
|
-
}
|
|
915
|
-
const setClauses = [];
|
|
916
|
-
const values = [];
|
|
917
|
-
const updatableFields = { ...fieldsToUpdate };
|
|
918
|
-
if (updatableFields.content) {
|
|
919
|
-
const existingContent = existingMessage.content || {};
|
|
920
|
-
const newContent = {
|
|
921
|
-
...existingContent,
|
|
922
|
-
...updatableFields.content,
|
|
923
|
-
// Deep merge metadata if it exists on both
|
|
924
|
-
...existingContent?.metadata && updatableFields.content.metadata ? {
|
|
925
|
-
metadata: {
|
|
926
|
-
...existingContent.metadata,
|
|
927
|
-
...updatableFields.content.metadata
|
|
928
|
-
}
|
|
929
|
-
} : {}
|
|
930
|
-
};
|
|
931
|
-
setClauses.push(`content = ?`);
|
|
932
|
-
values.push(JSON.stringify(newContent));
|
|
933
|
-
delete updatableFields.content;
|
|
934
|
-
}
|
|
935
|
-
for (const key in updatableFields) {
|
|
936
|
-
if (Object.prototype.hasOwnProperty.call(updatableFields, key)) {
|
|
937
|
-
const dbColumn = key === "threadId" ? "thread_id" : key;
|
|
938
|
-
setClauses.push(`${dbColumn} = ?`);
|
|
939
|
-
values.push(updatableFields[key]);
|
|
940
|
-
}
|
|
941
|
-
}
|
|
942
|
-
if (setClauses.length > 0) {
|
|
943
|
-
values.push(id);
|
|
944
|
-
const updateQuery = `UPDATE ${fullTableName} SET ${setClauses.join(", ")} WHERE id = ?`;
|
|
945
|
-
updateQueries.push({ sql: updateQuery, params: values });
|
|
946
|
-
}
|
|
947
|
-
}
|
|
948
|
-
for (const query of updateQueries) {
|
|
949
|
-
await this.operations.executeQuery(query);
|
|
950
|
-
}
|
|
951
|
-
if (threadIdsToUpdate.size > 0) {
|
|
952
|
-
const threadPlaceholders = Array.from(threadIdsToUpdate).map(() => "?").join(",");
|
|
953
|
-
const threadUpdateQuery = `UPDATE ${threadsTableName} SET updatedAt = ? WHERE id IN (${threadPlaceholders})`;
|
|
954
|
-
const threadUpdateParams = [(/* @__PURE__ */ new Date()).toISOString(), ...Array.from(threadIdsToUpdate)];
|
|
955
|
-
await this.operations.executeQuery({ sql: threadUpdateQuery, params: threadUpdateParams });
|
|
956
|
-
}
|
|
957
|
-
const updatedMessages = await this.operations.executeQuery({ sql: selectQuery, params: messageIds });
|
|
958
|
-
return updatedMessages.map((message) => {
|
|
959
|
-
if (typeof message.content === "string") {
|
|
960
|
-
try {
|
|
961
|
-
message.content = JSON.parse(message.content);
|
|
962
|
-
} catch {
|
|
963
|
-
}
|
|
964
|
-
}
|
|
965
|
-
return message;
|
|
966
|
-
});
|
|
799
|
+
await this.#db.executeQuery({ sql, params });
|
|
800
|
+
return updatedResource;
|
|
967
801
|
} catch (error) {
|
|
968
802
|
throw new MastraError(
|
|
969
803
|
{
|
|
970
|
-
id: "
|
|
804
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "UPDATE_RESOURCE", "FAILED"),
|
|
971
805
|
domain: ErrorDomain.STORAGE,
|
|
972
806
|
category: ErrorCategory.THIRD_PARTY,
|
|
973
|
-
|
|
807
|
+
text: `Failed to update resource ${resourceId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
808
|
+
details: { resourceId }
|
|
974
809
|
},
|
|
975
810
|
error
|
|
976
811
|
);
|
|
977
812
|
}
|
|
978
813
|
}
|
|
979
|
-
}
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
super();
|
|
986
|
-
this.client = config.client;
|
|
987
|
-
this.binding = config.binding;
|
|
988
|
-
this.tablePrefix = config.tablePrefix || "";
|
|
989
|
-
}
|
|
990
|
-
async hasColumn(table, column) {
|
|
991
|
-
const fullTableName = table.startsWith(this.tablePrefix) ? table : `${this.tablePrefix}${table}`;
|
|
992
|
-
const sql = `PRAGMA table_info(${fullTableName});`;
|
|
993
|
-
const result = await this.executeQuery({ sql, params: [] });
|
|
994
|
-
if (!result || !Array.isArray(result)) return false;
|
|
995
|
-
return result.some((col) => col.name === column || col.name === column.toLowerCase());
|
|
996
|
-
}
|
|
997
|
-
getTableName(tableName) {
|
|
998
|
-
return `${this.tablePrefix}${tableName}`;
|
|
999
|
-
}
|
|
1000
|
-
formatSqlParams(params) {
|
|
1001
|
-
return params.map((p) => p === void 0 || p === null ? null : p);
|
|
1002
|
-
}
|
|
1003
|
-
async executeWorkersBindingQuery({
|
|
1004
|
-
sql,
|
|
1005
|
-
params = [],
|
|
1006
|
-
first = false
|
|
1007
|
-
}) {
|
|
1008
|
-
if (!this.binding) {
|
|
1009
|
-
throw new Error("Workers binding is not configured");
|
|
1010
|
-
}
|
|
814
|
+
async getThreadById({ threadId }) {
|
|
815
|
+
const thread = await this.#db.load({
|
|
816
|
+
tableName: TABLE_THREADS,
|
|
817
|
+
keys: { id: threadId }
|
|
818
|
+
});
|
|
819
|
+
if (!thread) return null;
|
|
1011
820
|
try {
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
if (!result) return null;
|
|
1019
|
-
return result;
|
|
1020
|
-
} else {
|
|
1021
|
-
result = await statement.bind(...formattedParams).all();
|
|
1022
|
-
const results = result.results || [];
|
|
1023
|
-
return results;
|
|
1024
|
-
}
|
|
1025
|
-
} else {
|
|
1026
|
-
if (first) {
|
|
1027
|
-
result = await statement.first();
|
|
1028
|
-
if (!result) return null;
|
|
1029
|
-
return result;
|
|
1030
|
-
} else {
|
|
1031
|
-
result = await statement.all();
|
|
1032
|
-
const results = result.results || [];
|
|
1033
|
-
return results;
|
|
1034
|
-
}
|
|
1035
|
-
}
|
|
821
|
+
return {
|
|
822
|
+
...thread,
|
|
823
|
+
createdAt: ensureDate(thread.createdAt),
|
|
824
|
+
updatedAt: ensureDate(thread.updatedAt),
|
|
825
|
+
metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata || "{}") : thread.metadata || {}
|
|
826
|
+
};
|
|
1036
827
|
} catch (error) {
|
|
1037
|
-
|
|
828
|
+
const mastraError = new MastraError(
|
|
1038
829
|
{
|
|
1039
|
-
id: "
|
|
830
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "GET_THREAD_BY_ID", "FAILED"),
|
|
1040
831
|
domain: ErrorDomain.STORAGE,
|
|
1041
832
|
category: ErrorCategory.THIRD_PARTY,
|
|
1042
|
-
|
|
833
|
+
text: `Error processing thread ${threadId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
834
|
+
details: { threadId }
|
|
1043
835
|
},
|
|
1044
836
|
error
|
|
1045
837
|
);
|
|
838
|
+
this.logger?.error(mastraError.toString());
|
|
839
|
+
this.logger?.trackException(mastraError);
|
|
840
|
+
return null;
|
|
1046
841
|
}
|
|
1047
842
|
}
|
|
1048
|
-
async
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
843
|
+
async listThreadsByResourceId(args) {
|
|
844
|
+
const { resourceId, page = 0, perPage: perPageInput, orderBy } = args;
|
|
845
|
+
const perPage = normalizePerPage(perPageInput, 100);
|
|
846
|
+
if (page < 0) {
|
|
847
|
+
throw new MastraError(
|
|
848
|
+
{
|
|
849
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "LIST_THREADS_BY_RESOURCE_ID", "INVALID_PAGE"),
|
|
850
|
+
domain: ErrorDomain.STORAGE,
|
|
851
|
+
category: ErrorCategory.USER,
|
|
852
|
+
details: { page }
|
|
853
|
+
},
|
|
854
|
+
new Error("page must be >= 0")
|
|
855
|
+
);
|
|
1055
856
|
}
|
|
857
|
+
const { offset, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
|
|
858
|
+
const { field, direction } = this.parseOrderBy(orderBy);
|
|
859
|
+
const fullTableName = this.#db.getTableName(TABLE_THREADS);
|
|
860
|
+
const mapRowToStorageThreadType = (row) => ({
|
|
861
|
+
...row,
|
|
862
|
+
createdAt: ensureDate(row.createdAt),
|
|
863
|
+
updatedAt: ensureDate(row.updatedAt),
|
|
864
|
+
metadata: typeof row.metadata === "string" ? JSON.parse(row.metadata || "{}") : row.metadata || {}
|
|
865
|
+
});
|
|
1056
866
|
try {
|
|
1057
|
-
const
|
|
1058
|
-
const
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
const
|
|
1063
|
-
const
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
867
|
+
const countQuery = createSqlBuilder().count().from(fullTableName).where("resourceId = ?", resourceId);
|
|
868
|
+
const countResult = await this.#db.executeQuery(countQuery.build());
|
|
869
|
+
const total = Number(countResult?.[0]?.count ?? 0);
|
|
870
|
+
const limitValue = perPageInput === false ? total : perPage;
|
|
871
|
+
const selectQuery = createSqlBuilder().select("*").from(fullTableName).where("resourceId = ?", resourceId).orderBy(field, direction).limit(limitValue).offset(offset);
|
|
872
|
+
const results = await this.#db.executeQuery(selectQuery.build());
|
|
873
|
+
const threads = results.map(mapRowToStorageThreadType);
|
|
874
|
+
return {
|
|
875
|
+
threads,
|
|
876
|
+
total,
|
|
877
|
+
page,
|
|
878
|
+
perPage: perPageForResponse,
|
|
879
|
+
hasMore: perPageInput === false ? false : offset + perPage < total
|
|
880
|
+
};
|
|
1068
881
|
} catch (error) {
|
|
1069
|
-
|
|
882
|
+
const mastraError = new MastraError(
|
|
1070
883
|
{
|
|
1071
|
-
id: "
|
|
884
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "LIST_THREADS_BY_RESOURCE_ID", "FAILED"),
|
|
1072
885
|
domain: ErrorDomain.STORAGE,
|
|
1073
886
|
category: ErrorCategory.THIRD_PARTY,
|
|
1074
|
-
|
|
887
|
+
text: `Error getting threads by resourceId ${resourceId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
888
|
+
details: { resourceId }
|
|
1075
889
|
},
|
|
1076
890
|
error
|
|
1077
891
|
);
|
|
892
|
+
this.logger?.error(mastraError.toString());
|
|
893
|
+
this.logger?.trackException(mastraError);
|
|
894
|
+
return {
|
|
895
|
+
threads: [],
|
|
896
|
+
total: 0,
|
|
897
|
+
page,
|
|
898
|
+
perPage: perPageForResponse,
|
|
899
|
+
hasMore: false
|
|
900
|
+
};
|
|
1078
901
|
}
|
|
1079
902
|
}
|
|
1080
|
-
async
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
903
|
+
async saveThread({ thread }) {
|
|
904
|
+
const fullTableName = this.#db.getTableName(TABLE_THREADS);
|
|
905
|
+
const threadToSave = {
|
|
906
|
+
id: thread.id,
|
|
907
|
+
resourceId: thread.resourceId,
|
|
908
|
+
title: thread.title,
|
|
909
|
+
metadata: thread.metadata ? JSON.stringify(thread.metadata) : null,
|
|
910
|
+
createdAt: thread.createdAt.toISOString(),
|
|
911
|
+
updatedAt: thread.updatedAt.toISOString()
|
|
912
|
+
};
|
|
913
|
+
const processedRecord = await this.#db.processRecord(threadToSave);
|
|
914
|
+
const columns = Object.keys(processedRecord);
|
|
915
|
+
const values = Object.values(processedRecord);
|
|
916
|
+
const updateMap = {
|
|
917
|
+
resourceId: "excluded.resourceId",
|
|
918
|
+
title: "excluded.title",
|
|
919
|
+
metadata: "excluded.metadata",
|
|
920
|
+
createdAt: "excluded.createdAt",
|
|
921
|
+
updatedAt: "excluded.updatedAt"
|
|
922
|
+
};
|
|
923
|
+
const query = createSqlBuilder().insert(fullTableName, columns, values, ["id"], updateMap);
|
|
924
|
+
const { sql, params } = query.build();
|
|
1090
925
|
try {
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
if (!result || !Array.isArray(result)) {
|
|
1094
|
-
return [];
|
|
1095
|
-
}
|
|
1096
|
-
return result.map((row) => ({
|
|
1097
|
-
name: row.name,
|
|
1098
|
-
type: row.type
|
|
1099
|
-
}));
|
|
926
|
+
await this.#db.executeQuery({ sql, params });
|
|
927
|
+
return thread;
|
|
1100
928
|
} catch (error) {
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
}
|
|
1112
|
-
if (typeof value === "object") {
|
|
1113
|
-
return JSON.stringify(value);
|
|
1114
|
-
}
|
|
1115
|
-
return value;
|
|
1116
|
-
}
|
|
1117
|
-
getSqlType(type) {
|
|
1118
|
-
switch (type) {
|
|
1119
|
-
case "bigint":
|
|
1120
|
-
return "INTEGER";
|
|
1121
|
-
// SQLite uses INTEGER for all integer sizes
|
|
1122
|
-
case "jsonb":
|
|
1123
|
-
return "TEXT";
|
|
1124
|
-
// Store JSON as TEXT in SQLite
|
|
1125
|
-
default:
|
|
1126
|
-
return super.getSqlType(type);
|
|
929
|
+
throw new MastraError(
|
|
930
|
+
{
|
|
931
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "SAVE_THREAD", "FAILED"),
|
|
932
|
+
domain: ErrorDomain.STORAGE,
|
|
933
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
934
|
+
text: `Failed to save thread to ${fullTableName}: ${error instanceof Error ? error.message : String(error)}`,
|
|
935
|
+
details: { threadId: thread.id }
|
|
936
|
+
},
|
|
937
|
+
error
|
|
938
|
+
);
|
|
1127
939
|
}
|
|
1128
940
|
}
|
|
1129
|
-
async
|
|
1130
|
-
|
|
1131
|
-
|
|
941
|
+
async updateThread({
|
|
942
|
+
id,
|
|
943
|
+
title,
|
|
944
|
+
metadata
|
|
1132
945
|
}) {
|
|
946
|
+
const thread = await this.getThreadById({ threadId: id });
|
|
1133
947
|
try {
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
const type = this.getSqlType(colDef.type);
|
|
1137
|
-
const nullable = colDef.nullable === false ? "NOT NULL" : "";
|
|
1138
|
-
const primaryKey = colDef.primaryKey ? "PRIMARY KEY" : "";
|
|
1139
|
-
return `${colName} ${type} ${nullable} ${primaryKey}`.trim();
|
|
1140
|
-
});
|
|
1141
|
-
const tableConstraints = [];
|
|
1142
|
-
if (tableName === TABLE_WORKFLOW_SNAPSHOT) {
|
|
1143
|
-
tableConstraints.push("UNIQUE (workflow_name, run_id)");
|
|
948
|
+
if (!thread) {
|
|
949
|
+
throw new Error(`Thread ${id} not found`);
|
|
1144
950
|
}
|
|
1145
|
-
const
|
|
951
|
+
const fullTableName = this.#db.getTableName(TABLE_THREADS);
|
|
952
|
+
const mergedMetadata = {
|
|
953
|
+
...typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
|
|
954
|
+
...metadata
|
|
955
|
+
};
|
|
956
|
+
const updatedAt = /* @__PURE__ */ new Date();
|
|
957
|
+
const columns = ["title", "metadata", "updatedAt"];
|
|
958
|
+
const values = [title, JSON.stringify(mergedMetadata), updatedAt.toISOString()];
|
|
959
|
+
const query = createSqlBuilder().update(fullTableName, columns, values).where("id = ?", id);
|
|
1146
960
|
const { sql, params } = query.build();
|
|
1147
|
-
await this.executeQuery({ sql, params });
|
|
1148
|
-
|
|
961
|
+
await this.#db.executeQuery({ sql, params });
|
|
962
|
+
return {
|
|
963
|
+
...thread,
|
|
964
|
+
title,
|
|
965
|
+
metadata: {
|
|
966
|
+
...typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
|
|
967
|
+
...metadata
|
|
968
|
+
},
|
|
969
|
+
updatedAt
|
|
970
|
+
};
|
|
1149
971
|
} catch (error) {
|
|
1150
972
|
throw new MastraError(
|
|
1151
973
|
{
|
|
1152
|
-
id: "
|
|
974
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "UPDATE_THREAD", "FAILED"),
|
|
1153
975
|
domain: ErrorDomain.STORAGE,
|
|
1154
976
|
category: ErrorCategory.THIRD_PARTY,
|
|
1155
|
-
|
|
977
|
+
text: `Failed to update thread ${id}: ${error instanceof Error ? error.message : String(error)}`,
|
|
978
|
+
details: { threadId: id }
|
|
1156
979
|
},
|
|
1157
980
|
error
|
|
1158
981
|
);
|
|
1159
982
|
}
|
|
1160
983
|
}
|
|
1161
|
-
async
|
|
984
|
+
async deleteThread({ threadId }) {
|
|
985
|
+
const fullTableName = this.#db.getTableName(TABLE_THREADS);
|
|
1162
986
|
try {
|
|
1163
|
-
const
|
|
1164
|
-
const
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
987
|
+
const deleteThreadQuery = createSqlBuilder().delete(fullTableName).where("id = ?", threadId);
|
|
988
|
+
const { sql: threadSql, params: threadParams } = deleteThreadQuery.build();
|
|
989
|
+
await this.#db.executeQuery({ sql: threadSql, params: threadParams });
|
|
990
|
+
const messagesTableName = this.#db.getTableName(TABLE_MESSAGES);
|
|
991
|
+
const deleteMessagesQuery = createSqlBuilder().delete(messagesTableName).where("thread_id = ?", threadId);
|
|
992
|
+
const { sql: messagesSql, params: messagesParams } = deleteMessagesQuery.build();
|
|
993
|
+
await this.#db.executeQuery({ sql: messagesSql, params: messagesParams });
|
|
1168
994
|
} catch (error) {
|
|
1169
995
|
throw new MastraError(
|
|
1170
996
|
{
|
|
1171
|
-
id: "
|
|
997
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "DELETE_THREAD", "FAILED"),
|
|
1172
998
|
domain: ErrorDomain.STORAGE,
|
|
1173
999
|
category: ErrorCategory.THIRD_PARTY,
|
|
1174
|
-
|
|
1000
|
+
text: `Failed to delete thread ${threadId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
1001
|
+
details: { threadId }
|
|
1175
1002
|
},
|
|
1176
1003
|
error
|
|
1177
1004
|
);
|
|
1178
1005
|
}
|
|
1179
1006
|
}
|
|
1180
|
-
async
|
|
1007
|
+
async saveMessages(args) {
|
|
1008
|
+
const { messages } = args;
|
|
1009
|
+
if (messages.length === 0) return { messages: [] };
|
|
1181
1010
|
try {
|
|
1182
|
-
const
|
|
1183
|
-
const
|
|
1184
|
-
|
|
1185
|
-
|
|
1011
|
+
const now = /* @__PURE__ */ new Date();
|
|
1012
|
+
const threadId = messages[0]?.threadId;
|
|
1013
|
+
for (const [i, message] of messages.entries()) {
|
|
1014
|
+
if (!message.id) throw new Error(`Message at index ${i} missing id`);
|
|
1015
|
+
if (!message.threadId) {
|
|
1016
|
+
throw new Error(`Message at index ${i} missing threadId`);
|
|
1017
|
+
}
|
|
1018
|
+
if (!message.content) {
|
|
1019
|
+
throw new Error(`Message at index ${i} missing content`);
|
|
1020
|
+
}
|
|
1021
|
+
if (!message.role) {
|
|
1022
|
+
throw new Error(`Message at index ${i} missing role`);
|
|
1023
|
+
}
|
|
1024
|
+
if (!message.resourceId) {
|
|
1025
|
+
throw new Error(`Message at index ${i} missing resourceId`);
|
|
1026
|
+
}
|
|
1027
|
+
const thread = await this.getThreadById({ threadId: message.threadId });
|
|
1028
|
+
if (!thread) {
|
|
1029
|
+
throw new Error(`Thread ${message.threadId} not found`);
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
const messagesToInsert = messages.map((message) => {
|
|
1033
|
+
const createdAt = message.createdAt ? new Date(message.createdAt) : now;
|
|
1034
|
+
return {
|
|
1035
|
+
id: message.id,
|
|
1036
|
+
thread_id: message.threadId,
|
|
1037
|
+
content: typeof message.content === "string" ? message.content : JSON.stringify(message.content),
|
|
1038
|
+
createdAt: createdAt.toISOString(),
|
|
1039
|
+
role: message.role,
|
|
1040
|
+
type: message.type || "v2",
|
|
1041
|
+
resourceId: message.resourceId
|
|
1042
|
+
};
|
|
1043
|
+
});
|
|
1044
|
+
await Promise.all([
|
|
1045
|
+
this.#db.batchUpsert({
|
|
1046
|
+
tableName: TABLE_MESSAGES,
|
|
1047
|
+
records: messagesToInsert
|
|
1048
|
+
}),
|
|
1049
|
+
// Update thread's updatedAt timestamp
|
|
1050
|
+
this.#db.executeQuery({
|
|
1051
|
+
sql: `UPDATE ${this.#db.getTableName(TABLE_THREADS)} SET updatedAt = ? WHERE id = ?`,
|
|
1052
|
+
params: [now.toISOString(), threadId]
|
|
1053
|
+
})
|
|
1054
|
+
]);
|
|
1055
|
+
this.logger.debug(`Saved ${messages.length} messages`);
|
|
1056
|
+
const list = new MessageList().add(messages, "memory");
|
|
1057
|
+
return { messages: list.get.all.db() };
|
|
1186
1058
|
} catch (error) {
|
|
1187
1059
|
throw new MastraError(
|
|
1188
1060
|
{
|
|
1189
|
-
id: "
|
|
1061
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "SAVE_MESSAGES", "FAILED"),
|
|
1190
1062
|
domain: ErrorDomain.STORAGE,
|
|
1191
1063
|
category: ErrorCategory.THIRD_PARTY,
|
|
1192
|
-
|
|
1064
|
+
text: `Failed to save messages: ${error instanceof Error ? error.message : String(error)}`
|
|
1193
1065
|
},
|
|
1194
1066
|
error
|
|
1195
1067
|
);
|
|
1196
1068
|
}
|
|
1197
1069
|
}
|
|
1198
|
-
async
|
|
1070
|
+
async _getIncludedMessages(include) {
|
|
1071
|
+
if (!include || include.length === 0) return null;
|
|
1072
|
+
const unionQueries = [];
|
|
1073
|
+
const params = [];
|
|
1074
|
+
let paramIdx = 1;
|
|
1075
|
+
const tableName = this.#db.getTableName(TABLE_MESSAGES);
|
|
1076
|
+
for (const inc of include) {
|
|
1077
|
+
const { id, withPreviousMessages = 0, withNextMessages = 0 } = inc;
|
|
1078
|
+
unionQueries.push(`
|
|
1079
|
+
SELECT * FROM (
|
|
1080
|
+
WITH target_thread AS (
|
|
1081
|
+
SELECT thread_id FROM ${tableName} WHERE id = ?
|
|
1082
|
+
),
|
|
1083
|
+
ordered_messages AS (
|
|
1084
|
+
SELECT
|
|
1085
|
+
*,
|
|
1086
|
+
ROW_NUMBER() OVER (ORDER BY createdAt ASC) AS row_num
|
|
1087
|
+
FROM ${tableName}
|
|
1088
|
+
WHERE thread_id = (SELECT thread_id FROM target_thread)
|
|
1089
|
+
)
|
|
1090
|
+
SELECT
|
|
1091
|
+
m.id,
|
|
1092
|
+
m.content,
|
|
1093
|
+
m.role,
|
|
1094
|
+
m.type,
|
|
1095
|
+
m.createdAt,
|
|
1096
|
+
m.thread_id AS threadId,
|
|
1097
|
+
m.resourceId
|
|
1098
|
+
FROM ordered_messages m
|
|
1099
|
+
WHERE m.id = ?
|
|
1100
|
+
OR EXISTS (
|
|
1101
|
+
SELECT 1 FROM ordered_messages target
|
|
1102
|
+
WHERE target.id = ?
|
|
1103
|
+
AND (
|
|
1104
|
+
(m.row_num <= target.row_num + ? AND m.row_num > target.row_num)
|
|
1105
|
+
OR
|
|
1106
|
+
(m.row_num >= target.row_num - ? AND m.row_num < target.row_num)
|
|
1107
|
+
)
|
|
1108
|
+
)
|
|
1109
|
+
) AS query_${paramIdx}
|
|
1110
|
+
`);
|
|
1111
|
+
params.push(id, id, id, withNextMessages, withPreviousMessages);
|
|
1112
|
+
paramIdx++;
|
|
1113
|
+
}
|
|
1114
|
+
const finalQuery = unionQueries.join(" UNION ALL ") + " ORDER BY createdAt ASC";
|
|
1115
|
+
const messages = await this.#db.executeQuery({ sql: finalQuery, params });
|
|
1116
|
+
if (!Array.isArray(messages)) {
|
|
1117
|
+
return [];
|
|
1118
|
+
}
|
|
1119
|
+
const processedMessages = messages.map((message) => {
|
|
1120
|
+
const processedMsg = {};
|
|
1121
|
+
for (const [key, value] of Object.entries(message)) {
|
|
1122
|
+
if (key === `type` && value === `v2`) continue;
|
|
1123
|
+
processedMsg[key] = deserializeValue(value);
|
|
1124
|
+
}
|
|
1125
|
+
return processedMsg;
|
|
1126
|
+
});
|
|
1127
|
+
return processedMessages;
|
|
1128
|
+
}
|
|
1129
|
+
async listMessagesById({ messageIds }) {
|
|
1130
|
+
if (messageIds.length === 0) return { messages: [] };
|
|
1131
|
+
const fullTableName = this.#db.getTableName(TABLE_MESSAGES);
|
|
1132
|
+
const messages = [];
|
|
1199
1133
|
try {
|
|
1200
|
-
const
|
|
1201
|
-
|
|
1202
|
-
const
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1134
|
+
const query = createSqlBuilder().select(["id", "content", "role", "type", "createdAt", "thread_id AS threadId", "resourceId"]).from(fullTableName).where(`id in (${messageIds.map(() => "?").join(",")})`, ...messageIds);
|
|
1135
|
+
query.orderBy("createdAt", "DESC");
|
|
1136
|
+
const { sql, params } = query.build();
|
|
1137
|
+
const result = await this.#db.executeQuery({ sql, params });
|
|
1138
|
+
if (Array.isArray(result)) messages.push(...result);
|
|
1139
|
+
const processedMessages = messages.map((message) => {
|
|
1140
|
+
const processedMsg = {};
|
|
1141
|
+
for (const [key, value] of Object.entries(message)) {
|
|
1142
|
+
if (key === `type` && value === `v2`) continue;
|
|
1143
|
+
processedMsg[key] = deserializeValue(value);
|
|
1210
1144
|
}
|
|
1211
|
-
|
|
1145
|
+
return processedMsg;
|
|
1146
|
+
});
|
|
1147
|
+
this.logger.debug(`Retrieved ${messages.length} messages`);
|
|
1148
|
+
const list = new MessageList().add(processedMessages, "memory");
|
|
1149
|
+
return { messages: list.get.all.db() };
|
|
1212
1150
|
} catch (error) {
|
|
1213
|
-
|
|
1151
|
+
const mastraError = new MastraError(
|
|
1214
1152
|
{
|
|
1215
|
-
id: "
|
|
1153
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "LIST_MESSAGES_BY_ID", "FAILED"),
|
|
1216
1154
|
domain: ErrorDomain.STORAGE,
|
|
1217
1155
|
category: ErrorCategory.THIRD_PARTY,
|
|
1218
|
-
|
|
1156
|
+
text: `Failed to retrieve messages by ID: ${error instanceof Error ? error.message : String(error)}`,
|
|
1157
|
+
details: { messageIds: JSON.stringify(messageIds) }
|
|
1219
1158
|
},
|
|
1220
1159
|
error
|
|
1221
1160
|
);
|
|
1161
|
+
this.logger?.error(mastraError.toString());
|
|
1162
|
+
this.logger?.trackException(mastraError);
|
|
1163
|
+
throw mastraError;
|
|
1222
1164
|
}
|
|
1223
1165
|
}
|
|
1224
|
-
async
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
const columns = Object.keys(processedRecord);
|
|
1229
|
-
const values = Object.values(processedRecord);
|
|
1230
|
-
const query = createSqlBuilder().insert(fullTableName, columns, values);
|
|
1231
|
-
const { sql, params } = query.build();
|
|
1232
|
-
await this.executeQuery({ sql, params });
|
|
1233
|
-
} catch (error) {
|
|
1166
|
+
async listMessages(args) {
|
|
1167
|
+
const { threadId, resourceId, include, filter, perPage: perPageInput, page = 0, orderBy } = args;
|
|
1168
|
+
const threadIds = Array.isArray(threadId) ? threadId : [threadId];
|
|
1169
|
+
if (threadIds.length === 0 || threadIds.some((id) => !id.trim())) {
|
|
1234
1170
|
throw new MastraError(
|
|
1235
1171
|
{
|
|
1236
|
-
id: "
|
|
1172
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "LIST_MESSAGES", "INVALID_THREAD_ID"),
|
|
1237
1173
|
domain: ErrorDomain.STORAGE,
|
|
1238
1174
|
category: ErrorCategory.THIRD_PARTY,
|
|
1239
|
-
details: {
|
|
1175
|
+
details: { threadId: Array.isArray(threadId) ? threadId.join(",") : threadId }
|
|
1240
1176
|
},
|
|
1241
|
-
|
|
1177
|
+
new Error("threadId must be a non-empty string or array of non-empty strings")
|
|
1242
1178
|
);
|
|
1243
1179
|
}
|
|
1244
|
-
|
|
1245
|
-
|
|
1180
|
+
if (page < 0) {
|
|
1181
|
+
throw new MastraError(
|
|
1182
|
+
{
|
|
1183
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "LIST_MESSAGES", "INVALID_PAGE"),
|
|
1184
|
+
domain: ErrorDomain.STORAGE,
|
|
1185
|
+
category: ErrorCategory.USER,
|
|
1186
|
+
details: { page }
|
|
1187
|
+
},
|
|
1188
|
+
new Error("page must be >= 0")
|
|
1189
|
+
);
|
|
1190
|
+
}
|
|
1191
|
+
const perPage = normalizePerPage(perPageInput, 40);
|
|
1192
|
+
const { offset, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
|
|
1246
1193
|
try {
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1194
|
+
const fullTableName = this.#db.getTableName(TABLE_MESSAGES);
|
|
1195
|
+
let query = `
|
|
1196
|
+
SELECT id, content, role, type, createdAt, thread_id AS threadId, resourceId
|
|
1197
|
+
FROM ${fullTableName}
|
|
1198
|
+
WHERE thread_id = ?
|
|
1199
|
+
`;
|
|
1200
|
+
const queryParams = [threadId];
|
|
1201
|
+
if (resourceId) {
|
|
1202
|
+
query += ` AND resourceId = ?`;
|
|
1203
|
+
queryParams.push(resourceId);
|
|
1204
|
+
}
|
|
1205
|
+
const dateRange = filter?.dateRange;
|
|
1206
|
+
if (dateRange?.start) {
|
|
1207
|
+
const startDate = dateRange.start instanceof Date ? serializeDate(dateRange.start) : serializeDate(new Date(dateRange.start));
|
|
1208
|
+
const startOp = dateRange.startExclusive ? ">" : ">=";
|
|
1209
|
+
query += ` AND createdAt ${startOp} ?`;
|
|
1210
|
+
queryParams.push(startDate);
|
|
1211
|
+
}
|
|
1212
|
+
if (dateRange?.end) {
|
|
1213
|
+
const endDate = dateRange.end instanceof Date ? serializeDate(dateRange.end) : serializeDate(new Date(dateRange.end));
|
|
1214
|
+
const endOp = dateRange.endExclusive ? "<" : "<=";
|
|
1215
|
+
query += ` AND createdAt ${endOp} ?`;
|
|
1216
|
+
queryParams.push(endDate);
|
|
1217
|
+
}
|
|
1218
|
+
const { field, direction } = this.parseOrderBy(orderBy, "ASC");
|
|
1219
|
+
query += ` ORDER BY "${field}" ${direction}`;
|
|
1220
|
+
if (perPage !== Number.MAX_SAFE_INTEGER) {
|
|
1221
|
+
query += ` LIMIT ? OFFSET ?`;
|
|
1222
|
+
queryParams.push(perPage, offset);
|
|
1223
|
+
}
|
|
1224
|
+
const results = await this.#db.executeQuery({ sql: query, params: queryParams });
|
|
1225
|
+
const paginatedMessages = (isArrayOfRecords(results) ? results : []).map((message) => {
|
|
1226
|
+
const processedMsg = {};
|
|
1227
|
+
for (const [key, value] of Object.entries(message)) {
|
|
1228
|
+
if (key === `type` && value === `v2`) continue;
|
|
1229
|
+
processedMsg[key] = deserializeValue(value);
|
|
1230
|
+
}
|
|
1231
|
+
return processedMsg;
|
|
1232
|
+
});
|
|
1233
|
+
const paginatedCount = paginatedMessages.length;
|
|
1234
|
+
let countQuery = `SELECT count() as count FROM ${fullTableName} WHERE thread_id = ?`;
|
|
1235
|
+
const countParams = [threadId];
|
|
1236
|
+
if (resourceId) {
|
|
1237
|
+
countQuery += ` AND resourceId = ?`;
|
|
1238
|
+
countParams.push(resourceId);
|
|
1239
|
+
}
|
|
1240
|
+
if (dateRange?.start) {
|
|
1241
|
+
const startDate = dateRange.start instanceof Date ? serializeDate(dateRange.start) : serializeDate(new Date(dateRange.start));
|
|
1242
|
+
const startOp = dateRange.startExclusive ? ">" : ">=";
|
|
1243
|
+
countQuery += ` AND createdAt ${startOp} ?`;
|
|
1244
|
+
countParams.push(startDate);
|
|
1245
|
+
}
|
|
1246
|
+
if (dateRange?.end) {
|
|
1247
|
+
const endDate = dateRange.end instanceof Date ? serializeDate(dateRange.end) : serializeDate(new Date(dateRange.end));
|
|
1248
|
+
const endOp = dateRange.endExclusive ? "<" : "<=";
|
|
1249
|
+
countQuery += ` AND createdAt ${endOp} ?`;
|
|
1250
|
+
countParams.push(endDate);
|
|
1251
|
+
}
|
|
1252
|
+
const countResult = await this.#db.executeQuery({ sql: countQuery, params: countParams });
|
|
1253
|
+
const total = Number(countResult[0]?.count ?? 0);
|
|
1254
|
+
if (total === 0 && paginatedCount === 0 && (!include || include.length === 0)) {
|
|
1255
|
+
return {
|
|
1256
|
+
messages: [],
|
|
1257
|
+
total: 0,
|
|
1258
|
+
page,
|
|
1259
|
+
perPage: perPageForResponse,
|
|
1260
|
+
hasMore: false
|
|
1261
|
+
};
|
|
1262
|
+
}
|
|
1263
|
+
const messageIds = new Set(paginatedMessages.map((m) => m.id));
|
|
1264
|
+
let includeMessages = [];
|
|
1265
|
+
if (include && include.length > 0) {
|
|
1266
|
+
const includeResult = await this._getIncludedMessages(include);
|
|
1267
|
+
if (Array.isArray(includeResult)) {
|
|
1268
|
+
includeMessages = includeResult;
|
|
1269
|
+
for (const includeMsg of includeMessages) {
|
|
1270
|
+
if (!messageIds.has(includeMsg.id)) {
|
|
1271
|
+
paginatedMessages.push(includeMsg);
|
|
1272
|
+
messageIds.add(includeMsg.id);
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1256
1276
|
}
|
|
1277
|
+
const list = new MessageList().add(paginatedMessages, "memory");
|
|
1278
|
+
let finalMessages = list.get.all.db();
|
|
1279
|
+
finalMessages = finalMessages.sort((a, b) => {
|
|
1280
|
+
const isDateField = field === "createdAt" || field === "updatedAt";
|
|
1281
|
+
const aValue = isDateField ? new Date(a[field]).getTime() : a[field];
|
|
1282
|
+
const bValue = isDateField ? new Date(b[field]).getTime() : b[field];
|
|
1283
|
+
if (aValue === bValue) {
|
|
1284
|
+
return a.id.localeCompare(b.id);
|
|
1285
|
+
}
|
|
1286
|
+
if (typeof aValue === "number" && typeof bValue === "number") {
|
|
1287
|
+
return direction === "ASC" ? aValue - bValue : bValue - aValue;
|
|
1288
|
+
}
|
|
1289
|
+
return direction === "ASC" ? String(aValue).localeCompare(String(bValue)) : String(bValue).localeCompare(String(aValue));
|
|
1290
|
+
});
|
|
1291
|
+
const returnedThreadMessageIds = new Set(finalMessages.filter((m) => m.threadId === threadId).map((m) => m.id));
|
|
1292
|
+
const allThreadMessagesReturned = returnedThreadMessageIds.size >= total;
|
|
1293
|
+
const hasMore = perPageInput === false ? false : allThreadMessagesReturned ? false : offset + paginatedCount < total;
|
|
1294
|
+
return {
|
|
1295
|
+
messages: finalMessages,
|
|
1296
|
+
total,
|
|
1297
|
+
page,
|
|
1298
|
+
perPage: perPageForResponse,
|
|
1299
|
+
hasMore
|
|
1300
|
+
};
|
|
1257
1301
|
} catch (error) {
|
|
1258
|
-
|
|
1302
|
+
const mastraError = new MastraError(
|
|
1259
1303
|
{
|
|
1260
|
-
id: "
|
|
1304
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "LIST_MESSAGES", "FAILED"),
|
|
1261
1305
|
domain: ErrorDomain.STORAGE,
|
|
1262
1306
|
category: ErrorCategory.THIRD_PARTY,
|
|
1263
|
-
|
|
1307
|
+
text: `Failed to list messages for thread ${Array.isArray(threadId) ? threadId.join(",") : threadId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
1308
|
+
details: {
|
|
1309
|
+
threadId: Array.isArray(threadId) ? threadId.join(",") : threadId,
|
|
1310
|
+
resourceId: resourceId ?? ""
|
|
1311
|
+
}
|
|
1264
1312
|
},
|
|
1265
1313
|
error
|
|
1266
1314
|
);
|
|
1315
|
+
this.logger?.error?.(mastraError.toString());
|
|
1316
|
+
this.logger?.trackException?.(mastraError);
|
|
1317
|
+
return {
|
|
1318
|
+
messages: [],
|
|
1319
|
+
total: 0,
|
|
1320
|
+
page,
|
|
1321
|
+
perPage: perPageForResponse,
|
|
1322
|
+
hasMore: false
|
|
1323
|
+
};
|
|
1267
1324
|
}
|
|
1268
1325
|
}
|
|
1269
|
-
async
|
|
1326
|
+
async updateMessages(args) {
|
|
1327
|
+
const { messages } = args;
|
|
1328
|
+
this.logger.debug("Updating messages", { count: messages.length });
|
|
1329
|
+
if (!messages.length) {
|
|
1330
|
+
return [];
|
|
1331
|
+
}
|
|
1332
|
+
const messageIds = messages.map((m) => m.id);
|
|
1333
|
+
const fullTableName = this.#db.getTableName(TABLE_MESSAGES);
|
|
1334
|
+
const threadsTableName = this.#db.getTableName(TABLE_THREADS);
|
|
1270
1335
|
try {
|
|
1271
|
-
const
|
|
1272
|
-
const
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1336
|
+
const placeholders = messageIds.map(() => "?").join(",");
|
|
1337
|
+
const selectQuery = `SELECT id, content, role, type, createdAt, thread_id AS threadId, resourceId FROM ${fullTableName} WHERE id IN (${placeholders})`;
|
|
1338
|
+
const existingMessages = await this.#db.executeQuery({ sql: selectQuery, params: messageIds });
|
|
1339
|
+
if (existingMessages.length === 0) {
|
|
1340
|
+
return [];
|
|
1341
|
+
}
|
|
1342
|
+
const parsedExistingMessages = existingMessages.map((msg) => {
|
|
1343
|
+
if (typeof msg.content === "string") {
|
|
1344
|
+
try {
|
|
1345
|
+
msg.content = JSON.parse(msg.content);
|
|
1346
|
+
} catch {
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
return msg;
|
|
1350
|
+
});
|
|
1351
|
+
const threadIdsToUpdate = /* @__PURE__ */ new Set();
|
|
1352
|
+
const updateQueries = [];
|
|
1353
|
+
for (const existingMessage of parsedExistingMessages) {
|
|
1354
|
+
const updatePayload = messages.find((m) => m.id === existingMessage.id);
|
|
1355
|
+
if (!updatePayload) continue;
|
|
1356
|
+
const { id, ...fieldsToUpdate } = updatePayload;
|
|
1357
|
+
if (Object.keys(fieldsToUpdate).length === 0) continue;
|
|
1358
|
+
threadIdsToUpdate.add(existingMessage.threadId);
|
|
1359
|
+
if ("threadId" in updatePayload && updatePayload.threadId && updatePayload.threadId !== existingMessage.threadId) {
|
|
1360
|
+
threadIdsToUpdate.add(updatePayload.threadId);
|
|
1361
|
+
}
|
|
1362
|
+
const setClauses = [];
|
|
1363
|
+
const values = [];
|
|
1364
|
+
const updatableFields = { ...fieldsToUpdate };
|
|
1365
|
+
if (updatableFields.content) {
|
|
1366
|
+
const existingContent = existingMessage.content || {};
|
|
1367
|
+
const newContent = {
|
|
1368
|
+
...existingContent,
|
|
1369
|
+
...updatableFields.content,
|
|
1370
|
+
// Deep merge metadata if it exists on both
|
|
1371
|
+
...existingContent?.metadata && updatableFields.content.metadata ? {
|
|
1372
|
+
metadata: {
|
|
1373
|
+
...existingContent.metadata,
|
|
1374
|
+
...updatableFields.content.metadata
|
|
1375
|
+
}
|
|
1376
|
+
} : {}
|
|
1377
|
+
};
|
|
1378
|
+
setClauses.push(`content = ?`);
|
|
1379
|
+
values.push(JSON.stringify(newContent));
|
|
1380
|
+
delete updatableFields.content;
|
|
1381
|
+
}
|
|
1382
|
+
for (const key in updatableFields) {
|
|
1383
|
+
if (Object.prototype.hasOwnProperty.call(updatableFields, key)) {
|
|
1384
|
+
const dbColumn = key === "threadId" ? "thread_id" : key;
|
|
1385
|
+
setClauses.push(`${dbColumn} = ?`);
|
|
1386
|
+
values.push(updatableFields[key]);
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1389
|
+
if (setClauses.length > 0) {
|
|
1390
|
+
values.push(id);
|
|
1391
|
+
const updateQuery = `UPDATE ${fullTableName} SET ${setClauses.join(", ")} WHERE id = ?`;
|
|
1392
|
+
updateQueries.push({ sql: updateQuery, params: values });
|
|
1280
1393
|
}
|
|
1281
1394
|
}
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
const { sql, params } = query.build();
|
|
1285
|
-
const result = await this.executeQuery({ sql, params, first: true });
|
|
1286
|
-
if (!result) {
|
|
1287
|
-
return null;
|
|
1395
|
+
for (const query of updateQueries) {
|
|
1396
|
+
await this.#db.executeQuery(query);
|
|
1288
1397
|
}
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1398
|
+
if (threadIdsToUpdate.size > 0) {
|
|
1399
|
+
const threadPlaceholders = Array.from(threadIdsToUpdate).map(() => "?").join(",");
|
|
1400
|
+
const threadUpdateQuery = `UPDATE ${threadsTableName} SET updatedAt = ? WHERE id IN (${threadPlaceholders})`;
|
|
1401
|
+
const threadUpdateParams = [(/* @__PURE__ */ new Date()).toISOString(), ...Array.from(threadIdsToUpdate)];
|
|
1402
|
+
await this.#db.executeQuery({ sql: threadUpdateQuery, params: threadUpdateParams });
|
|
1292
1403
|
}
|
|
1293
|
-
|
|
1404
|
+
const updatedMessages = await this.#db.executeQuery({ sql: selectQuery, params: messageIds });
|
|
1405
|
+
return updatedMessages.map((message) => {
|
|
1406
|
+
if (typeof message.content === "string") {
|
|
1407
|
+
try {
|
|
1408
|
+
message.content = JSON.parse(message.content);
|
|
1409
|
+
} catch {
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
return message;
|
|
1413
|
+
});
|
|
1294
1414
|
} catch (error) {
|
|
1295
1415
|
throw new MastraError(
|
|
1296
1416
|
{
|
|
1297
|
-
id: "
|
|
1417
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "UPDATE_MESSAGES", "FAILED"),
|
|
1298
1418
|
domain: ErrorDomain.STORAGE,
|
|
1299
1419
|
category: ErrorCategory.THIRD_PARTY,
|
|
1300
|
-
details: {
|
|
1420
|
+
details: { count: messages.length }
|
|
1301
1421
|
},
|
|
1302
1422
|
error
|
|
1303
1423
|
);
|
|
1304
1424
|
}
|
|
1305
1425
|
}
|
|
1306
|
-
async
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
}
|
|
1311
|
-
return processed;
|
|
1312
|
-
}
|
|
1313
|
-
/**
|
|
1314
|
-
* Upsert multiple records in a batch operation
|
|
1315
|
-
* @param tableName The table to insert into
|
|
1316
|
-
* @param records The records to insert
|
|
1317
|
-
*/
|
|
1318
|
-
async batchUpsert({ tableName, records }) {
|
|
1319
|
-
if (records.length === 0) return;
|
|
1320
|
-
const fullTableName = this.getTableName(tableName);
|
|
1426
|
+
async deleteMessages(messageIds) {
|
|
1427
|
+
if (messageIds.length === 0) return;
|
|
1428
|
+
const fullTableName = this.#db.getTableName(TABLE_MESSAGES);
|
|
1429
|
+
const threadsTableName = this.#db.getTableName(TABLE_THREADS);
|
|
1321
1430
|
try {
|
|
1322
|
-
const
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
});
|
|
1335
|
-
const recordToUpsert = columns.reduce(
|
|
1336
|
-
(acc, col) => {
|
|
1337
|
-
if (col !== "createdAt") acc[col] = `excluded.${col}`;
|
|
1338
|
-
return acc;
|
|
1339
|
-
},
|
|
1340
|
-
{}
|
|
1341
|
-
);
|
|
1342
|
-
const query = createSqlBuilder().insert(fullTableName, columns, values, ["id"], recordToUpsert);
|
|
1343
|
-
const { sql, params } = query.build();
|
|
1344
|
-
await this.executeQuery({ sql, params });
|
|
1345
|
-
}
|
|
1346
|
-
}
|
|
1347
|
-
this.logger.debug(
|
|
1348
|
-
`Processed batch ${Math.floor(i / batchSize) + 1} of ${Math.ceil(records.length / batchSize)}`
|
|
1349
|
-
);
|
|
1431
|
+
const placeholders = messageIds.map(() => "?").join(",");
|
|
1432
|
+
const selectQuery = `SELECT DISTINCT thread_id FROM ${fullTableName} WHERE id IN (${placeholders})`;
|
|
1433
|
+
const threadResults = await this.#db.executeQuery({ sql: selectQuery, params: messageIds });
|
|
1434
|
+
const threadIds = threadResults.map((r) => r.thread_id).filter(Boolean);
|
|
1435
|
+
const deleteQuery = createSqlBuilder().delete(fullTableName).where(`id IN (${placeholders})`, ...messageIds);
|
|
1436
|
+
const { sql, params } = deleteQuery.build();
|
|
1437
|
+
await this.#db.executeQuery({ sql, params });
|
|
1438
|
+
if (threadIds.length > 0) {
|
|
1439
|
+
const threadPlaceholders = threadIds.map(() => "?").join(",");
|
|
1440
|
+
const threadUpdateQuery = `UPDATE ${threadsTableName} SET updatedAt = ? WHERE id IN (${threadPlaceholders})`;
|
|
1441
|
+
const threadUpdateParams = [(/* @__PURE__ */ new Date()).toISOString(), ...threadIds];
|
|
1442
|
+
await this.#db.executeQuery({ sql: threadUpdateQuery, params: threadUpdateParams });
|
|
1350
1443
|
}
|
|
1351
|
-
this.logger.debug(`Successfully batch upserted ${records.length} records into ${tableName}`);
|
|
1352
1444
|
} catch (error) {
|
|
1353
1445
|
throw new MastraError(
|
|
1354
1446
|
{
|
|
1355
|
-
id: "
|
|
1447
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "DELETE_MESSAGES", "FAILED"),
|
|
1356
1448
|
domain: ErrorDomain.STORAGE,
|
|
1357
1449
|
category: ErrorCategory.THIRD_PARTY,
|
|
1358
|
-
|
|
1359
|
-
details: { tableName }
|
|
1450
|
+
details: { messageIds: JSON.stringify(messageIds) }
|
|
1360
1451
|
},
|
|
1361
1452
|
error
|
|
1362
1453
|
);
|
|
@@ -1364,32 +1455,31 @@ var StoreOperationsD1 = class extends StoreOperations {
|
|
|
1364
1455
|
}
|
|
1365
1456
|
};
|
|
1366
1457
|
function transformScoreRow(row) {
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
deserialized.metadata = safelyParseJSON(row.metadata);
|
|
1374
|
-
deserialized.additionalContext = safelyParseJSON(row.additionalContext);
|
|
1375
|
-
deserialized.requestContext = safelyParseJSON(row.requestContext);
|
|
1376
|
-
deserialized.entity = safelyParseJSON(row.entity);
|
|
1377
|
-
deserialized.createdAt = row.createdAtZ || row.createdAt;
|
|
1378
|
-
deserialized.updatedAt = row.updatedAtZ || row.updatedAt;
|
|
1379
|
-
return deserialized;
|
|
1458
|
+
return transformScoreRow$1(row, {
|
|
1459
|
+
preferredTimestampFields: {
|
|
1460
|
+
createdAt: "createdAtZ",
|
|
1461
|
+
updatedAt: "updatedAtZ"
|
|
1462
|
+
}
|
|
1463
|
+
});
|
|
1380
1464
|
}
|
|
1381
1465
|
var ScoresStorageD1 = class extends ScoresStorage {
|
|
1382
|
-
|
|
1383
|
-
constructor(
|
|
1466
|
+
#db;
|
|
1467
|
+
constructor(config) {
|
|
1384
1468
|
super();
|
|
1385
|
-
this
|
|
1469
|
+
this.#db = new D1DB(resolveD1Config(config));
|
|
1470
|
+
}
|
|
1471
|
+
async init() {
|
|
1472
|
+
await this.#db.createTable({ tableName: TABLE_SCORERS, schema: TABLE_SCHEMAS[TABLE_SCORERS] });
|
|
1473
|
+
}
|
|
1474
|
+
async dangerouslyClearAll() {
|
|
1475
|
+
await this.#db.clearTable({ tableName: TABLE_SCORERS });
|
|
1386
1476
|
}
|
|
1387
1477
|
async getScoreById({ id }) {
|
|
1388
1478
|
try {
|
|
1389
|
-
const fullTableName = this.
|
|
1479
|
+
const fullTableName = this.#db.getTableName(TABLE_SCORERS);
|
|
1390
1480
|
const query = createSqlBuilder().select("*").from(fullTableName).where("id = ?", id);
|
|
1391
1481
|
const { sql, params } = query.build();
|
|
1392
|
-
const result = await this.
|
|
1482
|
+
const result = await this.#db.executeQuery({ sql, params, first: true });
|
|
1393
1483
|
if (!result) {
|
|
1394
1484
|
return null;
|
|
1395
1485
|
}
|
|
@@ -1397,7 +1487,7 @@ var ScoresStorageD1 = class extends ScoresStorage {
|
|
|
1397
1487
|
} catch (error) {
|
|
1398
1488
|
throw new MastraError(
|
|
1399
1489
|
{
|
|
1400
|
-
id: "
|
|
1490
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "GET_SCORE_BY_ID", "FAILED"),
|
|
1401
1491
|
domain: ErrorDomain.STORAGE,
|
|
1402
1492
|
category: ErrorCategory.THIRD_PARTY
|
|
1403
1493
|
},
|
|
@@ -1412,17 +1502,23 @@ var ScoresStorageD1 = class extends ScoresStorage {
|
|
|
1412
1502
|
} catch (error) {
|
|
1413
1503
|
throw new MastraError(
|
|
1414
1504
|
{
|
|
1415
|
-
id: "
|
|
1505
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "SAVE_SCORE", "VALIDATION_FAILED"),
|
|
1416
1506
|
domain: ErrorDomain.STORAGE,
|
|
1417
1507
|
category: ErrorCategory.USER,
|
|
1418
|
-
details: {
|
|
1508
|
+
details: {
|
|
1509
|
+
scorer: typeof score.scorer?.id === "string" ? score.scorer.id : String(score.scorer?.id ?? "unknown"),
|
|
1510
|
+
entityId: score.entityId ?? "unknown",
|
|
1511
|
+
entityType: score.entityType ?? "unknown",
|
|
1512
|
+
traceId: score.traceId ?? "",
|
|
1513
|
+
spanId: score.spanId ?? ""
|
|
1514
|
+
}
|
|
1419
1515
|
},
|
|
1420
1516
|
error
|
|
1421
1517
|
);
|
|
1422
1518
|
}
|
|
1519
|
+
const id = crypto.randomUUID();
|
|
1423
1520
|
try {
|
|
1424
|
-
const
|
|
1425
|
-
const fullTableName = this.operations.getTableName(TABLE_SCORERS);
|
|
1521
|
+
const fullTableName = this.#db.getTableName(TABLE_SCORERS);
|
|
1426
1522
|
const serializedRecord = {};
|
|
1427
1523
|
for (const [key, value] of Object.entries(parsedScore)) {
|
|
1428
1524
|
if (value !== null && value !== void 0) {
|
|
@@ -1435,22 +1531,23 @@ var ScoresStorageD1 = class extends ScoresStorage {
|
|
|
1435
1531
|
serializedRecord[key] = null;
|
|
1436
1532
|
}
|
|
1437
1533
|
}
|
|
1534
|
+
const now = /* @__PURE__ */ new Date();
|
|
1438
1535
|
serializedRecord.id = id;
|
|
1439
|
-
serializedRecord.createdAt =
|
|
1440
|
-
serializedRecord.updatedAt =
|
|
1536
|
+
serializedRecord.createdAt = now.toISOString();
|
|
1537
|
+
serializedRecord.updatedAt = now.toISOString();
|
|
1441
1538
|
const columns = Object.keys(serializedRecord);
|
|
1442
1539
|
const values = Object.values(serializedRecord);
|
|
1443
1540
|
const query = createSqlBuilder().insert(fullTableName, columns, values);
|
|
1444
1541
|
const { sql, params } = query.build();
|
|
1445
|
-
await this.
|
|
1446
|
-
|
|
1447
|
-
return { score: scoreFromDb };
|
|
1542
|
+
await this.#db.executeQuery({ sql, params });
|
|
1543
|
+
return { score: { ...parsedScore, id, createdAt: now, updatedAt: now } };
|
|
1448
1544
|
} catch (error) {
|
|
1449
1545
|
throw new MastraError(
|
|
1450
1546
|
{
|
|
1451
|
-
id: "
|
|
1547
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "SAVE_SCORE", "FAILED"),
|
|
1452
1548
|
domain: ErrorDomain.STORAGE,
|
|
1453
|
-
category: ErrorCategory.THIRD_PARTY
|
|
1549
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1550
|
+
details: { id }
|
|
1454
1551
|
},
|
|
1455
1552
|
error
|
|
1456
1553
|
);
|
|
@@ -1467,7 +1564,7 @@ var ScoresStorageD1 = class extends ScoresStorage {
|
|
|
1467
1564
|
const { page, perPage: perPageInput } = pagination;
|
|
1468
1565
|
const perPage = normalizePerPage(perPageInput, 100);
|
|
1469
1566
|
const { offset: start, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
|
|
1470
|
-
const fullTableName = this.
|
|
1567
|
+
const fullTableName = this.#db.getTableName(TABLE_SCORERS);
|
|
1471
1568
|
const countQuery = createSqlBuilder().count().from(fullTableName).where("scorerId = ?", scorerId);
|
|
1472
1569
|
if (entityId) {
|
|
1473
1570
|
countQuery.andWhere("entityId = ?", entityId);
|
|
@@ -1478,7 +1575,7 @@ var ScoresStorageD1 = class extends ScoresStorage {
|
|
|
1478
1575
|
if (source) {
|
|
1479
1576
|
countQuery.andWhere("source = ?", source);
|
|
1480
1577
|
}
|
|
1481
|
-
const countResult = await this.
|
|
1578
|
+
const countResult = await this.#db.executeQuery(countQuery.build());
|
|
1482
1579
|
const total = Array.isArray(countResult) ? Number(countResult?.[0]?.count ?? 0) : Number(countResult?.count ?? 0);
|
|
1483
1580
|
if (total === 0) {
|
|
1484
1581
|
return {
|
|
@@ -1505,7 +1602,7 @@ var ScoresStorageD1 = class extends ScoresStorage {
|
|
|
1505
1602
|
}
|
|
1506
1603
|
selectQuery.limit(limitValue).offset(start);
|
|
1507
1604
|
const { sql, params } = selectQuery.build();
|
|
1508
|
-
const results = await this.
|
|
1605
|
+
const results = await this.#db.executeQuery({ sql, params });
|
|
1509
1606
|
const scores = Array.isArray(results) ? results.map(transformScoreRow) : [];
|
|
1510
1607
|
return {
|
|
1511
1608
|
pagination: {
|
|
@@ -1519,7 +1616,7 @@ var ScoresStorageD1 = class extends ScoresStorage {
|
|
|
1519
1616
|
} catch (error) {
|
|
1520
1617
|
throw new MastraError(
|
|
1521
1618
|
{
|
|
1522
|
-
id: "
|
|
1619
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "GET_SCORES_BY_SCORER_ID", "FAILED"),
|
|
1523
1620
|
domain: ErrorDomain.STORAGE,
|
|
1524
1621
|
category: ErrorCategory.THIRD_PARTY
|
|
1525
1622
|
},
|
|
@@ -1535,9 +1632,9 @@ var ScoresStorageD1 = class extends ScoresStorage {
|
|
|
1535
1632
|
const { page, perPage: perPageInput } = pagination;
|
|
1536
1633
|
const perPage = normalizePerPage(perPageInput, 100);
|
|
1537
1634
|
const { offset: start, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
|
|
1538
|
-
const fullTableName = this.
|
|
1635
|
+
const fullTableName = this.#db.getTableName(TABLE_SCORERS);
|
|
1539
1636
|
const countQuery = createSqlBuilder().count().from(fullTableName).where("runId = ?", runId);
|
|
1540
|
-
const countResult = await this.
|
|
1637
|
+
const countResult = await this.#db.executeQuery(countQuery.build());
|
|
1541
1638
|
const total = Array.isArray(countResult) ? Number(countResult?.[0]?.count ?? 0) : Number(countResult?.count ?? 0);
|
|
1542
1639
|
if (total === 0) {
|
|
1543
1640
|
return {
|
|
@@ -1554,7 +1651,7 @@ var ScoresStorageD1 = class extends ScoresStorage {
|
|
|
1554
1651
|
const limitValue = perPageInput === false ? total : perPage;
|
|
1555
1652
|
const selectQuery = createSqlBuilder().select("*").from(fullTableName).where("runId = ?", runId).limit(limitValue).offset(start);
|
|
1556
1653
|
const { sql, params } = selectQuery.build();
|
|
1557
|
-
const results = await this.
|
|
1654
|
+
const results = await this.#db.executeQuery({ sql, params });
|
|
1558
1655
|
const scores = Array.isArray(results) ? results.map(transformScoreRow) : [];
|
|
1559
1656
|
return {
|
|
1560
1657
|
pagination: {
|
|
@@ -1568,7 +1665,7 @@ var ScoresStorageD1 = class extends ScoresStorage {
|
|
|
1568
1665
|
} catch (error) {
|
|
1569
1666
|
throw new MastraError(
|
|
1570
1667
|
{
|
|
1571
|
-
id: "
|
|
1668
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "GET_SCORES_BY_RUN_ID", "FAILED"),
|
|
1572
1669
|
domain: ErrorDomain.STORAGE,
|
|
1573
1670
|
category: ErrorCategory.THIRD_PARTY
|
|
1574
1671
|
},
|
|
@@ -1585,9 +1682,9 @@ var ScoresStorageD1 = class extends ScoresStorage {
|
|
|
1585
1682
|
const { page, perPage: perPageInput } = pagination;
|
|
1586
1683
|
const perPage = normalizePerPage(perPageInput, 100);
|
|
1587
1684
|
const { offset: start, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
|
|
1588
|
-
const fullTableName = this.
|
|
1685
|
+
const fullTableName = this.#db.getTableName(TABLE_SCORERS);
|
|
1589
1686
|
const countQuery = createSqlBuilder().count().from(fullTableName).where("entityId = ?", entityId).andWhere("entityType = ?", entityType);
|
|
1590
|
-
const countResult = await this.
|
|
1687
|
+
const countResult = await this.#db.executeQuery(countQuery.build());
|
|
1591
1688
|
const total = Array.isArray(countResult) ? Number(countResult?.[0]?.count ?? 0) : Number(countResult?.count ?? 0);
|
|
1592
1689
|
if (total === 0) {
|
|
1593
1690
|
return {
|
|
@@ -1604,7 +1701,7 @@ var ScoresStorageD1 = class extends ScoresStorage {
|
|
|
1604
1701
|
const limitValue = perPageInput === false ? total : perPage;
|
|
1605
1702
|
const selectQuery = createSqlBuilder().select("*").from(fullTableName).where("entityId = ?", entityId).andWhere("entityType = ?", entityType).limit(limitValue).offset(start);
|
|
1606
1703
|
const { sql, params } = selectQuery.build();
|
|
1607
|
-
const results = await this.
|
|
1704
|
+
const results = await this.#db.executeQuery({ sql, params });
|
|
1608
1705
|
const scores = Array.isArray(results) ? results.map(transformScoreRow) : [];
|
|
1609
1706
|
return {
|
|
1610
1707
|
pagination: {
|
|
@@ -1618,7 +1715,7 @@ var ScoresStorageD1 = class extends ScoresStorage {
|
|
|
1618
1715
|
} catch (error) {
|
|
1619
1716
|
throw new MastraError(
|
|
1620
1717
|
{
|
|
1621
|
-
id: "
|
|
1718
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "GET_SCORES_BY_ENTITY_ID", "FAILED"),
|
|
1622
1719
|
domain: ErrorDomain.STORAGE,
|
|
1623
1720
|
category: ErrorCategory.THIRD_PARTY
|
|
1624
1721
|
},
|
|
@@ -1635,9 +1732,9 @@ var ScoresStorageD1 = class extends ScoresStorage {
|
|
|
1635
1732
|
const { page, perPage: perPageInput } = pagination;
|
|
1636
1733
|
const perPage = normalizePerPage(perPageInput, 100);
|
|
1637
1734
|
const { offset: start, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
|
|
1638
|
-
const fullTableName = this.
|
|
1735
|
+
const fullTableName = this.#db.getTableName(TABLE_SCORERS);
|
|
1639
1736
|
const countQuery = createSqlBuilder().count().from(fullTableName).where("traceId = ?", traceId).andWhere("spanId = ?", spanId);
|
|
1640
|
-
const countResult = await this.
|
|
1737
|
+
const countResult = await this.#db.executeQuery(countQuery.build());
|
|
1641
1738
|
const total = Array.isArray(countResult) ? Number(countResult?.[0]?.count ?? 0) : Number(countResult?.count ?? 0);
|
|
1642
1739
|
if (total === 0) {
|
|
1643
1740
|
return {
|
|
@@ -1654,7 +1751,7 @@ var ScoresStorageD1 = class extends ScoresStorage {
|
|
|
1654
1751
|
const limitValue = perPageInput === false ? total : perPage;
|
|
1655
1752
|
const selectQuery = createSqlBuilder().select("*").from(fullTableName).where("traceId = ?", traceId).andWhere("spanId = ?", spanId).orderBy("createdAt", "DESC").limit(limitValue).offset(start);
|
|
1656
1753
|
const { sql, params } = selectQuery.build();
|
|
1657
|
-
const results = await this.
|
|
1754
|
+
const results = await this.#db.executeQuery({ sql, params });
|
|
1658
1755
|
const scores = Array.isArray(results) ? results.map(transformScoreRow) : [];
|
|
1659
1756
|
return {
|
|
1660
1757
|
pagination: {
|
|
@@ -1668,7 +1765,7 @@ var ScoresStorageD1 = class extends ScoresStorage {
|
|
|
1668
1765
|
} catch (error) {
|
|
1669
1766
|
throw new MastraError(
|
|
1670
1767
|
{
|
|
1671
|
-
id: "
|
|
1768
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "GET_SCORES_BY_SPAN", "FAILED"),
|
|
1672
1769
|
domain: ErrorDomain.STORAGE,
|
|
1673
1770
|
category: ErrorCategory.THIRD_PARTY
|
|
1674
1771
|
},
|
|
@@ -1678,10 +1775,16 @@ var ScoresStorageD1 = class extends ScoresStorage {
|
|
|
1678
1775
|
}
|
|
1679
1776
|
};
|
|
1680
1777
|
var WorkflowsStorageD1 = class extends WorkflowsStorage {
|
|
1681
|
-
|
|
1682
|
-
constructor(
|
|
1778
|
+
#db;
|
|
1779
|
+
constructor(config) {
|
|
1683
1780
|
super();
|
|
1684
|
-
this
|
|
1781
|
+
this.#db = new D1DB(resolveD1Config(config));
|
|
1782
|
+
}
|
|
1783
|
+
async init() {
|
|
1784
|
+
await this.#db.createTable({ tableName: TABLE_WORKFLOW_SNAPSHOT, schema: TABLE_SCHEMAS[TABLE_WORKFLOW_SNAPSHOT] });
|
|
1785
|
+
}
|
|
1786
|
+
async dangerouslyClearAll() {
|
|
1787
|
+
await this.#db.clearTable({ tableName: TABLE_WORKFLOW_SNAPSHOT });
|
|
1685
1788
|
}
|
|
1686
1789
|
updateWorkflowResults({
|
|
1687
1790
|
// workflowName,
|
|
@@ -1703,11 +1806,13 @@ var WorkflowsStorageD1 = class extends WorkflowsStorage {
|
|
|
1703
1806
|
workflowName,
|
|
1704
1807
|
runId,
|
|
1705
1808
|
resourceId,
|
|
1706
|
-
snapshot
|
|
1809
|
+
snapshot,
|
|
1810
|
+
createdAt,
|
|
1811
|
+
updatedAt
|
|
1707
1812
|
}) {
|
|
1708
|
-
const fullTableName = this.
|
|
1813
|
+
const fullTableName = this.#db.getTableName(TABLE_WORKFLOW_SNAPSHOT);
|
|
1709
1814
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1710
|
-
const currentSnapshot = await this.
|
|
1815
|
+
const currentSnapshot = await this.#db.load({
|
|
1711
1816
|
tableName: TABLE_WORKFLOW_SNAPSHOT,
|
|
1712
1817
|
keys: { workflow_name: workflowName, run_id: runId }
|
|
1713
1818
|
});
|
|
@@ -1715,16 +1820,16 @@ var WorkflowsStorageD1 = class extends WorkflowsStorage {
|
|
|
1715
1820
|
...currentSnapshot,
|
|
1716
1821
|
resourceId,
|
|
1717
1822
|
snapshot: JSON.stringify(snapshot),
|
|
1718
|
-
updatedAt: now
|
|
1823
|
+
updatedAt: updatedAt ? updatedAt.toISOString() : now
|
|
1719
1824
|
} : {
|
|
1720
1825
|
workflow_name: workflowName,
|
|
1721
1826
|
run_id: runId,
|
|
1722
1827
|
resourceId,
|
|
1723
1828
|
snapshot,
|
|
1724
|
-
createdAt: now,
|
|
1725
|
-
updatedAt: now
|
|
1829
|
+
createdAt: createdAt ? createdAt.toISOString() : now,
|
|
1830
|
+
updatedAt: updatedAt ? updatedAt.toISOString() : now
|
|
1726
1831
|
};
|
|
1727
|
-
const processedRecord = await this.
|
|
1832
|
+
const processedRecord = await this.#db.processRecord(persisting);
|
|
1728
1833
|
const columns = Object.keys(processedRecord);
|
|
1729
1834
|
const values = Object.values(processedRecord);
|
|
1730
1835
|
const updateMap = {
|
|
@@ -1735,11 +1840,11 @@ var WorkflowsStorageD1 = class extends WorkflowsStorage {
|
|
|
1735
1840
|
const query = createSqlBuilder().insert(fullTableName, columns, values, ["workflow_name", "run_id"], updateMap);
|
|
1736
1841
|
const { sql, params } = query.build();
|
|
1737
1842
|
try {
|
|
1738
|
-
await this.
|
|
1843
|
+
await this.#db.executeQuery({ sql, params });
|
|
1739
1844
|
} catch (error) {
|
|
1740
1845
|
throw new MastraError(
|
|
1741
1846
|
{
|
|
1742
|
-
id: "
|
|
1847
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "PERSIST_WORKFLOW_SNAPSHOT", "FAILED"),
|
|
1743
1848
|
domain: ErrorDomain.STORAGE,
|
|
1744
1849
|
category: ErrorCategory.THIRD_PARTY,
|
|
1745
1850
|
text: `Failed to persist workflow snapshot: ${error instanceof Error ? error.message : String(error)}`,
|
|
@@ -1753,7 +1858,7 @@ var WorkflowsStorageD1 = class extends WorkflowsStorage {
|
|
|
1753
1858
|
const { workflowName, runId } = params;
|
|
1754
1859
|
this.logger.debug("Loading workflow snapshot", { workflowName, runId });
|
|
1755
1860
|
try {
|
|
1756
|
-
const d = await this.
|
|
1861
|
+
const d = await this.#db.load({
|
|
1757
1862
|
tableName: TABLE_WORKFLOW_SNAPSHOT,
|
|
1758
1863
|
keys: {
|
|
1759
1864
|
workflow_name: workflowName,
|
|
@@ -1764,7 +1869,7 @@ var WorkflowsStorageD1 = class extends WorkflowsStorage {
|
|
|
1764
1869
|
} catch (error) {
|
|
1765
1870
|
throw new MastraError(
|
|
1766
1871
|
{
|
|
1767
|
-
id: "
|
|
1872
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "LOAD_WORKFLOW_SNAPSHOT", "FAILED"),
|
|
1768
1873
|
domain: ErrorDomain.STORAGE,
|
|
1769
1874
|
category: ErrorCategory.THIRD_PARTY,
|
|
1770
1875
|
text: `Failed to load workflow snapshot: ${error instanceof Error ? error.message : String(error)}`,
|
|
@@ -1780,7 +1885,7 @@ var WorkflowsStorageD1 = class extends WorkflowsStorage {
|
|
|
1780
1885
|
try {
|
|
1781
1886
|
parsedSnapshot = JSON.parse(row.snapshot);
|
|
1782
1887
|
} catch (e) {
|
|
1783
|
-
|
|
1888
|
+
this.logger.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
|
|
1784
1889
|
}
|
|
1785
1890
|
}
|
|
1786
1891
|
return {
|
|
@@ -1801,7 +1906,7 @@ var WorkflowsStorageD1 = class extends WorkflowsStorage {
|
|
|
1801
1906
|
resourceId,
|
|
1802
1907
|
status
|
|
1803
1908
|
} = {}) {
|
|
1804
|
-
const fullTableName = this.
|
|
1909
|
+
const fullTableName = this.#db.getTableName(TABLE_WORKFLOW_SNAPSHOT);
|
|
1805
1910
|
try {
|
|
1806
1911
|
const builder = createSqlBuilder().select().from(fullTableName);
|
|
1807
1912
|
const countBuilder = createSqlBuilder().count().from(fullTableName);
|
|
@@ -1811,12 +1916,12 @@ var WorkflowsStorageD1 = class extends WorkflowsStorage {
|
|
|
1811
1916
|
countBuilder.whereAnd("json_extract(snapshot, '$.status') = ?", status);
|
|
1812
1917
|
}
|
|
1813
1918
|
if (resourceId) {
|
|
1814
|
-
const hasResourceId = await this.
|
|
1919
|
+
const hasResourceId = await this.#db.hasColumn(fullTableName, "resourceId");
|
|
1815
1920
|
if (hasResourceId) {
|
|
1816
1921
|
builder.whereAnd("resourceId = ?", resourceId);
|
|
1817
1922
|
countBuilder.whereAnd("resourceId = ?", resourceId);
|
|
1818
1923
|
} else {
|
|
1819
|
-
|
|
1924
|
+
this.logger.warn(`[${fullTableName}] resourceId column not found. Skipping resourceId filter.`);
|
|
1820
1925
|
}
|
|
1821
1926
|
}
|
|
1822
1927
|
if (fromDate) {
|
|
@@ -1837,20 +1942,20 @@ var WorkflowsStorageD1 = class extends WorkflowsStorage {
|
|
|
1837
1942
|
let total = 0;
|
|
1838
1943
|
if (perPage !== void 0 && page !== void 0) {
|
|
1839
1944
|
const { sql: countSql, params: countParams } = countBuilder.build();
|
|
1840
|
-
const countResult = await this.
|
|
1945
|
+
const countResult = await this.#db.executeQuery({
|
|
1841
1946
|
sql: countSql,
|
|
1842
1947
|
params: countParams,
|
|
1843
1948
|
first: true
|
|
1844
1949
|
});
|
|
1845
1950
|
total = Number(countResult?.count ?? 0);
|
|
1846
1951
|
}
|
|
1847
|
-
const results = await this.
|
|
1952
|
+
const results = await this.#db.executeQuery({ sql, params });
|
|
1848
1953
|
const runs = (isArrayOfRecords(results) ? results : []).map((row) => this.parseWorkflowRun(row));
|
|
1849
1954
|
return { runs, total: total || runs.length };
|
|
1850
1955
|
} catch (error) {
|
|
1851
1956
|
throw new MastraError(
|
|
1852
1957
|
{
|
|
1853
|
-
id: "
|
|
1958
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "LIST_WORKFLOW_RUNS", "FAILED"),
|
|
1854
1959
|
domain: ErrorDomain.STORAGE,
|
|
1855
1960
|
category: ErrorCategory.THIRD_PARTY,
|
|
1856
1961
|
text: `Failed to retrieve workflow runs: ${error instanceof Error ? error.message : String(error)}`,
|
|
@@ -1867,7 +1972,7 @@ var WorkflowsStorageD1 = class extends WorkflowsStorage {
|
|
|
1867
1972
|
runId,
|
|
1868
1973
|
workflowName
|
|
1869
1974
|
}) {
|
|
1870
|
-
const fullTableName = this.
|
|
1975
|
+
const fullTableName = this.#db.getTableName(TABLE_WORKFLOW_SNAPSHOT);
|
|
1871
1976
|
try {
|
|
1872
1977
|
const conditions = [];
|
|
1873
1978
|
const params = [];
|
|
@@ -1881,13 +1986,13 @@ var WorkflowsStorageD1 = class extends WorkflowsStorage {
|
|
|
1881
1986
|
}
|
|
1882
1987
|
const whereClause = conditions.length > 0 ? "WHERE " + conditions.join(" AND ") : "";
|
|
1883
1988
|
const sql = `SELECT * FROM ${fullTableName} ${whereClause} ORDER BY createdAt DESC LIMIT 1`;
|
|
1884
|
-
const result = await this.
|
|
1989
|
+
const result = await this.#db.executeQuery({ sql, params, first: true });
|
|
1885
1990
|
if (!result) return null;
|
|
1886
1991
|
return this.parseWorkflowRun(result);
|
|
1887
1992
|
} catch (error) {
|
|
1888
1993
|
throw new MastraError(
|
|
1889
1994
|
{
|
|
1890
|
-
id: "
|
|
1995
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "GET_WORKFLOW_RUN_BY_ID", "FAILED"),
|
|
1891
1996
|
domain: ErrorDomain.STORAGE,
|
|
1892
1997
|
category: ErrorCategory.THIRD_PARTY,
|
|
1893
1998
|
text: `Failed to retrieve workflow run by ID: ${error instanceof Error ? error.message : String(error)}`,
|
|
@@ -1897,13 +2002,31 @@ var WorkflowsStorageD1 = class extends WorkflowsStorage {
|
|
|
1897
2002
|
);
|
|
1898
2003
|
}
|
|
1899
2004
|
}
|
|
2005
|
+
async deleteWorkflowRunById({ runId, workflowName }) {
|
|
2006
|
+
const fullTableName = this.#db.getTableName(TABLE_WORKFLOW_SNAPSHOT);
|
|
2007
|
+
try {
|
|
2008
|
+
const sql = `DELETE FROM ${fullTableName} WHERE workflow_name = ? AND run_id = ?`;
|
|
2009
|
+
const params = [workflowName, runId];
|
|
2010
|
+
await this.#db.executeQuery({ sql, params });
|
|
2011
|
+
} catch (error) {
|
|
2012
|
+
throw new MastraError(
|
|
2013
|
+
{
|
|
2014
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "DELETE_WORKFLOW_RUN_BY_ID", "FAILED"),
|
|
2015
|
+
domain: ErrorDomain.STORAGE,
|
|
2016
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2017
|
+
text: `Failed to delete workflow run by ID: ${error instanceof Error ? error.message : String(error)}`,
|
|
2018
|
+
details: { runId, workflowName }
|
|
2019
|
+
},
|
|
2020
|
+
error
|
|
2021
|
+
);
|
|
2022
|
+
}
|
|
2023
|
+
}
|
|
1900
2024
|
};
|
|
1901
2025
|
|
|
1902
2026
|
// src/storage/index.ts
|
|
1903
2027
|
var D1Store = class extends MastraStorage {
|
|
1904
2028
|
client;
|
|
1905
2029
|
binding;
|
|
1906
|
-
// D1Database binding
|
|
1907
2030
|
tablePrefix;
|
|
1908
2031
|
stores;
|
|
1909
2032
|
/**
|
|
@@ -1912,7 +2035,7 @@ var D1Store = class extends MastraStorage {
|
|
|
1912
2035
|
*/
|
|
1913
2036
|
constructor(config) {
|
|
1914
2037
|
try {
|
|
1915
|
-
super({ id: config.id, name: "D1" });
|
|
2038
|
+
super({ id: config.id, name: "D1", disableInit: config.disableInit });
|
|
1916
2039
|
if (config.tablePrefix && !/^[a-zA-Z0-9_]*$/.test(config.tablePrefix)) {
|
|
1917
2040
|
throw new Error("Invalid tablePrefix: only letters, numbers, and underscores are allowed.");
|
|
1918
2041
|
}
|
|
@@ -1950,7 +2073,7 @@ var D1Store = class extends MastraStorage {
|
|
|
1950
2073
|
} catch (error) {
|
|
1951
2074
|
throw new MastraError(
|
|
1952
2075
|
{
|
|
1953
|
-
id: "
|
|
2076
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "INITIALIZATION", "FAILED"),
|
|
1954
2077
|
domain: ErrorDomain.STORAGE,
|
|
1955
2078
|
category: ErrorCategory.SYSTEM,
|
|
1956
2079
|
text: "Error initializing D1Store"
|
|
@@ -1958,189 +2081,26 @@ var D1Store = class extends MastraStorage {
|
|
|
1958
2081
|
error
|
|
1959
2082
|
);
|
|
1960
2083
|
}
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
}
|
|
2084
|
+
let scores;
|
|
2085
|
+
let workflows;
|
|
2086
|
+
let memory;
|
|
2087
|
+
if (this.binding) {
|
|
2088
|
+
const domainConfig = { binding: this.binding, tablePrefix: this.tablePrefix };
|
|
2089
|
+
scores = new ScoresStorageD1(domainConfig);
|
|
2090
|
+
workflows = new WorkflowsStorageD1(domainConfig);
|
|
2091
|
+
memory = new MemoryStorageD1(domainConfig);
|
|
2092
|
+
} else {
|
|
2093
|
+
const domainConfig = { client: this.client, tablePrefix: this.tablePrefix };
|
|
2094
|
+
scores = new ScoresStorageD1(domainConfig);
|
|
2095
|
+
workflows = new WorkflowsStorageD1(domainConfig);
|
|
2096
|
+
memory = new MemoryStorageD1(domainConfig);
|
|
2097
|
+
}
|
|
1975
2098
|
this.stores = {
|
|
1976
|
-
operations,
|
|
1977
2099
|
scores,
|
|
1978
2100
|
workflows,
|
|
1979
2101
|
memory
|
|
1980
2102
|
};
|
|
1981
2103
|
}
|
|
1982
|
-
get supports() {
|
|
1983
|
-
return {
|
|
1984
|
-
selectByIncludeResourceScope: true,
|
|
1985
|
-
resourceWorkingMemory: true,
|
|
1986
|
-
hasColumn: true,
|
|
1987
|
-
createTable: true,
|
|
1988
|
-
deleteMessages: false,
|
|
1989
|
-
listScoresBySpan: true
|
|
1990
|
-
};
|
|
1991
|
-
}
|
|
1992
|
-
async createTable({
|
|
1993
|
-
tableName,
|
|
1994
|
-
schema
|
|
1995
|
-
}) {
|
|
1996
|
-
return this.stores.operations.createTable({ tableName, schema });
|
|
1997
|
-
}
|
|
1998
|
-
/**
|
|
1999
|
-
* Alters table schema to add columns if they don't exist
|
|
2000
|
-
* @param tableName Name of the table
|
|
2001
|
-
* @param schema Schema of the table
|
|
2002
|
-
* @param ifNotExists Array of column names to add if they don't exist
|
|
2003
|
-
*/
|
|
2004
|
-
async alterTable({
|
|
2005
|
-
tableName,
|
|
2006
|
-
schema,
|
|
2007
|
-
ifNotExists
|
|
2008
|
-
}) {
|
|
2009
|
-
return this.stores.operations.alterTable({ tableName, schema, ifNotExists });
|
|
2010
|
-
}
|
|
2011
|
-
async clearTable({ tableName }) {
|
|
2012
|
-
return this.stores.operations.clearTable({ tableName });
|
|
2013
|
-
}
|
|
2014
|
-
async dropTable({ tableName }) {
|
|
2015
|
-
return this.stores.operations.dropTable({ tableName });
|
|
2016
|
-
}
|
|
2017
|
-
async hasColumn(table, column) {
|
|
2018
|
-
return this.stores.operations.hasColumn(table, column);
|
|
2019
|
-
}
|
|
2020
|
-
async insert({ tableName, record }) {
|
|
2021
|
-
return this.stores.operations.insert({ tableName, record });
|
|
2022
|
-
}
|
|
2023
|
-
async load({ tableName, keys }) {
|
|
2024
|
-
return this.stores.operations.load({ tableName, keys });
|
|
2025
|
-
}
|
|
2026
|
-
async getThreadById({ threadId }) {
|
|
2027
|
-
return this.stores.memory.getThreadById({ threadId });
|
|
2028
|
-
}
|
|
2029
|
-
async saveThread({ thread }) {
|
|
2030
|
-
return this.stores.memory.saveThread({ thread });
|
|
2031
|
-
}
|
|
2032
|
-
async updateThread({
|
|
2033
|
-
id,
|
|
2034
|
-
title,
|
|
2035
|
-
metadata
|
|
2036
|
-
}) {
|
|
2037
|
-
return this.stores.memory.updateThread({ id, title, metadata });
|
|
2038
|
-
}
|
|
2039
|
-
async deleteThread({ threadId }) {
|
|
2040
|
-
return this.stores.memory.deleteThread({ threadId });
|
|
2041
|
-
}
|
|
2042
|
-
async saveMessages(args) {
|
|
2043
|
-
return this.stores.memory.saveMessages(args);
|
|
2044
|
-
}
|
|
2045
|
-
async updateWorkflowResults({
|
|
2046
|
-
workflowName,
|
|
2047
|
-
runId,
|
|
2048
|
-
stepId,
|
|
2049
|
-
result,
|
|
2050
|
-
requestContext
|
|
2051
|
-
}) {
|
|
2052
|
-
return this.stores.workflows.updateWorkflowResults({ workflowName, runId, stepId, result, requestContext });
|
|
2053
|
-
}
|
|
2054
|
-
async updateWorkflowState({
|
|
2055
|
-
workflowName,
|
|
2056
|
-
runId,
|
|
2057
|
-
opts
|
|
2058
|
-
}) {
|
|
2059
|
-
return this.stores.workflows.updateWorkflowState({ workflowName, runId, opts });
|
|
2060
|
-
}
|
|
2061
|
-
async persistWorkflowSnapshot({
|
|
2062
|
-
workflowName,
|
|
2063
|
-
runId,
|
|
2064
|
-
resourceId,
|
|
2065
|
-
snapshot
|
|
2066
|
-
}) {
|
|
2067
|
-
return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, resourceId, snapshot });
|
|
2068
|
-
}
|
|
2069
|
-
async loadWorkflowSnapshot(params) {
|
|
2070
|
-
return this.stores.workflows.loadWorkflowSnapshot(params);
|
|
2071
|
-
}
|
|
2072
|
-
async listWorkflowRuns(args = {}) {
|
|
2073
|
-
return this.stores.workflows.listWorkflowRuns(args);
|
|
2074
|
-
}
|
|
2075
|
-
async getWorkflowRunById({
|
|
2076
|
-
runId,
|
|
2077
|
-
workflowName
|
|
2078
|
-
}) {
|
|
2079
|
-
return this.stores.workflows.getWorkflowRunById({ runId, workflowName });
|
|
2080
|
-
}
|
|
2081
|
-
/**
|
|
2082
|
-
* Insert multiple records in a batch operation
|
|
2083
|
-
* @param tableName The table to insert into
|
|
2084
|
-
* @param records The records to insert
|
|
2085
|
-
*/
|
|
2086
|
-
async batchInsert({ tableName, records }) {
|
|
2087
|
-
return this.stores.operations.batchInsert({ tableName, records });
|
|
2088
|
-
}
|
|
2089
|
-
async updateMessages(_args) {
|
|
2090
|
-
return this.stores.memory.updateMessages(_args);
|
|
2091
|
-
}
|
|
2092
|
-
async getResourceById({ resourceId }) {
|
|
2093
|
-
return this.stores.memory.getResourceById({ resourceId });
|
|
2094
|
-
}
|
|
2095
|
-
async saveResource({ resource }) {
|
|
2096
|
-
return this.stores.memory.saveResource({ resource });
|
|
2097
|
-
}
|
|
2098
|
-
async updateResource({
|
|
2099
|
-
resourceId,
|
|
2100
|
-
workingMemory,
|
|
2101
|
-
metadata
|
|
2102
|
-
}) {
|
|
2103
|
-
return this.stores.memory.updateResource({ resourceId, workingMemory, metadata });
|
|
2104
|
-
}
|
|
2105
|
-
async getScoreById({ id: _id }) {
|
|
2106
|
-
return this.stores.scores.getScoreById({ id: _id });
|
|
2107
|
-
}
|
|
2108
|
-
async saveScore(_score) {
|
|
2109
|
-
return this.stores.scores.saveScore(_score);
|
|
2110
|
-
}
|
|
2111
|
-
async listScoresByRunId({
|
|
2112
|
-
runId: _runId,
|
|
2113
|
-
pagination: _pagination
|
|
2114
|
-
}) {
|
|
2115
|
-
return this.stores.scores.listScoresByRunId({ runId: _runId, pagination: _pagination });
|
|
2116
|
-
}
|
|
2117
|
-
async listScoresByEntityId({
|
|
2118
|
-
entityId: _entityId,
|
|
2119
|
-
entityType: _entityType,
|
|
2120
|
-
pagination: _pagination
|
|
2121
|
-
}) {
|
|
2122
|
-
return this.stores.scores.listScoresByEntityId({
|
|
2123
|
-
entityId: _entityId,
|
|
2124
|
-
entityType: _entityType,
|
|
2125
|
-
pagination: _pagination
|
|
2126
|
-
});
|
|
2127
|
-
}
|
|
2128
|
-
async listScoresByScorerId({
|
|
2129
|
-
scorerId,
|
|
2130
|
-
pagination,
|
|
2131
|
-
entityId,
|
|
2132
|
-
entityType,
|
|
2133
|
-
source
|
|
2134
|
-
}) {
|
|
2135
|
-
return this.stores.scores.listScoresByScorerId({ scorerId, pagination, entityId, entityType, source });
|
|
2136
|
-
}
|
|
2137
|
-
async listScoresBySpan({
|
|
2138
|
-
traceId,
|
|
2139
|
-
spanId,
|
|
2140
|
-
pagination
|
|
2141
|
-
}) {
|
|
2142
|
-
return this.stores.scores.listScoresBySpan({ traceId, spanId, pagination });
|
|
2143
|
-
}
|
|
2144
2104
|
/**
|
|
2145
2105
|
* Close the database connection
|
|
2146
2106
|
* No explicit cleanup needed for D1 in either REST or Workers Binding mode
|
|
@@ -2150,6 +2110,6 @@ var D1Store = class extends MastraStorage {
|
|
|
2150
2110
|
}
|
|
2151
2111
|
};
|
|
2152
2112
|
|
|
2153
|
-
export { D1Store };
|
|
2113
|
+
export { D1Store, MemoryStorageD1, ScoresStorageD1, WorkflowsStorageD1 };
|
|
2154
2114
|
//# sourceMappingURL=index.js.map
|
|
2155
2115
|
//# sourceMappingURL=index.js.map
|