@mastra/cloudflare-d1 1.0.0-beta.0 → 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 +488 -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 -1118
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1077 -1119
- 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 +15 -15
- package/dist/storage/domains/workflows/index.d.ts.map +1 -1
- package/dist/storage/index.d.ts +55 -184
- package/dist/storage/index.d.ts.map +1 -1
- package/package.json +12 -10
- 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,508 +253,600 @@ 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
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
624
|
+
return processed;
|
|
625
|
+
}
|
|
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);
|
|
634
|
+
try {
|
|
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
|
+
}
|
|
659
|
+
}
|
|
660
|
+
this.logger.debug(
|
|
661
|
+
`Processed batch ${Math.floor(i / batchSize) + 1} of ${Math.ceil(records.length / batchSize)}`
|
|
662
|
+
);
|
|
682
663
|
}
|
|
683
|
-
|
|
664
|
+
this.logger.debug(`Successfully batch upserted ${records.length} records into ${tableName}`);
|
|
665
|
+
} catch (error) {
|
|
666
|
+
throw new MastraError(
|
|
667
|
+
{
|
|
668
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "BATCH_UPSERT", "FAILED"),
|
|
669
|
+
domain: ErrorDomain.STORAGE,
|
|
670
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
671
|
+
text: `Failed to batch upsert into ${tableName}: ${error instanceof Error ? error.message : String(error)}`,
|
|
672
|
+
details: { tableName }
|
|
673
|
+
},
|
|
674
|
+
error
|
|
675
|
+
);
|
|
676
|
+
}
|
|
677
|
+
}
|
|
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"]
|
|
684
695
|
});
|
|
685
|
-
return processedMessages;
|
|
686
696
|
}
|
|
687
|
-
async
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
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;
|
|
691
708
|
try {
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
const processedMsg = {};
|
|
699
|
-
for (const [key, value] of Object.entries(message)) {
|
|
700
|
-
if (key === `type` && value === `v2`) continue;
|
|
701
|
-
processedMsg[key] = deserializeValue(value);
|
|
702
|
-
}
|
|
703
|
-
return processedMsg;
|
|
704
|
-
});
|
|
705
|
-
this.logger.debug(`Retrieved ${messages.length} messages`);
|
|
706
|
-
const list = new MessageList().add(processedMessages, "memory");
|
|
707
|
-
return { messages: list.get.all.db() };
|
|
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
|
+
};
|
|
708
715
|
} catch (error) {
|
|
709
716
|
const mastraError = new MastraError(
|
|
710
717
|
{
|
|
711
|
-
id: "
|
|
718
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "GET_RESOURCE_BY_ID", "FAILED"),
|
|
712
719
|
domain: ErrorDomain.STORAGE,
|
|
713
720
|
category: ErrorCategory.THIRD_PARTY,
|
|
714
|
-
text: `
|
|
715
|
-
details: {
|
|
721
|
+
text: `Error processing resource ${resourceId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
722
|
+
details: { resourceId }
|
|
716
723
|
},
|
|
717
724
|
error
|
|
718
725
|
);
|
|
719
726
|
this.logger?.error(mastraError.toString());
|
|
720
727
|
this.logger?.trackException(mastraError);
|
|
721
|
-
|
|
728
|
+
return null;
|
|
722
729
|
}
|
|
723
730
|
}
|
|
724
|
-
async
|
|
725
|
-
const
|
|
726
|
-
|
|
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();
|
|
751
|
+
try {
|
|
752
|
+
await this.#db.executeQuery({ sql, params });
|
|
753
|
+
return resource;
|
|
754
|
+
} catch (error) {
|
|
755
|
+
throw new MastraError(
|
|
756
|
+
{
|
|
757
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "SAVE_RESOURCE", "FAILED"),
|
|
758
|
+
domain: ErrorDomain.STORAGE,
|
|
759
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
760
|
+
text: `Failed to save resource to ${fullTableName}: ${error instanceof Error ? error.message : String(error)}`,
|
|
761
|
+
details: { resourceId: resource.id }
|
|
762
|
+
},
|
|
763
|
+
error
|
|
764
|
+
);
|
|
765
|
+
}
|
|
766
|
+
}
|
|
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 });
|
|
782
|
+
}
|
|
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();
|
|
798
|
+
try {
|
|
799
|
+
await this.#db.executeQuery({ sql, params });
|
|
800
|
+
return updatedResource;
|
|
801
|
+
} catch (error) {
|
|
727
802
|
throw new MastraError(
|
|
728
803
|
{
|
|
729
|
-
id: "
|
|
804
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "UPDATE_RESOURCE", "FAILED"),
|
|
805
|
+
domain: ErrorDomain.STORAGE,
|
|
806
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
807
|
+
text: `Failed to update resource ${resourceId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
808
|
+
details: { resourceId }
|
|
809
|
+
},
|
|
810
|
+
error
|
|
811
|
+
);
|
|
812
|
+
}
|
|
813
|
+
}
|
|
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;
|
|
820
|
+
try {
|
|
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
|
+
};
|
|
827
|
+
} catch (error) {
|
|
828
|
+
const mastraError = new MastraError(
|
|
829
|
+
{
|
|
830
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "GET_THREAD_BY_ID", "FAILED"),
|
|
730
831
|
domain: ErrorDomain.STORAGE,
|
|
731
832
|
category: ErrorCategory.THIRD_PARTY,
|
|
833
|
+
text: `Error processing thread ${threadId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
732
834
|
details: { threadId }
|
|
733
835
|
},
|
|
734
|
-
|
|
836
|
+
error
|
|
735
837
|
);
|
|
838
|
+
this.logger?.error(mastraError.toString());
|
|
839
|
+
this.logger?.trackException(mastraError);
|
|
840
|
+
return null;
|
|
736
841
|
}
|
|
842
|
+
}
|
|
843
|
+
async listThreadsByResourceId(args) {
|
|
844
|
+
const { resourceId, page = 0, perPage: perPageInput, orderBy } = args;
|
|
845
|
+
const perPage = normalizePerPage(perPageInput, 100);
|
|
737
846
|
if (page < 0) {
|
|
738
847
|
throw new MastraError(
|
|
739
848
|
{
|
|
740
|
-
id: "
|
|
849
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "LIST_THREADS_BY_RESOURCE_ID", "INVALID_PAGE"),
|
|
741
850
|
domain: ErrorDomain.STORAGE,
|
|
742
851
|
category: ErrorCategory.USER,
|
|
743
852
|
details: { page }
|
|
@@ -745,130 +854,45 @@ var MemoryStorageD1 = class extends MemoryStorage {
|
|
|
745
854
|
new Error("page must be >= 0")
|
|
746
855
|
);
|
|
747
856
|
}
|
|
748
|
-
const perPage = normalizePerPage(perPageInput, 40);
|
|
749
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
|
+
});
|
|
750
866
|
try {
|
|
751
|
-
const
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
const
|
|
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;
|
|
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);
|
|
847
874
|
return {
|
|
848
|
-
|
|
875
|
+
threads,
|
|
849
876
|
total,
|
|
850
877
|
page,
|
|
851
878
|
perPage: perPageForResponse,
|
|
852
|
-
hasMore
|
|
879
|
+
hasMore: perPageInput === false ? false : offset + perPage < total
|
|
853
880
|
};
|
|
854
881
|
} catch (error) {
|
|
855
882
|
const mastraError = new MastraError(
|
|
856
883
|
{
|
|
857
|
-
id: "
|
|
884
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "LIST_THREADS_BY_RESOURCE_ID", "FAILED"),
|
|
858
885
|
domain: ErrorDomain.STORAGE,
|
|
859
886
|
category: ErrorCategory.THIRD_PARTY,
|
|
860
|
-
text: `
|
|
861
|
-
details: {
|
|
862
|
-
threadId,
|
|
863
|
-
resourceId: resourceId ?? ""
|
|
864
|
-
}
|
|
887
|
+
text: `Error getting threads by resourceId ${resourceId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
888
|
+
details: { resourceId }
|
|
865
889
|
},
|
|
866
890
|
error
|
|
867
891
|
);
|
|
868
|
-
this.logger?.error
|
|
869
|
-
this.logger?.trackException
|
|
892
|
+
this.logger?.error(mastraError.toString());
|
|
893
|
+
this.logger?.trackException(mastraError);
|
|
870
894
|
return {
|
|
871
|
-
|
|
895
|
+
threads: [],
|
|
872
896
|
total: 0,
|
|
873
897
|
page,
|
|
874
898
|
perPage: perPageForResponse,
|
|
@@ -876,487 +900,554 @@ var MemoryStorageD1 = class extends MemoryStorage {
|
|
|
876
900
|
};
|
|
877
901
|
}
|
|
878
902
|
}
|
|
879
|
-
async
|
|
880
|
-
const
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
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();
|
|
888
925
|
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
|
-
});
|
|
926
|
+
await this.#db.executeQuery({ sql, params });
|
|
927
|
+
return thread;
|
|
967
928
|
} catch (error) {
|
|
968
929
|
throw new MastraError(
|
|
969
930
|
{
|
|
970
|
-
id: "
|
|
931
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "SAVE_THREAD", "FAILED"),
|
|
971
932
|
domain: ErrorDomain.STORAGE,
|
|
972
933
|
category: ErrorCategory.THIRD_PARTY,
|
|
973
|
-
|
|
934
|
+
text: `Failed to save thread to ${fullTableName}: ${error instanceof Error ? error.message : String(error)}`,
|
|
935
|
+
details: { threadId: thread.id }
|
|
974
936
|
},
|
|
975
937
|
error
|
|
976
938
|
);
|
|
977
939
|
}
|
|
978
940
|
}
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
tablePrefix;
|
|
984
|
-
constructor(config) {
|
|
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
|
|
941
|
+
async updateThread({
|
|
942
|
+
id,
|
|
943
|
+
title,
|
|
944
|
+
metadata
|
|
1007
945
|
}) {
|
|
1008
|
-
|
|
1009
|
-
throw new Error("Workers binding is not configured");
|
|
1010
|
-
}
|
|
946
|
+
const thread = await this.getThreadById({ threadId: id });
|
|
1011
947
|
try {
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
let result;
|
|
1015
|
-
if (formattedParams.length > 0) {
|
|
1016
|
-
if (first) {
|
|
1017
|
-
result = await statement.bind(...formattedParams).first();
|
|
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
|
-
}
|
|
948
|
+
if (!thread) {
|
|
949
|
+
throw new Error(`Thread ${id} not found`);
|
|
1035
950
|
}
|
|
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);
|
|
960
|
+
const { sql, params } = query.build();
|
|
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
|
+
};
|
|
1036
971
|
} catch (error) {
|
|
1037
972
|
throw new MastraError(
|
|
1038
973
|
{
|
|
1039
|
-
id: "
|
|
974
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "UPDATE_THREAD", "FAILED"),
|
|
1040
975
|
domain: ErrorDomain.STORAGE,
|
|
1041
976
|
category: ErrorCategory.THIRD_PARTY,
|
|
1042
|
-
|
|
977
|
+
text: `Failed to update thread ${id}: ${error instanceof Error ? error.message : String(error)}`,
|
|
978
|
+
details: { threadId: id }
|
|
1043
979
|
},
|
|
1044
980
|
error
|
|
1045
981
|
);
|
|
1046
982
|
}
|
|
1047
983
|
}
|
|
1048
|
-
async
|
|
1049
|
-
|
|
1050
|
-
params = [],
|
|
1051
|
-
first = false
|
|
1052
|
-
}) {
|
|
1053
|
-
if (!this.client) {
|
|
1054
|
-
throw new Error("D1 client is not configured");
|
|
1055
|
-
}
|
|
984
|
+
async deleteThread({ threadId }) {
|
|
985
|
+
const fullTableName = this.#db.getTableName(TABLE_THREADS);
|
|
1056
986
|
try {
|
|
1057
|
-
const
|
|
1058
|
-
const
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
const
|
|
1063
|
-
|
|
1064
|
-
if (first) {
|
|
1065
|
-
return results[0] || null;
|
|
1066
|
-
}
|
|
1067
|
-
return results;
|
|
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 });
|
|
1068
994
|
} catch (error) {
|
|
1069
995
|
throw new MastraError(
|
|
1070
996
|
{
|
|
1071
|
-
id: "
|
|
997
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "DELETE_THREAD", "FAILED"),
|
|
1072
998
|
domain: ErrorDomain.STORAGE,
|
|
1073
999
|
category: ErrorCategory.THIRD_PARTY,
|
|
1074
|
-
|
|
1000
|
+
text: `Failed to delete thread ${threadId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
1001
|
+
details: { threadId }
|
|
1075
1002
|
},
|
|
1076
1003
|
error
|
|
1077
1004
|
);
|
|
1078
1005
|
}
|
|
1079
1006
|
}
|
|
1080
|
-
async
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
} else if (this.client) {
|
|
1084
|
-
return this.executeRestQuery(options);
|
|
1085
|
-
} else {
|
|
1086
|
-
throw new Error("Neither binding nor client is configured");
|
|
1087
|
-
}
|
|
1088
|
-
}
|
|
1089
|
-
async getTableColumns(tableName) {
|
|
1007
|
+
async saveMessages(args) {
|
|
1008
|
+
const { messages } = args;
|
|
1009
|
+
if (messages.length === 0) return { messages: [] };
|
|
1090
1010
|
try {
|
|
1091
|
-
const
|
|
1092
|
-
const
|
|
1093
|
-
|
|
1094
|
-
|
|
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
|
+
}
|
|
1095
1031
|
}
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
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() };
|
|
1100
1058
|
} catch (error) {
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
return value.toISOString();
|
|
1111
|
-
}
|
|
1112
|
-
if (typeof value === "object") {
|
|
1113
|
-
return JSON.stringify(value);
|
|
1059
|
+
throw new MastraError(
|
|
1060
|
+
{
|
|
1061
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "SAVE_MESSAGES", "FAILED"),
|
|
1062
|
+
domain: ErrorDomain.STORAGE,
|
|
1063
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1064
|
+
text: `Failed to save messages: ${error instanceof Error ? error.message : String(error)}`
|
|
1065
|
+
},
|
|
1066
|
+
error
|
|
1067
|
+
);
|
|
1114
1068
|
}
|
|
1115
|
-
return value;
|
|
1116
1069
|
}
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
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++;
|
|
1127
1113
|
}
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
const
|
|
1135
|
-
const
|
|
1136
|
-
|
|
1137
|
-
|
|
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)");
|
|
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);
|
|
1144
1124
|
}
|
|
1145
|
-
|
|
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 = [];
|
|
1133
|
+
try {
|
|
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");
|
|
1146
1136
|
const { sql, params } = query.build();
|
|
1147
|
-
await this.executeQuery({ sql, params });
|
|
1148
|
-
|
|
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);
|
|
1144
|
+
}
|
|
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() };
|
|
1149
1150
|
} catch (error) {
|
|
1150
|
-
|
|
1151
|
+
const mastraError = new MastraError(
|
|
1151
1152
|
{
|
|
1152
|
-
id: "
|
|
1153
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "LIST_MESSAGES_BY_ID", "FAILED"),
|
|
1153
1154
|
domain: ErrorDomain.STORAGE,
|
|
1154
1155
|
category: ErrorCategory.THIRD_PARTY,
|
|
1155
|
-
|
|
1156
|
+
text: `Failed to retrieve messages by ID: ${error instanceof Error ? error.message : String(error)}`,
|
|
1157
|
+
details: { messageIds: JSON.stringify(messageIds) }
|
|
1156
1158
|
},
|
|
1157
1159
|
error
|
|
1158
1160
|
);
|
|
1161
|
+
this.logger?.error(mastraError.toString());
|
|
1162
|
+
this.logger?.trackException(mastraError);
|
|
1163
|
+
throw mastraError;
|
|
1159
1164
|
}
|
|
1160
1165
|
}
|
|
1161
|
-
async
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
const { sql, params } = query.build();
|
|
1166
|
-
await this.executeQuery({ sql, params });
|
|
1167
|
-
this.logger.debug(`Cleared table ${fullTableName}`);
|
|
1168
|
-
} 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())) {
|
|
1169
1170
|
throw new MastraError(
|
|
1170
1171
|
{
|
|
1171
|
-
id: "
|
|
1172
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "LIST_MESSAGES", "INVALID_THREAD_ID"),
|
|
1172
1173
|
domain: ErrorDomain.STORAGE,
|
|
1173
1174
|
category: ErrorCategory.THIRD_PARTY,
|
|
1174
|
-
details: {
|
|
1175
|
+
details: { threadId: Array.isArray(threadId) ? threadId.join(",") : threadId }
|
|
1175
1176
|
},
|
|
1176
|
-
|
|
1177
|
+
new Error("threadId must be a non-empty string or array of non-empty strings")
|
|
1177
1178
|
);
|
|
1178
1179
|
}
|
|
1179
|
-
|
|
1180
|
-
async dropTable({ tableName }) {
|
|
1181
|
-
try {
|
|
1182
|
-
const fullTableName = this.getTableName(tableName);
|
|
1183
|
-
const sql = `DROP TABLE IF EXISTS ${fullTableName}`;
|
|
1184
|
-
await this.executeQuery({ sql });
|
|
1185
|
-
this.logger.debug(`Dropped table ${fullTableName}`);
|
|
1186
|
-
} catch (error) {
|
|
1180
|
+
if (page < 0) {
|
|
1187
1181
|
throw new MastraError(
|
|
1188
1182
|
{
|
|
1189
|
-
id: "
|
|
1183
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "LIST_MESSAGES", "INVALID_PAGE"),
|
|
1190
1184
|
domain: ErrorDomain.STORAGE,
|
|
1191
|
-
category: ErrorCategory.
|
|
1192
|
-
details: {
|
|
1185
|
+
category: ErrorCategory.USER,
|
|
1186
|
+
details: { page }
|
|
1193
1187
|
},
|
|
1194
|
-
|
|
1188
|
+
new Error("page must be >= 0")
|
|
1195
1189
|
);
|
|
1196
1190
|
}
|
|
1197
|
-
|
|
1198
|
-
|
|
1191
|
+
const perPage = normalizePerPage(perPageInput, 40);
|
|
1192
|
+
const { offset, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
|
|
1199
1193
|
try {
|
|
1200
|
-
const fullTableName = this.getTableName(
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
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
|
+
}
|
|
1210
1275
|
}
|
|
1211
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
|
+
};
|
|
1212
1301
|
} catch (error) {
|
|
1213
|
-
|
|
1302
|
+
const mastraError = new MastraError(
|
|
1214
1303
|
{
|
|
1215
|
-
id: "
|
|
1304
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "LIST_MESSAGES", "FAILED"),
|
|
1216
1305
|
domain: ErrorDomain.STORAGE,
|
|
1217
1306
|
category: ErrorCategory.THIRD_PARTY,
|
|
1218
|
-
|
|
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
|
+
}
|
|
1219
1312
|
},
|
|
1220
1313
|
error
|
|
1221
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
|
+
};
|
|
1222
1324
|
}
|
|
1223
1325
|
}
|
|
1224
|
-
async
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
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) {
|
|
1234
|
-
throw new MastraError(
|
|
1235
|
-
{
|
|
1236
|
-
id: "CLOUDFLARE_D1_STORE_OPERATIONS_INSERT_FAILED",
|
|
1237
|
-
domain: ErrorDomain.STORAGE,
|
|
1238
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
1239
|
-
details: { tableName }
|
|
1240
|
-
},
|
|
1241
|
-
error
|
|
1242
|
-
);
|
|
1326
|
+
async updateMessages(args) {
|
|
1327
|
+
const { messages } = args;
|
|
1328
|
+
this.logger.debug("Updating messages", { count: messages.length });
|
|
1329
|
+
if (!messages.length) {
|
|
1330
|
+
return [];
|
|
1243
1331
|
}
|
|
1244
|
-
|
|
1245
|
-
|
|
1332
|
+
const messageIds = messages.map((m) => m.id);
|
|
1333
|
+
const fullTableName = this.#db.getTableName(TABLE_MESSAGES);
|
|
1334
|
+
const threadsTableName = this.#db.getTableName(TABLE_THREADS);
|
|
1246
1335
|
try {
|
|
1247
|
-
|
|
1248
|
-
const
|
|
1249
|
-
const
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
const values = Object.values(record);
|
|
1253
|
-
const query = createSqlBuilder().insert(fullTableName, columns, values);
|
|
1254
|
-
const { sql, params } = query.build();
|
|
1255
|
-
await this.executeQuery({ sql, params });
|
|
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 [];
|
|
1256
1341
|
}
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
);
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
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 {
|
|
@@ -1798,20 +1903,25 @@ var WorkflowsStorageD1 = class extends WorkflowsStorage {
|
|
|
1798
1903
|
toDate,
|
|
1799
1904
|
page,
|
|
1800
1905
|
perPage,
|
|
1801
|
-
resourceId
|
|
1906
|
+
resourceId,
|
|
1907
|
+
status
|
|
1802
1908
|
} = {}) {
|
|
1803
|
-
const fullTableName = this.
|
|
1909
|
+
const fullTableName = this.#db.getTableName(TABLE_WORKFLOW_SNAPSHOT);
|
|
1804
1910
|
try {
|
|
1805
1911
|
const builder = createSqlBuilder().select().from(fullTableName);
|
|
1806
1912
|
const countBuilder = createSqlBuilder().count().from(fullTableName);
|
|
1807
1913
|
if (workflowName) builder.whereAnd("workflow_name = ?", workflowName);
|
|
1914
|
+
if (status) {
|
|
1915
|
+
builder.whereAnd("json_extract(snapshot, '$.status') = ?", status);
|
|
1916
|
+
countBuilder.whereAnd("json_extract(snapshot, '$.status') = ?", status);
|
|
1917
|
+
}
|
|
1808
1918
|
if (resourceId) {
|
|
1809
|
-
const hasResourceId = await this.
|
|
1919
|
+
const hasResourceId = await this.#db.hasColumn(fullTableName, "resourceId");
|
|
1810
1920
|
if (hasResourceId) {
|
|
1811
1921
|
builder.whereAnd("resourceId = ?", resourceId);
|
|
1812
1922
|
countBuilder.whereAnd("resourceId = ?", resourceId);
|
|
1813
1923
|
} else {
|
|
1814
|
-
|
|
1924
|
+
this.logger.warn(`[${fullTableName}] resourceId column not found. Skipping resourceId filter.`);
|
|
1815
1925
|
}
|
|
1816
1926
|
}
|
|
1817
1927
|
if (fromDate) {
|
|
@@ -1832,20 +1942,20 @@ var WorkflowsStorageD1 = class extends WorkflowsStorage {
|
|
|
1832
1942
|
let total = 0;
|
|
1833
1943
|
if (perPage !== void 0 && page !== void 0) {
|
|
1834
1944
|
const { sql: countSql, params: countParams } = countBuilder.build();
|
|
1835
|
-
const countResult = await this.
|
|
1945
|
+
const countResult = await this.#db.executeQuery({
|
|
1836
1946
|
sql: countSql,
|
|
1837
1947
|
params: countParams,
|
|
1838
1948
|
first: true
|
|
1839
1949
|
});
|
|
1840
1950
|
total = Number(countResult?.count ?? 0);
|
|
1841
1951
|
}
|
|
1842
|
-
const results = await this.
|
|
1952
|
+
const results = await this.#db.executeQuery({ sql, params });
|
|
1843
1953
|
const runs = (isArrayOfRecords(results) ? results : []).map((row) => this.parseWorkflowRun(row));
|
|
1844
1954
|
return { runs, total: total || runs.length };
|
|
1845
1955
|
} catch (error) {
|
|
1846
1956
|
throw new MastraError(
|
|
1847
1957
|
{
|
|
1848
|
-
id: "
|
|
1958
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "LIST_WORKFLOW_RUNS", "FAILED"),
|
|
1849
1959
|
domain: ErrorDomain.STORAGE,
|
|
1850
1960
|
category: ErrorCategory.THIRD_PARTY,
|
|
1851
1961
|
text: `Failed to retrieve workflow runs: ${error instanceof Error ? error.message : String(error)}`,
|
|
@@ -1862,7 +1972,7 @@ var WorkflowsStorageD1 = class extends WorkflowsStorage {
|
|
|
1862
1972
|
runId,
|
|
1863
1973
|
workflowName
|
|
1864
1974
|
}) {
|
|
1865
|
-
const fullTableName = this.
|
|
1975
|
+
const fullTableName = this.#db.getTableName(TABLE_WORKFLOW_SNAPSHOT);
|
|
1866
1976
|
try {
|
|
1867
1977
|
const conditions = [];
|
|
1868
1978
|
const params = [];
|
|
@@ -1876,13 +1986,13 @@ var WorkflowsStorageD1 = class extends WorkflowsStorage {
|
|
|
1876
1986
|
}
|
|
1877
1987
|
const whereClause = conditions.length > 0 ? "WHERE " + conditions.join(" AND ") : "";
|
|
1878
1988
|
const sql = `SELECT * FROM ${fullTableName} ${whereClause} ORDER BY createdAt DESC LIMIT 1`;
|
|
1879
|
-
const result = await this.
|
|
1989
|
+
const result = await this.#db.executeQuery({ sql, params, first: true });
|
|
1880
1990
|
if (!result) return null;
|
|
1881
1991
|
return this.parseWorkflowRun(result);
|
|
1882
1992
|
} catch (error) {
|
|
1883
1993
|
throw new MastraError(
|
|
1884
1994
|
{
|
|
1885
|
-
id: "
|
|
1995
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "GET_WORKFLOW_RUN_BY_ID", "FAILED"),
|
|
1886
1996
|
domain: ErrorDomain.STORAGE,
|
|
1887
1997
|
category: ErrorCategory.THIRD_PARTY,
|
|
1888
1998
|
text: `Failed to retrieve workflow run by ID: ${error instanceof Error ? error.message : String(error)}`,
|
|
@@ -1892,13 +2002,31 @@ var WorkflowsStorageD1 = class extends WorkflowsStorage {
|
|
|
1892
2002
|
);
|
|
1893
2003
|
}
|
|
1894
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
|
+
}
|
|
1895
2024
|
};
|
|
1896
2025
|
|
|
1897
2026
|
// src/storage/index.ts
|
|
1898
2027
|
var D1Store = class extends MastraStorage {
|
|
1899
2028
|
client;
|
|
1900
2029
|
binding;
|
|
1901
|
-
// D1Database binding
|
|
1902
2030
|
tablePrefix;
|
|
1903
2031
|
stores;
|
|
1904
2032
|
/**
|
|
@@ -1907,7 +2035,7 @@ var D1Store = class extends MastraStorage {
|
|
|
1907
2035
|
*/
|
|
1908
2036
|
constructor(config) {
|
|
1909
2037
|
try {
|
|
1910
|
-
super({ id: config.id, name: "D1" });
|
|
2038
|
+
super({ id: config.id, name: "D1", disableInit: config.disableInit });
|
|
1911
2039
|
if (config.tablePrefix && !/^[a-zA-Z0-9_]*$/.test(config.tablePrefix)) {
|
|
1912
2040
|
throw new Error("Invalid tablePrefix: only letters, numbers, and underscores are allowed.");
|
|
1913
2041
|
}
|
|
@@ -1945,7 +2073,7 @@ var D1Store = class extends MastraStorage {
|
|
|
1945
2073
|
} catch (error) {
|
|
1946
2074
|
throw new MastraError(
|
|
1947
2075
|
{
|
|
1948
|
-
id: "
|
|
2076
|
+
id: createStorageErrorId("CLOUDFLARE_D1", "INITIALIZATION", "FAILED"),
|
|
1949
2077
|
domain: ErrorDomain.STORAGE,
|
|
1950
2078
|
category: ErrorCategory.SYSTEM,
|
|
1951
2079
|
text: "Error initializing D1Store"
|
|
@@ -1953,196 +2081,26 @@ var D1Store = class extends MastraStorage {
|
|
|
1953
2081
|
error
|
|
1954
2082
|
);
|
|
1955
2083
|
}
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
}
|
|
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
|
+
}
|
|
1970
2098
|
this.stores = {
|
|
1971
|
-
operations,
|
|
1972
2099
|
scores,
|
|
1973
2100
|
workflows,
|
|
1974
2101
|
memory
|
|
1975
2102
|
};
|
|
1976
2103
|
}
|
|
1977
|
-
get supports() {
|
|
1978
|
-
return {
|
|
1979
|
-
selectByIncludeResourceScope: true,
|
|
1980
|
-
resourceWorkingMemory: true,
|
|
1981
|
-
hasColumn: true,
|
|
1982
|
-
createTable: true,
|
|
1983
|
-
deleteMessages: false,
|
|
1984
|
-
listScoresBySpan: true
|
|
1985
|
-
};
|
|
1986
|
-
}
|
|
1987
|
-
async createTable({
|
|
1988
|
-
tableName,
|
|
1989
|
-
schema
|
|
1990
|
-
}) {
|
|
1991
|
-
return this.stores.operations.createTable({ tableName, schema });
|
|
1992
|
-
}
|
|
1993
|
-
/**
|
|
1994
|
-
* Alters table schema to add columns if they don't exist
|
|
1995
|
-
* @param tableName Name of the table
|
|
1996
|
-
* @param schema Schema of the table
|
|
1997
|
-
* @param ifNotExists Array of column names to add if they don't exist
|
|
1998
|
-
*/
|
|
1999
|
-
async alterTable({
|
|
2000
|
-
tableName,
|
|
2001
|
-
schema,
|
|
2002
|
-
ifNotExists
|
|
2003
|
-
}) {
|
|
2004
|
-
return this.stores.operations.alterTable({ tableName, schema, ifNotExists });
|
|
2005
|
-
}
|
|
2006
|
-
async clearTable({ tableName }) {
|
|
2007
|
-
return this.stores.operations.clearTable({ tableName });
|
|
2008
|
-
}
|
|
2009
|
-
async dropTable({ tableName }) {
|
|
2010
|
-
return this.stores.operations.dropTable({ tableName });
|
|
2011
|
-
}
|
|
2012
|
-
async hasColumn(table, column) {
|
|
2013
|
-
return this.stores.operations.hasColumn(table, column);
|
|
2014
|
-
}
|
|
2015
|
-
async insert({ tableName, record }) {
|
|
2016
|
-
return this.stores.operations.insert({ tableName, record });
|
|
2017
|
-
}
|
|
2018
|
-
async load({ tableName, keys }) {
|
|
2019
|
-
return this.stores.operations.load({ tableName, keys });
|
|
2020
|
-
}
|
|
2021
|
-
async getThreadById({ threadId }) {
|
|
2022
|
-
return this.stores.memory.getThreadById({ threadId });
|
|
2023
|
-
}
|
|
2024
|
-
async saveThread({ thread }) {
|
|
2025
|
-
return this.stores.memory.saveThread({ thread });
|
|
2026
|
-
}
|
|
2027
|
-
async updateThread({
|
|
2028
|
-
id,
|
|
2029
|
-
title,
|
|
2030
|
-
metadata
|
|
2031
|
-
}) {
|
|
2032
|
-
return this.stores.memory.updateThread({ id, title, metadata });
|
|
2033
|
-
}
|
|
2034
|
-
async deleteThread({ threadId }) {
|
|
2035
|
-
return this.stores.memory.deleteThread({ threadId });
|
|
2036
|
-
}
|
|
2037
|
-
async saveMessages(args) {
|
|
2038
|
-
return this.stores.memory.saveMessages(args);
|
|
2039
|
-
}
|
|
2040
|
-
async updateWorkflowResults({
|
|
2041
|
-
workflowName,
|
|
2042
|
-
runId,
|
|
2043
|
-
stepId,
|
|
2044
|
-
result,
|
|
2045
|
-
requestContext
|
|
2046
|
-
}) {
|
|
2047
|
-
return this.stores.workflows.updateWorkflowResults({ workflowName, runId, stepId, result, requestContext });
|
|
2048
|
-
}
|
|
2049
|
-
async updateWorkflowState({
|
|
2050
|
-
workflowName,
|
|
2051
|
-
runId,
|
|
2052
|
-
opts
|
|
2053
|
-
}) {
|
|
2054
|
-
return this.stores.workflows.updateWorkflowState({ workflowName, runId, opts });
|
|
2055
|
-
}
|
|
2056
|
-
async persistWorkflowSnapshot({
|
|
2057
|
-
workflowName,
|
|
2058
|
-
runId,
|
|
2059
|
-
resourceId,
|
|
2060
|
-
snapshot
|
|
2061
|
-
}) {
|
|
2062
|
-
return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, resourceId, snapshot });
|
|
2063
|
-
}
|
|
2064
|
-
async loadWorkflowSnapshot(params) {
|
|
2065
|
-
return this.stores.workflows.loadWorkflowSnapshot(params);
|
|
2066
|
-
}
|
|
2067
|
-
async listWorkflowRuns({
|
|
2068
|
-
workflowName,
|
|
2069
|
-
fromDate,
|
|
2070
|
-
toDate,
|
|
2071
|
-
perPage,
|
|
2072
|
-
page,
|
|
2073
|
-
resourceId
|
|
2074
|
-
} = {}) {
|
|
2075
|
-
return this.stores.workflows.listWorkflowRuns({ workflowName, fromDate, toDate, perPage, page, resourceId });
|
|
2076
|
-
}
|
|
2077
|
-
async getWorkflowRunById({
|
|
2078
|
-
runId,
|
|
2079
|
-
workflowName
|
|
2080
|
-
}) {
|
|
2081
|
-
return this.stores.workflows.getWorkflowRunById({ runId, workflowName });
|
|
2082
|
-
}
|
|
2083
|
-
/**
|
|
2084
|
-
* Insert multiple records in a batch operation
|
|
2085
|
-
* @param tableName The table to insert into
|
|
2086
|
-
* @param records The records to insert
|
|
2087
|
-
*/
|
|
2088
|
-
async batchInsert({ tableName, records }) {
|
|
2089
|
-
return this.stores.operations.batchInsert({ tableName, records });
|
|
2090
|
-
}
|
|
2091
|
-
async updateMessages(_args) {
|
|
2092
|
-
return this.stores.memory.updateMessages(_args);
|
|
2093
|
-
}
|
|
2094
|
-
async getResourceById({ resourceId }) {
|
|
2095
|
-
return this.stores.memory.getResourceById({ resourceId });
|
|
2096
|
-
}
|
|
2097
|
-
async saveResource({ resource }) {
|
|
2098
|
-
return this.stores.memory.saveResource({ resource });
|
|
2099
|
-
}
|
|
2100
|
-
async updateResource({
|
|
2101
|
-
resourceId,
|
|
2102
|
-
workingMemory,
|
|
2103
|
-
metadata
|
|
2104
|
-
}) {
|
|
2105
|
-
return this.stores.memory.updateResource({ resourceId, workingMemory, metadata });
|
|
2106
|
-
}
|
|
2107
|
-
async getScoreById({ id: _id }) {
|
|
2108
|
-
return this.stores.scores.getScoreById({ id: _id });
|
|
2109
|
-
}
|
|
2110
|
-
async saveScore(_score) {
|
|
2111
|
-
return this.stores.scores.saveScore(_score);
|
|
2112
|
-
}
|
|
2113
|
-
async listScoresByRunId({
|
|
2114
|
-
runId: _runId,
|
|
2115
|
-
pagination: _pagination
|
|
2116
|
-
}) {
|
|
2117
|
-
return this.stores.scores.listScoresByRunId({ runId: _runId, pagination: _pagination });
|
|
2118
|
-
}
|
|
2119
|
-
async listScoresByEntityId({
|
|
2120
|
-
entityId: _entityId,
|
|
2121
|
-
entityType: _entityType,
|
|
2122
|
-
pagination: _pagination
|
|
2123
|
-
}) {
|
|
2124
|
-
return this.stores.scores.listScoresByEntityId({
|
|
2125
|
-
entityId: _entityId,
|
|
2126
|
-
entityType: _entityType,
|
|
2127
|
-
pagination: _pagination
|
|
2128
|
-
});
|
|
2129
|
-
}
|
|
2130
|
-
async listScoresByScorerId({
|
|
2131
|
-
scorerId,
|
|
2132
|
-
pagination,
|
|
2133
|
-
entityId,
|
|
2134
|
-
entityType,
|
|
2135
|
-
source
|
|
2136
|
-
}) {
|
|
2137
|
-
return this.stores.scores.listScoresByScorerId({ scorerId, pagination, entityId, entityType, source });
|
|
2138
|
-
}
|
|
2139
|
-
async listScoresBySpan({
|
|
2140
|
-
traceId,
|
|
2141
|
-
spanId,
|
|
2142
|
-
pagination
|
|
2143
|
-
}) {
|
|
2144
|
-
return this.stores.scores.listScoresBySpan({ traceId, spanId, pagination });
|
|
2145
|
-
}
|
|
2146
2104
|
/**
|
|
2147
2105
|
* Close the database connection
|
|
2148
2106
|
* No explicit cleanup needed for D1 in either REST or Workers Binding mode
|
|
@@ -2152,6 +2110,6 @@ var D1Store = class extends MastraStorage {
|
|
|
2152
2110
|
}
|
|
2153
2111
|
};
|
|
2154
2112
|
|
|
2155
|
-
export { D1Store };
|
|
2113
|
+
export { D1Store, MemoryStorageD1, ScoresStorageD1, WorkflowsStorageD1 };
|
|
2156
2114
|
//# sourceMappingURL=index.js.map
|
|
2157
2115
|
//# sourceMappingURL=index.js.map
|