@mastra/mssql 0.0.0-pgvector-index-fix-20250905222058 → 0.0.0-playground-studio-again-20251114100107
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 +669 -10
- package/README.md +324 -37
- package/dist/index.cjs +1676 -726
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1678 -728
- package/dist/index.js.map +1 -1
- package/dist/storage/domains/memory/index.d.ts +14 -43
- package/dist/storage/domains/memory/index.d.ts.map +1 -1
- package/dist/storage/domains/observability/index.d.ts +44 -0
- package/dist/storage/domains/observability/index.d.ts.map +1 -0
- package/dist/storage/domains/operations/index.d.ts +67 -4
- package/dist/storage/domains/operations/index.d.ts.map +1 -1
- package/dist/storage/domains/scores/index.d.ts +13 -4
- package/dist/storage/domains/scores/index.d.ts.map +1 -1
- package/dist/storage/domains/utils.d.ts +19 -0
- package/dist/storage/domains/utils.d.ts.map +1 -1
- package/dist/storage/domains/workflows/index.d.ts +9 -13
- package/dist/storage/domains/workflows/index.d.ts.map +1 -1
- package/dist/storage/index.d.ts +73 -81
- package/dist/storage/index.d.ts.map +1 -1
- package/package.json +15 -10
- package/dist/storage/domains/legacy-evals/index.d.ts +0 -20
- package/dist/storage/domains/legacy-evals/index.d.ts.map +0 -1
- package/dist/storage/domains/traces/index.d.ts +0 -37
- package/dist/storage/domains/traces/index.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { MastraError, ErrorCategory, ErrorDomain } from '@mastra/core/error';
|
|
2
|
-
import { MastraStorage,
|
|
2
|
+
import { MastraStorage, StoreOperations, TABLE_WORKFLOW_SNAPSHOT, TABLE_SCHEMAS, TABLE_THREADS, TABLE_MESSAGES, TABLE_TRACES, TABLE_SCORERS, TABLE_SPANS, ScoresStorage, normalizePerPage, calculatePagination, WorkflowsStorage, MemoryStorage, TABLE_RESOURCES, ObservabilityStorage, safelyParseJSON } from '@mastra/core/storage';
|
|
3
3
|
import sql2 from 'mssql';
|
|
4
|
-
import { parseSqlIdentifier, parseFieldKey } from '@mastra/core/utils';
|
|
5
4
|
import { MessageList } from '@mastra/core/agent';
|
|
5
|
+
import { parseSqlIdentifier } from '@mastra/core/utils';
|
|
6
|
+
import { randomUUID } from 'crypto';
|
|
7
|
+
import { saveScorePayloadSchema } from '@mastra/core/evals';
|
|
6
8
|
|
|
7
9
|
// src/storage/index.ts
|
|
8
10
|
function getSchemaName(schema) {
|
|
@@ -14,154 +16,71 @@ function getTableName({ indexName, schemaName }) {
|
|
|
14
16
|
const quotedSchemaName = schemaName;
|
|
15
17
|
return quotedSchemaName ? `${quotedSchemaName}.${quotedIndexName}` : quotedIndexName;
|
|
16
18
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
if (row.test_info) {
|
|
22
|
-
try {
|
|
23
|
-
testInfoValue = typeof row.test_info === "string" ? JSON.parse(row.test_info) : row.test_info;
|
|
24
|
-
} catch {
|
|
25
|
-
}
|
|
19
|
+
function buildDateRangeFilter(dateRange, fieldName) {
|
|
20
|
+
const filters = {};
|
|
21
|
+
if (dateRange?.start) {
|
|
22
|
+
filters[`${fieldName}_gte`] = dateRange.start;
|
|
26
23
|
}
|
|
27
|
-
if (
|
|
28
|
-
|
|
29
|
-
resultValue = typeof row.result === "string" ? JSON.parse(row.result) : row.result;
|
|
30
|
-
} catch {
|
|
31
|
-
}
|
|
24
|
+
if (dateRange?.end) {
|
|
25
|
+
filters[`${fieldName}_lte`] = dateRange.end;
|
|
32
26
|
}
|
|
27
|
+
return filters;
|
|
28
|
+
}
|
|
29
|
+
function prepareWhereClause(filters, _schema) {
|
|
30
|
+
const conditions = [];
|
|
31
|
+
const params = {};
|
|
32
|
+
let paramIndex = 1;
|
|
33
|
+
Object.entries(filters).forEach(([key, value]) => {
|
|
34
|
+
if (value === void 0) return;
|
|
35
|
+
const paramName = `p${paramIndex++}`;
|
|
36
|
+
if (key.endsWith("_gte")) {
|
|
37
|
+
const fieldName = key.slice(0, -4);
|
|
38
|
+
conditions.push(`[${parseSqlIdentifier(fieldName, "field name")}] >= @${paramName}`);
|
|
39
|
+
params[paramName] = value instanceof Date ? value.toISOString() : value;
|
|
40
|
+
} else if (key.endsWith("_lte")) {
|
|
41
|
+
const fieldName = key.slice(0, -4);
|
|
42
|
+
conditions.push(`[${parseSqlIdentifier(fieldName, "field name")}] <= @${paramName}`);
|
|
43
|
+
params[paramName] = value instanceof Date ? value.toISOString() : value;
|
|
44
|
+
} else if (value === null) {
|
|
45
|
+
conditions.push(`[${parseSqlIdentifier(key, "field name")}] IS NULL`);
|
|
46
|
+
} else {
|
|
47
|
+
conditions.push(`[${parseSqlIdentifier(key, "field name")}] = @${paramName}`);
|
|
48
|
+
params[paramName] = value instanceof Date ? value.toISOString() : value;
|
|
49
|
+
}
|
|
50
|
+
});
|
|
33
51
|
return {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
output: row.output,
|
|
37
|
-
result: resultValue,
|
|
38
|
-
metricName: row.metric_name,
|
|
39
|
-
instructions: row.instructions,
|
|
40
|
-
testInfo: testInfoValue,
|
|
41
|
-
globalRunId: row.global_run_id,
|
|
42
|
-
runId: row.run_id,
|
|
43
|
-
createdAt: row.created_at
|
|
52
|
+
sql: conditions.length > 0 ? ` WHERE ${conditions.join(" AND ")}` : "",
|
|
53
|
+
params
|
|
44
54
|
};
|
|
45
55
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
query += " AND test_info IS NOT NULL AND JSON_VALUE(test_info, '$.testPath') IS NOT NULL";
|
|
60
|
-
} else if (type === "live") {
|
|
61
|
-
query += " AND (test_info IS NULL OR JSON_VALUE(test_info, '$.testPath') IS NULL)";
|
|
62
|
-
}
|
|
63
|
-
query += " ORDER BY created_at DESC";
|
|
64
|
-
const request = this.pool.request();
|
|
65
|
-
request.input("p1", agentName);
|
|
66
|
-
const result = await request.query(query);
|
|
67
|
-
const rows = result.recordset;
|
|
68
|
-
return typeof transformEvalRow === "function" ? rows?.map((row) => transformEvalRow(row)) ?? [] : rows ?? [];
|
|
69
|
-
} catch (error) {
|
|
70
|
-
if (error && error.number === 208 && error.message && error.message.includes("Invalid object name")) {
|
|
71
|
-
return [];
|
|
72
|
-
}
|
|
73
|
-
console.error("Failed to get evals for the specified agent: " + error?.message);
|
|
74
|
-
throw error;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
async getEvals(options = {}) {
|
|
78
|
-
const { agentName, type, page = 0, perPage = 100, dateRange } = options;
|
|
79
|
-
const fromDate = dateRange?.start;
|
|
80
|
-
const toDate = dateRange?.end;
|
|
81
|
-
const where = [];
|
|
82
|
-
const params = {};
|
|
83
|
-
if (agentName) {
|
|
84
|
-
where.push("agent_name = @agentName");
|
|
85
|
-
params["agentName"] = agentName;
|
|
86
|
-
}
|
|
87
|
-
if (type === "test") {
|
|
88
|
-
where.push("test_info IS NOT NULL AND JSON_VALUE(test_info, '$.testPath') IS NOT NULL");
|
|
89
|
-
} else if (type === "live") {
|
|
90
|
-
where.push("(test_info IS NULL OR JSON_VALUE(test_info, '$.testPath') IS NULL)");
|
|
91
|
-
}
|
|
92
|
-
if (fromDate instanceof Date && !isNaN(fromDate.getTime())) {
|
|
93
|
-
where.push(`[created_at] >= @fromDate`);
|
|
94
|
-
params[`fromDate`] = fromDate.toISOString();
|
|
95
|
-
}
|
|
96
|
-
if (toDate instanceof Date && !isNaN(toDate.getTime())) {
|
|
97
|
-
where.push(`[created_at] <= @toDate`);
|
|
98
|
-
params[`toDate`] = toDate.toISOString();
|
|
99
|
-
}
|
|
100
|
-
const whereClause = where.length > 0 ? `WHERE ${where.join(" AND ")}` : "";
|
|
101
|
-
const tableName = getTableName({ indexName: TABLE_EVALS, schemaName: getSchemaName(this.schema) });
|
|
102
|
-
const offset = page * perPage;
|
|
103
|
-
const countQuery = `SELECT COUNT(*) as total FROM ${tableName} ${whereClause}`;
|
|
104
|
-
const dataQuery = `SELECT * FROM ${tableName} ${whereClause} ORDER BY seq_id DESC OFFSET @offset ROWS FETCH NEXT @perPage ROWS ONLY`;
|
|
105
|
-
try {
|
|
106
|
-
const countReq = this.pool.request();
|
|
107
|
-
Object.entries(params).forEach(([key, value]) => {
|
|
108
|
-
if (value instanceof Date) {
|
|
109
|
-
countReq.input(key, sql2.DateTime, value);
|
|
110
|
-
} else {
|
|
111
|
-
countReq.input(key, value);
|
|
112
|
-
}
|
|
113
|
-
});
|
|
114
|
-
const countResult = await countReq.query(countQuery);
|
|
115
|
-
const total = countResult.recordset[0]?.total || 0;
|
|
116
|
-
if (total === 0) {
|
|
117
|
-
return {
|
|
118
|
-
evals: [],
|
|
119
|
-
total: 0,
|
|
120
|
-
page,
|
|
121
|
-
perPage,
|
|
122
|
-
hasMore: false
|
|
123
|
-
};
|
|
56
|
+
function transformFromSqlRow({
|
|
57
|
+
tableName,
|
|
58
|
+
sqlRow
|
|
59
|
+
}) {
|
|
60
|
+
const schema = TABLE_SCHEMAS[tableName];
|
|
61
|
+
const result = {};
|
|
62
|
+
Object.entries(sqlRow).forEach(([key, value]) => {
|
|
63
|
+
const columnSchema = schema?.[key];
|
|
64
|
+
if (columnSchema?.type === "jsonb" && typeof value === "string") {
|
|
65
|
+
try {
|
|
66
|
+
result[key] = JSON.parse(value);
|
|
67
|
+
} catch {
|
|
68
|
+
result[key] = value;
|
|
124
69
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
req.input("offset", offset);
|
|
134
|
-
req.input("perPage", perPage);
|
|
135
|
-
const result = await req.query(dataQuery);
|
|
136
|
-
const rows = result.recordset;
|
|
137
|
-
return {
|
|
138
|
-
evals: rows?.map((row) => transformEvalRow(row)) ?? [],
|
|
139
|
-
total,
|
|
140
|
-
page,
|
|
141
|
-
perPage,
|
|
142
|
-
hasMore: offset + (rows?.length ?? 0) < total
|
|
143
|
-
};
|
|
144
|
-
} catch (error) {
|
|
145
|
-
const mastraError = new MastraError(
|
|
146
|
-
{
|
|
147
|
-
id: "MASTRA_STORAGE_MSSQL_STORE_GET_EVALS_FAILED",
|
|
148
|
-
domain: ErrorDomain.STORAGE,
|
|
149
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
150
|
-
details: {
|
|
151
|
-
agentName: agentName || "all",
|
|
152
|
-
type: type || "all",
|
|
153
|
-
page,
|
|
154
|
-
perPage
|
|
155
|
-
}
|
|
156
|
-
},
|
|
157
|
-
error
|
|
158
|
-
);
|
|
159
|
-
this.logger?.error?.(mastraError.toString());
|
|
160
|
-
this.logger?.trackException(mastraError);
|
|
161
|
-
throw mastraError;
|
|
70
|
+
} else if (columnSchema?.type === "timestamp" && value && typeof value === "string") {
|
|
71
|
+
result[key] = new Date(value);
|
|
72
|
+
} else if (columnSchema?.type === "timestamp" && value instanceof Date) {
|
|
73
|
+
result[key] = value;
|
|
74
|
+
} else if (columnSchema?.type === "boolean") {
|
|
75
|
+
result[key] = Boolean(value);
|
|
76
|
+
} else {
|
|
77
|
+
result[key] = value;
|
|
162
78
|
}
|
|
163
|
-
}
|
|
164
|
-
|
|
79
|
+
});
|
|
80
|
+
return result;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// src/storage/domains/memory/index.ts
|
|
165
84
|
var MemoryMSSQL = class extends MemoryStorage {
|
|
166
85
|
pool;
|
|
167
86
|
schema;
|
|
@@ -179,7 +98,7 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
179
98
|
});
|
|
180
99
|
const cleanMessages = messagesWithParsedContent.map(({ seq_id, ...rest }) => rest);
|
|
181
100
|
const list = new MessageList().add(cleanMessages, "memory");
|
|
182
|
-
return format === "v2" ? list.get.all.
|
|
101
|
+
return format === "v2" ? list.get.all.db() : list.get.all.v1();
|
|
183
102
|
}
|
|
184
103
|
constructor({
|
|
185
104
|
pool,
|
|
@@ -193,7 +112,7 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
193
112
|
}
|
|
194
113
|
async getThreadById({ threadId }) {
|
|
195
114
|
try {
|
|
196
|
-
const
|
|
115
|
+
const sql5 = `SELECT
|
|
197
116
|
id,
|
|
198
117
|
[resourceId],
|
|
199
118
|
title,
|
|
@@ -204,7 +123,7 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
204
123
|
WHERE id = @threadId`;
|
|
205
124
|
const request = this.pool.request();
|
|
206
125
|
request.input("threadId", threadId);
|
|
207
|
-
const resultSet = await request.query(
|
|
126
|
+
const resultSet = await request.query(sql5);
|
|
208
127
|
const thread = resultSet.recordset[0] || null;
|
|
209
128
|
if (!thread) {
|
|
210
129
|
return null;
|
|
@@ -229,11 +148,24 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
229
148
|
);
|
|
230
149
|
}
|
|
231
150
|
}
|
|
232
|
-
async
|
|
233
|
-
const { resourceId, page = 0, perPage: perPageInput, orderBy
|
|
151
|
+
async listThreadsByResourceId(args) {
|
|
152
|
+
const { resourceId, page = 0, perPage: perPageInput, orderBy } = args;
|
|
153
|
+
if (page < 0) {
|
|
154
|
+
throw new MastraError({
|
|
155
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_INVALID_PAGE",
|
|
156
|
+
domain: ErrorDomain.STORAGE,
|
|
157
|
+
category: ErrorCategory.USER,
|
|
158
|
+
text: "Page number must be non-negative",
|
|
159
|
+
details: {
|
|
160
|
+
resourceId,
|
|
161
|
+
page
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
const perPage = normalizePerPage(perPageInput, 100);
|
|
166
|
+
const { offset, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
|
|
167
|
+
const { field, direction } = this.parseOrderBy(orderBy);
|
|
234
168
|
try {
|
|
235
|
-
const perPage = perPageInput !== void 0 ? perPageInput : 100;
|
|
236
|
-
const currentOffset = page * perPage;
|
|
237
169
|
const baseQuery = `FROM ${getTableName({ indexName: TABLE_THREADS, schemaName: getSchemaName(this.schema) })} WHERE [resourceId] = @resourceId`;
|
|
238
170
|
const countQuery = `SELECT COUNT(*) as count ${baseQuery}`;
|
|
239
171
|
const countRequest = this.pool.request();
|
|
@@ -245,16 +177,22 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
245
177
|
threads: [],
|
|
246
178
|
total: 0,
|
|
247
179
|
page,
|
|
248
|
-
perPage,
|
|
180
|
+
perPage: perPageForResponse,
|
|
249
181
|
hasMore: false
|
|
250
182
|
};
|
|
251
183
|
}
|
|
252
|
-
const orderByField =
|
|
253
|
-
const
|
|
184
|
+
const orderByField = field === "createdAt" ? "[createdAt]" : "[updatedAt]";
|
|
185
|
+
const dir = (direction || "DESC").toUpperCase() === "ASC" ? "ASC" : "DESC";
|
|
186
|
+
const limitValue = perPageInput === false ? total : perPage;
|
|
187
|
+
const dataQuery = `SELECT id, [resourceId], title, metadata, [createdAt], [updatedAt] ${baseQuery} ORDER BY ${orderByField} ${dir} OFFSET @offset ROWS FETCH NEXT @perPage ROWS ONLY`;
|
|
254
188
|
const dataRequest = this.pool.request();
|
|
255
189
|
dataRequest.input("resourceId", resourceId);
|
|
256
|
-
dataRequest.input("
|
|
257
|
-
|
|
190
|
+
dataRequest.input("offset", offset);
|
|
191
|
+
if (limitValue > 2147483647) {
|
|
192
|
+
dataRequest.input("perPage", sql2.BigInt, limitValue);
|
|
193
|
+
} else {
|
|
194
|
+
dataRequest.input("perPage", limitValue);
|
|
195
|
+
}
|
|
258
196
|
const rowsResult = await dataRequest.query(dataQuery);
|
|
259
197
|
const rows = rowsResult.recordset || [];
|
|
260
198
|
const threads = rows.map((thread) => ({
|
|
@@ -267,13 +205,13 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
267
205
|
threads,
|
|
268
206
|
total,
|
|
269
207
|
page,
|
|
270
|
-
perPage,
|
|
271
|
-
hasMore:
|
|
208
|
+
perPage: perPageForResponse,
|
|
209
|
+
hasMore: perPageInput === false ? false : offset + perPage < total
|
|
272
210
|
};
|
|
273
211
|
} catch (error) {
|
|
274
212
|
const mastraError = new MastraError(
|
|
275
213
|
{
|
|
276
|
-
id: "
|
|
214
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_LIST_THREADS_BY_RESOURCE_ID_FAILED",
|
|
277
215
|
domain: ErrorDomain.STORAGE,
|
|
278
216
|
category: ErrorCategory.THIRD_PARTY,
|
|
279
217
|
details: {
|
|
@@ -285,7 +223,13 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
285
223
|
);
|
|
286
224
|
this.logger?.error?.(mastraError.toString());
|
|
287
225
|
this.logger?.trackException?.(mastraError);
|
|
288
|
-
return {
|
|
226
|
+
return {
|
|
227
|
+
threads: [],
|
|
228
|
+
total: 0,
|
|
229
|
+
page,
|
|
230
|
+
perPage: perPageForResponse,
|
|
231
|
+
hasMore: false
|
|
232
|
+
};
|
|
289
233
|
}
|
|
290
234
|
}
|
|
291
235
|
async saveThread({ thread }) {
|
|
@@ -307,7 +251,12 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
307
251
|
req.input("id", thread.id);
|
|
308
252
|
req.input("resourceId", thread.resourceId);
|
|
309
253
|
req.input("title", thread.title);
|
|
310
|
-
|
|
254
|
+
const metadata = thread.metadata ? JSON.stringify(thread.metadata) : null;
|
|
255
|
+
if (metadata === null) {
|
|
256
|
+
req.input("metadata", sql2.NVarChar, null);
|
|
257
|
+
} else {
|
|
258
|
+
req.input("metadata", metadata);
|
|
259
|
+
}
|
|
311
260
|
req.input("createdAt", sql2.DateTime2, thread.createdAt);
|
|
312
261
|
req.input("updatedAt", sql2.DateTime2, thread.updatedAt);
|
|
313
262
|
await req.query(mergeSql);
|
|
@@ -326,30 +275,6 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
326
275
|
);
|
|
327
276
|
}
|
|
328
277
|
}
|
|
329
|
-
/**
|
|
330
|
-
* @deprecated use getThreadsByResourceIdPaginated instead
|
|
331
|
-
*/
|
|
332
|
-
async getThreadsByResourceId(args) {
|
|
333
|
-
const { resourceId, orderBy = "createdAt", sortDirection = "DESC" } = args;
|
|
334
|
-
try {
|
|
335
|
-
const baseQuery = `FROM ${getTableName({ indexName: TABLE_THREADS, schemaName: getSchemaName(this.schema) })} WHERE [resourceId] = @resourceId`;
|
|
336
|
-
const orderByField = orderBy === "createdAt" ? "[createdAt]" : "[updatedAt]";
|
|
337
|
-
const dataQuery = `SELECT id, [resourceId], title, metadata, [createdAt], [updatedAt] ${baseQuery} ORDER BY ${orderByField} ${sortDirection}`;
|
|
338
|
-
const request = this.pool.request();
|
|
339
|
-
request.input("resourceId", resourceId);
|
|
340
|
-
const resultSet = await request.query(dataQuery);
|
|
341
|
-
const rows = resultSet.recordset || [];
|
|
342
|
-
return rows.map((thread) => ({
|
|
343
|
-
...thread,
|
|
344
|
-
metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
|
|
345
|
-
createdAt: thread.createdAt,
|
|
346
|
-
updatedAt: thread.updatedAt
|
|
347
|
-
}));
|
|
348
|
-
} catch (error) {
|
|
349
|
-
this.logger?.error?.(`Error getting threads for resource ${resourceId}:`, error);
|
|
350
|
-
return [];
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
278
|
/**
|
|
354
279
|
* Updates a thread's title and metadata, merging with existing metadata. Returns the updated thread.
|
|
355
280
|
*/
|
|
@@ -377,7 +302,7 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
377
302
|
};
|
|
378
303
|
try {
|
|
379
304
|
const table = getTableName({ indexName: TABLE_THREADS, schemaName: getSchemaName(this.schema) });
|
|
380
|
-
const
|
|
305
|
+
const sql5 = `UPDATE ${table}
|
|
381
306
|
SET title = @title,
|
|
382
307
|
metadata = @metadata,
|
|
383
308
|
[updatedAt] = @updatedAt
|
|
@@ -388,7 +313,7 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
388
313
|
req.input("title", title);
|
|
389
314
|
req.input("metadata", JSON.stringify(mergedMetadata));
|
|
390
315
|
req.input("updatedAt", /* @__PURE__ */ new Date());
|
|
391
|
-
const result = await req.query(
|
|
316
|
+
const result = await req.query(sql5);
|
|
392
317
|
let thread = result.recordset && result.recordset[0];
|
|
393
318
|
if (thread && "seq_id" in thread) {
|
|
394
319
|
const { seq_id, ...rest } = thread;
|
|
@@ -458,11 +383,9 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
458
383
|
}
|
|
459
384
|
async _getIncludedMessages({
|
|
460
385
|
threadId,
|
|
461
|
-
|
|
462
|
-
orderByStatement
|
|
386
|
+
include
|
|
463
387
|
}) {
|
|
464
388
|
if (!threadId.trim()) throw new Error("threadId must be a non-empty string");
|
|
465
|
-
const include = selectBy?.include;
|
|
466
389
|
if (!include) return null;
|
|
467
390
|
const unionQueries = [];
|
|
468
391
|
const paramValues = [];
|
|
@@ -487,7 +410,7 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
487
410
|
m.[resourceId],
|
|
488
411
|
m.seq_id
|
|
489
412
|
FROM (
|
|
490
|
-
SELECT *, ROW_NUMBER() OVER (
|
|
413
|
+
SELECT *, ROW_NUMBER() OVER (ORDER BY [createdAt] ASC) as row_num
|
|
491
414
|
FROM ${getTableName({ indexName: TABLE_MESSAGES, schemaName: getSchemaName(this.schema) })}
|
|
492
415
|
WHERE [thread_id] = ${pThreadId}
|
|
493
416
|
) AS m
|
|
@@ -495,15 +418,17 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
495
418
|
OR EXISTS (
|
|
496
419
|
SELECT 1
|
|
497
420
|
FROM (
|
|
498
|
-
SELECT *, ROW_NUMBER() OVER (
|
|
421
|
+
SELECT *, ROW_NUMBER() OVER (ORDER BY [createdAt] ASC) as row_num
|
|
499
422
|
FROM ${getTableName({ indexName: TABLE_MESSAGES, schemaName: getSchemaName(this.schema) })}
|
|
500
423
|
WHERE [thread_id] = ${pThreadId}
|
|
501
424
|
) AS target
|
|
502
425
|
WHERE target.id = ${pId}
|
|
503
426
|
AND (
|
|
504
|
-
|
|
427
|
+
-- Get previous messages (messages that come BEFORE the target)
|
|
428
|
+
(m.row_num < target.row_num AND m.row_num >= target.row_num - ${pPrev})
|
|
505
429
|
OR
|
|
506
|
-
|
|
430
|
+
-- Get next messages (messages that come AFTER the target)
|
|
431
|
+
(m.row_num > target.row_num AND m.row_num <= target.row_num + ${pNext})
|
|
507
432
|
)
|
|
508
433
|
)
|
|
509
434
|
`
|
|
@@ -532,34 +457,16 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
532
457
|
});
|
|
533
458
|
return dedupedRows;
|
|
534
459
|
}
|
|
535
|
-
async
|
|
536
|
-
|
|
460
|
+
async listMessagesById({ messageIds }) {
|
|
461
|
+
if (messageIds.length === 0) return { messages: [] };
|
|
537
462
|
const selectStatement = `SELECT seq_id, id, content, role, type, [createdAt], thread_id AS threadId, resourceId`;
|
|
538
463
|
const orderByStatement = `ORDER BY [seq_id] DESC`;
|
|
539
|
-
const limit = resolveMessageLimit({ last: selectBy?.last, defaultLimit: 40 });
|
|
540
464
|
try {
|
|
541
|
-
if (!threadId.trim()) throw new Error("threadId must be a non-empty string");
|
|
542
465
|
let rows = [];
|
|
543
|
-
|
|
544
|
-
if (include?.length) {
|
|
545
|
-
const includeMessages = await this._getIncludedMessages({ threadId, selectBy, orderByStatement });
|
|
546
|
-
if (includeMessages) {
|
|
547
|
-
rows.push(...includeMessages);
|
|
548
|
-
}
|
|
549
|
-
}
|
|
550
|
-
const excludeIds = rows.map((m) => m.id).filter(Boolean);
|
|
551
|
-
let query = `${selectStatement} FROM ${getTableName({ indexName: TABLE_MESSAGES, schemaName: getSchemaName(this.schema) })} WHERE [thread_id] = @threadId`;
|
|
466
|
+
let query = `${selectStatement} FROM ${getTableName({ indexName: TABLE_MESSAGES, schemaName: getSchemaName(this.schema) })} WHERE [id] IN (${messageIds.map((_, i) => `@id${i}`).join(", ")})`;
|
|
552
467
|
const request = this.pool.request();
|
|
553
|
-
request.input(
|
|
554
|
-
|
|
555
|
-
const excludeParams = excludeIds.map((_, idx) => `@id${idx}`);
|
|
556
|
-
query += ` AND id NOT IN (${excludeParams.join(", ")})`;
|
|
557
|
-
excludeIds.forEach((id, idx) => {
|
|
558
|
-
request.input(`id${idx}`, id);
|
|
559
|
-
});
|
|
560
|
-
}
|
|
561
|
-
query += ` ${orderByStatement} OFFSET 0 ROWS FETCH NEXT @limit ROWS ONLY`;
|
|
562
|
-
request.input("limit", limit);
|
|
468
|
+
messageIds.forEach((id, i) => request.input(`id${i}`, id));
|
|
469
|
+
query += ` ${orderByStatement}`;
|
|
563
470
|
const result = await request.query(query);
|
|
564
471
|
const remainingRows = result.recordset || [];
|
|
565
472
|
rows.push(...remainingRows);
|
|
@@ -567,153 +474,171 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
567
474
|
const timeDiff = a.seq_id - b.seq_id;
|
|
568
475
|
return timeDiff;
|
|
569
476
|
});
|
|
570
|
-
|
|
571
|
-
|
|
477
|
+
const messagesWithParsedContent = rows.map((row) => {
|
|
478
|
+
if (typeof row.content === "string") {
|
|
479
|
+
try {
|
|
480
|
+
return { ...row, content: JSON.parse(row.content) };
|
|
481
|
+
} catch {
|
|
482
|
+
return row;
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
return row;
|
|
486
|
+
});
|
|
487
|
+
const cleanMessages = messagesWithParsedContent.map(({ seq_id, ...rest }) => rest);
|
|
488
|
+
const list = new MessageList().add(cleanMessages, "memory");
|
|
489
|
+
return { messages: list.get.all.db() };
|
|
572
490
|
} catch (error) {
|
|
573
491
|
const mastraError = new MastraError(
|
|
574
492
|
{
|
|
575
|
-
id: "
|
|
493
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_LIST_MESSAGES_BY_ID_FAILED",
|
|
576
494
|
domain: ErrorDomain.STORAGE,
|
|
577
495
|
category: ErrorCategory.THIRD_PARTY,
|
|
578
496
|
details: {
|
|
579
|
-
|
|
580
|
-
resourceId: resourceId ?? ""
|
|
497
|
+
messageIds: JSON.stringify(messageIds)
|
|
581
498
|
}
|
|
582
499
|
},
|
|
583
500
|
error
|
|
584
501
|
);
|
|
585
502
|
this.logger?.error?.(mastraError.toString());
|
|
586
|
-
this.logger?.trackException(mastraError);
|
|
587
|
-
return [];
|
|
503
|
+
this.logger?.trackException?.(mastraError);
|
|
504
|
+
return { messages: [] };
|
|
588
505
|
}
|
|
589
506
|
}
|
|
590
|
-
async
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
if (messageIds.length === 0) return [];
|
|
595
|
-
const selectStatement = `SELECT seq_id, id, content, role, type, [createdAt], thread_id AS threadId, resourceId`;
|
|
596
|
-
const orderByStatement = `ORDER BY [seq_id] DESC`;
|
|
597
|
-
try {
|
|
598
|
-
let rows = [];
|
|
599
|
-
let query = `${selectStatement} FROM ${getTableName({ indexName: TABLE_MESSAGES, schemaName: getSchemaName(this.schema) })} WHERE [id] IN (${messageIds.map((_, i) => `@id${i}`).join(", ")})`;
|
|
600
|
-
const request = this.pool.request();
|
|
601
|
-
messageIds.forEach((id, i) => request.input(`id${i}`, id));
|
|
602
|
-
query += ` ${orderByStatement}`;
|
|
603
|
-
const result = await request.query(query);
|
|
604
|
-
const remainingRows = result.recordset || [];
|
|
605
|
-
rows.push(...remainingRows);
|
|
606
|
-
rows.sort((a, b) => {
|
|
607
|
-
const timeDiff = a.seq_id - b.seq_id;
|
|
608
|
-
return timeDiff;
|
|
609
|
-
});
|
|
610
|
-
rows = rows.map(({ seq_id, ...rest }) => rest);
|
|
611
|
-
if (format === `v1`) return this._parseAndFormatMessages(rows, format);
|
|
612
|
-
return this._parseAndFormatMessages(rows, `v2`);
|
|
613
|
-
} catch (error) {
|
|
614
|
-
const mastraError = new MastraError(
|
|
507
|
+
async listMessages(args) {
|
|
508
|
+
const { threadId, resourceId, include, filter, perPage: perPageInput, page = 0, orderBy } = args;
|
|
509
|
+
if (!threadId.trim()) {
|
|
510
|
+
throw new MastraError(
|
|
615
511
|
{
|
|
616
|
-
id: "
|
|
512
|
+
id: "STORAGE_MSSQL_LIST_MESSAGES_INVALID_THREAD_ID",
|
|
617
513
|
domain: ErrorDomain.STORAGE,
|
|
618
514
|
category: ErrorCategory.THIRD_PARTY,
|
|
619
|
-
details: {
|
|
620
|
-
messageIds: JSON.stringify(messageIds)
|
|
621
|
-
}
|
|
515
|
+
details: { threadId }
|
|
622
516
|
},
|
|
623
|
-
|
|
517
|
+
new Error("threadId must be a non-empty string")
|
|
624
518
|
);
|
|
625
|
-
this.logger?.error?.(mastraError.toString());
|
|
626
|
-
this.logger?.trackException(mastraError);
|
|
627
|
-
return [];
|
|
628
519
|
}
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
520
|
+
if (page < 0) {
|
|
521
|
+
throw new MastraError({
|
|
522
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_INVALID_PAGE",
|
|
523
|
+
domain: ErrorDomain.STORAGE,
|
|
524
|
+
category: ErrorCategory.USER,
|
|
525
|
+
text: "Page number must be non-negative",
|
|
526
|
+
details: {
|
|
527
|
+
threadId,
|
|
528
|
+
page
|
|
529
|
+
}
|
|
530
|
+
});
|
|
531
|
+
}
|
|
532
|
+
const perPage = normalizePerPage(perPageInput, 40);
|
|
533
|
+
const { offset, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
|
|
633
534
|
try {
|
|
634
|
-
|
|
635
|
-
const
|
|
636
|
-
const
|
|
637
|
-
const
|
|
638
|
-
const
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
}
|
|
644
|
-
|
|
645
|
-
const
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
request
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
request.input("fromDate", fromDate.toISOString());
|
|
652
|
-
}
|
|
653
|
-
if (toDate instanceof Date && !isNaN(toDate.getTime())) {
|
|
654
|
-
conditions.push("[createdAt] <= @toDate");
|
|
655
|
-
request.input("toDate", toDate.toISOString());
|
|
656
|
-
}
|
|
657
|
-
const whereClause = `WHERE ${conditions.join(" AND ")}`;
|
|
658
|
-
const countQuery = `SELECT COUNT(*) as total FROM ${getTableName({ indexName: TABLE_MESSAGES, schemaName: getSchemaName(this.schema) })} ${whereClause}`;
|
|
659
|
-
const countResult = await request.query(countQuery);
|
|
535
|
+
const { field, direction } = this.parseOrderBy(orderBy, "ASC");
|
|
536
|
+
const orderByStatement = `ORDER BY [${field}] ${direction}, [seq_id] ${direction}`;
|
|
537
|
+
const tableName = getTableName({ indexName: TABLE_MESSAGES, schemaName: getSchemaName(this.schema) });
|
|
538
|
+
const baseQuery = `SELECT seq_id, id, content, role, type, [createdAt], thread_id AS threadId, resourceId FROM ${tableName}`;
|
|
539
|
+
const filters = {
|
|
540
|
+
thread_id: threadId,
|
|
541
|
+
...resourceId ? { resourceId } : {},
|
|
542
|
+
...buildDateRangeFilter(filter?.dateRange, "createdAt")
|
|
543
|
+
};
|
|
544
|
+
const { sql: actualWhereClause = "", params: whereParams } = prepareWhereClause(
|
|
545
|
+
filters);
|
|
546
|
+
const bindWhereParams = (req) => {
|
|
547
|
+
Object.entries(whereParams).forEach(([paramName, paramValue]) => req.input(paramName, paramValue));
|
|
548
|
+
};
|
|
549
|
+
const countRequest = this.pool.request();
|
|
550
|
+
bindWhereParams(countRequest);
|
|
551
|
+
const countResult = await countRequest.query(`SELECT COUNT(*) as total FROM ${tableName}${actualWhereClause}`);
|
|
660
552
|
const total = parseInt(countResult.recordset[0]?.total, 10) || 0;
|
|
661
|
-
|
|
662
|
-
const
|
|
553
|
+
const fetchBaseMessages = async () => {
|
|
554
|
+
const request = this.pool.request();
|
|
555
|
+
bindWhereParams(request);
|
|
556
|
+
if (perPageInput === false) {
|
|
557
|
+
const result2 = await request.query(`${baseQuery}${actualWhereClause} ${orderByStatement}`);
|
|
558
|
+
return result2.recordset || [];
|
|
559
|
+
}
|
|
560
|
+
request.input("offset", offset);
|
|
561
|
+
request.input("limit", perPage > 2147483647 ? sql2.BigInt : sql2.Int, perPage);
|
|
562
|
+
const result = await request.query(
|
|
563
|
+
`${baseQuery}${actualWhereClause} ${orderByStatement} OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY`
|
|
564
|
+
);
|
|
565
|
+
return result.recordset || [];
|
|
566
|
+
};
|
|
567
|
+
const baseRows = perPage === 0 ? [] : await fetchBaseMessages();
|
|
568
|
+
const messages = [...baseRows];
|
|
569
|
+
const seqById = /* @__PURE__ */ new Map();
|
|
570
|
+
messages.forEach((msg) => {
|
|
571
|
+
if (typeof msg.seq_id === "number") seqById.set(msg.id, msg.seq_id);
|
|
572
|
+
});
|
|
573
|
+
if (total === 0 && messages.length === 0 && (!include || include.length === 0)) {
|
|
663
574
|
return {
|
|
664
|
-
messages:
|
|
665
|
-
total:
|
|
575
|
+
messages: [],
|
|
576
|
+
total: 0,
|
|
666
577
|
page,
|
|
667
|
-
perPage,
|
|
578
|
+
perPage: perPageForResponse,
|
|
668
579
|
hasMore: false
|
|
669
580
|
};
|
|
670
581
|
}
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
const
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
const
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
582
|
+
if (include?.length) {
|
|
583
|
+
const messageIds = new Set(messages.map((m) => m.id));
|
|
584
|
+
const includeMessages = await this._getIncludedMessages({ threadId, include });
|
|
585
|
+
includeMessages?.forEach((msg) => {
|
|
586
|
+
if (!messageIds.has(msg.id)) {
|
|
587
|
+
messages.push(msg);
|
|
588
|
+
messageIds.add(msg.id);
|
|
589
|
+
if (typeof msg.seq_id === "number") seqById.set(msg.id, msg.seq_id);
|
|
590
|
+
}
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
const parsed = this._parseAndFormatMessages(messages, "v2");
|
|
594
|
+
const mult = direction === "ASC" ? 1 : -1;
|
|
595
|
+
const finalMessages = parsed.sort((a, b) => {
|
|
596
|
+
const aVal = field === "createdAt" ? new Date(a.createdAt).getTime() : a[field];
|
|
597
|
+
const bVal = field === "createdAt" ? new Date(b.createdAt).getTime() : b[field];
|
|
598
|
+
if (aVal == null || bVal == null) {
|
|
599
|
+
return aVal == null && bVal == null ? a.id.localeCompare(b.id) : aVal == null ? 1 : -1;
|
|
600
|
+
}
|
|
601
|
+
const diff = (typeof aVal === "number" && typeof bVal === "number" ? aVal - bVal : String(aVal).localeCompare(String(bVal))) * mult;
|
|
602
|
+
if (diff !== 0) return diff;
|
|
603
|
+
const seqA = seqById.get(a.id);
|
|
604
|
+
const seqB = seqById.get(b.id);
|
|
605
|
+
return seqA != null && seqB != null ? (seqA - seqB) * mult : a.id.localeCompare(b.id);
|
|
606
|
+
});
|
|
607
|
+
const returnedThreadMessageCount = finalMessages.filter((m) => m.threadId === threadId).length;
|
|
608
|
+
const hasMore = perPageInput !== false && returnedThreadMessageCount < total && offset + perPage < total;
|
|
686
609
|
return {
|
|
687
|
-
messages:
|
|
688
|
-
total
|
|
610
|
+
messages: finalMessages,
|
|
611
|
+
total,
|
|
689
612
|
page,
|
|
690
|
-
perPage,
|
|
691
|
-
hasMore
|
|
613
|
+
perPage: perPageForResponse,
|
|
614
|
+
hasMore
|
|
692
615
|
};
|
|
693
616
|
} catch (error) {
|
|
694
617
|
const mastraError = new MastraError(
|
|
695
618
|
{
|
|
696
|
-
id: "
|
|
619
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_LIST_MESSAGES_FAILED",
|
|
697
620
|
domain: ErrorDomain.STORAGE,
|
|
698
621
|
category: ErrorCategory.THIRD_PARTY,
|
|
699
622
|
details: {
|
|
700
623
|
threadId,
|
|
701
|
-
resourceId: resourceId ?? ""
|
|
702
|
-
page
|
|
624
|
+
resourceId: resourceId ?? ""
|
|
703
625
|
}
|
|
704
626
|
},
|
|
705
627
|
error
|
|
706
628
|
);
|
|
707
629
|
this.logger?.error?.(mastraError.toString());
|
|
708
|
-
this.logger?.trackException(mastraError);
|
|
709
|
-
return {
|
|
630
|
+
this.logger?.trackException?.(mastraError);
|
|
631
|
+
return {
|
|
632
|
+
messages: [],
|
|
633
|
+
total: 0,
|
|
634
|
+
page,
|
|
635
|
+
perPage: perPageForResponse,
|
|
636
|
+
hasMore: false
|
|
637
|
+
};
|
|
710
638
|
}
|
|
711
639
|
}
|
|
712
|
-
async saveMessages({
|
|
713
|
-
messages
|
|
714
|
-
format
|
|
715
|
-
}) {
|
|
716
|
-
if (messages.length === 0) return messages;
|
|
640
|
+
async saveMessages({ messages }) {
|
|
641
|
+
if (messages.length === 0) return { messages: [] };
|
|
717
642
|
const threadId = messages[0]?.threadId;
|
|
718
643
|
if (!threadId) {
|
|
719
644
|
throw new MastraError({
|
|
@@ -795,8 +720,7 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
795
720
|
return message;
|
|
796
721
|
});
|
|
797
722
|
const list = new MessageList().add(messagesWithParsedContent, "memory");
|
|
798
|
-
|
|
799
|
-
return list.get.all.v1();
|
|
723
|
+
return { messages: list.get.all.db() };
|
|
800
724
|
} catch (error) {
|
|
801
725
|
throw new MastraError(
|
|
802
726
|
{
|
|
@@ -972,8 +896,10 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
972
896
|
return null;
|
|
973
897
|
}
|
|
974
898
|
return {
|
|
975
|
-
|
|
976
|
-
|
|
899
|
+
id: result.id,
|
|
900
|
+
createdAt: result.createdAt,
|
|
901
|
+
updatedAt: result.updatedAt,
|
|
902
|
+
workingMemory: result.workingMemory,
|
|
977
903
|
metadata: typeof result.metadata === "string" ? JSON.parse(result.metadata) : result.metadata
|
|
978
904
|
};
|
|
979
905
|
} catch (error) {
|
|
@@ -987,7 +913,7 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
987
913
|
error
|
|
988
914
|
);
|
|
989
915
|
this.logger?.error?.(mastraError.toString());
|
|
990
|
-
this.logger?.trackException(mastraError);
|
|
916
|
+
this.logger?.trackException?.(mastraError);
|
|
991
917
|
throw mastraError;
|
|
992
918
|
}
|
|
993
919
|
}
|
|
@@ -996,7 +922,7 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
996
922
|
tableName: TABLE_RESOURCES,
|
|
997
923
|
record: {
|
|
998
924
|
...resource,
|
|
999
|
-
metadata:
|
|
925
|
+
metadata: resource.metadata
|
|
1000
926
|
}
|
|
1001
927
|
});
|
|
1002
928
|
return resource;
|
|
@@ -1054,72 +980,391 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
1054
980
|
error
|
|
1055
981
|
);
|
|
1056
982
|
this.logger?.error?.(mastraError.toString());
|
|
1057
|
-
this.logger?.trackException(mastraError);
|
|
983
|
+
this.logger?.trackException?.(mastraError);
|
|
1058
984
|
throw mastraError;
|
|
1059
985
|
}
|
|
1060
986
|
}
|
|
1061
987
|
};
|
|
1062
|
-
var
|
|
988
|
+
var ObservabilityMSSQL = class extends ObservabilityStorage {
|
|
1063
989
|
pool;
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
case "timestamp":
|
|
1072
|
-
return "DATETIME2(7)";
|
|
1073
|
-
case "uuid":
|
|
1074
|
-
return "UNIQUEIDENTIFIER";
|
|
1075
|
-
case "jsonb":
|
|
1076
|
-
return "NVARCHAR(MAX)";
|
|
1077
|
-
case "integer":
|
|
1078
|
-
return "INT";
|
|
1079
|
-
case "bigint":
|
|
1080
|
-
return "BIGINT";
|
|
1081
|
-
case "float":
|
|
1082
|
-
return "FLOAT";
|
|
1083
|
-
default:
|
|
1084
|
-
throw new MastraError({
|
|
1085
|
-
id: "MASTRA_STORAGE_MSSQL_STORE_TYPE_NOT_SUPPORTED",
|
|
1086
|
-
domain: ErrorDomain.STORAGE,
|
|
1087
|
-
category: ErrorCategory.THIRD_PARTY
|
|
1088
|
-
});
|
|
1089
|
-
}
|
|
1090
|
-
}
|
|
1091
|
-
constructor({ pool, schemaName }) {
|
|
990
|
+
operations;
|
|
991
|
+
schema;
|
|
992
|
+
constructor({
|
|
993
|
+
pool,
|
|
994
|
+
operations,
|
|
995
|
+
schema
|
|
996
|
+
}) {
|
|
1092
997
|
super();
|
|
1093
998
|
this.pool = pool;
|
|
1094
|
-
this.
|
|
999
|
+
this.operations = operations;
|
|
1000
|
+
this.schema = schema;
|
|
1095
1001
|
}
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
request.input("column", column);
|
|
1102
|
-
request.input("columnLower", column.toLowerCase());
|
|
1103
|
-
const result = await request.query(
|
|
1104
|
-
`SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = @schema AND TABLE_NAME = @table AND (COLUMN_NAME = @column OR COLUMN_NAME = @columnLower)`
|
|
1105
|
-
);
|
|
1106
|
-
return result.recordset.length > 0;
|
|
1002
|
+
get tracingStrategy() {
|
|
1003
|
+
return {
|
|
1004
|
+
preferred: "batch-with-updates",
|
|
1005
|
+
supported: ["batch-with-updates", "insert-only"]
|
|
1006
|
+
};
|
|
1107
1007
|
}
|
|
1108
|
-
async
|
|
1109
|
-
|
|
1110
|
-
|
|
1008
|
+
async createSpan(span) {
|
|
1009
|
+
try {
|
|
1010
|
+
const startedAt = span.startedAt instanceof Date ? span.startedAt.toISOString() : span.startedAt;
|
|
1011
|
+
const endedAt = span.endedAt instanceof Date ? span.endedAt.toISOString() : span.endedAt;
|
|
1012
|
+
const record = {
|
|
1013
|
+
...span,
|
|
1014
|
+
startedAt,
|
|
1015
|
+
endedAt
|
|
1016
|
+
// Note: createdAt/updatedAt will be set by default values
|
|
1017
|
+
};
|
|
1018
|
+
return this.operations.insert({ tableName: TABLE_SPANS, record });
|
|
1019
|
+
} catch (error) {
|
|
1020
|
+
throw new MastraError(
|
|
1021
|
+
{
|
|
1022
|
+
id: "MSSQL_STORE_CREATE_SPAN_FAILED",
|
|
1023
|
+
domain: ErrorDomain.STORAGE,
|
|
1024
|
+
category: ErrorCategory.USER,
|
|
1025
|
+
details: {
|
|
1026
|
+
spanId: span.spanId,
|
|
1027
|
+
traceId: span.traceId,
|
|
1028
|
+
spanType: span.spanType,
|
|
1029
|
+
spanName: span.name
|
|
1030
|
+
}
|
|
1031
|
+
},
|
|
1032
|
+
error
|
|
1033
|
+
);
|
|
1111
1034
|
}
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1035
|
+
}
|
|
1036
|
+
async getTrace(traceId) {
|
|
1037
|
+
try {
|
|
1038
|
+
const tableName = getTableName({
|
|
1039
|
+
indexName: TABLE_SPANS,
|
|
1040
|
+
schemaName: getSchemaName(this.schema)
|
|
1041
|
+
});
|
|
1042
|
+
const request = this.pool.request();
|
|
1043
|
+
request.input("traceId", traceId);
|
|
1044
|
+
const result = await request.query(
|
|
1045
|
+
`SELECT
|
|
1046
|
+
[traceId], [spanId], [parentSpanId], [name], [scope], [spanType],
|
|
1047
|
+
[attributes], [metadata], [links], [input], [output], [error], [isEvent],
|
|
1048
|
+
[startedAt], [endedAt], [createdAt], [updatedAt]
|
|
1049
|
+
FROM ${tableName}
|
|
1050
|
+
WHERE [traceId] = @traceId
|
|
1051
|
+
ORDER BY [startedAt] DESC`
|
|
1052
|
+
);
|
|
1053
|
+
if (!result.recordset || result.recordset.length === 0) {
|
|
1054
|
+
return null;
|
|
1055
|
+
}
|
|
1056
|
+
return {
|
|
1057
|
+
traceId,
|
|
1058
|
+
spans: result.recordset.map(
|
|
1059
|
+
(span) => transformFromSqlRow({
|
|
1060
|
+
tableName: TABLE_SPANS,
|
|
1061
|
+
sqlRow: span
|
|
1062
|
+
})
|
|
1063
|
+
)
|
|
1064
|
+
};
|
|
1065
|
+
} catch (error) {
|
|
1066
|
+
throw new MastraError(
|
|
1067
|
+
{
|
|
1068
|
+
id: "MSSQL_STORE_GET_TRACE_FAILED",
|
|
1069
|
+
domain: ErrorDomain.STORAGE,
|
|
1070
|
+
category: ErrorCategory.USER,
|
|
1071
|
+
details: {
|
|
1072
|
+
traceId
|
|
1073
|
+
}
|
|
1074
|
+
},
|
|
1075
|
+
error
|
|
1076
|
+
);
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
async updateSpan({
|
|
1080
|
+
spanId,
|
|
1081
|
+
traceId,
|
|
1082
|
+
updates
|
|
1083
|
+
}) {
|
|
1084
|
+
try {
|
|
1085
|
+
const data = { ...updates };
|
|
1086
|
+
if (data.endedAt instanceof Date) {
|
|
1087
|
+
data.endedAt = data.endedAt.toISOString();
|
|
1088
|
+
}
|
|
1089
|
+
if (data.startedAt instanceof Date) {
|
|
1090
|
+
data.startedAt = data.startedAt.toISOString();
|
|
1091
|
+
}
|
|
1092
|
+
await this.operations.update({
|
|
1093
|
+
tableName: TABLE_SPANS,
|
|
1094
|
+
keys: { spanId, traceId },
|
|
1095
|
+
data
|
|
1096
|
+
});
|
|
1097
|
+
} catch (error) {
|
|
1098
|
+
throw new MastraError(
|
|
1099
|
+
{
|
|
1100
|
+
id: "MSSQL_STORE_UPDATE_SPAN_FAILED",
|
|
1101
|
+
domain: ErrorDomain.STORAGE,
|
|
1102
|
+
category: ErrorCategory.USER,
|
|
1103
|
+
details: {
|
|
1104
|
+
spanId,
|
|
1105
|
+
traceId
|
|
1106
|
+
}
|
|
1107
|
+
},
|
|
1108
|
+
error
|
|
1109
|
+
);
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
async getTracesPaginated({
|
|
1113
|
+
filters,
|
|
1114
|
+
pagination
|
|
1115
|
+
}) {
|
|
1116
|
+
const page = pagination?.page ?? 0;
|
|
1117
|
+
const perPage = pagination?.perPage ?? 10;
|
|
1118
|
+
const { entityId, entityType, ...actualFilters } = filters || {};
|
|
1119
|
+
const filtersWithDateRange = {
|
|
1120
|
+
...actualFilters,
|
|
1121
|
+
...buildDateRangeFilter(pagination?.dateRange, "startedAt"),
|
|
1122
|
+
parentSpanId: null
|
|
1123
|
+
// Only get root spans for traces
|
|
1124
|
+
};
|
|
1125
|
+
const whereClause = prepareWhereClause(filtersWithDateRange);
|
|
1126
|
+
let actualWhereClause = whereClause.sql;
|
|
1127
|
+
const params = { ...whereClause.params };
|
|
1128
|
+
let currentParamIndex = Object.keys(params).length + 1;
|
|
1129
|
+
if (entityId && entityType) {
|
|
1130
|
+
let name = "";
|
|
1131
|
+
if (entityType === "workflow") {
|
|
1132
|
+
name = `workflow run: '${entityId}'`;
|
|
1133
|
+
} else if (entityType === "agent") {
|
|
1134
|
+
name = `agent run: '${entityId}'`;
|
|
1135
|
+
} else {
|
|
1136
|
+
const error = new MastraError({
|
|
1137
|
+
id: "MSSQL_STORE_GET_TRACES_PAGINATED_FAILED",
|
|
1138
|
+
domain: ErrorDomain.STORAGE,
|
|
1139
|
+
category: ErrorCategory.USER,
|
|
1140
|
+
details: {
|
|
1141
|
+
entityType
|
|
1142
|
+
},
|
|
1143
|
+
text: `Cannot filter by entity type: ${entityType}`
|
|
1144
|
+
});
|
|
1145
|
+
throw error;
|
|
1146
|
+
}
|
|
1147
|
+
const entityParam = `p${currentParamIndex++}`;
|
|
1148
|
+
if (actualWhereClause) {
|
|
1149
|
+
actualWhereClause += ` AND [name] = @${entityParam}`;
|
|
1150
|
+
} else {
|
|
1151
|
+
actualWhereClause = ` WHERE [name] = @${entityParam}`;
|
|
1152
|
+
}
|
|
1153
|
+
params[entityParam] = name;
|
|
1154
|
+
}
|
|
1155
|
+
const tableName = getTableName({
|
|
1156
|
+
indexName: TABLE_SPANS,
|
|
1157
|
+
schemaName: getSchemaName(this.schema)
|
|
1158
|
+
});
|
|
1159
|
+
try {
|
|
1160
|
+
const countRequest = this.pool.request();
|
|
1161
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
1162
|
+
countRequest.input(key, value);
|
|
1163
|
+
});
|
|
1164
|
+
const countResult = await countRequest.query(
|
|
1165
|
+
`SELECT COUNT(*) as count FROM ${tableName}${actualWhereClause}`
|
|
1166
|
+
);
|
|
1167
|
+
const total = countResult.recordset[0]?.count ?? 0;
|
|
1168
|
+
if (total === 0) {
|
|
1169
|
+
return {
|
|
1170
|
+
pagination: {
|
|
1171
|
+
total: 0,
|
|
1172
|
+
page,
|
|
1173
|
+
perPage,
|
|
1174
|
+
hasMore: false
|
|
1175
|
+
},
|
|
1176
|
+
spans: []
|
|
1177
|
+
};
|
|
1178
|
+
}
|
|
1179
|
+
const dataRequest = this.pool.request();
|
|
1180
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
1181
|
+
dataRequest.input(key, value);
|
|
1182
|
+
});
|
|
1183
|
+
dataRequest.input("offset", page * perPage);
|
|
1184
|
+
dataRequest.input("limit", perPage);
|
|
1185
|
+
const dataResult = await dataRequest.query(
|
|
1186
|
+
`SELECT * FROM ${tableName}${actualWhereClause} ORDER BY [startedAt] DESC OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY`
|
|
1187
|
+
);
|
|
1188
|
+
const spans = dataResult.recordset.map(
|
|
1189
|
+
(row) => transformFromSqlRow({
|
|
1190
|
+
tableName: TABLE_SPANS,
|
|
1191
|
+
sqlRow: row
|
|
1192
|
+
})
|
|
1193
|
+
);
|
|
1194
|
+
return {
|
|
1195
|
+
pagination: {
|
|
1196
|
+
total,
|
|
1197
|
+
page,
|
|
1198
|
+
perPage,
|
|
1199
|
+
hasMore: (page + 1) * perPage < total
|
|
1200
|
+
},
|
|
1201
|
+
spans
|
|
1202
|
+
};
|
|
1203
|
+
} catch (error) {
|
|
1204
|
+
throw new MastraError(
|
|
1205
|
+
{
|
|
1206
|
+
id: "MSSQL_STORE_GET_TRACES_PAGINATED_FAILED",
|
|
1207
|
+
domain: ErrorDomain.STORAGE,
|
|
1208
|
+
category: ErrorCategory.USER
|
|
1209
|
+
},
|
|
1210
|
+
error
|
|
1211
|
+
);
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
async batchCreateSpans(args) {
|
|
1215
|
+
if (!args.records || args.records.length === 0) {
|
|
1216
|
+
return;
|
|
1217
|
+
}
|
|
1218
|
+
try {
|
|
1219
|
+
await this.operations.batchInsert({
|
|
1220
|
+
tableName: TABLE_SPANS,
|
|
1221
|
+
records: args.records.map((span) => ({
|
|
1222
|
+
...span,
|
|
1223
|
+
startedAt: span.startedAt instanceof Date ? span.startedAt.toISOString() : span.startedAt,
|
|
1224
|
+
endedAt: span.endedAt instanceof Date ? span.endedAt.toISOString() : span.endedAt
|
|
1225
|
+
}))
|
|
1226
|
+
});
|
|
1227
|
+
} catch (error) {
|
|
1228
|
+
throw new MastraError(
|
|
1229
|
+
{
|
|
1230
|
+
id: "MSSQL_STORE_BATCH_CREATE_SPANS_FAILED",
|
|
1231
|
+
domain: ErrorDomain.STORAGE,
|
|
1232
|
+
category: ErrorCategory.USER,
|
|
1233
|
+
details: {
|
|
1234
|
+
count: args.records.length
|
|
1235
|
+
}
|
|
1236
|
+
},
|
|
1237
|
+
error
|
|
1238
|
+
);
|
|
1239
|
+
}
|
|
1240
|
+
}
|
|
1241
|
+
async batchUpdateSpans(args) {
|
|
1242
|
+
if (!args.records || args.records.length === 0) {
|
|
1243
|
+
return;
|
|
1244
|
+
}
|
|
1245
|
+
try {
|
|
1246
|
+
const updates = args.records.map(({ traceId, spanId, updates: data }) => {
|
|
1247
|
+
const processedData = { ...data };
|
|
1248
|
+
if (processedData.endedAt instanceof Date) {
|
|
1249
|
+
processedData.endedAt = processedData.endedAt.toISOString();
|
|
1250
|
+
}
|
|
1251
|
+
if (processedData.startedAt instanceof Date) {
|
|
1252
|
+
processedData.startedAt = processedData.startedAt.toISOString();
|
|
1253
|
+
}
|
|
1254
|
+
return {
|
|
1255
|
+
keys: { spanId, traceId },
|
|
1256
|
+
data: processedData
|
|
1257
|
+
};
|
|
1258
|
+
});
|
|
1259
|
+
await this.operations.batchUpdate({
|
|
1260
|
+
tableName: TABLE_SPANS,
|
|
1261
|
+
updates
|
|
1262
|
+
});
|
|
1263
|
+
} catch (error) {
|
|
1264
|
+
throw new MastraError(
|
|
1265
|
+
{
|
|
1266
|
+
id: "MSSQL_STORE_BATCH_UPDATE_SPANS_FAILED",
|
|
1267
|
+
domain: ErrorDomain.STORAGE,
|
|
1268
|
+
category: ErrorCategory.USER,
|
|
1269
|
+
details: {
|
|
1270
|
+
count: args.records.length
|
|
1271
|
+
}
|
|
1272
|
+
},
|
|
1273
|
+
error
|
|
1274
|
+
);
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
async batchDeleteTraces(args) {
|
|
1278
|
+
if (!args.traceIds || args.traceIds.length === 0) {
|
|
1279
|
+
return;
|
|
1280
|
+
}
|
|
1281
|
+
try {
|
|
1282
|
+
const keys = args.traceIds.map((traceId) => ({ traceId }));
|
|
1283
|
+
await this.operations.batchDelete({
|
|
1284
|
+
tableName: TABLE_SPANS,
|
|
1285
|
+
keys
|
|
1286
|
+
});
|
|
1287
|
+
} catch (error) {
|
|
1288
|
+
throw new MastraError(
|
|
1289
|
+
{
|
|
1290
|
+
id: "MSSQL_STORE_BATCH_DELETE_TRACES_FAILED",
|
|
1291
|
+
domain: ErrorDomain.STORAGE,
|
|
1292
|
+
category: ErrorCategory.USER,
|
|
1293
|
+
details: {
|
|
1294
|
+
count: args.traceIds.length
|
|
1295
|
+
}
|
|
1296
|
+
},
|
|
1297
|
+
error
|
|
1298
|
+
);
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
};
|
|
1302
|
+
var StoreOperationsMSSQL = class extends StoreOperations {
|
|
1303
|
+
pool;
|
|
1304
|
+
schemaName;
|
|
1305
|
+
setupSchemaPromise = null;
|
|
1306
|
+
schemaSetupComplete = void 0;
|
|
1307
|
+
getSqlType(type, isPrimaryKey = false, useLargeStorage = false) {
|
|
1308
|
+
switch (type) {
|
|
1309
|
+
case "text":
|
|
1310
|
+
if (useLargeStorage) {
|
|
1311
|
+
return "NVARCHAR(MAX)";
|
|
1312
|
+
}
|
|
1313
|
+
return isPrimaryKey ? "NVARCHAR(255)" : "NVARCHAR(400)";
|
|
1314
|
+
case "timestamp":
|
|
1315
|
+
return "DATETIME2(7)";
|
|
1316
|
+
case "uuid":
|
|
1317
|
+
return "UNIQUEIDENTIFIER";
|
|
1318
|
+
case "jsonb":
|
|
1319
|
+
return "NVARCHAR(MAX)";
|
|
1320
|
+
case "integer":
|
|
1321
|
+
return "INT";
|
|
1322
|
+
case "bigint":
|
|
1323
|
+
return "BIGINT";
|
|
1324
|
+
case "float":
|
|
1325
|
+
return "FLOAT";
|
|
1326
|
+
case "boolean":
|
|
1327
|
+
return "BIT";
|
|
1328
|
+
default:
|
|
1329
|
+
throw new MastraError({
|
|
1330
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_TYPE_NOT_SUPPORTED",
|
|
1331
|
+
domain: ErrorDomain.STORAGE,
|
|
1332
|
+
category: ErrorCategory.THIRD_PARTY
|
|
1333
|
+
});
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
constructor({ pool, schemaName }) {
|
|
1337
|
+
super();
|
|
1338
|
+
this.pool = pool;
|
|
1339
|
+
this.schemaName = schemaName;
|
|
1340
|
+
}
|
|
1341
|
+
async hasColumn(table, column) {
|
|
1342
|
+
const schema = this.schemaName || "dbo";
|
|
1343
|
+
const request = this.pool.request();
|
|
1344
|
+
request.input("schema", schema);
|
|
1345
|
+
request.input("table", table);
|
|
1346
|
+
request.input("column", column);
|
|
1347
|
+
request.input("columnLower", column.toLowerCase());
|
|
1348
|
+
const result = await request.query(
|
|
1349
|
+
`SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = @schema AND TABLE_NAME = @table AND (COLUMN_NAME = @column OR COLUMN_NAME = @columnLower)`
|
|
1350
|
+
);
|
|
1351
|
+
return result.recordset.length > 0;
|
|
1352
|
+
}
|
|
1353
|
+
async setupSchema() {
|
|
1354
|
+
if (!this.schemaName || this.schemaSetupComplete) {
|
|
1355
|
+
return;
|
|
1356
|
+
}
|
|
1357
|
+
if (!this.setupSchemaPromise) {
|
|
1358
|
+
this.setupSchemaPromise = (async () => {
|
|
1359
|
+
try {
|
|
1360
|
+
const checkRequest = this.pool.request();
|
|
1361
|
+
checkRequest.input("schemaName", this.schemaName);
|
|
1362
|
+
const checkResult = await checkRequest.query(`
|
|
1363
|
+
SELECT 1 AS found FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = @schemaName
|
|
1364
|
+
`);
|
|
1365
|
+
const schemaExists = Array.isArray(checkResult.recordset) && checkResult.recordset.length > 0;
|
|
1366
|
+
if (!schemaExists) {
|
|
1367
|
+
try {
|
|
1123
1368
|
await this.pool.request().query(`CREATE SCHEMA [${this.schemaName}]`);
|
|
1124
1369
|
this.logger?.info?.(`Schema "${this.schemaName}" created successfully`);
|
|
1125
1370
|
} catch (error) {
|
|
@@ -1142,20 +1387,26 @@ var StoreOperationsMSSQL = class extends StoreOperations {
|
|
|
1142
1387
|
}
|
|
1143
1388
|
await this.setupSchemaPromise;
|
|
1144
1389
|
}
|
|
1145
|
-
async insert({
|
|
1390
|
+
async insert({
|
|
1391
|
+
tableName,
|
|
1392
|
+
record,
|
|
1393
|
+
transaction
|
|
1394
|
+
}) {
|
|
1146
1395
|
try {
|
|
1147
|
-
const columns = Object.keys(record)
|
|
1148
|
-
const
|
|
1149
|
-
const paramNames =
|
|
1150
|
-
const insertSql = `INSERT INTO ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} (${
|
|
1151
|
-
const request = this.pool.request();
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
request.input(`param${i}`,
|
|
1396
|
+
const columns = Object.keys(record);
|
|
1397
|
+
const parsedColumns = columns.map((col) => parseSqlIdentifier(col, "column name"));
|
|
1398
|
+
const paramNames = columns.map((_, i) => `@param${i}`);
|
|
1399
|
+
const insertSql = `INSERT INTO ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} (${parsedColumns.map((c) => `[${c}]`).join(", ")}) VALUES (${paramNames.join(", ")})`;
|
|
1400
|
+
const request = transaction ? transaction.request() : this.pool.request();
|
|
1401
|
+
columns.forEach((col, i) => {
|
|
1402
|
+
const value = record[col];
|
|
1403
|
+
const preparedValue = this.prepareValue(value, col, tableName);
|
|
1404
|
+
if (preparedValue instanceof Date) {
|
|
1405
|
+
request.input(`param${i}`, sql2.DateTime2, preparedValue);
|
|
1406
|
+
} else if (preparedValue === null || preparedValue === void 0) {
|
|
1407
|
+
request.input(`param${i}`, this.getMssqlType(tableName, col), null);
|
|
1157
1408
|
} else {
|
|
1158
|
-
request.input(`param${i}`,
|
|
1409
|
+
request.input(`param${i}`, preparedValue);
|
|
1159
1410
|
}
|
|
1160
1411
|
});
|
|
1161
1412
|
await request.query(insertSql);
|
|
@@ -1179,7 +1430,7 @@ var StoreOperationsMSSQL = class extends StoreOperations {
|
|
|
1179
1430
|
try {
|
|
1180
1431
|
await this.pool.request().query(`TRUNCATE TABLE ${fullTableName}`);
|
|
1181
1432
|
} catch (truncateError) {
|
|
1182
|
-
if (truncateError
|
|
1433
|
+
if (truncateError?.number === 4712) {
|
|
1183
1434
|
await this.pool.request().query(`DELETE FROM ${fullTableName}`);
|
|
1184
1435
|
} else {
|
|
1185
1436
|
throw truncateError;
|
|
@@ -1202,9 +1453,11 @@ var StoreOperationsMSSQL = class extends StoreOperations {
|
|
|
1202
1453
|
getDefaultValue(type) {
|
|
1203
1454
|
switch (type) {
|
|
1204
1455
|
case "timestamp":
|
|
1205
|
-
return "DEFAULT
|
|
1456
|
+
return "DEFAULT SYSUTCDATETIME()";
|
|
1206
1457
|
case "jsonb":
|
|
1207
1458
|
return "DEFAULT N'{}'";
|
|
1459
|
+
case "boolean":
|
|
1460
|
+
return "DEFAULT 0";
|
|
1208
1461
|
default:
|
|
1209
1462
|
return super.getDefaultValue(type);
|
|
1210
1463
|
}
|
|
@@ -1215,13 +1468,29 @@ var StoreOperationsMSSQL = class extends StoreOperations {
|
|
|
1215
1468
|
}) {
|
|
1216
1469
|
try {
|
|
1217
1470
|
const uniqueConstraintColumns = tableName === TABLE_WORKFLOW_SNAPSHOT ? ["workflow_name", "run_id"] : [];
|
|
1471
|
+
const largeDataColumns = [
|
|
1472
|
+
"workingMemory",
|
|
1473
|
+
"snapshot",
|
|
1474
|
+
"metadata",
|
|
1475
|
+
"content",
|
|
1476
|
+
// messages.content - can be very long conversation content
|
|
1477
|
+
"input",
|
|
1478
|
+
// evals.input - test input data
|
|
1479
|
+
"output",
|
|
1480
|
+
// evals.output - test output data
|
|
1481
|
+
"instructions",
|
|
1482
|
+
// evals.instructions - evaluation instructions
|
|
1483
|
+
"other"
|
|
1484
|
+
// traces.other - additional trace data
|
|
1485
|
+
];
|
|
1218
1486
|
const columns = Object.entries(schema).map(([name, def]) => {
|
|
1219
1487
|
const parsedName = parseSqlIdentifier(name, "column name");
|
|
1220
1488
|
const constraints = [];
|
|
1221
1489
|
if (def.primaryKey) constraints.push("PRIMARY KEY");
|
|
1222
1490
|
if (!def.nullable) constraints.push("NOT NULL");
|
|
1223
1491
|
const isIndexed = !!def.primaryKey || uniqueConstraintColumns.includes(name);
|
|
1224
|
-
|
|
1492
|
+
const useLargeStorage = largeDataColumns.includes(name);
|
|
1493
|
+
return `[${parsedName}] ${this.getSqlType(def.type, isIndexed, useLargeStorage)} ${constraints.join(" ")}`.trim();
|
|
1225
1494
|
}).join(",\n");
|
|
1226
1495
|
if (this.schemaName) {
|
|
1227
1496
|
await this.setupSchema();
|
|
@@ -1308,7 +1577,19 @@ ${columns}
|
|
|
1308
1577
|
const columnExists = Array.isArray(checkResult.recordset) && checkResult.recordset.length > 0;
|
|
1309
1578
|
if (!columnExists) {
|
|
1310
1579
|
const columnDef = schema[columnName];
|
|
1311
|
-
const
|
|
1580
|
+
const largeDataColumns = [
|
|
1581
|
+
"workingMemory",
|
|
1582
|
+
"snapshot",
|
|
1583
|
+
"metadata",
|
|
1584
|
+
"content",
|
|
1585
|
+
"input",
|
|
1586
|
+
"output",
|
|
1587
|
+
"instructions",
|
|
1588
|
+
"other"
|
|
1589
|
+
];
|
|
1590
|
+
const useLargeStorage = largeDataColumns.includes(columnName);
|
|
1591
|
+
const isIndexed = !!columnDef.primaryKey;
|
|
1592
|
+
const sqlType = this.getSqlType(columnDef.type, isIndexed, useLargeStorage);
|
|
1312
1593
|
const nullable = columnDef.nullable === false ? "NOT NULL" : "";
|
|
1313
1594
|
const defaultValue = columnDef.nullable === false ? this.getDefaultValue(columnDef.type) : "";
|
|
1314
1595
|
const parsedColumnName = parseSqlIdentifier(columnName, "column name");
|
|
@@ -1336,13 +1617,17 @@ ${columns}
|
|
|
1336
1617
|
try {
|
|
1337
1618
|
const keyEntries = Object.entries(keys).map(([key, value]) => [parseSqlIdentifier(key, "column name"), value]);
|
|
1338
1619
|
const conditions = keyEntries.map(([key], i) => `[${key}] = @param${i}`).join(" AND ");
|
|
1339
|
-
const
|
|
1340
|
-
const sql7 = `SELECT * FROM ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} WHERE ${conditions}`;
|
|
1620
|
+
const sql5 = `SELECT * FROM ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} WHERE ${conditions}`;
|
|
1341
1621
|
const request = this.pool.request();
|
|
1342
|
-
|
|
1343
|
-
|
|
1622
|
+
keyEntries.forEach(([key, value], i) => {
|
|
1623
|
+
const preparedValue = this.prepareValue(value, key, tableName);
|
|
1624
|
+
if (preparedValue === null || preparedValue === void 0) {
|
|
1625
|
+
request.input(`param${i}`, this.getMssqlType(tableName, key), null);
|
|
1626
|
+
} else {
|
|
1627
|
+
request.input(`param${i}`, preparedValue);
|
|
1628
|
+
}
|
|
1344
1629
|
});
|
|
1345
|
-
const resultSet = await request.query(
|
|
1630
|
+
const resultSet = await request.query(sql5);
|
|
1346
1631
|
const result = resultSet.recordset[0] || null;
|
|
1347
1632
|
if (!result) {
|
|
1348
1633
|
return null;
|
|
@@ -1374,7 +1659,7 @@ ${columns}
|
|
|
1374
1659
|
try {
|
|
1375
1660
|
await transaction.begin();
|
|
1376
1661
|
for (const record of records) {
|
|
1377
|
-
await this.insert({ tableName, record });
|
|
1662
|
+
await this.insert({ tableName, record, transaction });
|
|
1378
1663
|
}
|
|
1379
1664
|
await transaction.commit();
|
|
1380
1665
|
} catch (error) {
|
|
@@ -1393,44 +1678,594 @@ ${columns}
|
|
|
1393
1678
|
);
|
|
1394
1679
|
}
|
|
1395
1680
|
}
|
|
1396
|
-
async dropTable({ tableName }) {
|
|
1681
|
+
async dropTable({ tableName }) {
|
|
1682
|
+
try {
|
|
1683
|
+
const tableNameWithSchema = getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) });
|
|
1684
|
+
await this.pool.request().query(`DROP TABLE IF EXISTS ${tableNameWithSchema}`);
|
|
1685
|
+
} catch (error) {
|
|
1686
|
+
throw new MastraError(
|
|
1687
|
+
{
|
|
1688
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_DROP_TABLE_FAILED",
|
|
1689
|
+
domain: ErrorDomain.STORAGE,
|
|
1690
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1691
|
+
details: {
|
|
1692
|
+
tableName
|
|
1693
|
+
}
|
|
1694
|
+
},
|
|
1695
|
+
error
|
|
1696
|
+
);
|
|
1697
|
+
}
|
|
1698
|
+
}
|
|
1699
|
+
/**
|
|
1700
|
+
* Prepares a value for database operations, handling Date objects and JSON serialization
|
|
1701
|
+
*/
|
|
1702
|
+
prepareValue(value, columnName, tableName) {
|
|
1703
|
+
if (value === null || value === void 0) {
|
|
1704
|
+
return value;
|
|
1705
|
+
}
|
|
1706
|
+
if (value instanceof Date) {
|
|
1707
|
+
return value;
|
|
1708
|
+
}
|
|
1709
|
+
const schema = TABLE_SCHEMAS[tableName];
|
|
1710
|
+
const columnSchema = schema?.[columnName];
|
|
1711
|
+
if (columnSchema?.type === "boolean") {
|
|
1712
|
+
return value ? 1 : 0;
|
|
1713
|
+
}
|
|
1714
|
+
if (columnSchema?.type === "jsonb") {
|
|
1715
|
+
if (typeof value === "string") {
|
|
1716
|
+
const trimmed = value.trim();
|
|
1717
|
+
if (trimmed.length > 0) {
|
|
1718
|
+
try {
|
|
1719
|
+
JSON.parse(trimmed);
|
|
1720
|
+
return trimmed;
|
|
1721
|
+
} catch {
|
|
1722
|
+
}
|
|
1723
|
+
}
|
|
1724
|
+
return JSON.stringify(value);
|
|
1725
|
+
}
|
|
1726
|
+
if (typeof value === "bigint") {
|
|
1727
|
+
return value.toString();
|
|
1728
|
+
}
|
|
1729
|
+
return JSON.stringify(value);
|
|
1730
|
+
}
|
|
1731
|
+
if (typeof value === "object") {
|
|
1732
|
+
return JSON.stringify(value);
|
|
1733
|
+
}
|
|
1734
|
+
return value;
|
|
1735
|
+
}
|
|
1736
|
+
/**
|
|
1737
|
+
* Maps TABLE_SCHEMAS types to mssql param types (used when value is null)
|
|
1738
|
+
*/
|
|
1739
|
+
getMssqlType(tableName, columnName) {
|
|
1740
|
+
const col = TABLE_SCHEMAS[tableName]?.[columnName];
|
|
1741
|
+
switch (col?.type) {
|
|
1742
|
+
case "text":
|
|
1743
|
+
return sql2.NVarChar;
|
|
1744
|
+
case "timestamp":
|
|
1745
|
+
return sql2.DateTime2;
|
|
1746
|
+
case "uuid":
|
|
1747
|
+
return sql2.UniqueIdentifier;
|
|
1748
|
+
case "jsonb":
|
|
1749
|
+
return sql2.NVarChar;
|
|
1750
|
+
case "integer":
|
|
1751
|
+
return sql2.Int;
|
|
1752
|
+
case "bigint":
|
|
1753
|
+
return sql2.BigInt;
|
|
1754
|
+
case "float":
|
|
1755
|
+
return sql2.Float;
|
|
1756
|
+
case "boolean":
|
|
1757
|
+
return sql2.Bit;
|
|
1758
|
+
default:
|
|
1759
|
+
return sql2.NVarChar;
|
|
1760
|
+
}
|
|
1761
|
+
}
|
|
1762
|
+
/**
|
|
1763
|
+
* Update a single record in the database
|
|
1764
|
+
*/
|
|
1765
|
+
async update({
|
|
1766
|
+
tableName,
|
|
1767
|
+
keys,
|
|
1768
|
+
data,
|
|
1769
|
+
transaction
|
|
1770
|
+
}) {
|
|
1771
|
+
try {
|
|
1772
|
+
if (!data || Object.keys(data).length === 0) {
|
|
1773
|
+
throw new MastraError({
|
|
1774
|
+
id: "MASTRA_STORAGE_MSSQL_UPDATE_EMPTY_DATA",
|
|
1775
|
+
domain: ErrorDomain.STORAGE,
|
|
1776
|
+
category: ErrorCategory.USER,
|
|
1777
|
+
text: "Cannot update with empty data payload"
|
|
1778
|
+
});
|
|
1779
|
+
}
|
|
1780
|
+
if (!keys || Object.keys(keys).length === 0) {
|
|
1781
|
+
throw new MastraError({
|
|
1782
|
+
id: "MASTRA_STORAGE_MSSQL_UPDATE_EMPTY_KEYS",
|
|
1783
|
+
domain: ErrorDomain.STORAGE,
|
|
1784
|
+
category: ErrorCategory.USER,
|
|
1785
|
+
text: "Cannot update without keys to identify records"
|
|
1786
|
+
});
|
|
1787
|
+
}
|
|
1788
|
+
const setClauses = [];
|
|
1789
|
+
const request = transaction ? transaction.request() : this.pool.request();
|
|
1790
|
+
let paramIndex = 0;
|
|
1791
|
+
Object.entries(data).forEach(([key, value]) => {
|
|
1792
|
+
const parsedKey = parseSqlIdentifier(key, "column name");
|
|
1793
|
+
const paramName = `set${paramIndex++}`;
|
|
1794
|
+
setClauses.push(`[${parsedKey}] = @${paramName}`);
|
|
1795
|
+
const preparedValue = this.prepareValue(value, key, tableName);
|
|
1796
|
+
if (preparedValue === null || preparedValue === void 0) {
|
|
1797
|
+
request.input(paramName, this.getMssqlType(tableName, key), null);
|
|
1798
|
+
} else {
|
|
1799
|
+
request.input(paramName, preparedValue);
|
|
1800
|
+
}
|
|
1801
|
+
});
|
|
1802
|
+
const whereConditions = [];
|
|
1803
|
+
Object.entries(keys).forEach(([key, value]) => {
|
|
1804
|
+
const parsedKey = parseSqlIdentifier(key, "column name");
|
|
1805
|
+
const paramName = `where${paramIndex++}`;
|
|
1806
|
+
whereConditions.push(`[${parsedKey}] = @${paramName}`);
|
|
1807
|
+
const preparedValue = this.prepareValue(value, key, tableName);
|
|
1808
|
+
if (preparedValue === null || preparedValue === void 0) {
|
|
1809
|
+
request.input(paramName, this.getMssqlType(tableName, key), null);
|
|
1810
|
+
} else {
|
|
1811
|
+
request.input(paramName, preparedValue);
|
|
1812
|
+
}
|
|
1813
|
+
});
|
|
1814
|
+
const tableName_ = getTableName({
|
|
1815
|
+
indexName: tableName,
|
|
1816
|
+
schemaName: getSchemaName(this.schemaName)
|
|
1817
|
+
});
|
|
1818
|
+
const updateSql = `UPDATE ${tableName_} SET ${setClauses.join(", ")} WHERE ${whereConditions.join(" AND ")}`;
|
|
1819
|
+
await request.query(updateSql);
|
|
1820
|
+
} catch (error) {
|
|
1821
|
+
throw new MastraError(
|
|
1822
|
+
{
|
|
1823
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_UPDATE_FAILED",
|
|
1824
|
+
domain: ErrorDomain.STORAGE,
|
|
1825
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1826
|
+
details: {
|
|
1827
|
+
tableName
|
|
1828
|
+
}
|
|
1829
|
+
},
|
|
1830
|
+
error
|
|
1831
|
+
);
|
|
1832
|
+
}
|
|
1833
|
+
}
|
|
1834
|
+
/**
|
|
1835
|
+
* Update multiple records in a single batch transaction
|
|
1836
|
+
*/
|
|
1837
|
+
async batchUpdate({
|
|
1838
|
+
tableName,
|
|
1839
|
+
updates
|
|
1840
|
+
}) {
|
|
1841
|
+
const transaction = this.pool.transaction();
|
|
1842
|
+
try {
|
|
1843
|
+
await transaction.begin();
|
|
1844
|
+
for (const { keys, data } of updates) {
|
|
1845
|
+
await this.update({ tableName, keys, data, transaction });
|
|
1846
|
+
}
|
|
1847
|
+
await transaction.commit();
|
|
1848
|
+
} catch (error) {
|
|
1849
|
+
await transaction.rollback();
|
|
1850
|
+
throw new MastraError(
|
|
1851
|
+
{
|
|
1852
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_BATCH_UPDATE_FAILED",
|
|
1853
|
+
domain: ErrorDomain.STORAGE,
|
|
1854
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1855
|
+
details: {
|
|
1856
|
+
tableName,
|
|
1857
|
+
numberOfRecords: updates.length
|
|
1858
|
+
}
|
|
1859
|
+
},
|
|
1860
|
+
error
|
|
1861
|
+
);
|
|
1862
|
+
}
|
|
1863
|
+
}
|
|
1864
|
+
/**
|
|
1865
|
+
* Delete multiple records by keys
|
|
1866
|
+
*/
|
|
1867
|
+
async batchDelete({ tableName, keys }) {
|
|
1868
|
+
if (keys.length === 0) {
|
|
1869
|
+
return;
|
|
1870
|
+
}
|
|
1871
|
+
const tableName_ = getTableName({
|
|
1872
|
+
indexName: tableName,
|
|
1873
|
+
schemaName: getSchemaName(this.schemaName)
|
|
1874
|
+
});
|
|
1875
|
+
const transaction = this.pool.transaction();
|
|
1876
|
+
try {
|
|
1877
|
+
await transaction.begin();
|
|
1878
|
+
for (const keySet of keys) {
|
|
1879
|
+
const conditions = [];
|
|
1880
|
+
const request = transaction.request();
|
|
1881
|
+
let paramIndex = 0;
|
|
1882
|
+
Object.entries(keySet).forEach(([key, value]) => {
|
|
1883
|
+
const parsedKey = parseSqlIdentifier(key, "column name");
|
|
1884
|
+
const paramName = `p${paramIndex++}`;
|
|
1885
|
+
conditions.push(`[${parsedKey}] = @${paramName}`);
|
|
1886
|
+
const preparedValue = this.prepareValue(value, key, tableName);
|
|
1887
|
+
if (preparedValue === null || preparedValue === void 0) {
|
|
1888
|
+
request.input(paramName, this.getMssqlType(tableName, key), null);
|
|
1889
|
+
} else {
|
|
1890
|
+
request.input(paramName, preparedValue);
|
|
1891
|
+
}
|
|
1892
|
+
});
|
|
1893
|
+
const deleteSql = `DELETE FROM ${tableName_} WHERE ${conditions.join(" AND ")}`;
|
|
1894
|
+
await request.query(deleteSql);
|
|
1895
|
+
}
|
|
1896
|
+
await transaction.commit();
|
|
1897
|
+
} catch (error) {
|
|
1898
|
+
await transaction.rollback();
|
|
1899
|
+
throw new MastraError(
|
|
1900
|
+
{
|
|
1901
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_BATCH_DELETE_FAILED",
|
|
1902
|
+
domain: ErrorDomain.STORAGE,
|
|
1903
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1904
|
+
details: {
|
|
1905
|
+
tableName,
|
|
1906
|
+
numberOfRecords: keys.length
|
|
1907
|
+
}
|
|
1908
|
+
},
|
|
1909
|
+
error
|
|
1910
|
+
);
|
|
1911
|
+
}
|
|
1912
|
+
}
|
|
1913
|
+
/**
|
|
1914
|
+
* Create a new index on a table
|
|
1915
|
+
*/
|
|
1916
|
+
async createIndex(options) {
|
|
1917
|
+
try {
|
|
1918
|
+
const { name, table, columns, unique = false, where } = options;
|
|
1919
|
+
const schemaName = this.schemaName || "dbo";
|
|
1920
|
+
const fullTableName = getTableName({
|
|
1921
|
+
indexName: table,
|
|
1922
|
+
schemaName: getSchemaName(this.schemaName)
|
|
1923
|
+
});
|
|
1924
|
+
const indexNameSafe = parseSqlIdentifier(name, "index name");
|
|
1925
|
+
const checkRequest = this.pool.request();
|
|
1926
|
+
checkRequest.input("indexName", indexNameSafe);
|
|
1927
|
+
checkRequest.input("schemaName", schemaName);
|
|
1928
|
+
checkRequest.input("tableName", table);
|
|
1929
|
+
const indexExists = await checkRequest.query(`
|
|
1930
|
+
SELECT 1 as found
|
|
1931
|
+
FROM sys.indexes i
|
|
1932
|
+
INNER JOIN sys.tables t ON i.object_id = t.object_id
|
|
1933
|
+
INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
|
|
1934
|
+
WHERE i.name = @indexName
|
|
1935
|
+
AND s.name = @schemaName
|
|
1936
|
+
AND t.name = @tableName
|
|
1937
|
+
`);
|
|
1938
|
+
if (indexExists.recordset && indexExists.recordset.length > 0) {
|
|
1939
|
+
return;
|
|
1940
|
+
}
|
|
1941
|
+
const uniqueStr = unique ? "UNIQUE " : "";
|
|
1942
|
+
const columnsStr = columns.map((col) => {
|
|
1943
|
+
if (col.includes(" DESC") || col.includes(" ASC")) {
|
|
1944
|
+
const [colName, ...modifiers] = col.split(" ");
|
|
1945
|
+
if (!colName) {
|
|
1946
|
+
throw new Error(`Invalid column specification: ${col}`);
|
|
1947
|
+
}
|
|
1948
|
+
return `[${parseSqlIdentifier(colName, "column name")}] ${modifiers.join(" ")}`;
|
|
1949
|
+
}
|
|
1950
|
+
return `[${parseSqlIdentifier(col, "column name")}]`;
|
|
1951
|
+
}).join(", ");
|
|
1952
|
+
const whereStr = where ? ` WHERE ${where}` : "";
|
|
1953
|
+
const createIndexSql = `CREATE ${uniqueStr}INDEX [${indexNameSafe}] ON ${fullTableName} (${columnsStr})${whereStr}`;
|
|
1954
|
+
await this.pool.request().query(createIndexSql);
|
|
1955
|
+
} catch (error) {
|
|
1956
|
+
throw new MastraError(
|
|
1957
|
+
{
|
|
1958
|
+
id: "MASTRA_STORAGE_MSSQL_INDEX_CREATE_FAILED",
|
|
1959
|
+
domain: ErrorDomain.STORAGE,
|
|
1960
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1961
|
+
details: {
|
|
1962
|
+
indexName: options.name,
|
|
1963
|
+
tableName: options.table
|
|
1964
|
+
}
|
|
1965
|
+
},
|
|
1966
|
+
error
|
|
1967
|
+
);
|
|
1968
|
+
}
|
|
1969
|
+
}
|
|
1970
|
+
/**
|
|
1971
|
+
* Drop an existing index
|
|
1972
|
+
*/
|
|
1973
|
+
async dropIndex(indexName) {
|
|
1974
|
+
try {
|
|
1975
|
+
const schemaName = this.schemaName || "dbo";
|
|
1976
|
+
const indexNameSafe = parseSqlIdentifier(indexName, "index name");
|
|
1977
|
+
const checkRequest = this.pool.request();
|
|
1978
|
+
checkRequest.input("indexName", indexNameSafe);
|
|
1979
|
+
checkRequest.input("schemaName", schemaName);
|
|
1980
|
+
const result = await checkRequest.query(`
|
|
1981
|
+
SELECT t.name as table_name
|
|
1982
|
+
FROM sys.indexes i
|
|
1983
|
+
INNER JOIN sys.tables t ON i.object_id = t.object_id
|
|
1984
|
+
INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
|
|
1985
|
+
WHERE i.name = @indexName
|
|
1986
|
+
AND s.name = @schemaName
|
|
1987
|
+
`);
|
|
1988
|
+
if (!result.recordset || result.recordset.length === 0) {
|
|
1989
|
+
return;
|
|
1990
|
+
}
|
|
1991
|
+
if (result.recordset.length > 1) {
|
|
1992
|
+
const tables = result.recordset.map((r) => r.table_name).join(", ");
|
|
1993
|
+
throw new MastraError({
|
|
1994
|
+
id: "MASTRA_STORAGE_MSSQL_INDEX_AMBIGUOUS",
|
|
1995
|
+
domain: ErrorDomain.STORAGE,
|
|
1996
|
+
category: ErrorCategory.USER,
|
|
1997
|
+
text: `Index "${indexNameSafe}" exists on multiple tables (${tables}) in schema "${schemaName}". Please drop indexes manually or ensure unique index names.`
|
|
1998
|
+
});
|
|
1999
|
+
}
|
|
2000
|
+
const tableName = result.recordset[0].table_name;
|
|
2001
|
+
const fullTableName = getTableName({
|
|
2002
|
+
indexName: tableName,
|
|
2003
|
+
schemaName: getSchemaName(this.schemaName)
|
|
2004
|
+
});
|
|
2005
|
+
const dropSql = `DROP INDEX [${indexNameSafe}] ON ${fullTableName}`;
|
|
2006
|
+
await this.pool.request().query(dropSql);
|
|
2007
|
+
} catch (error) {
|
|
2008
|
+
throw new MastraError(
|
|
2009
|
+
{
|
|
2010
|
+
id: "MASTRA_STORAGE_MSSQL_INDEX_DROP_FAILED",
|
|
2011
|
+
domain: ErrorDomain.STORAGE,
|
|
2012
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2013
|
+
details: {
|
|
2014
|
+
indexName
|
|
2015
|
+
}
|
|
2016
|
+
},
|
|
2017
|
+
error
|
|
2018
|
+
);
|
|
2019
|
+
}
|
|
2020
|
+
}
|
|
2021
|
+
/**
|
|
2022
|
+
* List indexes for a specific table or all tables
|
|
2023
|
+
*/
|
|
2024
|
+
async listIndexes(tableName) {
|
|
2025
|
+
try {
|
|
2026
|
+
const schemaName = this.schemaName || "dbo";
|
|
2027
|
+
let query;
|
|
2028
|
+
const request = this.pool.request();
|
|
2029
|
+
request.input("schemaName", schemaName);
|
|
2030
|
+
if (tableName) {
|
|
2031
|
+
query = `
|
|
2032
|
+
SELECT
|
|
2033
|
+
i.name as name,
|
|
2034
|
+
o.name as [table],
|
|
2035
|
+
i.is_unique as is_unique,
|
|
2036
|
+
CAST(SUM(s.used_page_count) * 8 / 1024.0 AS VARCHAR(50)) + ' MB' as size
|
|
2037
|
+
FROM sys.indexes i
|
|
2038
|
+
INNER JOIN sys.objects o ON i.object_id = o.object_id
|
|
2039
|
+
INNER JOIN sys.schemas sch ON o.schema_id = sch.schema_id
|
|
2040
|
+
LEFT JOIN sys.dm_db_partition_stats s ON i.object_id = s.object_id AND i.index_id = s.index_id
|
|
2041
|
+
WHERE sch.name = @schemaName
|
|
2042
|
+
AND o.name = @tableName
|
|
2043
|
+
AND i.name IS NOT NULL
|
|
2044
|
+
GROUP BY i.name, o.name, i.is_unique
|
|
2045
|
+
`;
|
|
2046
|
+
request.input("tableName", tableName);
|
|
2047
|
+
} else {
|
|
2048
|
+
query = `
|
|
2049
|
+
SELECT
|
|
2050
|
+
i.name as name,
|
|
2051
|
+
o.name as [table],
|
|
2052
|
+
i.is_unique as is_unique,
|
|
2053
|
+
CAST(SUM(s.used_page_count) * 8 / 1024.0 AS VARCHAR(50)) + ' MB' as size
|
|
2054
|
+
FROM sys.indexes i
|
|
2055
|
+
INNER JOIN sys.objects o ON i.object_id = o.object_id
|
|
2056
|
+
INNER JOIN sys.schemas sch ON o.schema_id = sch.schema_id
|
|
2057
|
+
LEFT JOIN sys.dm_db_partition_stats s ON i.object_id = s.object_id AND i.index_id = s.index_id
|
|
2058
|
+
WHERE sch.name = @schemaName
|
|
2059
|
+
AND i.name IS NOT NULL
|
|
2060
|
+
GROUP BY i.name, o.name, i.is_unique
|
|
2061
|
+
`;
|
|
2062
|
+
}
|
|
2063
|
+
const result = await request.query(query);
|
|
2064
|
+
const indexes = [];
|
|
2065
|
+
for (const row of result.recordset) {
|
|
2066
|
+
const colRequest = this.pool.request();
|
|
2067
|
+
colRequest.input("indexName", row.name);
|
|
2068
|
+
colRequest.input("schemaName", schemaName);
|
|
2069
|
+
const colResult = await colRequest.query(`
|
|
2070
|
+
SELECT c.name as column_name
|
|
2071
|
+
FROM sys.indexes i
|
|
2072
|
+
INNER JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
|
|
2073
|
+
INNER JOIN sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id
|
|
2074
|
+
INNER JOIN sys.objects o ON i.object_id = o.object_id
|
|
2075
|
+
INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
|
|
2076
|
+
WHERE i.name = @indexName
|
|
2077
|
+
AND s.name = @schemaName
|
|
2078
|
+
ORDER BY ic.key_ordinal
|
|
2079
|
+
`);
|
|
2080
|
+
indexes.push({
|
|
2081
|
+
name: row.name,
|
|
2082
|
+
table: row.table,
|
|
2083
|
+
columns: colResult.recordset.map((c) => c.column_name),
|
|
2084
|
+
unique: row.is_unique || false,
|
|
2085
|
+
size: row.size || "0 MB",
|
|
2086
|
+
definition: ""
|
|
2087
|
+
// MSSQL doesn't store definition like PG
|
|
2088
|
+
});
|
|
2089
|
+
}
|
|
2090
|
+
return indexes;
|
|
2091
|
+
} catch (error) {
|
|
2092
|
+
throw new MastraError(
|
|
2093
|
+
{
|
|
2094
|
+
id: "MASTRA_STORAGE_MSSQL_INDEX_LIST_FAILED",
|
|
2095
|
+
domain: ErrorDomain.STORAGE,
|
|
2096
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2097
|
+
details: tableName ? {
|
|
2098
|
+
tableName
|
|
2099
|
+
} : {}
|
|
2100
|
+
},
|
|
2101
|
+
error
|
|
2102
|
+
);
|
|
2103
|
+
}
|
|
2104
|
+
}
|
|
2105
|
+
/**
|
|
2106
|
+
* Get detailed statistics for a specific index
|
|
2107
|
+
*/
|
|
2108
|
+
async describeIndex(indexName) {
|
|
2109
|
+
try {
|
|
2110
|
+
const schemaName = this.schemaName || "dbo";
|
|
2111
|
+
const request = this.pool.request();
|
|
2112
|
+
request.input("indexName", indexName);
|
|
2113
|
+
request.input("schemaName", schemaName);
|
|
2114
|
+
const query = `
|
|
2115
|
+
SELECT
|
|
2116
|
+
i.name as name,
|
|
2117
|
+
o.name as [table],
|
|
2118
|
+
i.is_unique as is_unique,
|
|
2119
|
+
CAST(SUM(s.used_page_count) * 8 / 1024.0 AS VARCHAR(50)) + ' MB' as size,
|
|
2120
|
+
i.type_desc as method,
|
|
2121
|
+
ISNULL(us.user_scans, 0) as scans,
|
|
2122
|
+
ISNULL(us.user_seeks + us.user_scans, 0) as tuples_read,
|
|
2123
|
+
ISNULL(us.user_lookups, 0) as tuples_fetched
|
|
2124
|
+
FROM sys.indexes i
|
|
2125
|
+
INNER JOIN sys.objects o ON i.object_id = o.object_id
|
|
2126
|
+
INNER JOIN sys.schemas sch ON o.schema_id = sch.schema_id
|
|
2127
|
+
LEFT JOIN sys.dm_db_partition_stats s ON i.object_id = s.object_id AND i.index_id = s.index_id
|
|
2128
|
+
LEFT JOIN sys.dm_db_index_usage_stats us ON i.object_id = us.object_id AND i.index_id = us.index_id
|
|
2129
|
+
WHERE i.name = @indexName
|
|
2130
|
+
AND sch.name = @schemaName
|
|
2131
|
+
GROUP BY i.name, o.name, i.is_unique, i.type_desc, us.user_seeks, us.user_scans, us.user_lookups
|
|
2132
|
+
`;
|
|
2133
|
+
const result = await request.query(query);
|
|
2134
|
+
if (!result.recordset || result.recordset.length === 0) {
|
|
2135
|
+
throw new Error(`Index "${indexName}" not found in schema "${schemaName}"`);
|
|
2136
|
+
}
|
|
2137
|
+
const row = result.recordset[0];
|
|
2138
|
+
const colRequest = this.pool.request();
|
|
2139
|
+
colRequest.input("indexName", indexName);
|
|
2140
|
+
colRequest.input("schemaName", schemaName);
|
|
2141
|
+
const colResult = await colRequest.query(`
|
|
2142
|
+
SELECT c.name as column_name
|
|
2143
|
+
FROM sys.indexes i
|
|
2144
|
+
INNER JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
|
|
2145
|
+
INNER JOIN sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id
|
|
2146
|
+
INNER JOIN sys.objects o ON i.object_id = o.object_id
|
|
2147
|
+
INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
|
|
2148
|
+
WHERE i.name = @indexName
|
|
2149
|
+
AND s.name = @schemaName
|
|
2150
|
+
ORDER BY ic.key_ordinal
|
|
2151
|
+
`);
|
|
2152
|
+
return {
|
|
2153
|
+
name: row.name,
|
|
2154
|
+
table: row.table,
|
|
2155
|
+
columns: colResult.recordset.map((c) => c.column_name),
|
|
2156
|
+
unique: row.is_unique || false,
|
|
2157
|
+
size: row.size || "0 MB",
|
|
2158
|
+
definition: "",
|
|
2159
|
+
method: row.method?.toLowerCase() || "nonclustered",
|
|
2160
|
+
scans: Number(row.scans) || 0,
|
|
2161
|
+
tuples_read: Number(row.tuples_read) || 0,
|
|
2162
|
+
tuples_fetched: Number(row.tuples_fetched) || 0
|
|
2163
|
+
};
|
|
2164
|
+
} catch (error) {
|
|
2165
|
+
throw new MastraError(
|
|
2166
|
+
{
|
|
2167
|
+
id: "MASTRA_STORAGE_MSSQL_INDEX_DESCRIBE_FAILED",
|
|
2168
|
+
domain: ErrorDomain.STORAGE,
|
|
2169
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2170
|
+
details: {
|
|
2171
|
+
indexName
|
|
2172
|
+
}
|
|
2173
|
+
},
|
|
2174
|
+
error
|
|
2175
|
+
);
|
|
2176
|
+
}
|
|
2177
|
+
}
|
|
2178
|
+
/**
|
|
2179
|
+
* Returns definitions for automatic performance indexes
|
|
2180
|
+
* IMPORTANT: Uses seq_id DESC instead of createdAt DESC for MSSQL due to millisecond accuracy limitations
|
|
2181
|
+
* NOTE: Using NVARCHAR(400) for text columns (800 bytes) leaves room for composite indexes
|
|
2182
|
+
*/
|
|
2183
|
+
getAutomaticIndexDefinitions() {
|
|
2184
|
+
const schemaPrefix = this.schemaName ? `${this.schemaName}_` : "";
|
|
2185
|
+
return [
|
|
2186
|
+
// Composite indexes for optimal filtering + sorting performance
|
|
2187
|
+
// NVARCHAR(400) = 800 bytes, plus BIGINT (8 bytes) = 808 bytes total (under 900-byte limit)
|
|
2188
|
+
{
|
|
2189
|
+
name: `${schemaPrefix}mastra_threads_resourceid_seqid_idx`,
|
|
2190
|
+
table: TABLE_THREADS,
|
|
2191
|
+
columns: ["resourceId", "seq_id DESC"]
|
|
2192
|
+
},
|
|
2193
|
+
{
|
|
2194
|
+
name: `${schemaPrefix}mastra_messages_thread_id_seqid_idx`,
|
|
2195
|
+
table: TABLE_MESSAGES,
|
|
2196
|
+
columns: ["thread_id", "seq_id DESC"]
|
|
2197
|
+
},
|
|
2198
|
+
{
|
|
2199
|
+
name: `${schemaPrefix}mastra_traces_name_seqid_idx`,
|
|
2200
|
+
table: TABLE_TRACES,
|
|
2201
|
+
columns: ["name", "seq_id DESC"]
|
|
2202
|
+
},
|
|
2203
|
+
{
|
|
2204
|
+
name: `${schemaPrefix}mastra_scores_trace_id_span_id_seqid_idx`,
|
|
2205
|
+
table: TABLE_SCORERS,
|
|
2206
|
+
columns: ["traceId", "spanId", "seq_id DESC"]
|
|
2207
|
+
},
|
|
2208
|
+
// Spans indexes for optimal trace querying
|
|
2209
|
+
{
|
|
2210
|
+
name: `${schemaPrefix}mastra_ai_spans_traceid_startedat_idx`,
|
|
2211
|
+
table: TABLE_SPANS,
|
|
2212
|
+
columns: ["traceId", "startedAt DESC"]
|
|
2213
|
+
},
|
|
2214
|
+
{
|
|
2215
|
+
name: `${schemaPrefix}mastra_ai_spans_parentspanid_startedat_idx`,
|
|
2216
|
+
table: TABLE_SPANS,
|
|
2217
|
+
columns: ["parentSpanId", "startedAt DESC"]
|
|
2218
|
+
},
|
|
2219
|
+
{
|
|
2220
|
+
name: `${schemaPrefix}mastra_ai_spans_name_idx`,
|
|
2221
|
+
table: TABLE_SPANS,
|
|
2222
|
+
columns: ["name"]
|
|
2223
|
+
},
|
|
2224
|
+
{
|
|
2225
|
+
name: `${schemaPrefix}mastra_ai_spans_spantype_startedat_idx`,
|
|
2226
|
+
table: TABLE_SPANS,
|
|
2227
|
+
columns: ["spanType", "startedAt DESC"]
|
|
2228
|
+
}
|
|
2229
|
+
];
|
|
2230
|
+
}
|
|
2231
|
+
/**
|
|
2232
|
+
* Creates automatic indexes for optimal query performance
|
|
2233
|
+
* Uses getAutomaticIndexDefinitions() to determine which indexes to create
|
|
2234
|
+
*/
|
|
2235
|
+
async createAutomaticIndexes() {
|
|
1397
2236
|
try {
|
|
1398
|
-
const
|
|
1399
|
-
|
|
2237
|
+
const indexes = this.getAutomaticIndexDefinitions();
|
|
2238
|
+
for (const indexOptions of indexes) {
|
|
2239
|
+
try {
|
|
2240
|
+
await this.createIndex(indexOptions);
|
|
2241
|
+
} catch (error) {
|
|
2242
|
+
this.logger?.warn?.(`Failed to create index ${indexOptions.name}:`, error);
|
|
2243
|
+
}
|
|
2244
|
+
}
|
|
1400
2245
|
} catch (error) {
|
|
1401
2246
|
throw new MastraError(
|
|
1402
2247
|
{
|
|
1403
|
-
id: "
|
|
2248
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_CREATE_PERFORMANCE_INDEXES_FAILED",
|
|
1404
2249
|
domain: ErrorDomain.STORAGE,
|
|
1405
|
-
category: ErrorCategory.THIRD_PARTY
|
|
1406
|
-
details: {
|
|
1407
|
-
tableName
|
|
1408
|
-
}
|
|
2250
|
+
category: ErrorCategory.THIRD_PARTY
|
|
1409
2251
|
},
|
|
1410
2252
|
error
|
|
1411
2253
|
);
|
|
1412
2254
|
}
|
|
1413
2255
|
}
|
|
1414
2256
|
};
|
|
1415
|
-
function parseJSON(jsonString) {
|
|
1416
|
-
try {
|
|
1417
|
-
return JSON.parse(jsonString);
|
|
1418
|
-
} catch {
|
|
1419
|
-
return jsonString;
|
|
1420
|
-
}
|
|
1421
|
-
}
|
|
1422
2257
|
function transformScoreRow(row) {
|
|
1423
2258
|
return {
|
|
1424
2259
|
...row,
|
|
1425
|
-
input:
|
|
1426
|
-
scorer:
|
|
1427
|
-
preprocessStepResult:
|
|
1428
|
-
analyzeStepResult:
|
|
1429
|
-
metadata:
|
|
1430
|
-
output:
|
|
1431
|
-
additionalContext:
|
|
1432
|
-
|
|
1433
|
-
entity:
|
|
2260
|
+
input: safelyParseJSON(row.input),
|
|
2261
|
+
scorer: safelyParseJSON(row.scorer),
|
|
2262
|
+
preprocessStepResult: safelyParseJSON(row.preprocessStepResult),
|
|
2263
|
+
analyzeStepResult: safelyParseJSON(row.analyzeStepResult),
|
|
2264
|
+
metadata: safelyParseJSON(row.metadata),
|
|
2265
|
+
output: safelyParseJSON(row.output),
|
|
2266
|
+
additionalContext: safelyParseJSON(row.additionalContext),
|
|
2267
|
+
requestContext: safelyParseJSON(row.requestContext),
|
|
2268
|
+
entity: safelyParseJSON(row.entity),
|
|
1434
2269
|
createdAt: row.createdAt,
|
|
1435
2270
|
updatedAt: row.updatedAt
|
|
1436
2271
|
};
|
|
@@ -1473,8 +2308,21 @@ var ScoresMSSQL = class extends ScoresStorage {
|
|
|
1473
2308
|
}
|
|
1474
2309
|
}
|
|
1475
2310
|
async saveScore(score) {
|
|
2311
|
+
let validatedScore;
|
|
2312
|
+
try {
|
|
2313
|
+
validatedScore = saveScorePayloadSchema.parse(score);
|
|
2314
|
+
} catch (error) {
|
|
2315
|
+
throw new MastraError(
|
|
2316
|
+
{
|
|
2317
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_SAVE_SCORE_VALIDATION_FAILED",
|
|
2318
|
+
domain: ErrorDomain.STORAGE,
|
|
2319
|
+
category: ErrorCategory.THIRD_PARTY
|
|
2320
|
+
},
|
|
2321
|
+
error
|
|
2322
|
+
);
|
|
2323
|
+
}
|
|
1476
2324
|
try {
|
|
1477
|
-
const scoreId =
|
|
2325
|
+
const scoreId = randomUUID();
|
|
1478
2326
|
const {
|
|
1479
2327
|
scorer,
|
|
1480
2328
|
preprocessStepResult,
|
|
@@ -1483,24 +2331,24 @@ var ScoresMSSQL = class extends ScoresStorage {
|
|
|
1483
2331
|
input,
|
|
1484
2332
|
output,
|
|
1485
2333
|
additionalContext,
|
|
1486
|
-
|
|
2334
|
+
requestContext,
|
|
1487
2335
|
entity,
|
|
1488
2336
|
...rest
|
|
1489
|
-
} =
|
|
2337
|
+
} = validatedScore;
|
|
1490
2338
|
await this.operations.insert({
|
|
1491
2339
|
tableName: TABLE_SCORERS,
|
|
1492
2340
|
record: {
|
|
1493
2341
|
id: scoreId,
|
|
1494
2342
|
...rest,
|
|
1495
|
-
input:
|
|
1496
|
-
output:
|
|
1497
|
-
preprocessStepResult: preprocessStepResult
|
|
1498
|
-
analyzeStepResult: analyzeStepResult
|
|
1499
|
-
metadata: metadata
|
|
1500
|
-
additionalContext: additionalContext
|
|
1501
|
-
|
|
1502
|
-
entity: entity
|
|
1503
|
-
scorer: scorer
|
|
2343
|
+
input: input || "",
|
|
2344
|
+
output: output || "",
|
|
2345
|
+
preprocessStepResult: preprocessStepResult || null,
|
|
2346
|
+
analyzeStepResult: analyzeStepResult || null,
|
|
2347
|
+
metadata: metadata || null,
|
|
2348
|
+
additionalContext: additionalContext || null,
|
|
2349
|
+
requestContext: requestContext || null,
|
|
2350
|
+
entity: entity || null,
|
|
2351
|
+
scorer: scorer || null,
|
|
1504
2352
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1505
2353
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1506
2354
|
}
|
|
@@ -1518,41 +2366,70 @@ var ScoresMSSQL = class extends ScoresStorage {
|
|
|
1518
2366
|
);
|
|
1519
2367
|
}
|
|
1520
2368
|
}
|
|
1521
|
-
async
|
|
2369
|
+
async listScoresByScorerId({
|
|
1522
2370
|
scorerId,
|
|
1523
|
-
pagination
|
|
2371
|
+
pagination,
|
|
2372
|
+
entityId,
|
|
2373
|
+
entityType,
|
|
2374
|
+
source
|
|
1524
2375
|
}) {
|
|
1525
2376
|
try {
|
|
1526
|
-
const
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
2377
|
+
const conditions = ["[scorerId] = @p1"];
|
|
2378
|
+
const params = { p1: scorerId };
|
|
2379
|
+
let paramIndex = 2;
|
|
2380
|
+
if (entityId) {
|
|
2381
|
+
conditions.push(`[entityId] = @p${paramIndex}`);
|
|
2382
|
+
params[`p${paramIndex}`] = entityId;
|
|
2383
|
+
paramIndex++;
|
|
2384
|
+
}
|
|
2385
|
+
if (entityType) {
|
|
2386
|
+
conditions.push(`[entityType] = @p${paramIndex}`);
|
|
2387
|
+
params[`p${paramIndex}`] = entityType;
|
|
2388
|
+
paramIndex++;
|
|
2389
|
+
}
|
|
2390
|
+
if (source) {
|
|
2391
|
+
conditions.push(`[source] = @p${paramIndex}`);
|
|
2392
|
+
params[`p${paramIndex}`] = source;
|
|
2393
|
+
paramIndex++;
|
|
2394
|
+
}
|
|
2395
|
+
const whereClause = conditions.join(" AND ");
|
|
2396
|
+
const tableName = getTableName({ indexName: TABLE_SCORERS, schemaName: getSchemaName(this.schema) });
|
|
2397
|
+
const countRequest = this.pool.request();
|
|
2398
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
2399
|
+
countRequest.input(key, value);
|
|
2400
|
+
});
|
|
2401
|
+
const totalResult = await countRequest.query(`SELECT COUNT(*) as count FROM ${tableName} WHERE ${whereClause}`);
|
|
1531
2402
|
const total = totalResult.recordset[0]?.count || 0;
|
|
2403
|
+
const { page, perPage: perPageInput } = pagination;
|
|
1532
2404
|
if (total === 0) {
|
|
1533
2405
|
return {
|
|
1534
2406
|
pagination: {
|
|
1535
2407
|
total: 0,
|
|
1536
|
-
page
|
|
1537
|
-
perPage:
|
|
2408
|
+
page,
|
|
2409
|
+
perPage: perPageInput,
|
|
1538
2410
|
hasMore: false
|
|
1539
2411
|
},
|
|
1540
2412
|
scores: []
|
|
1541
2413
|
};
|
|
1542
2414
|
}
|
|
2415
|
+
const perPage = normalizePerPage(perPageInput, 100);
|
|
2416
|
+
const { offset: start, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
|
|
2417
|
+
const limitValue = perPageInput === false ? total : perPage;
|
|
2418
|
+
const end = perPageInput === false ? total : start + perPage;
|
|
1543
2419
|
const dataRequest = this.pool.request();
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
2420
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
2421
|
+
dataRequest.input(key, value);
|
|
2422
|
+
});
|
|
2423
|
+
dataRequest.input("perPage", limitValue);
|
|
2424
|
+
dataRequest.input("offset", start);
|
|
2425
|
+
const dataQuery = `SELECT * FROM ${tableName} WHERE ${whereClause} ORDER BY [createdAt] DESC OFFSET @offset ROWS FETCH NEXT @perPage ROWS ONLY`;
|
|
2426
|
+
const result = await dataRequest.query(dataQuery);
|
|
1550
2427
|
return {
|
|
1551
2428
|
pagination: {
|
|
1552
2429
|
total: Number(total),
|
|
1553
|
-
page
|
|
1554
|
-
perPage:
|
|
1555
|
-
hasMore:
|
|
2430
|
+
page,
|
|
2431
|
+
perPage: perPageForResponse,
|
|
2432
|
+
hasMore: end < total
|
|
1556
2433
|
},
|
|
1557
2434
|
scores: result.recordset.map((row) => transformScoreRow(row))
|
|
1558
2435
|
};
|
|
@@ -1568,7 +2445,7 @@ var ScoresMSSQL = class extends ScoresStorage {
|
|
|
1568
2445
|
);
|
|
1569
2446
|
}
|
|
1570
2447
|
}
|
|
1571
|
-
async
|
|
2448
|
+
async listScoresByRunId({
|
|
1572
2449
|
runId,
|
|
1573
2450
|
pagination
|
|
1574
2451
|
}) {
|
|
@@ -1579,30 +2456,35 @@ var ScoresMSSQL = class extends ScoresStorage {
|
|
|
1579
2456
|
`SELECT COUNT(*) as count FROM ${getTableName({ indexName: TABLE_SCORERS, schemaName: getSchemaName(this.schema) })} WHERE [runId] = @p1`
|
|
1580
2457
|
);
|
|
1581
2458
|
const total = totalResult.recordset[0]?.count || 0;
|
|
2459
|
+
const { page, perPage: perPageInput } = pagination;
|
|
1582
2460
|
if (total === 0) {
|
|
1583
2461
|
return {
|
|
1584
2462
|
pagination: {
|
|
1585
2463
|
total: 0,
|
|
1586
|
-
page
|
|
1587
|
-
perPage:
|
|
2464
|
+
page,
|
|
2465
|
+
perPage: perPageInput,
|
|
1588
2466
|
hasMore: false
|
|
1589
2467
|
},
|
|
1590
2468
|
scores: []
|
|
1591
2469
|
};
|
|
1592
2470
|
}
|
|
2471
|
+
const perPage = normalizePerPage(perPageInput, 100);
|
|
2472
|
+
const { offset: start, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
|
|
2473
|
+
const limitValue = perPageInput === false ? total : perPage;
|
|
2474
|
+
const end = perPageInput === false ? total : start + perPage;
|
|
1593
2475
|
const dataRequest = this.pool.request();
|
|
1594
2476
|
dataRequest.input("p1", runId);
|
|
1595
|
-
dataRequest.input("p2",
|
|
1596
|
-
dataRequest.input("p3",
|
|
2477
|
+
dataRequest.input("p2", limitValue);
|
|
2478
|
+
dataRequest.input("p3", start);
|
|
1597
2479
|
const result = await dataRequest.query(
|
|
1598
2480
|
`SELECT * FROM ${getTableName({ indexName: TABLE_SCORERS, schemaName: getSchemaName(this.schema) })} WHERE [runId] = @p1 ORDER BY [createdAt] DESC OFFSET @p3 ROWS FETCH NEXT @p2 ROWS ONLY`
|
|
1599
2481
|
);
|
|
1600
2482
|
return {
|
|
1601
2483
|
pagination: {
|
|
1602
2484
|
total: Number(total),
|
|
1603
|
-
page
|
|
1604
|
-
perPage:
|
|
1605
|
-
hasMore:
|
|
2485
|
+
page,
|
|
2486
|
+
perPage: perPageForResponse,
|
|
2487
|
+
hasMore: end < total
|
|
1606
2488
|
},
|
|
1607
2489
|
scores: result.recordset.map((row) => transformScoreRow(row))
|
|
1608
2490
|
};
|
|
@@ -1618,7 +2500,7 @@ var ScoresMSSQL = class extends ScoresStorage {
|
|
|
1618
2500
|
);
|
|
1619
2501
|
}
|
|
1620
2502
|
}
|
|
1621
|
-
async
|
|
2503
|
+
async listScoresByEntityId({
|
|
1622
2504
|
entityId,
|
|
1623
2505
|
entityType,
|
|
1624
2506
|
pagination
|
|
@@ -1631,31 +2513,36 @@ var ScoresMSSQL = class extends ScoresStorage {
|
|
|
1631
2513
|
`SELECT COUNT(*) as count FROM ${getTableName({ indexName: TABLE_SCORERS, schemaName: getSchemaName(this.schema) })} WHERE [entityId] = @p1 AND [entityType] = @p2`
|
|
1632
2514
|
);
|
|
1633
2515
|
const total = totalResult.recordset[0]?.count || 0;
|
|
2516
|
+
const { page, perPage: perPageInput } = pagination;
|
|
2517
|
+
const perPage = normalizePerPage(perPageInput, 100);
|
|
2518
|
+
const { offset: start, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
|
|
1634
2519
|
if (total === 0) {
|
|
1635
2520
|
return {
|
|
1636
2521
|
pagination: {
|
|
1637
2522
|
total: 0,
|
|
1638
|
-
page
|
|
1639
|
-
perPage:
|
|
2523
|
+
page,
|
|
2524
|
+
perPage: perPageForResponse,
|
|
1640
2525
|
hasMore: false
|
|
1641
2526
|
},
|
|
1642
2527
|
scores: []
|
|
1643
2528
|
};
|
|
1644
2529
|
}
|
|
2530
|
+
const limitValue = perPageInput === false ? total : perPage;
|
|
2531
|
+
const end = perPageInput === false ? total : start + perPage;
|
|
1645
2532
|
const dataRequest = this.pool.request();
|
|
1646
2533
|
dataRequest.input("p1", entityId);
|
|
1647
2534
|
dataRequest.input("p2", entityType);
|
|
1648
|
-
dataRequest.input("p3",
|
|
1649
|
-
dataRequest.input("p4",
|
|
2535
|
+
dataRequest.input("p3", limitValue);
|
|
2536
|
+
dataRequest.input("p4", start);
|
|
1650
2537
|
const result = await dataRequest.query(
|
|
1651
2538
|
`SELECT * FROM ${getTableName({ indexName: TABLE_SCORERS, schemaName: getSchemaName(this.schema) })} WHERE [entityId] = @p1 AND [entityType] = @p2 ORDER BY [createdAt] DESC OFFSET @p4 ROWS FETCH NEXT @p3 ROWS ONLY`
|
|
1652
2539
|
);
|
|
1653
2540
|
return {
|
|
1654
2541
|
pagination: {
|
|
1655
2542
|
total: Number(total),
|
|
1656
|
-
page
|
|
1657
|
-
perPage:
|
|
1658
|
-
hasMore:
|
|
2543
|
+
page,
|
|
2544
|
+
perPage: perPageForResponse,
|
|
2545
|
+
hasMore: end < total
|
|
1659
2546
|
},
|
|
1660
2547
|
scores: result.recordset.map((row) => transformScoreRow(row))
|
|
1661
2548
|
};
|
|
@@ -1671,8 +2558,66 @@ var ScoresMSSQL = class extends ScoresStorage {
|
|
|
1671
2558
|
);
|
|
1672
2559
|
}
|
|
1673
2560
|
}
|
|
2561
|
+
async listScoresBySpan({
|
|
2562
|
+
traceId,
|
|
2563
|
+
spanId,
|
|
2564
|
+
pagination
|
|
2565
|
+
}) {
|
|
2566
|
+
try {
|
|
2567
|
+
const request = this.pool.request();
|
|
2568
|
+
request.input("p1", traceId);
|
|
2569
|
+
request.input("p2", spanId);
|
|
2570
|
+
const totalResult = await request.query(
|
|
2571
|
+
`SELECT COUNT(*) as count FROM ${getTableName({ indexName: TABLE_SCORERS, schemaName: getSchemaName(this.schema) })} WHERE [traceId] = @p1 AND [spanId] = @p2`
|
|
2572
|
+
);
|
|
2573
|
+
const total = totalResult.recordset[0]?.count || 0;
|
|
2574
|
+
const { page, perPage: perPageInput } = pagination;
|
|
2575
|
+
const perPage = normalizePerPage(perPageInput, 100);
|
|
2576
|
+
const { offset: start, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
|
|
2577
|
+
if (total === 0) {
|
|
2578
|
+
return {
|
|
2579
|
+
pagination: {
|
|
2580
|
+
total: 0,
|
|
2581
|
+
page,
|
|
2582
|
+
perPage: perPageForResponse,
|
|
2583
|
+
hasMore: false
|
|
2584
|
+
},
|
|
2585
|
+
scores: []
|
|
2586
|
+
};
|
|
2587
|
+
}
|
|
2588
|
+
const limitValue = perPageInput === false ? total : perPage;
|
|
2589
|
+
const end = perPageInput === false ? total : start + perPage;
|
|
2590
|
+
const dataRequest = this.pool.request();
|
|
2591
|
+
dataRequest.input("p1", traceId);
|
|
2592
|
+
dataRequest.input("p2", spanId);
|
|
2593
|
+
dataRequest.input("p3", limitValue);
|
|
2594
|
+
dataRequest.input("p4", start);
|
|
2595
|
+
const result = await dataRequest.query(
|
|
2596
|
+
`SELECT * FROM ${getTableName({ indexName: TABLE_SCORERS, schemaName: getSchemaName(this.schema) })} WHERE [traceId] = @p1 AND [spanId] = @p2 ORDER BY [createdAt] DESC OFFSET @p4 ROWS FETCH NEXT @p3 ROWS ONLY`
|
|
2597
|
+
);
|
|
2598
|
+
return {
|
|
2599
|
+
pagination: {
|
|
2600
|
+
total: Number(total),
|
|
2601
|
+
page,
|
|
2602
|
+
perPage: perPageForResponse,
|
|
2603
|
+
hasMore: end < total
|
|
2604
|
+
},
|
|
2605
|
+
scores: result.recordset.map((row) => transformScoreRow(row))
|
|
2606
|
+
};
|
|
2607
|
+
} catch (error) {
|
|
2608
|
+
throw new MastraError(
|
|
2609
|
+
{
|
|
2610
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_GET_SCORES_BY_SPAN_FAILED",
|
|
2611
|
+
domain: ErrorDomain.STORAGE,
|
|
2612
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2613
|
+
details: { traceId, spanId }
|
|
2614
|
+
},
|
|
2615
|
+
error
|
|
2616
|
+
);
|
|
2617
|
+
}
|
|
2618
|
+
}
|
|
1674
2619
|
};
|
|
1675
|
-
var
|
|
2620
|
+
var WorkflowsMSSQL = class extends WorkflowsStorage {
|
|
1676
2621
|
pool;
|
|
1677
2622
|
operations;
|
|
1678
2623
|
schema;
|
|
@@ -1686,210 +2631,169 @@ var TracesMSSQL = class extends TracesStorage {
|
|
|
1686
2631
|
this.operations = operations;
|
|
1687
2632
|
this.schema = schema;
|
|
1688
2633
|
}
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
if (
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
2634
|
+
parseWorkflowRun(row) {
|
|
2635
|
+
let parsedSnapshot = row.snapshot;
|
|
2636
|
+
if (typeof parsedSnapshot === "string") {
|
|
2637
|
+
try {
|
|
2638
|
+
parsedSnapshot = JSON.parse(row.snapshot);
|
|
2639
|
+
} catch (e) {
|
|
2640
|
+
this.logger?.warn?.(`Failed to parse snapshot for workflow ${row.workflow_name}:`, e);
|
|
2641
|
+
}
|
|
1696
2642
|
}
|
|
1697
|
-
|
|
1698
|
-
|
|
2643
|
+
return {
|
|
2644
|
+
workflowName: row.workflow_name,
|
|
2645
|
+
runId: row.run_id,
|
|
2646
|
+
snapshot: parsedSnapshot,
|
|
2647
|
+
createdAt: row.createdAt,
|
|
2648
|
+
updatedAt: row.updatedAt,
|
|
2649
|
+
resourceId: row.resourceId
|
|
2650
|
+
};
|
|
1699
2651
|
}
|
|
1700
|
-
async
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
const
|
|
1708
|
-
|
|
1709
|
-
if (name) {
|
|
1710
|
-
const paramName = `p${paramIndex++}`;
|
|
1711
|
-
conditions.push(`[name] LIKE @${paramName}`);
|
|
1712
|
-
paramMap[paramName] = `${name}%`;
|
|
1713
|
-
}
|
|
1714
|
-
if (scope) {
|
|
1715
|
-
const paramName = `p${paramIndex++}`;
|
|
1716
|
-
conditions.push(`[scope] = @${paramName}`);
|
|
1717
|
-
paramMap[paramName] = scope;
|
|
1718
|
-
}
|
|
1719
|
-
if (attributes) {
|
|
1720
|
-
Object.entries(attributes).forEach(([key, value]) => {
|
|
1721
|
-
const parsedKey = parseFieldKey(key);
|
|
1722
|
-
const paramName = `p${paramIndex++}`;
|
|
1723
|
-
conditions.push(`JSON_VALUE([attributes], '$.${parsedKey}') = @${paramName}`);
|
|
1724
|
-
paramMap[paramName] = value;
|
|
1725
|
-
});
|
|
1726
|
-
}
|
|
1727
|
-
if (filters) {
|
|
1728
|
-
Object.entries(filters).forEach(([key, value]) => {
|
|
1729
|
-
const parsedKey = parseFieldKey(key);
|
|
1730
|
-
const paramName = `p${paramIndex++}`;
|
|
1731
|
-
conditions.push(`[${parsedKey}] = @${paramName}`);
|
|
1732
|
-
paramMap[paramName] = value;
|
|
1733
|
-
});
|
|
1734
|
-
}
|
|
1735
|
-
if (fromDate instanceof Date && !isNaN(fromDate.getTime())) {
|
|
1736
|
-
const paramName = `p${paramIndex++}`;
|
|
1737
|
-
conditions.push(`[createdAt] >= @${paramName}`);
|
|
1738
|
-
paramMap[paramName] = fromDate.toISOString();
|
|
1739
|
-
}
|
|
1740
|
-
if (toDate instanceof Date && !isNaN(toDate.getTime())) {
|
|
1741
|
-
const paramName = `p${paramIndex++}`;
|
|
1742
|
-
conditions.push(`[createdAt] <= @${paramName}`);
|
|
1743
|
-
paramMap[paramName] = toDate.toISOString();
|
|
1744
|
-
}
|
|
1745
|
-
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
1746
|
-
const countQuery = `SELECT COUNT(*) as total FROM ${getTableName({ indexName: TABLE_TRACES, schemaName: getSchemaName(this.schema) })} ${whereClause}`;
|
|
1747
|
-
let total = 0;
|
|
2652
|
+
async updateWorkflowResults({
|
|
2653
|
+
workflowName,
|
|
2654
|
+
runId,
|
|
2655
|
+
stepId,
|
|
2656
|
+
result,
|
|
2657
|
+
requestContext
|
|
2658
|
+
}) {
|
|
2659
|
+
const table = getTableName({ indexName: TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName(this.schema) });
|
|
2660
|
+
const transaction = this.pool.transaction();
|
|
1748
2661
|
try {
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
2662
|
+
await transaction.begin();
|
|
2663
|
+
const selectRequest = new sql2.Request(transaction);
|
|
2664
|
+
selectRequest.input("workflow_name", workflowName);
|
|
2665
|
+
selectRequest.input("run_id", runId);
|
|
2666
|
+
const existingSnapshotResult = await selectRequest.query(
|
|
2667
|
+
`SELECT snapshot FROM ${table} WITH (UPDLOCK, HOLDLOCK) WHERE workflow_name = @workflow_name AND run_id = @run_id`
|
|
2668
|
+
);
|
|
2669
|
+
let snapshot;
|
|
2670
|
+
if (!existingSnapshotResult.recordset || existingSnapshotResult.recordset.length === 0) {
|
|
2671
|
+
snapshot = {
|
|
2672
|
+
context: {},
|
|
2673
|
+
activePaths: [],
|
|
2674
|
+
activeStepsPath: {},
|
|
2675
|
+
timestamp: Date.now(),
|
|
2676
|
+
suspendedPaths: {},
|
|
2677
|
+
resumeLabels: {},
|
|
2678
|
+
serializedStepGraph: [],
|
|
2679
|
+
status: "pending",
|
|
2680
|
+
value: {},
|
|
2681
|
+
waitingPaths: {},
|
|
2682
|
+
runId,
|
|
2683
|
+
requestContext: {}
|
|
2684
|
+
};
|
|
2685
|
+
} else {
|
|
2686
|
+
const existingSnapshot = existingSnapshotResult.recordset[0].snapshot;
|
|
2687
|
+
snapshot = typeof existingSnapshot === "string" ? JSON.parse(existingSnapshot) : existingSnapshot;
|
|
2688
|
+
}
|
|
2689
|
+
snapshot.context[stepId] = result;
|
|
2690
|
+
snapshot.requestContext = { ...snapshot.requestContext, ...requestContext };
|
|
2691
|
+
const upsertReq = new sql2.Request(transaction);
|
|
2692
|
+
upsertReq.input("workflow_name", workflowName);
|
|
2693
|
+
upsertReq.input("run_id", runId);
|
|
2694
|
+
upsertReq.input("snapshot", JSON.stringify(snapshot));
|
|
2695
|
+
upsertReq.input("createdAt", sql2.DateTime2, /* @__PURE__ */ new Date());
|
|
2696
|
+
upsertReq.input("updatedAt", sql2.DateTime2, /* @__PURE__ */ new Date());
|
|
2697
|
+
await upsertReq.query(
|
|
2698
|
+
`MERGE ${table} AS target
|
|
2699
|
+
USING (SELECT @workflow_name AS workflow_name, @run_id AS run_id) AS src
|
|
2700
|
+
ON target.workflow_name = src.workflow_name AND target.run_id = src.run_id
|
|
2701
|
+
WHEN MATCHED THEN UPDATE SET snapshot = @snapshot, [updatedAt] = @updatedAt
|
|
2702
|
+
WHEN NOT MATCHED THEN INSERT (workflow_name, run_id, snapshot, [createdAt], [updatedAt])
|
|
2703
|
+
VALUES (@workflow_name, @run_id, @snapshot, @createdAt, @updatedAt);`
|
|
2704
|
+
);
|
|
2705
|
+
await transaction.commit();
|
|
2706
|
+
return snapshot.context;
|
|
1759
2707
|
} catch (error) {
|
|
2708
|
+
try {
|
|
2709
|
+
await transaction.rollback();
|
|
2710
|
+
} catch {
|
|
2711
|
+
}
|
|
1760
2712
|
throw new MastraError(
|
|
1761
2713
|
{
|
|
1762
|
-
id: "
|
|
2714
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_UPDATE_WORKFLOW_RESULTS_FAILED",
|
|
1763
2715
|
domain: ErrorDomain.STORAGE,
|
|
1764
2716
|
category: ErrorCategory.THIRD_PARTY,
|
|
1765
2717
|
details: {
|
|
1766
|
-
|
|
1767
|
-
|
|
2718
|
+
workflowName,
|
|
2719
|
+
runId,
|
|
2720
|
+
stepId
|
|
1768
2721
|
}
|
|
1769
2722
|
},
|
|
1770
2723
|
error
|
|
1771
2724
|
);
|
|
1772
2725
|
}
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
}
|
|
1782
|
-
const dataQuery = `SELECT * FROM ${getTableName({ indexName: TABLE_TRACES, schemaName: getSchemaName(this.schema) })} ${whereClause} ORDER BY [seq_id] DESC OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY`;
|
|
1783
|
-
const dataRequest = this.pool.request();
|
|
1784
|
-
Object.entries(paramMap).forEach(([key, value]) => {
|
|
1785
|
-
if (value instanceof Date) {
|
|
1786
|
-
dataRequest.input(key, sql2.DateTime, value);
|
|
1787
|
-
} else {
|
|
1788
|
-
dataRequest.input(key, value);
|
|
1789
|
-
}
|
|
1790
|
-
});
|
|
1791
|
-
dataRequest.input("offset", currentOffset);
|
|
1792
|
-
dataRequest.input("limit", perPage);
|
|
2726
|
+
}
|
|
2727
|
+
async updateWorkflowState({
|
|
2728
|
+
workflowName,
|
|
2729
|
+
runId,
|
|
2730
|
+
opts
|
|
2731
|
+
}) {
|
|
2732
|
+
const table = getTableName({ indexName: TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName(this.schema) });
|
|
2733
|
+
const transaction = this.pool.transaction();
|
|
1793
2734
|
try {
|
|
1794
|
-
|
|
1795
|
-
const
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
2735
|
+
await transaction.begin();
|
|
2736
|
+
const selectRequest = new sql2.Request(transaction);
|
|
2737
|
+
selectRequest.input("workflow_name", workflowName);
|
|
2738
|
+
selectRequest.input("run_id", runId);
|
|
2739
|
+
const existingSnapshotResult = await selectRequest.query(
|
|
2740
|
+
`SELECT snapshot FROM ${table} WITH (UPDLOCK, HOLDLOCK) WHERE workflow_name = @workflow_name AND run_id = @run_id`
|
|
2741
|
+
);
|
|
2742
|
+
if (!existingSnapshotResult.recordset || existingSnapshotResult.recordset.length === 0) {
|
|
2743
|
+
await transaction.rollback();
|
|
2744
|
+
return void 0;
|
|
2745
|
+
}
|
|
2746
|
+
const existingSnapshot = existingSnapshotResult.recordset[0].snapshot;
|
|
2747
|
+
const snapshot = typeof existingSnapshot === "string" ? JSON.parse(existingSnapshot) : existingSnapshot;
|
|
2748
|
+
if (!snapshot || !snapshot?.context) {
|
|
2749
|
+
await transaction.rollback();
|
|
2750
|
+
throw new MastraError(
|
|
2751
|
+
{
|
|
2752
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_UPDATE_WORKFLOW_STATE_SNAPSHOT_NOT_FOUND",
|
|
2753
|
+
domain: ErrorDomain.STORAGE,
|
|
2754
|
+
category: ErrorCategory.SYSTEM,
|
|
2755
|
+
details: {
|
|
2756
|
+
workflowName,
|
|
2757
|
+
runId
|
|
2758
|
+
}
|
|
2759
|
+
},
|
|
2760
|
+
new Error(`Snapshot not found for runId ${runId}`)
|
|
2761
|
+
);
|
|
2762
|
+
}
|
|
2763
|
+
const updatedSnapshot = { ...snapshot, ...opts };
|
|
2764
|
+
const updateRequest = new sql2.Request(transaction);
|
|
2765
|
+
updateRequest.input("snapshot", JSON.stringify(updatedSnapshot));
|
|
2766
|
+
updateRequest.input("workflow_name", workflowName);
|
|
2767
|
+
updateRequest.input("run_id", runId);
|
|
2768
|
+
updateRequest.input("updatedAt", sql2.DateTime2, /* @__PURE__ */ new Date());
|
|
2769
|
+
await updateRequest.query(
|
|
2770
|
+
`UPDATE ${table} SET snapshot = @snapshot, [updatedAt] = @updatedAt WHERE workflow_name = @workflow_name AND run_id = @run_id`
|
|
2771
|
+
);
|
|
2772
|
+
await transaction.commit();
|
|
2773
|
+
return updatedSnapshot;
|
|
1819
2774
|
} catch (error) {
|
|
2775
|
+
try {
|
|
2776
|
+
await transaction.rollback();
|
|
2777
|
+
} catch {
|
|
2778
|
+
}
|
|
1820
2779
|
throw new MastraError(
|
|
1821
2780
|
{
|
|
1822
|
-
id: "
|
|
2781
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_UPDATE_WORKFLOW_STATE_FAILED",
|
|
1823
2782
|
domain: ErrorDomain.STORAGE,
|
|
1824
2783
|
category: ErrorCategory.THIRD_PARTY,
|
|
1825
2784
|
details: {
|
|
1826
|
-
|
|
1827
|
-
|
|
2785
|
+
workflowName,
|
|
2786
|
+
runId
|
|
1828
2787
|
}
|
|
1829
2788
|
},
|
|
1830
2789
|
error
|
|
1831
2790
|
);
|
|
1832
2791
|
}
|
|
1833
2792
|
}
|
|
1834
|
-
async batchTraceInsert({ records }) {
|
|
1835
|
-
this.logger.debug("Batch inserting traces", { count: records.length });
|
|
1836
|
-
await this.operations.batchInsert({
|
|
1837
|
-
tableName: TABLE_TRACES,
|
|
1838
|
-
records
|
|
1839
|
-
});
|
|
1840
|
-
}
|
|
1841
|
-
};
|
|
1842
|
-
function parseWorkflowRun(row) {
|
|
1843
|
-
let parsedSnapshot = row.snapshot;
|
|
1844
|
-
if (typeof parsedSnapshot === "string") {
|
|
1845
|
-
try {
|
|
1846
|
-
parsedSnapshot = JSON.parse(row.snapshot);
|
|
1847
|
-
} catch (e) {
|
|
1848
|
-
console.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
|
|
1849
|
-
}
|
|
1850
|
-
}
|
|
1851
|
-
return {
|
|
1852
|
-
workflowName: row.workflow_name,
|
|
1853
|
-
runId: row.run_id,
|
|
1854
|
-
snapshot: parsedSnapshot,
|
|
1855
|
-
createdAt: row.createdAt,
|
|
1856
|
-
updatedAt: row.updatedAt,
|
|
1857
|
-
resourceId: row.resourceId
|
|
1858
|
-
};
|
|
1859
|
-
}
|
|
1860
|
-
var WorkflowsMSSQL = class extends WorkflowsStorage {
|
|
1861
|
-
pool;
|
|
1862
|
-
operations;
|
|
1863
|
-
schema;
|
|
1864
|
-
constructor({
|
|
1865
|
-
pool,
|
|
1866
|
-
operations,
|
|
1867
|
-
schema
|
|
1868
|
-
}) {
|
|
1869
|
-
super();
|
|
1870
|
-
this.pool = pool;
|
|
1871
|
-
this.operations = operations;
|
|
1872
|
-
this.schema = schema;
|
|
1873
|
-
}
|
|
1874
|
-
updateWorkflowResults({
|
|
1875
|
-
// workflowName,
|
|
1876
|
-
// runId,
|
|
1877
|
-
// stepId,
|
|
1878
|
-
// result,
|
|
1879
|
-
// runtimeContext,
|
|
1880
|
-
}) {
|
|
1881
|
-
throw new Error("Method not implemented.");
|
|
1882
|
-
}
|
|
1883
|
-
updateWorkflowState({
|
|
1884
|
-
// workflowName,
|
|
1885
|
-
// runId,
|
|
1886
|
-
// opts,
|
|
1887
|
-
}) {
|
|
1888
|
-
throw new Error("Method not implemented.");
|
|
1889
|
-
}
|
|
1890
2793
|
async persistWorkflowSnapshot({
|
|
1891
2794
|
workflowName,
|
|
1892
2795
|
runId,
|
|
2796
|
+
resourceId,
|
|
1893
2797
|
snapshot
|
|
1894
2798
|
}) {
|
|
1895
2799
|
const table = getTableName({ indexName: TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName(this.schema) });
|
|
@@ -1898,6 +2802,7 @@ var WorkflowsMSSQL = class extends WorkflowsStorage {
|
|
|
1898
2802
|
const request = this.pool.request();
|
|
1899
2803
|
request.input("workflow_name", workflowName);
|
|
1900
2804
|
request.input("run_id", runId);
|
|
2805
|
+
request.input("resourceId", resourceId);
|
|
1901
2806
|
request.input("snapshot", JSON.stringify(snapshot));
|
|
1902
2807
|
request.input("createdAt", sql2.DateTime2, new Date(now));
|
|
1903
2808
|
request.input("updatedAt", sql2.DateTime2, new Date(now));
|
|
@@ -1905,10 +2810,11 @@ var WorkflowsMSSQL = class extends WorkflowsStorage {
|
|
|
1905
2810
|
USING (SELECT @workflow_name AS workflow_name, @run_id AS run_id) AS src
|
|
1906
2811
|
ON target.workflow_name = src.workflow_name AND target.run_id = src.run_id
|
|
1907
2812
|
WHEN MATCHED THEN UPDATE SET
|
|
2813
|
+
resourceId = @resourceId,
|
|
1908
2814
|
snapshot = @snapshot,
|
|
1909
2815
|
[updatedAt] = @updatedAt
|
|
1910
|
-
WHEN NOT MATCHED THEN INSERT (workflow_name, run_id, snapshot, [createdAt], [updatedAt])
|
|
1911
|
-
VALUES (@workflow_name, @run_id, @snapshot, @createdAt, @updatedAt);`;
|
|
2816
|
+
WHEN NOT MATCHED THEN INSERT (workflow_name, run_id, resourceId, snapshot, [createdAt], [updatedAt])
|
|
2817
|
+
VALUES (@workflow_name, @run_id, @resourceId, @snapshot, @createdAt, @updatedAt);`;
|
|
1912
2818
|
await request.query(mergeSql);
|
|
1913
2819
|
} catch (error) {
|
|
1914
2820
|
throw new MastraError(
|
|
@@ -1980,7 +2886,7 @@ var WorkflowsMSSQL = class extends WorkflowsStorage {
|
|
|
1980
2886
|
if (!result.recordset || result.recordset.length === 0) {
|
|
1981
2887
|
return null;
|
|
1982
2888
|
}
|
|
1983
|
-
return parseWorkflowRun(result.recordset[0]);
|
|
2889
|
+
return this.parseWorkflowRun(result.recordset[0]);
|
|
1984
2890
|
} catch (error) {
|
|
1985
2891
|
throw new MastraError(
|
|
1986
2892
|
{
|
|
@@ -1996,13 +2902,14 @@ var WorkflowsMSSQL = class extends WorkflowsStorage {
|
|
|
1996
2902
|
);
|
|
1997
2903
|
}
|
|
1998
2904
|
}
|
|
1999
|
-
async
|
|
2905
|
+
async listWorkflowRuns({
|
|
2000
2906
|
workflowName,
|
|
2001
2907
|
fromDate,
|
|
2002
2908
|
toDate,
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
resourceId
|
|
2909
|
+
page,
|
|
2910
|
+
perPage,
|
|
2911
|
+
resourceId,
|
|
2912
|
+
status
|
|
2006
2913
|
} = {}) {
|
|
2007
2914
|
try {
|
|
2008
2915
|
const conditions = [];
|
|
@@ -2011,13 +2918,17 @@ var WorkflowsMSSQL = class extends WorkflowsStorage {
|
|
|
2011
2918
|
conditions.push(`[workflow_name] = @workflowName`);
|
|
2012
2919
|
paramMap["workflowName"] = workflowName;
|
|
2013
2920
|
}
|
|
2921
|
+
if (status) {
|
|
2922
|
+
conditions.push(`JSON_VALUE([snapshot], '$.status') = @status`);
|
|
2923
|
+
paramMap["status"] = status;
|
|
2924
|
+
}
|
|
2014
2925
|
if (resourceId) {
|
|
2015
2926
|
const hasResourceId = await this.operations.hasColumn(TABLE_WORKFLOW_SNAPSHOT, "resourceId");
|
|
2016
2927
|
if (hasResourceId) {
|
|
2017
2928
|
conditions.push(`[resourceId] = @resourceId`);
|
|
2018
2929
|
paramMap["resourceId"] = resourceId;
|
|
2019
2930
|
} else {
|
|
2020
|
-
|
|
2931
|
+
this.logger?.warn?.(`[${TABLE_WORKFLOW_SNAPSHOT}] resourceId column not found. Skipping resourceId filter.`);
|
|
2021
2932
|
}
|
|
2022
2933
|
}
|
|
2023
2934
|
if (fromDate instanceof Date && !isNaN(fromDate.getTime())) {
|
|
@@ -2039,24 +2950,27 @@ var WorkflowsMSSQL = class extends WorkflowsStorage {
|
|
|
2039
2950
|
request.input(key, value);
|
|
2040
2951
|
}
|
|
2041
2952
|
});
|
|
2042
|
-
|
|
2953
|
+
const usePagination = typeof perPage === "number" && typeof page === "number";
|
|
2954
|
+
if (usePagination) {
|
|
2043
2955
|
const countQuery = `SELECT COUNT(*) as count FROM ${tableName} ${whereClause}`;
|
|
2044
2956
|
const countResult = await request.query(countQuery);
|
|
2045
2957
|
total = Number(countResult.recordset[0]?.count || 0);
|
|
2046
2958
|
}
|
|
2047
2959
|
let query = `SELECT * FROM ${tableName} ${whereClause} ORDER BY [seq_id] DESC`;
|
|
2048
|
-
if (
|
|
2049
|
-
|
|
2050
|
-
|
|
2960
|
+
if (usePagination) {
|
|
2961
|
+
const normalizedPerPage = normalizePerPage(perPage, Number.MAX_SAFE_INTEGER);
|
|
2962
|
+
const offset = page * normalizedPerPage;
|
|
2963
|
+
query += ` OFFSET @offset ROWS FETCH NEXT @perPage ROWS ONLY`;
|
|
2964
|
+
request.input("perPage", normalizedPerPage);
|
|
2051
2965
|
request.input("offset", offset);
|
|
2052
2966
|
}
|
|
2053
2967
|
const result = await request.query(query);
|
|
2054
|
-
const runs = (result.recordset || []).map((row) => parseWorkflowRun(row));
|
|
2968
|
+
const runs = (result.recordset || []).map((row) => this.parseWorkflowRun(row));
|
|
2055
2969
|
return { runs, total: total || runs.length };
|
|
2056
2970
|
} catch (error) {
|
|
2057
2971
|
throw new MastraError(
|
|
2058
2972
|
{
|
|
2059
|
-
id: "
|
|
2973
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_LIST_WORKFLOW_RUNS_FAILED",
|
|
2060
2974
|
domain: ErrorDomain.STORAGE,
|
|
2061
2975
|
category: ErrorCategory.THIRD_PARTY,
|
|
2062
2976
|
details: {
|
|
@@ -2076,7 +2990,10 @@ var MSSQLStore = class extends MastraStorage {
|
|
|
2076
2990
|
isConnected = null;
|
|
2077
2991
|
stores;
|
|
2078
2992
|
constructor(config) {
|
|
2079
|
-
|
|
2993
|
+
if (!config.id || typeof config.id !== "string" || config.id.trim() === "") {
|
|
2994
|
+
throw new Error("MSSQLStore: id must be provided and cannot be empty.");
|
|
2995
|
+
}
|
|
2996
|
+
super({ id: config.id, name: "MSSQLStore" });
|
|
2080
2997
|
try {
|
|
2081
2998
|
if ("connectionString" in config) {
|
|
2082
2999
|
if (!config.connectionString || typeof config.connectionString !== "string" || config.connectionString.trim() === "") {
|
|
@@ -2099,19 +3016,17 @@ var MSSQLStore = class extends MastraStorage {
|
|
|
2099
3016
|
port: config.port,
|
|
2100
3017
|
options: config.options || { encrypt: true, trustServerCertificate: true }
|
|
2101
3018
|
});
|
|
2102
|
-
const legacyEvals = new LegacyEvalsMSSQL({ pool: this.pool, schema: this.schema });
|
|
2103
3019
|
const operations = new StoreOperationsMSSQL({ pool: this.pool, schemaName: this.schema });
|
|
2104
3020
|
const scores = new ScoresMSSQL({ pool: this.pool, operations, schema: this.schema });
|
|
2105
|
-
const traces = new TracesMSSQL({ pool: this.pool, operations, schema: this.schema });
|
|
2106
3021
|
const workflows = new WorkflowsMSSQL({ pool: this.pool, operations, schema: this.schema });
|
|
2107
3022
|
const memory = new MemoryMSSQL({ pool: this.pool, schema: this.schema, operations });
|
|
3023
|
+
const observability = new ObservabilityMSSQL({ pool: this.pool, operations, schema: this.schema });
|
|
2108
3024
|
this.stores = {
|
|
2109
3025
|
operations,
|
|
2110
3026
|
scores,
|
|
2111
|
-
traces,
|
|
2112
3027
|
workflows,
|
|
2113
|
-
|
|
2114
|
-
|
|
3028
|
+
memory,
|
|
3029
|
+
observability
|
|
2115
3030
|
};
|
|
2116
3031
|
} catch (e) {
|
|
2117
3032
|
throw new MastraError(
|
|
@@ -2131,6 +3046,11 @@ var MSSQLStore = class extends MastraStorage {
|
|
|
2131
3046
|
try {
|
|
2132
3047
|
await this.isConnected;
|
|
2133
3048
|
await super.init();
|
|
3049
|
+
try {
|
|
3050
|
+
await this.stores.operations.createAutomaticIndexes();
|
|
3051
|
+
} catch (indexError) {
|
|
3052
|
+
this.logger?.warn?.("Failed to create indexes:", indexError);
|
|
3053
|
+
}
|
|
2134
3054
|
} catch (error) {
|
|
2135
3055
|
this.isConnected = null;
|
|
2136
3056
|
throw new MastraError(
|
|
@@ -2157,28 +3077,12 @@ var MSSQLStore = class extends MastraStorage {
|
|
|
2157
3077
|
resourceWorkingMemory: true,
|
|
2158
3078
|
hasColumn: true,
|
|
2159
3079
|
createTable: true,
|
|
2160
|
-
deleteMessages: true
|
|
3080
|
+
deleteMessages: true,
|
|
3081
|
+
listScoresBySpan: true,
|
|
3082
|
+
observabilityInstance: true,
|
|
3083
|
+
indexManagement: true
|
|
2161
3084
|
};
|
|
2162
3085
|
}
|
|
2163
|
-
/** @deprecated use getEvals instead */
|
|
2164
|
-
async getEvalsByAgentName(agentName, type) {
|
|
2165
|
-
return this.stores.legacyEvals.getEvalsByAgentName(agentName, type);
|
|
2166
|
-
}
|
|
2167
|
-
async getEvals(options = {}) {
|
|
2168
|
-
return this.stores.legacyEvals.getEvals(options);
|
|
2169
|
-
}
|
|
2170
|
-
/**
|
|
2171
|
-
* @deprecated use getTracesPaginated instead
|
|
2172
|
-
*/
|
|
2173
|
-
async getTraces(args) {
|
|
2174
|
-
return this.stores.traces.getTraces(args);
|
|
2175
|
-
}
|
|
2176
|
-
async getTracesPaginated(args) {
|
|
2177
|
-
return this.stores.traces.getTracesPaginated(args);
|
|
2178
|
-
}
|
|
2179
|
-
async batchTraceInsert({ records }) {
|
|
2180
|
-
return this.stores.traces.batchTraceInsert({ records });
|
|
2181
|
-
}
|
|
2182
3086
|
async createTable({
|
|
2183
3087
|
tableName,
|
|
2184
3088
|
schema
|
|
@@ -2213,15 +3117,6 @@ var MSSQLStore = class extends MastraStorage {
|
|
|
2213
3117
|
async getThreadById({ threadId }) {
|
|
2214
3118
|
return this.stores.memory.getThreadById({ threadId });
|
|
2215
3119
|
}
|
|
2216
|
-
/**
|
|
2217
|
-
* @deprecated use getThreadsByResourceIdPaginated instead
|
|
2218
|
-
*/
|
|
2219
|
-
async getThreadsByResourceId(args) {
|
|
2220
|
-
return this.stores.memory.getThreadsByResourceId(args);
|
|
2221
|
-
}
|
|
2222
|
-
async getThreadsByResourceIdPaginated(args) {
|
|
2223
|
-
return this.stores.memory.getThreadsByResourceIdPaginated(args);
|
|
2224
|
-
}
|
|
2225
3120
|
async saveThread({ thread }) {
|
|
2226
3121
|
return this.stores.memory.saveThread({ thread });
|
|
2227
3122
|
}
|
|
@@ -2235,17 +3130,8 @@ var MSSQLStore = class extends MastraStorage {
|
|
|
2235
3130
|
async deleteThread({ threadId }) {
|
|
2236
3131
|
return this.stores.memory.deleteThread({ threadId });
|
|
2237
3132
|
}
|
|
2238
|
-
async
|
|
2239
|
-
return this.stores.memory.
|
|
2240
|
-
}
|
|
2241
|
-
async getMessagesById({
|
|
2242
|
-
messageIds,
|
|
2243
|
-
format
|
|
2244
|
-
}) {
|
|
2245
|
-
return this.stores.memory.getMessagesById({ messageIds, format });
|
|
2246
|
-
}
|
|
2247
|
-
async getMessagesPaginated(args) {
|
|
2248
|
-
return this.stores.memory.getMessagesPaginated(args);
|
|
3133
|
+
async listMessagesById({ messageIds }) {
|
|
3134
|
+
return this.stores.memory.listMessagesById({ messageIds });
|
|
2249
3135
|
}
|
|
2250
3136
|
async saveMessages(args) {
|
|
2251
3137
|
return this.stores.memory.saveMessages(args);
|
|
@@ -2279,9 +3165,9 @@ var MSSQLStore = class extends MastraStorage {
|
|
|
2279
3165
|
runId,
|
|
2280
3166
|
stepId,
|
|
2281
3167
|
result,
|
|
2282
|
-
|
|
3168
|
+
requestContext
|
|
2283
3169
|
}) {
|
|
2284
|
-
return this.stores.workflows.updateWorkflowResults({ workflowName, runId, stepId, result,
|
|
3170
|
+
return this.stores.workflows.updateWorkflowResults({ workflowName, runId, stepId, result, requestContext });
|
|
2285
3171
|
}
|
|
2286
3172
|
async updateWorkflowState({
|
|
2287
3173
|
workflowName,
|
|
@@ -2293,9 +3179,10 @@ var MSSQLStore = class extends MastraStorage {
|
|
|
2293
3179
|
async persistWorkflowSnapshot({
|
|
2294
3180
|
workflowName,
|
|
2295
3181
|
runId,
|
|
3182
|
+
resourceId,
|
|
2296
3183
|
snapshot
|
|
2297
3184
|
}) {
|
|
2298
|
-
return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, snapshot });
|
|
3185
|
+
return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, resourceId, snapshot });
|
|
2299
3186
|
}
|
|
2300
3187
|
async loadWorkflowSnapshot({
|
|
2301
3188
|
workflowName,
|
|
@@ -2303,15 +3190,8 @@ var MSSQLStore = class extends MastraStorage {
|
|
|
2303
3190
|
}) {
|
|
2304
3191
|
return this.stores.workflows.loadWorkflowSnapshot({ workflowName, runId });
|
|
2305
3192
|
}
|
|
2306
|
-
async
|
|
2307
|
-
|
|
2308
|
-
fromDate,
|
|
2309
|
-
toDate,
|
|
2310
|
-
limit,
|
|
2311
|
-
offset,
|
|
2312
|
-
resourceId
|
|
2313
|
-
} = {}) {
|
|
2314
|
-
return this.stores.workflows.getWorkflowRuns({ workflowName, fromDate, toDate, limit, offset, resourceId });
|
|
3193
|
+
async listWorkflowRuns(args = {}) {
|
|
3194
|
+
return this.stores.workflows.listWorkflowRuns(args);
|
|
2315
3195
|
}
|
|
2316
3196
|
async getWorkflowRunById({
|
|
2317
3197
|
runId,
|
|
@@ -2322,38 +3202,108 @@ var MSSQLStore = class extends MastraStorage {
|
|
|
2322
3202
|
async close() {
|
|
2323
3203
|
await this.pool.close();
|
|
2324
3204
|
}
|
|
3205
|
+
/**
|
|
3206
|
+
* Index Management
|
|
3207
|
+
*/
|
|
3208
|
+
async createIndex(options) {
|
|
3209
|
+
return this.stores.operations.createIndex(options);
|
|
3210
|
+
}
|
|
3211
|
+
async listIndexes(tableName) {
|
|
3212
|
+
return this.stores.operations.listIndexes(tableName);
|
|
3213
|
+
}
|
|
3214
|
+
async describeIndex(indexName) {
|
|
3215
|
+
return this.stores.operations.describeIndex(indexName);
|
|
3216
|
+
}
|
|
3217
|
+
async dropIndex(indexName) {
|
|
3218
|
+
return this.stores.operations.dropIndex(indexName);
|
|
3219
|
+
}
|
|
3220
|
+
/**
|
|
3221
|
+
* Tracing / Observability
|
|
3222
|
+
*/
|
|
3223
|
+
getObservabilityStore() {
|
|
3224
|
+
if (!this.stores.observability) {
|
|
3225
|
+
throw new MastraError({
|
|
3226
|
+
id: "MSSQL_STORE_OBSERVABILITY_NOT_INITIALIZED",
|
|
3227
|
+
domain: ErrorDomain.STORAGE,
|
|
3228
|
+
category: ErrorCategory.SYSTEM,
|
|
3229
|
+
text: "Observability storage is not initialized"
|
|
3230
|
+
});
|
|
3231
|
+
}
|
|
3232
|
+
return this.stores.observability;
|
|
3233
|
+
}
|
|
3234
|
+
async createSpan(span) {
|
|
3235
|
+
return this.getObservabilityStore().createSpan(span);
|
|
3236
|
+
}
|
|
3237
|
+
async updateSpan({
|
|
3238
|
+
spanId,
|
|
3239
|
+
traceId,
|
|
3240
|
+
updates
|
|
3241
|
+
}) {
|
|
3242
|
+
return this.getObservabilityStore().updateSpan({ spanId, traceId, updates });
|
|
3243
|
+
}
|
|
3244
|
+
async getTrace(traceId) {
|
|
3245
|
+
return this.getObservabilityStore().getTrace(traceId);
|
|
3246
|
+
}
|
|
3247
|
+
async getTracesPaginated(args) {
|
|
3248
|
+
return this.getObservabilityStore().getTracesPaginated(args);
|
|
3249
|
+
}
|
|
3250
|
+
async batchCreateSpans(args) {
|
|
3251
|
+
return this.getObservabilityStore().batchCreateSpans(args);
|
|
3252
|
+
}
|
|
3253
|
+
async batchUpdateSpans(args) {
|
|
3254
|
+
return this.getObservabilityStore().batchUpdateSpans(args);
|
|
3255
|
+
}
|
|
3256
|
+
async batchDeleteTraces(args) {
|
|
3257
|
+
return this.getObservabilityStore().batchDeleteTraces(args);
|
|
3258
|
+
}
|
|
2325
3259
|
/**
|
|
2326
3260
|
* Scorers
|
|
2327
3261
|
*/
|
|
2328
3262
|
async getScoreById({ id: _id }) {
|
|
2329
3263
|
return this.stores.scores.getScoreById({ id: _id });
|
|
2330
3264
|
}
|
|
2331
|
-
async
|
|
3265
|
+
async listScoresByScorerId({
|
|
2332
3266
|
scorerId: _scorerId,
|
|
2333
|
-
pagination: _pagination
|
|
3267
|
+
pagination: _pagination,
|
|
3268
|
+
entityId: _entityId,
|
|
3269
|
+
entityType: _entityType,
|
|
3270
|
+
source: _source
|
|
2334
3271
|
}) {
|
|
2335
|
-
return this.stores.scores.
|
|
3272
|
+
return this.stores.scores.listScoresByScorerId({
|
|
3273
|
+
scorerId: _scorerId,
|
|
3274
|
+
pagination: _pagination,
|
|
3275
|
+
entityId: _entityId,
|
|
3276
|
+
entityType: _entityType,
|
|
3277
|
+
source: _source
|
|
3278
|
+
});
|
|
2336
3279
|
}
|
|
2337
3280
|
async saveScore(_score) {
|
|
2338
3281
|
return this.stores.scores.saveScore(_score);
|
|
2339
3282
|
}
|
|
2340
|
-
async
|
|
3283
|
+
async listScoresByRunId({
|
|
2341
3284
|
runId: _runId,
|
|
2342
3285
|
pagination: _pagination
|
|
2343
3286
|
}) {
|
|
2344
|
-
return this.stores.scores.
|
|
3287
|
+
return this.stores.scores.listScoresByRunId({ runId: _runId, pagination: _pagination });
|
|
2345
3288
|
}
|
|
2346
|
-
async
|
|
3289
|
+
async listScoresByEntityId({
|
|
2347
3290
|
entityId: _entityId,
|
|
2348
3291
|
entityType: _entityType,
|
|
2349
3292
|
pagination: _pagination
|
|
2350
3293
|
}) {
|
|
2351
|
-
return this.stores.scores.
|
|
3294
|
+
return this.stores.scores.listScoresByEntityId({
|
|
2352
3295
|
entityId: _entityId,
|
|
2353
3296
|
entityType: _entityType,
|
|
2354
3297
|
pagination: _pagination
|
|
2355
3298
|
});
|
|
2356
3299
|
}
|
|
3300
|
+
async listScoresBySpan({
|
|
3301
|
+
traceId,
|
|
3302
|
+
spanId,
|
|
3303
|
+
pagination: _pagination
|
|
3304
|
+
}) {
|
|
3305
|
+
return this.stores.scores.listScoresBySpan({ traceId, spanId, pagination: _pagination });
|
|
3306
|
+
}
|
|
2357
3307
|
};
|
|
2358
3308
|
|
|
2359
3309
|
export { MSSQLStore };
|