@mastra/mssql 0.0.0-iterate-traces-ui-again-20250912091900 → 0.0.0-main-test-20251105183450
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 +385 -3
- package/README.md +315 -37
- package/dist/index.cjs +1641 -740
- 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 +1643 -742
- 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 +72 -81
- package/dist/storage/index.d.ts.map +1 -1
- package/package.json +10 -7
- 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_AI_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,12 @@ 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
|
+
const perPage = normalizePerPage(perPageInput, 100);
|
|
154
|
+
const { offset, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
|
|
155
|
+
const { field, direction } = this.parseOrderBy(orderBy);
|
|
234
156
|
try {
|
|
235
|
-
const perPage = perPageInput !== void 0 ? perPageInput : 100;
|
|
236
|
-
const currentOffset = page * perPage;
|
|
237
157
|
const baseQuery = `FROM ${getTableName({ indexName: TABLE_THREADS, schemaName: getSchemaName(this.schema) })} WHERE [resourceId] = @resourceId`;
|
|
238
158
|
const countQuery = `SELECT COUNT(*) as count ${baseQuery}`;
|
|
239
159
|
const countRequest = this.pool.request();
|
|
@@ -245,16 +165,22 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
245
165
|
threads: [],
|
|
246
166
|
total: 0,
|
|
247
167
|
page,
|
|
248
|
-
perPage,
|
|
168
|
+
perPage: perPageForResponse,
|
|
249
169
|
hasMore: false
|
|
250
170
|
};
|
|
251
171
|
}
|
|
252
|
-
const orderByField =
|
|
253
|
-
const
|
|
172
|
+
const orderByField = field === "createdAt" ? "[createdAt]" : "[updatedAt]";
|
|
173
|
+
const dir = (direction || "DESC").toUpperCase() === "ASC" ? "ASC" : "DESC";
|
|
174
|
+
const limitValue = perPageInput === false ? total : perPage;
|
|
175
|
+
const dataQuery = `SELECT id, [resourceId], title, metadata, [createdAt], [updatedAt] ${baseQuery} ORDER BY ${orderByField} ${dir} OFFSET @offset ROWS FETCH NEXT @perPage ROWS ONLY`;
|
|
254
176
|
const dataRequest = this.pool.request();
|
|
255
177
|
dataRequest.input("resourceId", resourceId);
|
|
256
|
-
dataRequest.input("
|
|
257
|
-
|
|
178
|
+
dataRequest.input("offset", offset);
|
|
179
|
+
if (limitValue > 2147483647) {
|
|
180
|
+
dataRequest.input("perPage", sql2.BigInt, limitValue);
|
|
181
|
+
} else {
|
|
182
|
+
dataRequest.input("perPage", limitValue);
|
|
183
|
+
}
|
|
258
184
|
const rowsResult = await dataRequest.query(dataQuery);
|
|
259
185
|
const rows = rowsResult.recordset || [];
|
|
260
186
|
const threads = rows.map((thread) => ({
|
|
@@ -267,13 +193,13 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
267
193
|
threads,
|
|
268
194
|
total,
|
|
269
195
|
page,
|
|
270
|
-
perPage,
|
|
271
|
-
hasMore:
|
|
196
|
+
perPage: perPageForResponse,
|
|
197
|
+
hasMore: perPageInput === false ? false : offset + perPage < total
|
|
272
198
|
};
|
|
273
199
|
} catch (error) {
|
|
274
200
|
const mastraError = new MastraError(
|
|
275
201
|
{
|
|
276
|
-
id: "
|
|
202
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_LIST_THREADS_BY_RESOURCE_ID_FAILED",
|
|
277
203
|
domain: ErrorDomain.STORAGE,
|
|
278
204
|
category: ErrorCategory.THIRD_PARTY,
|
|
279
205
|
details: {
|
|
@@ -285,7 +211,13 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
285
211
|
);
|
|
286
212
|
this.logger?.error?.(mastraError.toString());
|
|
287
213
|
this.logger?.trackException?.(mastraError);
|
|
288
|
-
return {
|
|
214
|
+
return {
|
|
215
|
+
threads: [],
|
|
216
|
+
total: 0,
|
|
217
|
+
page,
|
|
218
|
+
perPage: perPageForResponse,
|
|
219
|
+
hasMore: false
|
|
220
|
+
};
|
|
289
221
|
}
|
|
290
222
|
}
|
|
291
223
|
async saveThread({ thread }) {
|
|
@@ -307,7 +239,12 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
307
239
|
req.input("id", thread.id);
|
|
308
240
|
req.input("resourceId", thread.resourceId);
|
|
309
241
|
req.input("title", thread.title);
|
|
310
|
-
|
|
242
|
+
const metadata = thread.metadata ? JSON.stringify(thread.metadata) : null;
|
|
243
|
+
if (metadata === null) {
|
|
244
|
+
req.input("metadata", sql2.NVarChar, null);
|
|
245
|
+
} else {
|
|
246
|
+
req.input("metadata", metadata);
|
|
247
|
+
}
|
|
311
248
|
req.input("createdAt", sql2.DateTime2, thread.createdAt);
|
|
312
249
|
req.input("updatedAt", sql2.DateTime2, thread.updatedAt);
|
|
313
250
|
await req.query(mergeSql);
|
|
@@ -326,30 +263,6 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
326
263
|
);
|
|
327
264
|
}
|
|
328
265
|
}
|
|
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
266
|
/**
|
|
354
267
|
* Updates a thread's title and metadata, merging with existing metadata. Returns the updated thread.
|
|
355
268
|
*/
|
|
@@ -377,7 +290,7 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
377
290
|
};
|
|
378
291
|
try {
|
|
379
292
|
const table = getTableName({ indexName: TABLE_THREADS, schemaName: getSchemaName(this.schema) });
|
|
380
|
-
const
|
|
293
|
+
const sql5 = `UPDATE ${table}
|
|
381
294
|
SET title = @title,
|
|
382
295
|
metadata = @metadata,
|
|
383
296
|
[updatedAt] = @updatedAt
|
|
@@ -388,7 +301,7 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
388
301
|
req.input("title", title);
|
|
389
302
|
req.input("metadata", JSON.stringify(mergedMetadata));
|
|
390
303
|
req.input("updatedAt", /* @__PURE__ */ new Date());
|
|
391
|
-
const result = await req.query(
|
|
304
|
+
const result = await req.query(sql5);
|
|
392
305
|
let thread = result.recordset && result.recordset[0];
|
|
393
306
|
if (thread && "seq_id" in thread) {
|
|
394
307
|
const { seq_id, ...rest } = thread;
|
|
@@ -458,11 +371,9 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
458
371
|
}
|
|
459
372
|
async _getIncludedMessages({
|
|
460
373
|
threadId,
|
|
461
|
-
|
|
462
|
-
orderByStatement
|
|
374
|
+
include
|
|
463
375
|
}) {
|
|
464
376
|
if (!threadId.trim()) throw new Error("threadId must be a non-empty string");
|
|
465
|
-
const include = selectBy?.include;
|
|
466
377
|
if (!include) return null;
|
|
467
378
|
const unionQueries = [];
|
|
468
379
|
const paramValues = [];
|
|
@@ -487,7 +398,7 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
487
398
|
m.[resourceId],
|
|
488
399
|
m.seq_id
|
|
489
400
|
FROM (
|
|
490
|
-
SELECT *, ROW_NUMBER() OVER (
|
|
401
|
+
SELECT *, ROW_NUMBER() OVER (ORDER BY [createdAt] ASC) as row_num
|
|
491
402
|
FROM ${getTableName({ indexName: TABLE_MESSAGES, schemaName: getSchemaName(this.schema) })}
|
|
492
403
|
WHERE [thread_id] = ${pThreadId}
|
|
493
404
|
) AS m
|
|
@@ -495,15 +406,17 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
495
406
|
OR EXISTS (
|
|
496
407
|
SELECT 1
|
|
497
408
|
FROM (
|
|
498
|
-
SELECT *, ROW_NUMBER() OVER (
|
|
409
|
+
SELECT *, ROW_NUMBER() OVER (ORDER BY [createdAt] ASC) as row_num
|
|
499
410
|
FROM ${getTableName({ indexName: TABLE_MESSAGES, schemaName: getSchemaName(this.schema) })}
|
|
500
411
|
WHERE [thread_id] = ${pThreadId}
|
|
501
412
|
) AS target
|
|
502
413
|
WHERE target.id = ${pId}
|
|
503
414
|
AND (
|
|
504
|
-
|
|
415
|
+
-- Get previous messages (messages that come BEFORE the target)
|
|
416
|
+
(m.row_num < target.row_num AND m.row_num >= target.row_num - ${pPrev})
|
|
505
417
|
OR
|
|
506
|
-
|
|
418
|
+
-- Get next messages (messages that come AFTER the target)
|
|
419
|
+
(m.row_num > target.row_num AND m.row_num <= target.row_num + ${pNext})
|
|
507
420
|
)
|
|
508
421
|
)
|
|
509
422
|
`
|
|
@@ -532,34 +445,16 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
532
445
|
});
|
|
533
446
|
return dedupedRows;
|
|
534
447
|
}
|
|
535
|
-
async
|
|
536
|
-
|
|
448
|
+
async listMessagesById({ messageIds }) {
|
|
449
|
+
if (messageIds.length === 0) return { messages: [] };
|
|
537
450
|
const selectStatement = `SELECT seq_id, id, content, role, type, [createdAt], thread_id AS threadId, resourceId`;
|
|
538
451
|
const orderByStatement = `ORDER BY [seq_id] DESC`;
|
|
539
|
-
const limit = resolveMessageLimit({ last: selectBy?.last, defaultLimit: 40 });
|
|
540
452
|
try {
|
|
541
|
-
if (!threadId.trim()) throw new Error("threadId must be a non-empty string");
|
|
542
453
|
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`;
|
|
454
|
+
let query = `${selectStatement} FROM ${getTableName({ indexName: TABLE_MESSAGES, schemaName: getSchemaName(this.schema) })} WHERE [id] IN (${messageIds.map((_, i) => `@id${i}`).join(", ")})`;
|
|
552
455
|
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);
|
|
456
|
+
messageIds.forEach((id, i) => request.input(`id${i}`, id));
|
|
457
|
+
query += ` ${orderByStatement}`;
|
|
563
458
|
const result = await request.query(query);
|
|
564
459
|
const remainingRows = result.recordset || [];
|
|
565
460
|
rows.push(...remainingRows);
|
|
@@ -567,153 +462,150 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
567
462
|
const timeDiff = a.seq_id - b.seq_id;
|
|
568
463
|
return timeDiff;
|
|
569
464
|
});
|
|
570
|
-
|
|
571
|
-
|
|
465
|
+
const messagesWithParsedContent = rows.map((row) => {
|
|
466
|
+
if (typeof row.content === "string") {
|
|
467
|
+
try {
|
|
468
|
+
return { ...row, content: JSON.parse(row.content) };
|
|
469
|
+
} catch {
|
|
470
|
+
return row;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
return row;
|
|
474
|
+
});
|
|
475
|
+
const cleanMessages = messagesWithParsedContent.map(({ seq_id, ...rest }) => rest);
|
|
476
|
+
const list = new MessageList().add(cleanMessages, "memory");
|
|
477
|
+
return { messages: list.get.all.db() };
|
|
572
478
|
} catch (error) {
|
|
573
479
|
const mastraError = new MastraError(
|
|
574
480
|
{
|
|
575
|
-
id: "
|
|
481
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_LIST_MESSAGES_BY_ID_FAILED",
|
|
576
482
|
domain: ErrorDomain.STORAGE,
|
|
577
483
|
category: ErrorCategory.THIRD_PARTY,
|
|
578
484
|
details: {
|
|
579
|
-
|
|
580
|
-
resourceId: resourceId ?? ""
|
|
485
|
+
messageIds: JSON.stringify(messageIds)
|
|
581
486
|
}
|
|
582
487
|
},
|
|
583
488
|
error
|
|
584
489
|
);
|
|
585
490
|
this.logger?.error?.(mastraError.toString());
|
|
586
|
-
this.logger?.trackException(mastraError);
|
|
587
|
-
return [];
|
|
491
|
+
this.logger?.trackException?.(mastraError);
|
|
492
|
+
return { messages: [] };
|
|
588
493
|
}
|
|
589
494
|
}
|
|
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(
|
|
495
|
+
async listMessages(args) {
|
|
496
|
+
const { threadId, resourceId, include, filter, perPage: perPageInput, page = 0, orderBy } = args;
|
|
497
|
+
if (!threadId.trim()) {
|
|
498
|
+
throw new MastraError(
|
|
615
499
|
{
|
|
616
|
-
id: "
|
|
500
|
+
id: "STORAGE_MSSQL_LIST_MESSAGES_INVALID_THREAD_ID",
|
|
617
501
|
domain: ErrorDomain.STORAGE,
|
|
618
502
|
category: ErrorCategory.THIRD_PARTY,
|
|
619
|
-
details: {
|
|
620
|
-
messageIds: JSON.stringify(messageIds)
|
|
621
|
-
}
|
|
503
|
+
details: { threadId }
|
|
622
504
|
},
|
|
623
|
-
|
|
505
|
+
new Error("threadId must be a non-empty string")
|
|
624
506
|
);
|
|
625
|
-
this.logger?.error?.(mastraError.toString());
|
|
626
|
-
this.logger?.trackException(mastraError);
|
|
627
|
-
return [];
|
|
628
507
|
}
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
const { threadId, resourceId, format, selectBy } = args;
|
|
632
|
-
const { page = 0, perPage: perPageInput, dateRange } = selectBy?.pagination || {};
|
|
508
|
+
const perPage = normalizePerPage(perPageInput, 40);
|
|
509
|
+
const { offset, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
|
|
633
510
|
try {
|
|
634
|
-
|
|
635
|
-
const
|
|
636
|
-
const toDate = dateRange?.end;
|
|
511
|
+
const { field, direction } = this.parseOrderBy(orderBy, "ASC");
|
|
512
|
+
const orderByStatement = `ORDER BY [${field}] ${direction}`;
|
|
637
513
|
const selectStatement = `SELECT seq_id, id, content, role, type, [createdAt], thread_id AS threadId, resourceId`;
|
|
638
|
-
const
|
|
639
|
-
let messages = [];
|
|
640
|
-
if (selectBy?.include?.length) {
|
|
641
|
-
const includeMessages = await this._getIncludedMessages({ threadId, selectBy, orderByStatement });
|
|
642
|
-
if (includeMessages) messages.push(...includeMessages);
|
|
643
|
-
}
|
|
644
|
-
const perPage = perPageInput !== void 0 ? perPageInput : resolveMessageLimit({ last: selectBy?.last, defaultLimit: 40 });
|
|
645
|
-
const currentOffset = page * perPage;
|
|
514
|
+
const tableName = getTableName({ indexName: TABLE_MESSAGES, schemaName: getSchemaName(this.schema) });
|
|
646
515
|
const conditions = ["[thread_id] = @threadId"];
|
|
647
516
|
const request = this.pool.request();
|
|
648
517
|
request.input("threadId", threadId);
|
|
649
|
-
if (
|
|
518
|
+
if (resourceId) {
|
|
519
|
+
conditions.push("[resourceId] = @resourceId");
|
|
520
|
+
request.input("resourceId", resourceId);
|
|
521
|
+
}
|
|
522
|
+
if (filter?.dateRange?.start) {
|
|
650
523
|
conditions.push("[createdAt] >= @fromDate");
|
|
651
|
-
request.input("fromDate",
|
|
524
|
+
request.input("fromDate", filter.dateRange.start);
|
|
652
525
|
}
|
|
653
|
-
if (
|
|
526
|
+
if (filter?.dateRange?.end) {
|
|
654
527
|
conditions.push("[createdAt] <= @toDate");
|
|
655
|
-
request.input("toDate",
|
|
528
|
+
request.input("toDate", filter.dateRange.end);
|
|
656
529
|
}
|
|
657
530
|
const whereClause = `WHERE ${conditions.join(" AND ")}`;
|
|
658
|
-
const countQuery = `SELECT COUNT(*) as total FROM ${
|
|
531
|
+
const countQuery = `SELECT COUNT(*) as total FROM ${tableName} ${whereClause}`;
|
|
659
532
|
const countResult = await request.query(countQuery);
|
|
660
533
|
const total = parseInt(countResult.recordset[0]?.total, 10) || 0;
|
|
661
|
-
|
|
662
|
-
|
|
534
|
+
const limitValue = perPageInput === false ? total : perPage;
|
|
535
|
+
const dataQuery = `${selectStatement} FROM ${tableName} ${whereClause} ${orderByStatement} OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY`;
|
|
536
|
+
request.input("offset", offset);
|
|
537
|
+
if (limitValue > 2147483647) {
|
|
538
|
+
request.input("limit", sql2.BigInt, limitValue);
|
|
539
|
+
} else {
|
|
540
|
+
request.input("limit", limitValue);
|
|
541
|
+
}
|
|
542
|
+
const rowsResult = await request.query(dataQuery);
|
|
543
|
+
const rows = rowsResult.recordset || [];
|
|
544
|
+
const messages = [...rows];
|
|
545
|
+
if (total === 0 && messages.length === 0 && (!include || include.length === 0)) {
|
|
663
546
|
return {
|
|
664
|
-
messages:
|
|
665
|
-
total:
|
|
547
|
+
messages: [],
|
|
548
|
+
total: 0,
|
|
666
549
|
page,
|
|
667
|
-
perPage,
|
|
550
|
+
perPage: perPageForResponse,
|
|
668
551
|
hasMore: false
|
|
669
552
|
};
|
|
670
553
|
}
|
|
671
|
-
const
|
|
672
|
-
if (
|
|
673
|
-
const
|
|
674
|
-
|
|
675
|
-
|
|
554
|
+
const messageIds = new Set(messages.map((m) => m.id));
|
|
555
|
+
if (include && include.length > 0) {
|
|
556
|
+
const includeMessages = await this._getIncludedMessages({ threadId, include });
|
|
557
|
+
if (includeMessages) {
|
|
558
|
+
for (const includeMsg of includeMessages) {
|
|
559
|
+
if (!messageIds.has(includeMsg.id)) {
|
|
560
|
+
messages.push(includeMsg);
|
|
561
|
+
messageIds.add(includeMsg.id);
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
}
|
|
676
565
|
}
|
|
677
|
-
const
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
const
|
|
566
|
+
const parsed = this._parseAndFormatMessages(messages, "v2");
|
|
567
|
+
let finalMessages = parsed;
|
|
568
|
+
finalMessages = finalMessages.sort((a, b) => {
|
|
569
|
+
const aValue = field === "createdAt" ? new Date(a.createdAt).getTime() : a[field];
|
|
570
|
+
const bValue = field === "createdAt" ? new Date(b.createdAt).getTime() : b[field];
|
|
571
|
+
return direction === "ASC" ? aValue - bValue : bValue - aValue;
|
|
572
|
+
});
|
|
573
|
+
const returnedThreadMessageIds = new Set(finalMessages.filter((m) => m.threadId === threadId).map((m) => m.id));
|
|
574
|
+
const allThreadMessagesReturned = returnedThreadMessageIds.size >= total;
|
|
575
|
+
const hasMore = perPageInput !== false && !allThreadMessagesReturned && offset + perPage < total;
|
|
686
576
|
return {
|
|
687
|
-
messages:
|
|
688
|
-
total
|
|
577
|
+
messages: finalMessages,
|
|
578
|
+
total,
|
|
689
579
|
page,
|
|
690
|
-
perPage,
|
|
691
|
-
hasMore
|
|
580
|
+
perPage: perPageForResponse,
|
|
581
|
+
hasMore
|
|
692
582
|
};
|
|
693
583
|
} catch (error) {
|
|
694
584
|
const mastraError = new MastraError(
|
|
695
585
|
{
|
|
696
|
-
id: "
|
|
586
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_LIST_MESSAGES_FAILED",
|
|
697
587
|
domain: ErrorDomain.STORAGE,
|
|
698
588
|
category: ErrorCategory.THIRD_PARTY,
|
|
699
589
|
details: {
|
|
700
590
|
threadId,
|
|
701
|
-
resourceId: resourceId ?? ""
|
|
702
|
-
page
|
|
591
|
+
resourceId: resourceId ?? ""
|
|
703
592
|
}
|
|
704
593
|
},
|
|
705
594
|
error
|
|
706
595
|
);
|
|
707
596
|
this.logger?.error?.(mastraError.toString());
|
|
708
|
-
this.logger?.trackException(mastraError);
|
|
709
|
-
return {
|
|
597
|
+
this.logger?.trackException?.(mastraError);
|
|
598
|
+
return {
|
|
599
|
+
messages: [],
|
|
600
|
+
total: 0,
|
|
601
|
+
page,
|
|
602
|
+
perPage: perPageForResponse,
|
|
603
|
+
hasMore: false
|
|
604
|
+
};
|
|
710
605
|
}
|
|
711
606
|
}
|
|
712
|
-
async saveMessages({
|
|
713
|
-
messages
|
|
714
|
-
format
|
|
715
|
-
}) {
|
|
716
|
-
if (messages.length === 0) return messages;
|
|
607
|
+
async saveMessages({ messages }) {
|
|
608
|
+
if (messages.length === 0) return { messages: [] };
|
|
717
609
|
const threadId = messages[0]?.threadId;
|
|
718
610
|
if (!threadId) {
|
|
719
611
|
throw new MastraError({
|
|
@@ -795,8 +687,7 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
795
687
|
return message;
|
|
796
688
|
});
|
|
797
689
|
const list = new MessageList().add(messagesWithParsedContent, "memory");
|
|
798
|
-
|
|
799
|
-
return list.get.all.v1();
|
|
690
|
+
return { messages: list.get.all.db() };
|
|
800
691
|
} catch (error) {
|
|
801
692
|
throw new MastraError(
|
|
802
693
|
{
|
|
@@ -972,8 +863,10 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
972
863
|
return null;
|
|
973
864
|
}
|
|
974
865
|
return {
|
|
975
|
-
|
|
976
|
-
|
|
866
|
+
id: result.id,
|
|
867
|
+
createdAt: result.createdAt,
|
|
868
|
+
updatedAt: result.updatedAt,
|
|
869
|
+
workingMemory: result.workingMemory,
|
|
977
870
|
metadata: typeof result.metadata === "string" ? JSON.parse(result.metadata) : result.metadata
|
|
978
871
|
};
|
|
979
872
|
} catch (error) {
|
|
@@ -987,7 +880,7 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
987
880
|
error
|
|
988
881
|
);
|
|
989
882
|
this.logger?.error?.(mastraError.toString());
|
|
990
|
-
this.logger?.trackException(mastraError);
|
|
883
|
+
this.logger?.trackException?.(mastraError);
|
|
991
884
|
throw mastraError;
|
|
992
885
|
}
|
|
993
886
|
}
|
|
@@ -996,7 +889,7 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
996
889
|
tableName: TABLE_RESOURCES,
|
|
997
890
|
record: {
|
|
998
891
|
...resource,
|
|
999
|
-
metadata:
|
|
892
|
+
metadata: resource.metadata
|
|
1000
893
|
}
|
|
1001
894
|
});
|
|
1002
895
|
return resource;
|
|
@@ -1054,111 +947,436 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
1054
947
|
error
|
|
1055
948
|
);
|
|
1056
949
|
this.logger?.error?.(mastraError.toString());
|
|
1057
|
-
this.logger?.trackException(mastraError);
|
|
950
|
+
this.logger?.trackException?.(mastraError);
|
|
1058
951
|
throw mastraError;
|
|
1059
952
|
}
|
|
1060
953
|
}
|
|
1061
954
|
};
|
|
1062
|
-
var
|
|
955
|
+
var ObservabilityMSSQL = class extends ObservabilityStorage {
|
|
1063
956
|
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 }) {
|
|
957
|
+
operations;
|
|
958
|
+
schema;
|
|
959
|
+
constructor({
|
|
960
|
+
pool,
|
|
961
|
+
operations,
|
|
962
|
+
schema
|
|
963
|
+
}) {
|
|
1092
964
|
super();
|
|
1093
965
|
this.pool = pool;
|
|
1094
|
-
this.
|
|
1095
|
-
|
|
1096
|
-
async hasColumn(table, column) {
|
|
1097
|
-
const schema = this.schemaName || "dbo";
|
|
1098
|
-
const request = this.pool.request();
|
|
1099
|
-
request.input("schema", schema);
|
|
1100
|
-
request.input("table", table);
|
|
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;
|
|
966
|
+
this.operations = operations;
|
|
967
|
+
this.schema = schema;
|
|
1107
968
|
}
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
this.setupSchemaPromise = (async () => {
|
|
1114
|
-
try {
|
|
1115
|
-
const checkRequest = this.pool.request();
|
|
1116
|
-
checkRequest.input("schemaName", this.schemaName);
|
|
1117
|
-
const checkResult = await checkRequest.query(`
|
|
1118
|
-
SELECT 1 AS found FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = @schemaName
|
|
1119
|
-
`);
|
|
1120
|
-
const schemaExists = Array.isArray(checkResult.recordset) && checkResult.recordset.length > 0;
|
|
1121
|
-
if (!schemaExists) {
|
|
1122
|
-
try {
|
|
1123
|
-
await this.pool.request().query(`CREATE SCHEMA [${this.schemaName}]`);
|
|
1124
|
-
this.logger?.info?.(`Schema "${this.schemaName}" created successfully`);
|
|
1125
|
-
} catch (error) {
|
|
1126
|
-
this.logger?.error?.(`Failed to create schema "${this.schemaName}"`, { error });
|
|
1127
|
-
throw new Error(
|
|
1128
|
-
`Unable to create schema "${this.schemaName}". This requires CREATE privilege on the database. Either create the schema manually or grant CREATE privilege to the user.`
|
|
1129
|
-
);
|
|
1130
|
-
}
|
|
1131
|
-
}
|
|
1132
|
-
this.schemaSetupComplete = true;
|
|
1133
|
-
this.logger?.debug?.(`Schema "${this.schemaName}" is ready for use`);
|
|
1134
|
-
} catch (error) {
|
|
1135
|
-
this.schemaSetupComplete = void 0;
|
|
1136
|
-
this.setupSchemaPromise = null;
|
|
1137
|
-
throw error;
|
|
1138
|
-
} finally {
|
|
1139
|
-
this.setupSchemaPromise = null;
|
|
1140
|
-
}
|
|
1141
|
-
})();
|
|
1142
|
-
}
|
|
1143
|
-
await this.setupSchemaPromise;
|
|
969
|
+
get tracingStrategy() {
|
|
970
|
+
return {
|
|
971
|
+
preferred: "batch-with-updates",
|
|
972
|
+
supported: ["batch-with-updates", "insert-only"]
|
|
973
|
+
};
|
|
1144
974
|
}
|
|
1145
|
-
async
|
|
975
|
+
async createSpan(span) {
|
|
1146
976
|
try {
|
|
1147
|
-
const
|
|
1148
|
-
const
|
|
1149
|
-
const
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
977
|
+
const startedAt = span.startedAt instanceof Date ? span.startedAt.toISOString() : span.startedAt;
|
|
978
|
+
const endedAt = span.endedAt instanceof Date ? span.endedAt.toISOString() : span.endedAt;
|
|
979
|
+
const record = {
|
|
980
|
+
...span,
|
|
981
|
+
startedAt,
|
|
982
|
+
endedAt
|
|
983
|
+
// Note: createdAt/updatedAt will be set by default values
|
|
984
|
+
};
|
|
985
|
+
return this.operations.insert({ tableName: TABLE_AI_SPANS, record });
|
|
986
|
+
} catch (error) {
|
|
987
|
+
throw new MastraError(
|
|
988
|
+
{
|
|
989
|
+
id: "MSSQL_STORE_CREATE_AI_SPAN_FAILED",
|
|
990
|
+
domain: ErrorDomain.STORAGE,
|
|
991
|
+
category: ErrorCategory.USER,
|
|
992
|
+
details: {
|
|
993
|
+
spanId: span.spanId,
|
|
994
|
+
traceId: span.traceId,
|
|
995
|
+
spanType: span.spanType,
|
|
996
|
+
spanName: span.name
|
|
997
|
+
}
|
|
998
|
+
},
|
|
999
|
+
error
|
|
1000
|
+
);
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
async getAITrace(traceId) {
|
|
1004
|
+
try {
|
|
1005
|
+
const tableName = getTableName({
|
|
1006
|
+
indexName: TABLE_AI_SPANS,
|
|
1007
|
+
schemaName: getSchemaName(this.schema)
|
|
1008
|
+
});
|
|
1009
|
+
const request = this.pool.request();
|
|
1010
|
+
request.input("traceId", traceId);
|
|
1011
|
+
const result = await request.query(
|
|
1012
|
+
`SELECT
|
|
1013
|
+
[traceId], [spanId], [parentSpanId], [name], [scope], [spanType],
|
|
1014
|
+
[attributes], [metadata], [links], [input], [output], [error], [isEvent],
|
|
1015
|
+
[startedAt], [endedAt], [createdAt], [updatedAt]
|
|
1016
|
+
FROM ${tableName}
|
|
1017
|
+
WHERE [traceId] = @traceId
|
|
1018
|
+
ORDER BY [startedAt] DESC`
|
|
1019
|
+
);
|
|
1020
|
+
if (!result.recordset || result.recordset.length === 0) {
|
|
1021
|
+
return null;
|
|
1022
|
+
}
|
|
1023
|
+
return {
|
|
1024
|
+
traceId,
|
|
1025
|
+
spans: result.recordset.map(
|
|
1026
|
+
(span) => transformFromSqlRow({
|
|
1027
|
+
tableName: TABLE_AI_SPANS,
|
|
1028
|
+
sqlRow: span
|
|
1029
|
+
})
|
|
1030
|
+
)
|
|
1031
|
+
};
|
|
1032
|
+
} catch (error) {
|
|
1033
|
+
throw new MastraError(
|
|
1034
|
+
{
|
|
1035
|
+
id: "MSSQL_STORE_GET_AI_TRACE_FAILED",
|
|
1036
|
+
domain: ErrorDomain.STORAGE,
|
|
1037
|
+
category: ErrorCategory.USER,
|
|
1038
|
+
details: {
|
|
1039
|
+
traceId
|
|
1040
|
+
}
|
|
1041
|
+
},
|
|
1042
|
+
error
|
|
1043
|
+
);
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
async updateSpan({
|
|
1047
|
+
spanId,
|
|
1048
|
+
traceId,
|
|
1049
|
+
updates
|
|
1050
|
+
}) {
|
|
1051
|
+
try {
|
|
1052
|
+
const data = { ...updates };
|
|
1053
|
+
if (data.endedAt instanceof Date) {
|
|
1054
|
+
data.endedAt = data.endedAt.toISOString();
|
|
1055
|
+
}
|
|
1056
|
+
if (data.startedAt instanceof Date) {
|
|
1057
|
+
data.startedAt = data.startedAt.toISOString();
|
|
1058
|
+
}
|
|
1059
|
+
await this.operations.update({
|
|
1060
|
+
tableName: TABLE_AI_SPANS,
|
|
1061
|
+
keys: { spanId, traceId },
|
|
1062
|
+
data
|
|
1063
|
+
});
|
|
1064
|
+
} catch (error) {
|
|
1065
|
+
throw new MastraError(
|
|
1066
|
+
{
|
|
1067
|
+
id: "MSSQL_STORE_UPDATE_AI_SPAN_FAILED",
|
|
1068
|
+
domain: ErrorDomain.STORAGE,
|
|
1069
|
+
category: ErrorCategory.USER,
|
|
1070
|
+
details: {
|
|
1071
|
+
spanId,
|
|
1072
|
+
traceId
|
|
1073
|
+
}
|
|
1074
|
+
},
|
|
1075
|
+
error
|
|
1076
|
+
);
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
async getAITracesPaginated({
|
|
1080
|
+
filters,
|
|
1081
|
+
pagination
|
|
1082
|
+
}) {
|
|
1083
|
+
const page = pagination?.page ?? 0;
|
|
1084
|
+
const perPage = pagination?.perPage ?? 10;
|
|
1085
|
+
const { entityId, entityType, ...actualFilters } = filters || {};
|
|
1086
|
+
const filtersWithDateRange = {
|
|
1087
|
+
...actualFilters,
|
|
1088
|
+
...buildDateRangeFilter(pagination?.dateRange, "startedAt"),
|
|
1089
|
+
parentSpanId: null
|
|
1090
|
+
// Only get root spans for traces
|
|
1091
|
+
};
|
|
1092
|
+
const whereClause = prepareWhereClause(filtersWithDateRange);
|
|
1093
|
+
let actualWhereClause = whereClause.sql;
|
|
1094
|
+
const params = { ...whereClause.params };
|
|
1095
|
+
let currentParamIndex = Object.keys(params).length + 1;
|
|
1096
|
+
if (entityId && entityType) {
|
|
1097
|
+
let name = "";
|
|
1098
|
+
if (entityType === "workflow") {
|
|
1099
|
+
name = `workflow run: '${entityId}'`;
|
|
1100
|
+
} else if (entityType === "agent") {
|
|
1101
|
+
name = `agent run: '${entityId}'`;
|
|
1102
|
+
} else {
|
|
1103
|
+
const error = new MastraError({
|
|
1104
|
+
id: "MSSQL_STORE_GET_AI_TRACES_PAGINATED_FAILED",
|
|
1105
|
+
domain: ErrorDomain.STORAGE,
|
|
1106
|
+
category: ErrorCategory.USER,
|
|
1107
|
+
details: {
|
|
1108
|
+
entityType
|
|
1109
|
+
},
|
|
1110
|
+
text: `Cannot filter by entity type: ${entityType}`
|
|
1111
|
+
});
|
|
1112
|
+
throw error;
|
|
1113
|
+
}
|
|
1114
|
+
const entityParam = `p${currentParamIndex++}`;
|
|
1115
|
+
if (actualWhereClause) {
|
|
1116
|
+
actualWhereClause += ` AND [name] = @${entityParam}`;
|
|
1117
|
+
} else {
|
|
1118
|
+
actualWhereClause = ` WHERE [name] = @${entityParam}`;
|
|
1119
|
+
}
|
|
1120
|
+
params[entityParam] = name;
|
|
1121
|
+
}
|
|
1122
|
+
const tableName = getTableName({
|
|
1123
|
+
indexName: TABLE_AI_SPANS,
|
|
1124
|
+
schemaName: getSchemaName(this.schema)
|
|
1125
|
+
});
|
|
1126
|
+
try {
|
|
1127
|
+
const countRequest = this.pool.request();
|
|
1128
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
1129
|
+
countRequest.input(key, value);
|
|
1130
|
+
});
|
|
1131
|
+
const countResult = await countRequest.query(
|
|
1132
|
+
`SELECT COUNT(*) as count FROM ${tableName}${actualWhereClause}`
|
|
1133
|
+
);
|
|
1134
|
+
const total = countResult.recordset[0]?.count ?? 0;
|
|
1135
|
+
if (total === 0) {
|
|
1136
|
+
return {
|
|
1137
|
+
pagination: {
|
|
1138
|
+
total: 0,
|
|
1139
|
+
page,
|
|
1140
|
+
perPage,
|
|
1141
|
+
hasMore: false
|
|
1142
|
+
},
|
|
1143
|
+
spans: []
|
|
1144
|
+
};
|
|
1145
|
+
}
|
|
1146
|
+
const dataRequest = this.pool.request();
|
|
1147
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
1148
|
+
dataRequest.input(key, value);
|
|
1149
|
+
});
|
|
1150
|
+
dataRequest.input("offset", page * perPage);
|
|
1151
|
+
dataRequest.input("limit", perPage);
|
|
1152
|
+
const dataResult = await dataRequest.query(
|
|
1153
|
+
`SELECT * FROM ${tableName}${actualWhereClause} ORDER BY [startedAt] DESC OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY`
|
|
1154
|
+
);
|
|
1155
|
+
const spans = dataResult.recordset.map(
|
|
1156
|
+
(row) => transformFromSqlRow({
|
|
1157
|
+
tableName: TABLE_AI_SPANS,
|
|
1158
|
+
sqlRow: row
|
|
1159
|
+
})
|
|
1160
|
+
);
|
|
1161
|
+
return {
|
|
1162
|
+
pagination: {
|
|
1163
|
+
total,
|
|
1164
|
+
page,
|
|
1165
|
+
perPage,
|
|
1166
|
+
hasMore: (page + 1) * perPage < total
|
|
1167
|
+
},
|
|
1168
|
+
spans
|
|
1169
|
+
};
|
|
1170
|
+
} catch (error) {
|
|
1171
|
+
throw new MastraError(
|
|
1172
|
+
{
|
|
1173
|
+
id: "MSSQL_STORE_GET_AI_TRACES_PAGINATED_FAILED",
|
|
1174
|
+
domain: ErrorDomain.STORAGE,
|
|
1175
|
+
category: ErrorCategory.USER
|
|
1176
|
+
},
|
|
1177
|
+
error
|
|
1178
|
+
);
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
async batchCreateSpans(args) {
|
|
1182
|
+
if (!args.records || args.records.length === 0) {
|
|
1183
|
+
return;
|
|
1184
|
+
}
|
|
1185
|
+
try {
|
|
1186
|
+
await this.operations.batchInsert({
|
|
1187
|
+
tableName: TABLE_AI_SPANS,
|
|
1188
|
+
records: args.records.map((span) => ({
|
|
1189
|
+
...span,
|
|
1190
|
+
startedAt: span.startedAt instanceof Date ? span.startedAt.toISOString() : span.startedAt,
|
|
1191
|
+
endedAt: span.endedAt instanceof Date ? span.endedAt.toISOString() : span.endedAt
|
|
1192
|
+
}))
|
|
1193
|
+
});
|
|
1194
|
+
} catch (error) {
|
|
1195
|
+
throw new MastraError(
|
|
1196
|
+
{
|
|
1197
|
+
id: "MSSQL_STORE_BATCH_CREATE_AI_SPANS_FAILED",
|
|
1198
|
+
domain: ErrorDomain.STORAGE,
|
|
1199
|
+
category: ErrorCategory.USER,
|
|
1200
|
+
details: {
|
|
1201
|
+
count: args.records.length
|
|
1202
|
+
}
|
|
1203
|
+
},
|
|
1204
|
+
error
|
|
1205
|
+
);
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
async batchUpdateSpans(args) {
|
|
1209
|
+
if (!args.records || args.records.length === 0) {
|
|
1210
|
+
return;
|
|
1211
|
+
}
|
|
1212
|
+
try {
|
|
1213
|
+
const updates = args.records.map(({ traceId, spanId, updates: data }) => {
|
|
1214
|
+
const processedData = { ...data };
|
|
1215
|
+
if (processedData.endedAt instanceof Date) {
|
|
1216
|
+
processedData.endedAt = processedData.endedAt.toISOString();
|
|
1217
|
+
}
|
|
1218
|
+
if (processedData.startedAt instanceof Date) {
|
|
1219
|
+
processedData.startedAt = processedData.startedAt.toISOString();
|
|
1220
|
+
}
|
|
1221
|
+
return {
|
|
1222
|
+
keys: { spanId, traceId },
|
|
1223
|
+
data: processedData
|
|
1224
|
+
};
|
|
1225
|
+
});
|
|
1226
|
+
await this.operations.batchUpdate({
|
|
1227
|
+
tableName: TABLE_AI_SPANS,
|
|
1228
|
+
updates
|
|
1229
|
+
});
|
|
1230
|
+
} catch (error) {
|
|
1231
|
+
throw new MastraError(
|
|
1232
|
+
{
|
|
1233
|
+
id: "MSSQL_STORE_BATCH_UPDATE_AI_SPANS_FAILED",
|
|
1234
|
+
domain: ErrorDomain.STORAGE,
|
|
1235
|
+
category: ErrorCategory.USER,
|
|
1236
|
+
details: {
|
|
1237
|
+
count: args.records.length
|
|
1238
|
+
}
|
|
1239
|
+
},
|
|
1240
|
+
error
|
|
1241
|
+
);
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
async batchDeleteAITraces(args) {
|
|
1245
|
+
if (!args.traceIds || args.traceIds.length === 0) {
|
|
1246
|
+
return;
|
|
1247
|
+
}
|
|
1248
|
+
try {
|
|
1249
|
+
const keys = args.traceIds.map((traceId) => ({ traceId }));
|
|
1250
|
+
await this.operations.batchDelete({
|
|
1251
|
+
tableName: TABLE_AI_SPANS,
|
|
1252
|
+
keys
|
|
1253
|
+
});
|
|
1254
|
+
} catch (error) {
|
|
1255
|
+
throw new MastraError(
|
|
1256
|
+
{
|
|
1257
|
+
id: "MSSQL_STORE_BATCH_DELETE_AI_TRACES_FAILED",
|
|
1258
|
+
domain: ErrorDomain.STORAGE,
|
|
1259
|
+
category: ErrorCategory.USER,
|
|
1260
|
+
details: {
|
|
1261
|
+
count: args.traceIds.length
|
|
1262
|
+
}
|
|
1263
|
+
},
|
|
1264
|
+
error
|
|
1265
|
+
);
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
};
|
|
1269
|
+
var StoreOperationsMSSQL = class extends StoreOperations {
|
|
1270
|
+
pool;
|
|
1271
|
+
schemaName;
|
|
1272
|
+
setupSchemaPromise = null;
|
|
1273
|
+
schemaSetupComplete = void 0;
|
|
1274
|
+
getSqlType(type, isPrimaryKey = false, useLargeStorage = false) {
|
|
1275
|
+
switch (type) {
|
|
1276
|
+
case "text":
|
|
1277
|
+
if (useLargeStorage) {
|
|
1278
|
+
return "NVARCHAR(MAX)";
|
|
1279
|
+
}
|
|
1280
|
+
return isPrimaryKey ? "NVARCHAR(255)" : "NVARCHAR(400)";
|
|
1281
|
+
case "timestamp":
|
|
1282
|
+
return "DATETIME2(7)";
|
|
1283
|
+
case "uuid":
|
|
1284
|
+
return "UNIQUEIDENTIFIER";
|
|
1285
|
+
case "jsonb":
|
|
1286
|
+
return "NVARCHAR(MAX)";
|
|
1287
|
+
case "integer":
|
|
1288
|
+
return "INT";
|
|
1289
|
+
case "bigint":
|
|
1290
|
+
return "BIGINT";
|
|
1291
|
+
case "float":
|
|
1292
|
+
return "FLOAT";
|
|
1293
|
+
case "boolean":
|
|
1294
|
+
return "BIT";
|
|
1295
|
+
default:
|
|
1296
|
+
throw new MastraError({
|
|
1297
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_TYPE_NOT_SUPPORTED",
|
|
1298
|
+
domain: ErrorDomain.STORAGE,
|
|
1299
|
+
category: ErrorCategory.THIRD_PARTY
|
|
1300
|
+
});
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
constructor({ pool, schemaName }) {
|
|
1304
|
+
super();
|
|
1305
|
+
this.pool = pool;
|
|
1306
|
+
this.schemaName = schemaName;
|
|
1307
|
+
}
|
|
1308
|
+
async hasColumn(table, column) {
|
|
1309
|
+
const schema = this.schemaName || "dbo";
|
|
1310
|
+
const request = this.pool.request();
|
|
1311
|
+
request.input("schema", schema);
|
|
1312
|
+
request.input("table", table);
|
|
1313
|
+
request.input("column", column);
|
|
1314
|
+
request.input("columnLower", column.toLowerCase());
|
|
1315
|
+
const result = await request.query(
|
|
1316
|
+
`SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = @schema AND TABLE_NAME = @table AND (COLUMN_NAME = @column OR COLUMN_NAME = @columnLower)`
|
|
1317
|
+
);
|
|
1318
|
+
return result.recordset.length > 0;
|
|
1319
|
+
}
|
|
1320
|
+
async setupSchema() {
|
|
1321
|
+
if (!this.schemaName || this.schemaSetupComplete) {
|
|
1322
|
+
return;
|
|
1323
|
+
}
|
|
1324
|
+
if (!this.setupSchemaPromise) {
|
|
1325
|
+
this.setupSchemaPromise = (async () => {
|
|
1326
|
+
try {
|
|
1327
|
+
const checkRequest = this.pool.request();
|
|
1328
|
+
checkRequest.input("schemaName", this.schemaName);
|
|
1329
|
+
const checkResult = await checkRequest.query(`
|
|
1330
|
+
SELECT 1 AS found FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = @schemaName
|
|
1331
|
+
`);
|
|
1332
|
+
const schemaExists = Array.isArray(checkResult.recordset) && checkResult.recordset.length > 0;
|
|
1333
|
+
if (!schemaExists) {
|
|
1334
|
+
try {
|
|
1335
|
+
await this.pool.request().query(`CREATE SCHEMA [${this.schemaName}]`);
|
|
1336
|
+
this.logger?.info?.(`Schema "${this.schemaName}" created successfully`);
|
|
1337
|
+
} catch (error) {
|
|
1338
|
+
this.logger?.error?.(`Failed to create schema "${this.schemaName}"`, { error });
|
|
1339
|
+
throw new Error(
|
|
1340
|
+
`Unable to create schema "${this.schemaName}". This requires CREATE privilege on the database. Either create the schema manually or grant CREATE privilege to the user.`
|
|
1341
|
+
);
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
this.schemaSetupComplete = true;
|
|
1345
|
+
this.logger?.debug?.(`Schema "${this.schemaName}" is ready for use`);
|
|
1346
|
+
} catch (error) {
|
|
1347
|
+
this.schemaSetupComplete = void 0;
|
|
1348
|
+
this.setupSchemaPromise = null;
|
|
1349
|
+
throw error;
|
|
1350
|
+
} finally {
|
|
1351
|
+
this.setupSchemaPromise = null;
|
|
1352
|
+
}
|
|
1353
|
+
})();
|
|
1354
|
+
}
|
|
1355
|
+
await this.setupSchemaPromise;
|
|
1356
|
+
}
|
|
1357
|
+
async insert({
|
|
1358
|
+
tableName,
|
|
1359
|
+
record,
|
|
1360
|
+
transaction
|
|
1361
|
+
}) {
|
|
1362
|
+
try {
|
|
1363
|
+
const columns = Object.keys(record);
|
|
1364
|
+
const parsedColumns = columns.map((col) => parseSqlIdentifier(col, "column name"));
|
|
1365
|
+
const paramNames = columns.map((_, i) => `@param${i}`);
|
|
1366
|
+
const insertSql = `INSERT INTO ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} (${parsedColumns.map((c) => `[${c}]`).join(", ")}) VALUES (${paramNames.join(", ")})`;
|
|
1367
|
+
const request = transaction ? transaction.request() : this.pool.request();
|
|
1368
|
+
columns.forEach((col, i) => {
|
|
1369
|
+
const value = record[col];
|
|
1370
|
+
const preparedValue = this.prepareValue(value, col, tableName);
|
|
1371
|
+
if (preparedValue instanceof Date) {
|
|
1372
|
+
request.input(`param${i}`, sql2.DateTime2, preparedValue);
|
|
1373
|
+
} else if (preparedValue === null || preparedValue === void 0) {
|
|
1374
|
+
request.input(`param${i}`, this.getMssqlType(tableName, col), null);
|
|
1375
|
+
} else {
|
|
1376
|
+
request.input(`param${i}`, preparedValue);
|
|
1377
|
+
}
|
|
1378
|
+
});
|
|
1379
|
+
await request.query(insertSql);
|
|
1162
1380
|
} catch (error) {
|
|
1163
1381
|
throw new MastraError(
|
|
1164
1382
|
{
|
|
@@ -1179,7 +1397,7 @@ var StoreOperationsMSSQL = class extends StoreOperations {
|
|
|
1179
1397
|
try {
|
|
1180
1398
|
await this.pool.request().query(`TRUNCATE TABLE ${fullTableName}`);
|
|
1181
1399
|
} catch (truncateError) {
|
|
1182
|
-
if (truncateError
|
|
1400
|
+
if (truncateError?.number === 4712) {
|
|
1183
1401
|
await this.pool.request().query(`DELETE FROM ${fullTableName}`);
|
|
1184
1402
|
} else {
|
|
1185
1403
|
throw truncateError;
|
|
@@ -1202,9 +1420,11 @@ var StoreOperationsMSSQL = class extends StoreOperations {
|
|
|
1202
1420
|
getDefaultValue(type) {
|
|
1203
1421
|
switch (type) {
|
|
1204
1422
|
case "timestamp":
|
|
1205
|
-
return "DEFAULT
|
|
1423
|
+
return "DEFAULT SYSUTCDATETIME()";
|
|
1206
1424
|
case "jsonb":
|
|
1207
1425
|
return "DEFAULT N'{}'";
|
|
1426
|
+
case "boolean":
|
|
1427
|
+
return "DEFAULT 0";
|
|
1208
1428
|
default:
|
|
1209
1429
|
return super.getDefaultValue(type);
|
|
1210
1430
|
}
|
|
@@ -1215,13 +1435,29 @@ var StoreOperationsMSSQL = class extends StoreOperations {
|
|
|
1215
1435
|
}) {
|
|
1216
1436
|
try {
|
|
1217
1437
|
const uniqueConstraintColumns = tableName === TABLE_WORKFLOW_SNAPSHOT ? ["workflow_name", "run_id"] : [];
|
|
1438
|
+
const largeDataColumns = [
|
|
1439
|
+
"workingMemory",
|
|
1440
|
+
"snapshot",
|
|
1441
|
+
"metadata",
|
|
1442
|
+
"content",
|
|
1443
|
+
// messages.content - can be very long conversation content
|
|
1444
|
+
"input",
|
|
1445
|
+
// evals.input - test input data
|
|
1446
|
+
"output",
|
|
1447
|
+
// evals.output - test output data
|
|
1448
|
+
"instructions",
|
|
1449
|
+
// evals.instructions - evaluation instructions
|
|
1450
|
+
"other"
|
|
1451
|
+
// traces.other - additional trace data
|
|
1452
|
+
];
|
|
1218
1453
|
const columns = Object.entries(schema).map(([name, def]) => {
|
|
1219
1454
|
const parsedName = parseSqlIdentifier(name, "column name");
|
|
1220
1455
|
const constraints = [];
|
|
1221
1456
|
if (def.primaryKey) constraints.push("PRIMARY KEY");
|
|
1222
1457
|
if (!def.nullable) constraints.push("NOT NULL");
|
|
1223
1458
|
const isIndexed = !!def.primaryKey || uniqueConstraintColumns.includes(name);
|
|
1224
|
-
|
|
1459
|
+
const useLargeStorage = largeDataColumns.includes(name);
|
|
1460
|
+
return `[${parsedName}] ${this.getSqlType(def.type, isIndexed, useLargeStorage)} ${constraints.join(" ")}`.trim();
|
|
1225
1461
|
}).join(",\n");
|
|
1226
1462
|
if (this.schemaName) {
|
|
1227
1463
|
await this.setupSchema();
|
|
@@ -1308,7 +1544,19 @@ ${columns}
|
|
|
1308
1544
|
const columnExists = Array.isArray(checkResult.recordset) && checkResult.recordset.length > 0;
|
|
1309
1545
|
if (!columnExists) {
|
|
1310
1546
|
const columnDef = schema[columnName];
|
|
1311
|
-
const
|
|
1547
|
+
const largeDataColumns = [
|
|
1548
|
+
"workingMemory",
|
|
1549
|
+
"snapshot",
|
|
1550
|
+
"metadata",
|
|
1551
|
+
"content",
|
|
1552
|
+
"input",
|
|
1553
|
+
"output",
|
|
1554
|
+
"instructions",
|
|
1555
|
+
"other"
|
|
1556
|
+
];
|
|
1557
|
+
const useLargeStorage = largeDataColumns.includes(columnName);
|
|
1558
|
+
const isIndexed = !!columnDef.primaryKey;
|
|
1559
|
+
const sqlType = this.getSqlType(columnDef.type, isIndexed, useLargeStorage);
|
|
1312
1560
|
const nullable = columnDef.nullable === false ? "NOT NULL" : "";
|
|
1313
1561
|
const defaultValue = columnDef.nullable === false ? this.getDefaultValue(columnDef.type) : "";
|
|
1314
1562
|
const parsedColumnName = parseSqlIdentifier(columnName, "column name");
|
|
@@ -1336,13 +1584,17 @@ ${columns}
|
|
|
1336
1584
|
try {
|
|
1337
1585
|
const keyEntries = Object.entries(keys).map(([key, value]) => [parseSqlIdentifier(key, "column name"), value]);
|
|
1338
1586
|
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}`;
|
|
1587
|
+
const sql5 = `SELECT * FROM ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} WHERE ${conditions}`;
|
|
1341
1588
|
const request = this.pool.request();
|
|
1342
|
-
|
|
1343
|
-
|
|
1589
|
+
keyEntries.forEach(([key, value], i) => {
|
|
1590
|
+
const preparedValue = this.prepareValue(value, key, tableName);
|
|
1591
|
+
if (preparedValue === null || preparedValue === void 0) {
|
|
1592
|
+
request.input(`param${i}`, this.getMssqlType(tableName, key), null);
|
|
1593
|
+
} else {
|
|
1594
|
+
request.input(`param${i}`, preparedValue);
|
|
1595
|
+
}
|
|
1344
1596
|
});
|
|
1345
|
-
const resultSet = await request.query(
|
|
1597
|
+
const resultSet = await request.query(sql5);
|
|
1346
1598
|
const result = resultSet.recordset[0] || null;
|
|
1347
1599
|
if (!result) {
|
|
1348
1600
|
return null;
|
|
@@ -1374,63 +1626,599 @@ ${columns}
|
|
|
1374
1626
|
try {
|
|
1375
1627
|
await transaction.begin();
|
|
1376
1628
|
for (const record of records) {
|
|
1377
|
-
await this.insert({ tableName, record });
|
|
1629
|
+
await this.insert({ tableName, record, transaction });
|
|
1378
1630
|
}
|
|
1379
1631
|
await transaction.commit();
|
|
1380
1632
|
} catch (error) {
|
|
1381
|
-
await transaction.rollback();
|
|
1633
|
+
await transaction.rollback();
|
|
1634
|
+
throw new MastraError(
|
|
1635
|
+
{
|
|
1636
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_BATCH_INSERT_FAILED",
|
|
1637
|
+
domain: ErrorDomain.STORAGE,
|
|
1638
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1639
|
+
details: {
|
|
1640
|
+
tableName,
|
|
1641
|
+
numberOfRecords: records.length
|
|
1642
|
+
}
|
|
1643
|
+
},
|
|
1644
|
+
error
|
|
1645
|
+
);
|
|
1646
|
+
}
|
|
1647
|
+
}
|
|
1648
|
+
async dropTable({ tableName }) {
|
|
1649
|
+
try {
|
|
1650
|
+
const tableNameWithSchema = getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) });
|
|
1651
|
+
await this.pool.request().query(`DROP TABLE IF EXISTS ${tableNameWithSchema}`);
|
|
1652
|
+
} catch (error) {
|
|
1653
|
+
throw new MastraError(
|
|
1654
|
+
{
|
|
1655
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_DROP_TABLE_FAILED",
|
|
1656
|
+
domain: ErrorDomain.STORAGE,
|
|
1657
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1658
|
+
details: {
|
|
1659
|
+
tableName
|
|
1660
|
+
}
|
|
1661
|
+
},
|
|
1662
|
+
error
|
|
1663
|
+
);
|
|
1664
|
+
}
|
|
1665
|
+
}
|
|
1666
|
+
/**
|
|
1667
|
+
* Prepares a value for database operations, handling Date objects and JSON serialization
|
|
1668
|
+
*/
|
|
1669
|
+
prepareValue(value, columnName, tableName) {
|
|
1670
|
+
if (value === null || value === void 0) {
|
|
1671
|
+
return value;
|
|
1672
|
+
}
|
|
1673
|
+
if (value instanceof Date) {
|
|
1674
|
+
return value;
|
|
1675
|
+
}
|
|
1676
|
+
const schema = TABLE_SCHEMAS[tableName];
|
|
1677
|
+
const columnSchema = schema?.[columnName];
|
|
1678
|
+
if (columnSchema?.type === "boolean") {
|
|
1679
|
+
return value ? 1 : 0;
|
|
1680
|
+
}
|
|
1681
|
+
if (columnSchema?.type === "jsonb") {
|
|
1682
|
+
return JSON.stringify(value);
|
|
1683
|
+
}
|
|
1684
|
+
if (typeof value === "object") {
|
|
1685
|
+
return JSON.stringify(value);
|
|
1686
|
+
}
|
|
1687
|
+
return value;
|
|
1688
|
+
}
|
|
1689
|
+
/**
|
|
1690
|
+
* Maps TABLE_SCHEMAS types to mssql param types (used when value is null)
|
|
1691
|
+
*/
|
|
1692
|
+
getMssqlType(tableName, columnName) {
|
|
1693
|
+
const col = TABLE_SCHEMAS[tableName]?.[columnName];
|
|
1694
|
+
switch (col?.type) {
|
|
1695
|
+
case "text":
|
|
1696
|
+
return sql2.NVarChar;
|
|
1697
|
+
case "timestamp":
|
|
1698
|
+
return sql2.DateTime2;
|
|
1699
|
+
case "uuid":
|
|
1700
|
+
return sql2.UniqueIdentifier;
|
|
1701
|
+
case "jsonb":
|
|
1702
|
+
return sql2.NVarChar;
|
|
1703
|
+
case "integer":
|
|
1704
|
+
return sql2.Int;
|
|
1705
|
+
case "bigint":
|
|
1706
|
+
return sql2.BigInt;
|
|
1707
|
+
case "float":
|
|
1708
|
+
return sql2.Float;
|
|
1709
|
+
case "boolean":
|
|
1710
|
+
return sql2.Bit;
|
|
1711
|
+
default:
|
|
1712
|
+
return sql2.NVarChar;
|
|
1713
|
+
}
|
|
1714
|
+
}
|
|
1715
|
+
/**
|
|
1716
|
+
* Update a single record in the database
|
|
1717
|
+
*/
|
|
1718
|
+
async update({
|
|
1719
|
+
tableName,
|
|
1720
|
+
keys,
|
|
1721
|
+
data,
|
|
1722
|
+
transaction
|
|
1723
|
+
}) {
|
|
1724
|
+
try {
|
|
1725
|
+
if (!data || Object.keys(data).length === 0) {
|
|
1726
|
+
throw new MastraError({
|
|
1727
|
+
id: "MASTRA_STORAGE_MSSQL_UPDATE_EMPTY_DATA",
|
|
1728
|
+
domain: ErrorDomain.STORAGE,
|
|
1729
|
+
category: ErrorCategory.USER,
|
|
1730
|
+
text: "Cannot update with empty data payload"
|
|
1731
|
+
});
|
|
1732
|
+
}
|
|
1733
|
+
if (!keys || Object.keys(keys).length === 0) {
|
|
1734
|
+
throw new MastraError({
|
|
1735
|
+
id: "MASTRA_STORAGE_MSSQL_UPDATE_EMPTY_KEYS",
|
|
1736
|
+
domain: ErrorDomain.STORAGE,
|
|
1737
|
+
category: ErrorCategory.USER,
|
|
1738
|
+
text: "Cannot update without keys to identify records"
|
|
1739
|
+
});
|
|
1740
|
+
}
|
|
1741
|
+
const setClauses = [];
|
|
1742
|
+
const request = transaction ? transaction.request() : this.pool.request();
|
|
1743
|
+
let paramIndex = 0;
|
|
1744
|
+
Object.entries(data).forEach(([key, value]) => {
|
|
1745
|
+
const parsedKey = parseSqlIdentifier(key, "column name");
|
|
1746
|
+
const paramName = `set${paramIndex++}`;
|
|
1747
|
+
setClauses.push(`[${parsedKey}] = @${paramName}`);
|
|
1748
|
+
const preparedValue = this.prepareValue(value, key, tableName);
|
|
1749
|
+
if (preparedValue === null || preparedValue === void 0) {
|
|
1750
|
+
request.input(paramName, this.getMssqlType(tableName, key), null);
|
|
1751
|
+
} else {
|
|
1752
|
+
request.input(paramName, preparedValue);
|
|
1753
|
+
}
|
|
1754
|
+
});
|
|
1755
|
+
const whereConditions = [];
|
|
1756
|
+
Object.entries(keys).forEach(([key, value]) => {
|
|
1757
|
+
const parsedKey = parseSqlIdentifier(key, "column name");
|
|
1758
|
+
const paramName = `where${paramIndex++}`;
|
|
1759
|
+
whereConditions.push(`[${parsedKey}] = @${paramName}`);
|
|
1760
|
+
const preparedValue = this.prepareValue(value, key, tableName);
|
|
1761
|
+
if (preparedValue === null || preparedValue === void 0) {
|
|
1762
|
+
request.input(paramName, this.getMssqlType(tableName, key), null);
|
|
1763
|
+
} else {
|
|
1764
|
+
request.input(paramName, preparedValue);
|
|
1765
|
+
}
|
|
1766
|
+
});
|
|
1767
|
+
const tableName_ = getTableName({
|
|
1768
|
+
indexName: tableName,
|
|
1769
|
+
schemaName: getSchemaName(this.schemaName)
|
|
1770
|
+
});
|
|
1771
|
+
const updateSql = `UPDATE ${tableName_} SET ${setClauses.join(", ")} WHERE ${whereConditions.join(" AND ")}`;
|
|
1772
|
+
await request.query(updateSql);
|
|
1773
|
+
} catch (error) {
|
|
1774
|
+
throw new MastraError(
|
|
1775
|
+
{
|
|
1776
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_UPDATE_FAILED",
|
|
1777
|
+
domain: ErrorDomain.STORAGE,
|
|
1778
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1779
|
+
details: {
|
|
1780
|
+
tableName
|
|
1781
|
+
}
|
|
1782
|
+
},
|
|
1783
|
+
error
|
|
1784
|
+
);
|
|
1785
|
+
}
|
|
1786
|
+
}
|
|
1787
|
+
/**
|
|
1788
|
+
* Update multiple records in a single batch transaction
|
|
1789
|
+
*/
|
|
1790
|
+
async batchUpdate({
|
|
1791
|
+
tableName,
|
|
1792
|
+
updates
|
|
1793
|
+
}) {
|
|
1794
|
+
const transaction = this.pool.transaction();
|
|
1795
|
+
try {
|
|
1796
|
+
await transaction.begin();
|
|
1797
|
+
for (const { keys, data } of updates) {
|
|
1798
|
+
await this.update({ tableName, keys, data, transaction });
|
|
1799
|
+
}
|
|
1800
|
+
await transaction.commit();
|
|
1801
|
+
} catch (error) {
|
|
1802
|
+
await transaction.rollback();
|
|
1803
|
+
throw new MastraError(
|
|
1804
|
+
{
|
|
1805
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_BATCH_UPDATE_FAILED",
|
|
1806
|
+
domain: ErrorDomain.STORAGE,
|
|
1807
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1808
|
+
details: {
|
|
1809
|
+
tableName,
|
|
1810
|
+
numberOfRecords: updates.length
|
|
1811
|
+
}
|
|
1812
|
+
},
|
|
1813
|
+
error
|
|
1814
|
+
);
|
|
1815
|
+
}
|
|
1816
|
+
}
|
|
1817
|
+
/**
|
|
1818
|
+
* Delete multiple records by keys
|
|
1819
|
+
*/
|
|
1820
|
+
async batchDelete({ tableName, keys }) {
|
|
1821
|
+
if (keys.length === 0) {
|
|
1822
|
+
return;
|
|
1823
|
+
}
|
|
1824
|
+
const tableName_ = getTableName({
|
|
1825
|
+
indexName: tableName,
|
|
1826
|
+
schemaName: getSchemaName(this.schemaName)
|
|
1827
|
+
});
|
|
1828
|
+
const transaction = this.pool.transaction();
|
|
1829
|
+
try {
|
|
1830
|
+
await transaction.begin();
|
|
1831
|
+
for (const keySet of keys) {
|
|
1832
|
+
const conditions = [];
|
|
1833
|
+
const request = transaction.request();
|
|
1834
|
+
let paramIndex = 0;
|
|
1835
|
+
Object.entries(keySet).forEach(([key, value]) => {
|
|
1836
|
+
const parsedKey = parseSqlIdentifier(key, "column name");
|
|
1837
|
+
const paramName = `p${paramIndex++}`;
|
|
1838
|
+
conditions.push(`[${parsedKey}] = @${paramName}`);
|
|
1839
|
+
const preparedValue = this.prepareValue(value, key, tableName);
|
|
1840
|
+
if (preparedValue === null || preparedValue === void 0) {
|
|
1841
|
+
request.input(paramName, this.getMssqlType(tableName, key), null);
|
|
1842
|
+
} else {
|
|
1843
|
+
request.input(paramName, preparedValue);
|
|
1844
|
+
}
|
|
1845
|
+
});
|
|
1846
|
+
const deleteSql = `DELETE FROM ${tableName_} WHERE ${conditions.join(" AND ")}`;
|
|
1847
|
+
await request.query(deleteSql);
|
|
1848
|
+
}
|
|
1849
|
+
await transaction.commit();
|
|
1850
|
+
} catch (error) {
|
|
1851
|
+
await transaction.rollback();
|
|
1852
|
+
throw new MastraError(
|
|
1853
|
+
{
|
|
1854
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_BATCH_DELETE_FAILED",
|
|
1855
|
+
domain: ErrorDomain.STORAGE,
|
|
1856
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1857
|
+
details: {
|
|
1858
|
+
tableName,
|
|
1859
|
+
numberOfRecords: keys.length
|
|
1860
|
+
}
|
|
1861
|
+
},
|
|
1862
|
+
error
|
|
1863
|
+
);
|
|
1864
|
+
}
|
|
1865
|
+
}
|
|
1866
|
+
/**
|
|
1867
|
+
* Create a new index on a table
|
|
1868
|
+
*/
|
|
1869
|
+
async createIndex(options) {
|
|
1870
|
+
try {
|
|
1871
|
+
const { name, table, columns, unique = false, where } = options;
|
|
1872
|
+
const schemaName = this.schemaName || "dbo";
|
|
1873
|
+
const fullTableName = getTableName({
|
|
1874
|
+
indexName: table,
|
|
1875
|
+
schemaName: getSchemaName(this.schemaName)
|
|
1876
|
+
});
|
|
1877
|
+
const indexNameSafe = parseSqlIdentifier(name, "index name");
|
|
1878
|
+
const checkRequest = this.pool.request();
|
|
1879
|
+
checkRequest.input("indexName", indexNameSafe);
|
|
1880
|
+
checkRequest.input("schemaName", schemaName);
|
|
1881
|
+
checkRequest.input("tableName", table);
|
|
1882
|
+
const indexExists = await checkRequest.query(`
|
|
1883
|
+
SELECT 1 as found
|
|
1884
|
+
FROM sys.indexes i
|
|
1885
|
+
INNER JOIN sys.tables t ON i.object_id = t.object_id
|
|
1886
|
+
INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
|
|
1887
|
+
WHERE i.name = @indexName
|
|
1888
|
+
AND s.name = @schemaName
|
|
1889
|
+
AND t.name = @tableName
|
|
1890
|
+
`);
|
|
1891
|
+
if (indexExists.recordset && indexExists.recordset.length > 0) {
|
|
1892
|
+
return;
|
|
1893
|
+
}
|
|
1894
|
+
const uniqueStr = unique ? "UNIQUE " : "";
|
|
1895
|
+
const columnsStr = columns.map((col) => {
|
|
1896
|
+
if (col.includes(" DESC") || col.includes(" ASC")) {
|
|
1897
|
+
const [colName, ...modifiers] = col.split(" ");
|
|
1898
|
+
if (!colName) {
|
|
1899
|
+
throw new Error(`Invalid column specification: ${col}`);
|
|
1900
|
+
}
|
|
1901
|
+
return `[${parseSqlIdentifier(colName, "column name")}] ${modifiers.join(" ")}`;
|
|
1902
|
+
}
|
|
1903
|
+
return `[${parseSqlIdentifier(col, "column name")}]`;
|
|
1904
|
+
}).join(", ");
|
|
1905
|
+
const whereStr = where ? ` WHERE ${where}` : "";
|
|
1906
|
+
const createIndexSql = `CREATE ${uniqueStr}INDEX [${indexNameSafe}] ON ${fullTableName} (${columnsStr})${whereStr}`;
|
|
1907
|
+
await this.pool.request().query(createIndexSql);
|
|
1908
|
+
} catch (error) {
|
|
1909
|
+
throw new MastraError(
|
|
1910
|
+
{
|
|
1911
|
+
id: "MASTRA_STORAGE_MSSQL_INDEX_CREATE_FAILED",
|
|
1912
|
+
domain: ErrorDomain.STORAGE,
|
|
1913
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1914
|
+
details: {
|
|
1915
|
+
indexName: options.name,
|
|
1916
|
+
tableName: options.table
|
|
1917
|
+
}
|
|
1918
|
+
},
|
|
1919
|
+
error
|
|
1920
|
+
);
|
|
1921
|
+
}
|
|
1922
|
+
}
|
|
1923
|
+
/**
|
|
1924
|
+
* Drop an existing index
|
|
1925
|
+
*/
|
|
1926
|
+
async dropIndex(indexName) {
|
|
1927
|
+
try {
|
|
1928
|
+
const schemaName = this.schemaName || "dbo";
|
|
1929
|
+
const indexNameSafe = parseSqlIdentifier(indexName, "index name");
|
|
1930
|
+
const checkRequest = this.pool.request();
|
|
1931
|
+
checkRequest.input("indexName", indexNameSafe);
|
|
1932
|
+
checkRequest.input("schemaName", schemaName);
|
|
1933
|
+
const result = await checkRequest.query(`
|
|
1934
|
+
SELECT t.name as table_name
|
|
1935
|
+
FROM sys.indexes i
|
|
1936
|
+
INNER JOIN sys.tables t ON i.object_id = t.object_id
|
|
1937
|
+
INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
|
|
1938
|
+
WHERE i.name = @indexName
|
|
1939
|
+
AND s.name = @schemaName
|
|
1940
|
+
`);
|
|
1941
|
+
if (!result.recordset || result.recordset.length === 0) {
|
|
1942
|
+
return;
|
|
1943
|
+
}
|
|
1944
|
+
if (result.recordset.length > 1) {
|
|
1945
|
+
const tables = result.recordset.map((r) => r.table_name).join(", ");
|
|
1946
|
+
throw new MastraError({
|
|
1947
|
+
id: "MASTRA_STORAGE_MSSQL_INDEX_AMBIGUOUS",
|
|
1948
|
+
domain: ErrorDomain.STORAGE,
|
|
1949
|
+
category: ErrorCategory.USER,
|
|
1950
|
+
text: `Index "${indexNameSafe}" exists on multiple tables (${tables}) in schema "${schemaName}". Please drop indexes manually or ensure unique index names.`
|
|
1951
|
+
});
|
|
1952
|
+
}
|
|
1953
|
+
const tableName = result.recordset[0].table_name;
|
|
1954
|
+
const fullTableName = getTableName({
|
|
1955
|
+
indexName: tableName,
|
|
1956
|
+
schemaName: getSchemaName(this.schemaName)
|
|
1957
|
+
});
|
|
1958
|
+
const dropSql = `DROP INDEX [${indexNameSafe}] ON ${fullTableName}`;
|
|
1959
|
+
await this.pool.request().query(dropSql);
|
|
1960
|
+
} catch (error) {
|
|
1961
|
+
throw new MastraError(
|
|
1962
|
+
{
|
|
1963
|
+
id: "MASTRA_STORAGE_MSSQL_INDEX_DROP_FAILED",
|
|
1964
|
+
domain: ErrorDomain.STORAGE,
|
|
1965
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1966
|
+
details: {
|
|
1967
|
+
indexName
|
|
1968
|
+
}
|
|
1969
|
+
},
|
|
1970
|
+
error
|
|
1971
|
+
);
|
|
1972
|
+
}
|
|
1973
|
+
}
|
|
1974
|
+
/**
|
|
1975
|
+
* List indexes for a specific table or all tables
|
|
1976
|
+
*/
|
|
1977
|
+
async listIndexes(tableName) {
|
|
1978
|
+
try {
|
|
1979
|
+
const schemaName = this.schemaName || "dbo";
|
|
1980
|
+
let query;
|
|
1981
|
+
const request = this.pool.request();
|
|
1982
|
+
request.input("schemaName", schemaName);
|
|
1983
|
+
if (tableName) {
|
|
1984
|
+
query = `
|
|
1985
|
+
SELECT
|
|
1986
|
+
i.name as name,
|
|
1987
|
+
o.name as [table],
|
|
1988
|
+
i.is_unique as is_unique,
|
|
1989
|
+
CAST(SUM(s.used_page_count) * 8 / 1024.0 AS VARCHAR(50)) + ' MB' as size
|
|
1990
|
+
FROM sys.indexes i
|
|
1991
|
+
INNER JOIN sys.objects o ON i.object_id = o.object_id
|
|
1992
|
+
INNER JOIN sys.schemas sch ON o.schema_id = sch.schema_id
|
|
1993
|
+
LEFT JOIN sys.dm_db_partition_stats s ON i.object_id = s.object_id AND i.index_id = s.index_id
|
|
1994
|
+
WHERE sch.name = @schemaName
|
|
1995
|
+
AND o.name = @tableName
|
|
1996
|
+
AND i.name IS NOT NULL
|
|
1997
|
+
GROUP BY i.name, o.name, i.is_unique
|
|
1998
|
+
`;
|
|
1999
|
+
request.input("tableName", tableName);
|
|
2000
|
+
} else {
|
|
2001
|
+
query = `
|
|
2002
|
+
SELECT
|
|
2003
|
+
i.name as name,
|
|
2004
|
+
o.name as [table],
|
|
2005
|
+
i.is_unique as is_unique,
|
|
2006
|
+
CAST(SUM(s.used_page_count) * 8 / 1024.0 AS VARCHAR(50)) + ' MB' as size
|
|
2007
|
+
FROM sys.indexes i
|
|
2008
|
+
INNER JOIN sys.objects o ON i.object_id = o.object_id
|
|
2009
|
+
INNER JOIN sys.schemas sch ON o.schema_id = sch.schema_id
|
|
2010
|
+
LEFT JOIN sys.dm_db_partition_stats s ON i.object_id = s.object_id AND i.index_id = s.index_id
|
|
2011
|
+
WHERE sch.name = @schemaName
|
|
2012
|
+
AND i.name IS NOT NULL
|
|
2013
|
+
GROUP BY i.name, o.name, i.is_unique
|
|
2014
|
+
`;
|
|
2015
|
+
}
|
|
2016
|
+
const result = await request.query(query);
|
|
2017
|
+
const indexes = [];
|
|
2018
|
+
for (const row of result.recordset) {
|
|
2019
|
+
const colRequest = this.pool.request();
|
|
2020
|
+
colRequest.input("indexName", row.name);
|
|
2021
|
+
colRequest.input("schemaName", schemaName);
|
|
2022
|
+
const colResult = await colRequest.query(`
|
|
2023
|
+
SELECT c.name as column_name
|
|
2024
|
+
FROM sys.indexes i
|
|
2025
|
+
INNER JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
|
|
2026
|
+
INNER JOIN sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id
|
|
2027
|
+
INNER JOIN sys.objects o ON i.object_id = o.object_id
|
|
2028
|
+
INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
|
|
2029
|
+
WHERE i.name = @indexName
|
|
2030
|
+
AND s.name = @schemaName
|
|
2031
|
+
ORDER BY ic.key_ordinal
|
|
2032
|
+
`);
|
|
2033
|
+
indexes.push({
|
|
2034
|
+
name: row.name,
|
|
2035
|
+
table: row.table,
|
|
2036
|
+
columns: colResult.recordset.map((c) => c.column_name),
|
|
2037
|
+
unique: row.is_unique || false,
|
|
2038
|
+
size: row.size || "0 MB",
|
|
2039
|
+
definition: ""
|
|
2040
|
+
// MSSQL doesn't store definition like PG
|
|
2041
|
+
});
|
|
2042
|
+
}
|
|
2043
|
+
return indexes;
|
|
2044
|
+
} catch (error) {
|
|
2045
|
+
throw new MastraError(
|
|
2046
|
+
{
|
|
2047
|
+
id: "MASTRA_STORAGE_MSSQL_INDEX_LIST_FAILED",
|
|
2048
|
+
domain: ErrorDomain.STORAGE,
|
|
2049
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2050
|
+
details: tableName ? {
|
|
2051
|
+
tableName
|
|
2052
|
+
} : {}
|
|
2053
|
+
},
|
|
2054
|
+
error
|
|
2055
|
+
);
|
|
2056
|
+
}
|
|
2057
|
+
}
|
|
2058
|
+
/**
|
|
2059
|
+
* Get detailed statistics for a specific index
|
|
2060
|
+
*/
|
|
2061
|
+
async describeIndex(indexName) {
|
|
2062
|
+
try {
|
|
2063
|
+
const schemaName = this.schemaName || "dbo";
|
|
2064
|
+
const request = this.pool.request();
|
|
2065
|
+
request.input("indexName", indexName);
|
|
2066
|
+
request.input("schemaName", schemaName);
|
|
2067
|
+
const query = `
|
|
2068
|
+
SELECT
|
|
2069
|
+
i.name as name,
|
|
2070
|
+
o.name as [table],
|
|
2071
|
+
i.is_unique as is_unique,
|
|
2072
|
+
CAST(SUM(s.used_page_count) * 8 / 1024.0 AS VARCHAR(50)) + ' MB' as size,
|
|
2073
|
+
i.type_desc as method,
|
|
2074
|
+
ISNULL(us.user_scans, 0) as scans,
|
|
2075
|
+
ISNULL(us.user_seeks + us.user_scans, 0) as tuples_read,
|
|
2076
|
+
ISNULL(us.user_lookups, 0) as tuples_fetched
|
|
2077
|
+
FROM sys.indexes i
|
|
2078
|
+
INNER JOIN sys.objects o ON i.object_id = o.object_id
|
|
2079
|
+
INNER JOIN sys.schemas sch ON o.schema_id = sch.schema_id
|
|
2080
|
+
LEFT JOIN sys.dm_db_partition_stats s ON i.object_id = s.object_id AND i.index_id = s.index_id
|
|
2081
|
+
LEFT JOIN sys.dm_db_index_usage_stats us ON i.object_id = us.object_id AND i.index_id = us.index_id
|
|
2082
|
+
WHERE i.name = @indexName
|
|
2083
|
+
AND sch.name = @schemaName
|
|
2084
|
+
GROUP BY i.name, o.name, i.is_unique, i.type_desc, us.user_seeks, us.user_scans, us.user_lookups
|
|
2085
|
+
`;
|
|
2086
|
+
const result = await request.query(query);
|
|
2087
|
+
if (!result.recordset || result.recordset.length === 0) {
|
|
2088
|
+
throw new Error(`Index "${indexName}" not found in schema "${schemaName}"`);
|
|
2089
|
+
}
|
|
2090
|
+
const row = result.recordset[0];
|
|
2091
|
+
const colRequest = this.pool.request();
|
|
2092
|
+
colRequest.input("indexName", indexName);
|
|
2093
|
+
colRequest.input("schemaName", schemaName);
|
|
2094
|
+
const colResult = await colRequest.query(`
|
|
2095
|
+
SELECT c.name as column_name
|
|
2096
|
+
FROM sys.indexes i
|
|
2097
|
+
INNER JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
|
|
2098
|
+
INNER JOIN sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id
|
|
2099
|
+
INNER JOIN sys.objects o ON i.object_id = o.object_id
|
|
2100
|
+
INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
|
|
2101
|
+
WHERE i.name = @indexName
|
|
2102
|
+
AND s.name = @schemaName
|
|
2103
|
+
ORDER BY ic.key_ordinal
|
|
2104
|
+
`);
|
|
2105
|
+
return {
|
|
2106
|
+
name: row.name,
|
|
2107
|
+
table: row.table,
|
|
2108
|
+
columns: colResult.recordset.map((c) => c.column_name),
|
|
2109
|
+
unique: row.is_unique || false,
|
|
2110
|
+
size: row.size || "0 MB",
|
|
2111
|
+
definition: "",
|
|
2112
|
+
method: row.method?.toLowerCase() || "nonclustered",
|
|
2113
|
+
scans: Number(row.scans) || 0,
|
|
2114
|
+
tuples_read: Number(row.tuples_read) || 0,
|
|
2115
|
+
tuples_fetched: Number(row.tuples_fetched) || 0
|
|
2116
|
+
};
|
|
2117
|
+
} catch (error) {
|
|
1382
2118
|
throw new MastraError(
|
|
1383
2119
|
{
|
|
1384
|
-
id: "
|
|
2120
|
+
id: "MASTRA_STORAGE_MSSQL_INDEX_DESCRIBE_FAILED",
|
|
1385
2121
|
domain: ErrorDomain.STORAGE,
|
|
1386
2122
|
category: ErrorCategory.THIRD_PARTY,
|
|
1387
2123
|
details: {
|
|
1388
|
-
|
|
1389
|
-
numberOfRecords: records.length
|
|
2124
|
+
indexName
|
|
1390
2125
|
}
|
|
1391
2126
|
},
|
|
1392
2127
|
error
|
|
1393
2128
|
);
|
|
1394
2129
|
}
|
|
1395
2130
|
}
|
|
1396
|
-
|
|
2131
|
+
/**
|
|
2132
|
+
* Returns definitions for automatic performance indexes
|
|
2133
|
+
* IMPORTANT: Uses seq_id DESC instead of createdAt DESC for MSSQL due to millisecond accuracy limitations
|
|
2134
|
+
* NOTE: Using NVARCHAR(400) for text columns (800 bytes) leaves room for composite indexes
|
|
2135
|
+
*/
|
|
2136
|
+
getAutomaticIndexDefinitions() {
|
|
2137
|
+
const schemaPrefix = this.schemaName ? `${this.schemaName}_` : "";
|
|
2138
|
+
return [
|
|
2139
|
+
// Composite indexes for optimal filtering + sorting performance
|
|
2140
|
+
// NVARCHAR(400) = 800 bytes, plus BIGINT (8 bytes) = 808 bytes total (under 900-byte limit)
|
|
2141
|
+
{
|
|
2142
|
+
name: `${schemaPrefix}mastra_threads_resourceid_seqid_idx`,
|
|
2143
|
+
table: TABLE_THREADS,
|
|
2144
|
+
columns: ["resourceId", "seq_id DESC"]
|
|
2145
|
+
},
|
|
2146
|
+
{
|
|
2147
|
+
name: `${schemaPrefix}mastra_messages_thread_id_seqid_idx`,
|
|
2148
|
+
table: TABLE_MESSAGES,
|
|
2149
|
+
columns: ["thread_id", "seq_id DESC"]
|
|
2150
|
+
},
|
|
2151
|
+
{
|
|
2152
|
+
name: `${schemaPrefix}mastra_traces_name_seqid_idx`,
|
|
2153
|
+
table: TABLE_TRACES,
|
|
2154
|
+
columns: ["name", "seq_id DESC"]
|
|
2155
|
+
},
|
|
2156
|
+
{
|
|
2157
|
+
name: `${schemaPrefix}mastra_scores_trace_id_span_id_seqid_idx`,
|
|
2158
|
+
table: TABLE_SCORERS,
|
|
2159
|
+
columns: ["traceId", "spanId", "seq_id DESC"]
|
|
2160
|
+
},
|
|
2161
|
+
// Spans indexes for optimal trace querying
|
|
2162
|
+
{
|
|
2163
|
+
name: `${schemaPrefix}mastra_ai_spans_traceid_startedat_idx`,
|
|
2164
|
+
table: TABLE_AI_SPANS,
|
|
2165
|
+
columns: ["traceId", "startedAt DESC"]
|
|
2166
|
+
},
|
|
2167
|
+
{
|
|
2168
|
+
name: `${schemaPrefix}mastra_ai_spans_parentspanid_startedat_idx`,
|
|
2169
|
+
table: TABLE_AI_SPANS,
|
|
2170
|
+
columns: ["parentSpanId", "startedAt DESC"]
|
|
2171
|
+
},
|
|
2172
|
+
{
|
|
2173
|
+
name: `${schemaPrefix}mastra_ai_spans_name_idx`,
|
|
2174
|
+
table: TABLE_AI_SPANS,
|
|
2175
|
+
columns: ["name"]
|
|
2176
|
+
},
|
|
2177
|
+
{
|
|
2178
|
+
name: `${schemaPrefix}mastra_ai_spans_spantype_startedat_idx`,
|
|
2179
|
+
table: TABLE_AI_SPANS,
|
|
2180
|
+
columns: ["spanType", "startedAt DESC"]
|
|
2181
|
+
}
|
|
2182
|
+
];
|
|
2183
|
+
}
|
|
2184
|
+
/**
|
|
2185
|
+
* Creates automatic indexes for optimal query performance
|
|
2186
|
+
* Uses getAutomaticIndexDefinitions() to determine which indexes to create
|
|
2187
|
+
*/
|
|
2188
|
+
async createAutomaticIndexes() {
|
|
1397
2189
|
try {
|
|
1398
|
-
const
|
|
1399
|
-
|
|
2190
|
+
const indexes = this.getAutomaticIndexDefinitions();
|
|
2191
|
+
for (const indexOptions of indexes) {
|
|
2192
|
+
try {
|
|
2193
|
+
await this.createIndex(indexOptions);
|
|
2194
|
+
} catch (error) {
|
|
2195
|
+
this.logger?.warn?.(`Failed to create index ${indexOptions.name}:`, error);
|
|
2196
|
+
}
|
|
2197
|
+
}
|
|
1400
2198
|
} catch (error) {
|
|
1401
2199
|
throw new MastraError(
|
|
1402
2200
|
{
|
|
1403
|
-
id: "
|
|
2201
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_CREATE_PERFORMANCE_INDEXES_FAILED",
|
|
1404
2202
|
domain: ErrorDomain.STORAGE,
|
|
1405
|
-
category: ErrorCategory.THIRD_PARTY
|
|
1406
|
-
details: {
|
|
1407
|
-
tableName
|
|
1408
|
-
}
|
|
2203
|
+
category: ErrorCategory.THIRD_PARTY
|
|
1409
2204
|
},
|
|
1410
2205
|
error
|
|
1411
2206
|
);
|
|
1412
2207
|
}
|
|
1413
2208
|
}
|
|
1414
2209
|
};
|
|
1415
|
-
function parseJSON(jsonString) {
|
|
1416
|
-
try {
|
|
1417
|
-
return JSON.parse(jsonString);
|
|
1418
|
-
} catch {
|
|
1419
|
-
return jsonString;
|
|
1420
|
-
}
|
|
1421
|
-
}
|
|
1422
2210
|
function transformScoreRow(row) {
|
|
1423
2211
|
return {
|
|
1424
2212
|
...row,
|
|
1425
|
-
input:
|
|
1426
|
-
scorer:
|
|
1427
|
-
preprocessStepResult:
|
|
1428
|
-
analyzeStepResult:
|
|
1429
|
-
metadata:
|
|
1430
|
-
output:
|
|
1431
|
-
additionalContext:
|
|
1432
|
-
|
|
1433
|
-
entity:
|
|
2213
|
+
input: safelyParseJSON(row.input),
|
|
2214
|
+
scorer: safelyParseJSON(row.scorer),
|
|
2215
|
+
preprocessStepResult: safelyParseJSON(row.preprocessStepResult),
|
|
2216
|
+
analyzeStepResult: safelyParseJSON(row.analyzeStepResult),
|
|
2217
|
+
metadata: safelyParseJSON(row.metadata),
|
|
2218
|
+
output: safelyParseJSON(row.output),
|
|
2219
|
+
additionalContext: safelyParseJSON(row.additionalContext),
|
|
2220
|
+
requestContext: safelyParseJSON(row.requestContext),
|
|
2221
|
+
entity: safelyParseJSON(row.entity),
|
|
1434
2222
|
createdAt: row.createdAt,
|
|
1435
2223
|
updatedAt: row.updatedAt
|
|
1436
2224
|
};
|
|
@@ -1473,8 +2261,21 @@ var ScoresMSSQL = class extends ScoresStorage {
|
|
|
1473
2261
|
}
|
|
1474
2262
|
}
|
|
1475
2263
|
async saveScore(score) {
|
|
2264
|
+
let validatedScore;
|
|
2265
|
+
try {
|
|
2266
|
+
validatedScore = saveScorePayloadSchema.parse(score);
|
|
2267
|
+
} catch (error) {
|
|
2268
|
+
throw new MastraError(
|
|
2269
|
+
{
|
|
2270
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_SAVE_SCORE_VALIDATION_FAILED",
|
|
2271
|
+
domain: ErrorDomain.STORAGE,
|
|
2272
|
+
category: ErrorCategory.THIRD_PARTY
|
|
2273
|
+
},
|
|
2274
|
+
error
|
|
2275
|
+
);
|
|
2276
|
+
}
|
|
1476
2277
|
try {
|
|
1477
|
-
const scoreId =
|
|
2278
|
+
const scoreId = randomUUID();
|
|
1478
2279
|
const {
|
|
1479
2280
|
scorer,
|
|
1480
2281
|
preprocessStepResult,
|
|
@@ -1483,24 +2284,24 @@ var ScoresMSSQL = class extends ScoresStorage {
|
|
|
1483
2284
|
input,
|
|
1484
2285
|
output,
|
|
1485
2286
|
additionalContext,
|
|
1486
|
-
|
|
2287
|
+
requestContext,
|
|
1487
2288
|
entity,
|
|
1488
2289
|
...rest
|
|
1489
|
-
} =
|
|
2290
|
+
} = validatedScore;
|
|
1490
2291
|
await this.operations.insert({
|
|
1491
2292
|
tableName: TABLE_SCORERS,
|
|
1492
2293
|
record: {
|
|
1493
2294
|
id: scoreId,
|
|
1494
2295
|
...rest,
|
|
1495
|
-
input:
|
|
1496
|
-
output:
|
|
1497
|
-
preprocessStepResult: preprocessStepResult
|
|
1498
|
-
analyzeStepResult: analyzeStepResult
|
|
1499
|
-
metadata: metadata
|
|
1500
|
-
additionalContext: additionalContext
|
|
1501
|
-
|
|
1502
|
-
entity: entity
|
|
1503
|
-
scorer: scorer
|
|
2296
|
+
input: input || "",
|
|
2297
|
+
output: output || "",
|
|
2298
|
+
preprocessStepResult: preprocessStepResult || null,
|
|
2299
|
+
analyzeStepResult: analyzeStepResult || null,
|
|
2300
|
+
metadata: metadata || null,
|
|
2301
|
+
additionalContext: additionalContext || null,
|
|
2302
|
+
requestContext: requestContext || null,
|
|
2303
|
+
entity: entity || null,
|
|
2304
|
+
scorer: scorer || null,
|
|
1504
2305
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1505
2306
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1506
2307
|
}
|
|
@@ -1518,41 +2319,70 @@ var ScoresMSSQL = class extends ScoresStorage {
|
|
|
1518
2319
|
);
|
|
1519
2320
|
}
|
|
1520
2321
|
}
|
|
1521
|
-
async
|
|
2322
|
+
async listScoresByScorerId({
|
|
1522
2323
|
scorerId,
|
|
1523
|
-
pagination
|
|
2324
|
+
pagination,
|
|
2325
|
+
entityId,
|
|
2326
|
+
entityType,
|
|
2327
|
+
source
|
|
1524
2328
|
}) {
|
|
1525
2329
|
try {
|
|
1526
|
-
const
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
2330
|
+
const conditions = ["[scorerId] = @p1"];
|
|
2331
|
+
const params = { p1: scorerId };
|
|
2332
|
+
let paramIndex = 2;
|
|
2333
|
+
if (entityId) {
|
|
2334
|
+
conditions.push(`[entityId] = @p${paramIndex}`);
|
|
2335
|
+
params[`p${paramIndex}`] = entityId;
|
|
2336
|
+
paramIndex++;
|
|
2337
|
+
}
|
|
2338
|
+
if (entityType) {
|
|
2339
|
+
conditions.push(`[entityType] = @p${paramIndex}`);
|
|
2340
|
+
params[`p${paramIndex}`] = entityType;
|
|
2341
|
+
paramIndex++;
|
|
2342
|
+
}
|
|
2343
|
+
if (source) {
|
|
2344
|
+
conditions.push(`[source] = @p${paramIndex}`);
|
|
2345
|
+
params[`p${paramIndex}`] = source;
|
|
2346
|
+
paramIndex++;
|
|
2347
|
+
}
|
|
2348
|
+
const whereClause = conditions.join(" AND ");
|
|
2349
|
+
const tableName = getTableName({ indexName: TABLE_SCORERS, schemaName: getSchemaName(this.schema) });
|
|
2350
|
+
const countRequest = this.pool.request();
|
|
2351
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
2352
|
+
countRequest.input(key, value);
|
|
2353
|
+
});
|
|
2354
|
+
const totalResult = await countRequest.query(`SELECT COUNT(*) as count FROM ${tableName} WHERE ${whereClause}`);
|
|
1531
2355
|
const total = totalResult.recordset[0]?.count || 0;
|
|
2356
|
+
const { page, perPage: perPageInput } = pagination;
|
|
1532
2357
|
if (total === 0) {
|
|
1533
2358
|
return {
|
|
1534
2359
|
pagination: {
|
|
1535
2360
|
total: 0,
|
|
1536
|
-
page
|
|
1537
|
-
perPage:
|
|
2361
|
+
page,
|
|
2362
|
+
perPage: perPageInput,
|
|
1538
2363
|
hasMore: false
|
|
1539
2364
|
},
|
|
1540
2365
|
scores: []
|
|
1541
2366
|
};
|
|
1542
2367
|
}
|
|
2368
|
+
const perPage = normalizePerPage(perPageInput, 100);
|
|
2369
|
+
const { offset: start, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
|
|
2370
|
+
const limitValue = perPageInput === false ? total : perPage;
|
|
2371
|
+
const end = perPageInput === false ? total : start + perPage;
|
|
1543
2372
|
const dataRequest = this.pool.request();
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
2373
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
2374
|
+
dataRequest.input(key, value);
|
|
2375
|
+
});
|
|
2376
|
+
dataRequest.input("perPage", limitValue);
|
|
2377
|
+
dataRequest.input("offset", start);
|
|
2378
|
+
const dataQuery = `SELECT * FROM ${tableName} WHERE ${whereClause} ORDER BY [createdAt] DESC OFFSET @offset ROWS FETCH NEXT @perPage ROWS ONLY`;
|
|
2379
|
+
const result = await dataRequest.query(dataQuery);
|
|
1550
2380
|
return {
|
|
1551
2381
|
pagination: {
|
|
1552
2382
|
total: Number(total),
|
|
1553
|
-
page
|
|
1554
|
-
perPage:
|
|
1555
|
-
hasMore:
|
|
2383
|
+
page,
|
|
2384
|
+
perPage: perPageForResponse,
|
|
2385
|
+
hasMore: end < total
|
|
1556
2386
|
},
|
|
1557
2387
|
scores: result.recordset.map((row) => transformScoreRow(row))
|
|
1558
2388
|
};
|
|
@@ -1568,7 +2398,7 @@ var ScoresMSSQL = class extends ScoresStorage {
|
|
|
1568
2398
|
);
|
|
1569
2399
|
}
|
|
1570
2400
|
}
|
|
1571
|
-
async
|
|
2401
|
+
async listScoresByRunId({
|
|
1572
2402
|
runId,
|
|
1573
2403
|
pagination
|
|
1574
2404
|
}) {
|
|
@@ -1579,30 +2409,35 @@ var ScoresMSSQL = class extends ScoresStorage {
|
|
|
1579
2409
|
`SELECT COUNT(*) as count FROM ${getTableName({ indexName: TABLE_SCORERS, schemaName: getSchemaName(this.schema) })} WHERE [runId] = @p1`
|
|
1580
2410
|
);
|
|
1581
2411
|
const total = totalResult.recordset[0]?.count || 0;
|
|
2412
|
+
const { page, perPage: perPageInput } = pagination;
|
|
1582
2413
|
if (total === 0) {
|
|
1583
2414
|
return {
|
|
1584
2415
|
pagination: {
|
|
1585
2416
|
total: 0,
|
|
1586
|
-
page
|
|
1587
|
-
perPage:
|
|
2417
|
+
page,
|
|
2418
|
+
perPage: perPageInput,
|
|
1588
2419
|
hasMore: false
|
|
1589
2420
|
},
|
|
1590
2421
|
scores: []
|
|
1591
2422
|
};
|
|
1592
2423
|
}
|
|
2424
|
+
const perPage = normalizePerPage(perPageInput, 100);
|
|
2425
|
+
const { offset: start, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
|
|
2426
|
+
const limitValue = perPageInput === false ? total : perPage;
|
|
2427
|
+
const end = perPageInput === false ? total : start + perPage;
|
|
1593
2428
|
const dataRequest = this.pool.request();
|
|
1594
2429
|
dataRequest.input("p1", runId);
|
|
1595
|
-
dataRequest.input("p2",
|
|
1596
|
-
dataRequest.input("p3",
|
|
2430
|
+
dataRequest.input("p2", limitValue);
|
|
2431
|
+
dataRequest.input("p3", start);
|
|
1597
2432
|
const result = await dataRequest.query(
|
|
1598
2433
|
`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
2434
|
);
|
|
1600
2435
|
return {
|
|
1601
2436
|
pagination: {
|
|
1602
2437
|
total: Number(total),
|
|
1603
|
-
page
|
|
1604
|
-
perPage:
|
|
1605
|
-
hasMore:
|
|
2438
|
+
page,
|
|
2439
|
+
perPage: perPageForResponse,
|
|
2440
|
+
hasMore: end < total
|
|
1606
2441
|
},
|
|
1607
2442
|
scores: result.recordset.map((row) => transformScoreRow(row))
|
|
1608
2443
|
};
|
|
@@ -1618,7 +2453,7 @@ var ScoresMSSQL = class extends ScoresStorage {
|
|
|
1618
2453
|
);
|
|
1619
2454
|
}
|
|
1620
2455
|
}
|
|
1621
|
-
async
|
|
2456
|
+
async listScoresByEntityId({
|
|
1622
2457
|
entityId,
|
|
1623
2458
|
entityType,
|
|
1624
2459
|
pagination
|
|
@@ -1631,31 +2466,36 @@ var ScoresMSSQL = class extends ScoresStorage {
|
|
|
1631
2466
|
`SELECT COUNT(*) as count FROM ${getTableName({ indexName: TABLE_SCORERS, schemaName: getSchemaName(this.schema) })} WHERE [entityId] = @p1 AND [entityType] = @p2`
|
|
1632
2467
|
);
|
|
1633
2468
|
const total = totalResult.recordset[0]?.count || 0;
|
|
2469
|
+
const { page, perPage: perPageInput } = pagination;
|
|
2470
|
+
const perPage = normalizePerPage(perPageInput, 100);
|
|
2471
|
+
const { offset: start, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
|
|
1634
2472
|
if (total === 0) {
|
|
1635
2473
|
return {
|
|
1636
2474
|
pagination: {
|
|
1637
2475
|
total: 0,
|
|
1638
|
-
page
|
|
1639
|
-
perPage:
|
|
2476
|
+
page,
|
|
2477
|
+
perPage: perPageForResponse,
|
|
1640
2478
|
hasMore: false
|
|
1641
2479
|
},
|
|
1642
2480
|
scores: []
|
|
1643
2481
|
};
|
|
1644
2482
|
}
|
|
2483
|
+
const limitValue = perPageInput === false ? total : perPage;
|
|
2484
|
+
const end = perPageInput === false ? total : start + perPage;
|
|
1645
2485
|
const dataRequest = this.pool.request();
|
|
1646
2486
|
dataRequest.input("p1", entityId);
|
|
1647
2487
|
dataRequest.input("p2", entityType);
|
|
1648
|
-
dataRequest.input("p3",
|
|
1649
|
-
dataRequest.input("p4",
|
|
2488
|
+
dataRequest.input("p3", limitValue);
|
|
2489
|
+
dataRequest.input("p4", start);
|
|
1650
2490
|
const result = await dataRequest.query(
|
|
1651
2491
|
`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
2492
|
);
|
|
1653
2493
|
return {
|
|
1654
2494
|
pagination: {
|
|
1655
2495
|
total: Number(total),
|
|
1656
|
-
page
|
|
1657
|
-
perPage:
|
|
1658
|
-
hasMore:
|
|
2496
|
+
page,
|
|
2497
|
+
perPage: perPageForResponse,
|
|
2498
|
+
hasMore: end < total
|
|
1659
2499
|
},
|
|
1660
2500
|
scores: result.recordset.map((row) => transformScoreRow(row))
|
|
1661
2501
|
};
|
|
@@ -1671,8 +2511,66 @@ var ScoresMSSQL = class extends ScoresStorage {
|
|
|
1671
2511
|
);
|
|
1672
2512
|
}
|
|
1673
2513
|
}
|
|
2514
|
+
async listScoresBySpan({
|
|
2515
|
+
traceId,
|
|
2516
|
+
spanId,
|
|
2517
|
+
pagination
|
|
2518
|
+
}) {
|
|
2519
|
+
try {
|
|
2520
|
+
const request = this.pool.request();
|
|
2521
|
+
request.input("p1", traceId);
|
|
2522
|
+
request.input("p2", spanId);
|
|
2523
|
+
const totalResult = await request.query(
|
|
2524
|
+
`SELECT COUNT(*) as count FROM ${getTableName({ indexName: TABLE_SCORERS, schemaName: getSchemaName(this.schema) })} WHERE [traceId] = @p1 AND [spanId] = @p2`
|
|
2525
|
+
);
|
|
2526
|
+
const total = totalResult.recordset[0]?.count || 0;
|
|
2527
|
+
const { page, perPage: perPageInput } = pagination;
|
|
2528
|
+
const perPage = normalizePerPage(perPageInput, 100);
|
|
2529
|
+
const { offset: start, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
|
|
2530
|
+
if (total === 0) {
|
|
2531
|
+
return {
|
|
2532
|
+
pagination: {
|
|
2533
|
+
total: 0,
|
|
2534
|
+
page,
|
|
2535
|
+
perPage: perPageForResponse,
|
|
2536
|
+
hasMore: false
|
|
2537
|
+
},
|
|
2538
|
+
scores: []
|
|
2539
|
+
};
|
|
2540
|
+
}
|
|
2541
|
+
const limitValue = perPageInput === false ? total : perPage;
|
|
2542
|
+
const end = perPageInput === false ? total : start + perPage;
|
|
2543
|
+
const dataRequest = this.pool.request();
|
|
2544
|
+
dataRequest.input("p1", traceId);
|
|
2545
|
+
dataRequest.input("p2", spanId);
|
|
2546
|
+
dataRequest.input("p3", limitValue);
|
|
2547
|
+
dataRequest.input("p4", start);
|
|
2548
|
+
const result = await dataRequest.query(
|
|
2549
|
+
`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`
|
|
2550
|
+
);
|
|
2551
|
+
return {
|
|
2552
|
+
pagination: {
|
|
2553
|
+
total: Number(total),
|
|
2554
|
+
page,
|
|
2555
|
+
perPage: perPageForResponse,
|
|
2556
|
+
hasMore: end < total
|
|
2557
|
+
},
|
|
2558
|
+
scores: result.recordset.map((row) => transformScoreRow(row))
|
|
2559
|
+
};
|
|
2560
|
+
} catch (error) {
|
|
2561
|
+
throw new MastraError(
|
|
2562
|
+
{
|
|
2563
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_GET_SCORES_BY_SPAN_FAILED",
|
|
2564
|
+
domain: ErrorDomain.STORAGE,
|
|
2565
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2566
|
+
details: { traceId, spanId }
|
|
2567
|
+
},
|
|
2568
|
+
error
|
|
2569
|
+
);
|
|
2570
|
+
}
|
|
2571
|
+
}
|
|
1674
2572
|
};
|
|
1675
|
-
var
|
|
2573
|
+
var WorkflowsMSSQL = class extends WorkflowsStorage {
|
|
1676
2574
|
pool;
|
|
1677
2575
|
operations;
|
|
1678
2576
|
schema;
|
|
@@ -1686,210 +2584,168 @@ var TracesMSSQL = class extends TracesStorage {
|
|
|
1686
2584
|
this.operations = operations;
|
|
1687
2585
|
this.schema = schema;
|
|
1688
2586
|
}
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
if (
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
const result = await this.getTracesPaginated(args);
|
|
1698
|
-
return result.traces;
|
|
1699
|
-
}
|
|
1700
|
-
async getTracesPaginated(args) {
|
|
1701
|
-
const { name, scope, page = 0, perPage: perPageInput, attributes, filters, dateRange } = args;
|
|
1702
|
-
const fromDate = dateRange?.start;
|
|
1703
|
-
const toDate = dateRange?.end;
|
|
1704
|
-
const perPage = perPageInput !== void 0 ? perPageInput : 100;
|
|
1705
|
-
const currentOffset = page * perPage;
|
|
1706
|
-
const paramMap = {};
|
|
1707
|
-
const conditions = [];
|
|
1708
|
-
let paramIndex = 1;
|
|
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();
|
|
2587
|
+
parseWorkflowRun(row) {
|
|
2588
|
+
let parsedSnapshot = row.snapshot;
|
|
2589
|
+
if (typeof parsedSnapshot === "string") {
|
|
2590
|
+
try {
|
|
2591
|
+
parsedSnapshot = JSON.parse(row.snapshot);
|
|
2592
|
+
} catch (e) {
|
|
2593
|
+
this.logger?.warn?.(`Failed to parse snapshot for workflow ${row.workflow_name}:`, e);
|
|
2594
|
+
}
|
|
1744
2595
|
}
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
2596
|
+
return {
|
|
2597
|
+
workflowName: row.workflow_name,
|
|
2598
|
+
runId: row.run_id,
|
|
2599
|
+
snapshot: parsedSnapshot,
|
|
2600
|
+
createdAt: row.createdAt,
|
|
2601
|
+
updatedAt: row.updatedAt,
|
|
2602
|
+
resourceId: row.resourceId
|
|
2603
|
+
};
|
|
2604
|
+
}
|
|
2605
|
+
async updateWorkflowResults({
|
|
2606
|
+
workflowName,
|
|
2607
|
+
runId,
|
|
2608
|
+
stepId,
|
|
2609
|
+
result,
|
|
2610
|
+
requestContext
|
|
2611
|
+
}) {
|
|
2612
|
+
const table = getTableName({ indexName: TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName(this.schema) });
|
|
2613
|
+
const transaction = this.pool.transaction();
|
|
1748
2614
|
try {
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
2615
|
+
await transaction.begin();
|
|
2616
|
+
const selectRequest = new sql2.Request(transaction);
|
|
2617
|
+
selectRequest.input("workflow_name", workflowName);
|
|
2618
|
+
selectRequest.input("run_id", runId);
|
|
2619
|
+
const existingSnapshotResult = await selectRequest.query(
|
|
2620
|
+
`SELECT snapshot FROM ${table} WITH (UPDLOCK, HOLDLOCK) WHERE workflow_name = @workflow_name AND run_id = @run_id`
|
|
2621
|
+
);
|
|
2622
|
+
let snapshot;
|
|
2623
|
+
if (!existingSnapshotResult.recordset || existingSnapshotResult.recordset.length === 0) {
|
|
2624
|
+
snapshot = {
|
|
2625
|
+
context: {},
|
|
2626
|
+
activePaths: [],
|
|
2627
|
+
timestamp: Date.now(),
|
|
2628
|
+
suspendedPaths: {},
|
|
2629
|
+
resumeLabels: {},
|
|
2630
|
+
serializedStepGraph: [],
|
|
2631
|
+
value: {},
|
|
2632
|
+
waitingPaths: {},
|
|
2633
|
+
status: "pending",
|
|
2634
|
+
runId,
|
|
2635
|
+
requestContext: {}
|
|
2636
|
+
};
|
|
2637
|
+
} else {
|
|
2638
|
+
const existingSnapshot = existingSnapshotResult.recordset[0].snapshot;
|
|
2639
|
+
snapshot = typeof existingSnapshot === "string" ? JSON.parse(existingSnapshot) : existingSnapshot;
|
|
2640
|
+
}
|
|
2641
|
+
snapshot.context[stepId] = result;
|
|
2642
|
+
snapshot.requestContext = { ...snapshot.requestContext, ...requestContext };
|
|
2643
|
+
const upsertReq = new sql2.Request(transaction);
|
|
2644
|
+
upsertReq.input("workflow_name", workflowName);
|
|
2645
|
+
upsertReq.input("run_id", runId);
|
|
2646
|
+
upsertReq.input("snapshot", JSON.stringify(snapshot));
|
|
2647
|
+
upsertReq.input("createdAt", sql2.DateTime2, /* @__PURE__ */ new Date());
|
|
2648
|
+
upsertReq.input("updatedAt", sql2.DateTime2, /* @__PURE__ */ new Date());
|
|
2649
|
+
await upsertReq.query(
|
|
2650
|
+
`MERGE ${table} AS target
|
|
2651
|
+
USING (SELECT @workflow_name AS workflow_name, @run_id AS run_id) AS src
|
|
2652
|
+
ON target.workflow_name = src.workflow_name AND target.run_id = src.run_id
|
|
2653
|
+
WHEN MATCHED THEN UPDATE SET snapshot = @snapshot, [updatedAt] = @updatedAt
|
|
2654
|
+
WHEN NOT MATCHED THEN INSERT (workflow_name, run_id, snapshot, [createdAt], [updatedAt])
|
|
2655
|
+
VALUES (@workflow_name, @run_id, @snapshot, @createdAt, @updatedAt);`
|
|
2656
|
+
);
|
|
2657
|
+
await transaction.commit();
|
|
2658
|
+
return snapshot.context;
|
|
1759
2659
|
} catch (error) {
|
|
2660
|
+
try {
|
|
2661
|
+
await transaction.rollback();
|
|
2662
|
+
} catch {
|
|
2663
|
+
}
|
|
1760
2664
|
throw new MastraError(
|
|
1761
2665
|
{
|
|
1762
|
-
id: "
|
|
2666
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_UPDATE_WORKFLOW_RESULTS_FAILED",
|
|
1763
2667
|
domain: ErrorDomain.STORAGE,
|
|
1764
2668
|
category: ErrorCategory.THIRD_PARTY,
|
|
1765
2669
|
details: {
|
|
1766
|
-
|
|
1767
|
-
|
|
2670
|
+
workflowName,
|
|
2671
|
+
runId,
|
|
2672
|
+
stepId
|
|
1768
2673
|
}
|
|
1769
2674
|
},
|
|
1770
2675
|
error
|
|
1771
2676
|
);
|
|
1772
2677
|
}
|
|
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);
|
|
2678
|
+
}
|
|
2679
|
+
async updateWorkflowState({
|
|
2680
|
+
workflowName,
|
|
2681
|
+
runId,
|
|
2682
|
+
opts
|
|
2683
|
+
}) {
|
|
2684
|
+
const table = getTableName({ indexName: TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName(this.schema) });
|
|
2685
|
+
const transaction = this.pool.transaction();
|
|
1793
2686
|
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
|
-
|
|
2687
|
+
await transaction.begin();
|
|
2688
|
+
const selectRequest = new sql2.Request(transaction);
|
|
2689
|
+
selectRequest.input("workflow_name", workflowName);
|
|
2690
|
+
selectRequest.input("run_id", runId);
|
|
2691
|
+
const existingSnapshotResult = await selectRequest.query(
|
|
2692
|
+
`SELECT snapshot FROM ${table} WITH (UPDLOCK, HOLDLOCK) WHERE workflow_name = @workflow_name AND run_id = @run_id`
|
|
2693
|
+
);
|
|
2694
|
+
if (!existingSnapshotResult.recordset || existingSnapshotResult.recordset.length === 0) {
|
|
2695
|
+
await transaction.rollback();
|
|
2696
|
+
return void 0;
|
|
2697
|
+
}
|
|
2698
|
+
const existingSnapshot = existingSnapshotResult.recordset[0].snapshot;
|
|
2699
|
+
const snapshot = typeof existingSnapshot === "string" ? JSON.parse(existingSnapshot) : existingSnapshot;
|
|
2700
|
+
if (!snapshot || !snapshot?.context) {
|
|
2701
|
+
await transaction.rollback();
|
|
2702
|
+
throw new MastraError(
|
|
2703
|
+
{
|
|
2704
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_UPDATE_WORKFLOW_STATE_SNAPSHOT_NOT_FOUND",
|
|
2705
|
+
domain: ErrorDomain.STORAGE,
|
|
2706
|
+
category: ErrorCategory.SYSTEM,
|
|
2707
|
+
details: {
|
|
2708
|
+
workflowName,
|
|
2709
|
+
runId
|
|
2710
|
+
}
|
|
2711
|
+
},
|
|
2712
|
+
new Error(`Snapshot not found for runId ${runId}`)
|
|
2713
|
+
);
|
|
2714
|
+
}
|
|
2715
|
+
const updatedSnapshot = { ...snapshot, ...opts };
|
|
2716
|
+
const updateRequest = new sql2.Request(transaction);
|
|
2717
|
+
updateRequest.input("snapshot", JSON.stringify(updatedSnapshot));
|
|
2718
|
+
updateRequest.input("workflow_name", workflowName);
|
|
2719
|
+
updateRequest.input("run_id", runId);
|
|
2720
|
+
updateRequest.input("updatedAt", sql2.DateTime2, /* @__PURE__ */ new Date());
|
|
2721
|
+
await updateRequest.query(
|
|
2722
|
+
`UPDATE ${table} SET snapshot = @snapshot, [updatedAt] = @updatedAt WHERE workflow_name = @workflow_name AND run_id = @run_id`
|
|
2723
|
+
);
|
|
2724
|
+
await transaction.commit();
|
|
2725
|
+
return updatedSnapshot;
|
|
1819
2726
|
} catch (error) {
|
|
2727
|
+
try {
|
|
2728
|
+
await transaction.rollback();
|
|
2729
|
+
} catch {
|
|
2730
|
+
}
|
|
1820
2731
|
throw new MastraError(
|
|
1821
2732
|
{
|
|
1822
|
-
id: "
|
|
2733
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_UPDATE_WORKFLOW_STATE_FAILED",
|
|
1823
2734
|
domain: ErrorDomain.STORAGE,
|
|
1824
2735
|
category: ErrorCategory.THIRD_PARTY,
|
|
1825
2736
|
details: {
|
|
1826
|
-
|
|
1827
|
-
|
|
2737
|
+
workflowName,
|
|
2738
|
+
runId
|
|
1828
2739
|
}
|
|
1829
2740
|
},
|
|
1830
2741
|
error
|
|
1831
2742
|
);
|
|
1832
2743
|
}
|
|
1833
2744
|
}
|
|
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
2745
|
async persistWorkflowSnapshot({
|
|
1891
2746
|
workflowName,
|
|
1892
2747
|
runId,
|
|
2748
|
+
resourceId,
|
|
1893
2749
|
snapshot
|
|
1894
2750
|
}) {
|
|
1895
2751
|
const table = getTableName({ indexName: TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName(this.schema) });
|
|
@@ -1898,6 +2754,7 @@ var WorkflowsMSSQL = class extends WorkflowsStorage {
|
|
|
1898
2754
|
const request = this.pool.request();
|
|
1899
2755
|
request.input("workflow_name", workflowName);
|
|
1900
2756
|
request.input("run_id", runId);
|
|
2757
|
+
request.input("resourceId", resourceId);
|
|
1901
2758
|
request.input("snapshot", JSON.stringify(snapshot));
|
|
1902
2759
|
request.input("createdAt", sql2.DateTime2, new Date(now));
|
|
1903
2760
|
request.input("updatedAt", sql2.DateTime2, new Date(now));
|
|
@@ -1905,10 +2762,11 @@ var WorkflowsMSSQL = class extends WorkflowsStorage {
|
|
|
1905
2762
|
USING (SELECT @workflow_name AS workflow_name, @run_id AS run_id) AS src
|
|
1906
2763
|
ON target.workflow_name = src.workflow_name AND target.run_id = src.run_id
|
|
1907
2764
|
WHEN MATCHED THEN UPDATE SET
|
|
2765
|
+
resourceId = @resourceId,
|
|
1908
2766
|
snapshot = @snapshot,
|
|
1909
2767
|
[updatedAt] = @updatedAt
|
|
1910
|
-
WHEN NOT MATCHED THEN INSERT (workflow_name, run_id, snapshot, [createdAt], [updatedAt])
|
|
1911
|
-
VALUES (@workflow_name, @run_id, @snapshot, @createdAt, @updatedAt);`;
|
|
2768
|
+
WHEN NOT MATCHED THEN INSERT (workflow_name, run_id, resourceId, snapshot, [createdAt], [updatedAt])
|
|
2769
|
+
VALUES (@workflow_name, @run_id, @resourceId, @snapshot, @createdAt, @updatedAt);`;
|
|
1912
2770
|
await request.query(mergeSql);
|
|
1913
2771
|
} catch (error) {
|
|
1914
2772
|
throw new MastraError(
|
|
@@ -1980,7 +2838,7 @@ var WorkflowsMSSQL = class extends WorkflowsStorage {
|
|
|
1980
2838
|
if (!result.recordset || result.recordset.length === 0) {
|
|
1981
2839
|
return null;
|
|
1982
2840
|
}
|
|
1983
|
-
return parseWorkflowRun(result.recordset[0]);
|
|
2841
|
+
return this.parseWorkflowRun(result.recordset[0]);
|
|
1984
2842
|
} catch (error) {
|
|
1985
2843
|
throw new MastraError(
|
|
1986
2844
|
{
|
|
@@ -1996,12 +2854,12 @@ var WorkflowsMSSQL = class extends WorkflowsStorage {
|
|
|
1996
2854
|
);
|
|
1997
2855
|
}
|
|
1998
2856
|
}
|
|
1999
|
-
async
|
|
2857
|
+
async listWorkflowRuns({
|
|
2000
2858
|
workflowName,
|
|
2001
2859
|
fromDate,
|
|
2002
2860
|
toDate,
|
|
2003
|
-
|
|
2004
|
-
|
|
2861
|
+
page,
|
|
2862
|
+
perPage,
|
|
2005
2863
|
resourceId
|
|
2006
2864
|
} = {}) {
|
|
2007
2865
|
try {
|
|
@@ -2017,7 +2875,7 @@ var WorkflowsMSSQL = class extends WorkflowsStorage {
|
|
|
2017
2875
|
conditions.push(`[resourceId] = @resourceId`);
|
|
2018
2876
|
paramMap["resourceId"] = resourceId;
|
|
2019
2877
|
} else {
|
|
2020
|
-
|
|
2878
|
+
this.logger?.warn?.(`[${TABLE_WORKFLOW_SNAPSHOT}] resourceId column not found. Skipping resourceId filter.`);
|
|
2021
2879
|
}
|
|
2022
2880
|
}
|
|
2023
2881
|
if (fromDate instanceof Date && !isNaN(fromDate.getTime())) {
|
|
@@ -2039,24 +2897,27 @@ var WorkflowsMSSQL = class extends WorkflowsStorage {
|
|
|
2039
2897
|
request.input(key, value);
|
|
2040
2898
|
}
|
|
2041
2899
|
});
|
|
2042
|
-
|
|
2900
|
+
const usePagination = typeof perPage === "number" && typeof page === "number";
|
|
2901
|
+
if (usePagination) {
|
|
2043
2902
|
const countQuery = `SELECT COUNT(*) as count FROM ${tableName} ${whereClause}`;
|
|
2044
2903
|
const countResult = await request.query(countQuery);
|
|
2045
2904
|
total = Number(countResult.recordset[0]?.count || 0);
|
|
2046
2905
|
}
|
|
2047
2906
|
let query = `SELECT * FROM ${tableName} ${whereClause} ORDER BY [seq_id] DESC`;
|
|
2048
|
-
if (
|
|
2049
|
-
|
|
2050
|
-
|
|
2907
|
+
if (usePagination) {
|
|
2908
|
+
const normalizedPerPage = normalizePerPage(perPage, Number.MAX_SAFE_INTEGER);
|
|
2909
|
+
const offset = page * normalizedPerPage;
|
|
2910
|
+
query += ` OFFSET @offset ROWS FETCH NEXT @perPage ROWS ONLY`;
|
|
2911
|
+
request.input("perPage", normalizedPerPage);
|
|
2051
2912
|
request.input("offset", offset);
|
|
2052
2913
|
}
|
|
2053
2914
|
const result = await request.query(query);
|
|
2054
|
-
const runs = (result.recordset || []).map((row) => parseWorkflowRun(row));
|
|
2915
|
+
const runs = (result.recordset || []).map((row) => this.parseWorkflowRun(row));
|
|
2055
2916
|
return { runs, total: total || runs.length };
|
|
2056
2917
|
} catch (error) {
|
|
2057
2918
|
throw new MastraError(
|
|
2058
2919
|
{
|
|
2059
|
-
id: "
|
|
2920
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_LIST_WORKFLOW_RUNS_FAILED",
|
|
2060
2921
|
domain: ErrorDomain.STORAGE,
|
|
2061
2922
|
category: ErrorCategory.THIRD_PARTY,
|
|
2062
2923
|
details: {
|
|
@@ -2099,19 +2960,17 @@ var MSSQLStore = class extends MastraStorage {
|
|
|
2099
2960
|
port: config.port,
|
|
2100
2961
|
options: config.options || { encrypt: true, trustServerCertificate: true }
|
|
2101
2962
|
});
|
|
2102
|
-
const legacyEvals = new LegacyEvalsMSSQL({ pool: this.pool, schema: this.schema });
|
|
2103
2963
|
const operations = new StoreOperationsMSSQL({ pool: this.pool, schemaName: this.schema });
|
|
2104
2964
|
const scores = new ScoresMSSQL({ pool: this.pool, operations, schema: this.schema });
|
|
2105
|
-
const traces = new TracesMSSQL({ pool: this.pool, operations, schema: this.schema });
|
|
2106
2965
|
const workflows = new WorkflowsMSSQL({ pool: this.pool, operations, schema: this.schema });
|
|
2107
2966
|
const memory = new MemoryMSSQL({ pool: this.pool, schema: this.schema, operations });
|
|
2967
|
+
const observability = new ObservabilityMSSQL({ pool: this.pool, operations, schema: this.schema });
|
|
2108
2968
|
this.stores = {
|
|
2109
2969
|
operations,
|
|
2110
2970
|
scores,
|
|
2111
|
-
traces,
|
|
2112
2971
|
workflows,
|
|
2113
|
-
|
|
2114
|
-
|
|
2972
|
+
memory,
|
|
2973
|
+
observability
|
|
2115
2974
|
};
|
|
2116
2975
|
} catch (e) {
|
|
2117
2976
|
throw new MastraError(
|
|
@@ -2131,6 +2990,11 @@ var MSSQLStore = class extends MastraStorage {
|
|
|
2131
2990
|
try {
|
|
2132
2991
|
await this.isConnected;
|
|
2133
2992
|
await super.init();
|
|
2993
|
+
try {
|
|
2994
|
+
await this.stores.operations.createAutomaticIndexes();
|
|
2995
|
+
} catch (indexError) {
|
|
2996
|
+
this.logger?.warn?.("Failed to create indexes:", indexError);
|
|
2997
|
+
}
|
|
2134
2998
|
} catch (error) {
|
|
2135
2999
|
this.isConnected = null;
|
|
2136
3000
|
throw new MastraError(
|
|
@@ -2157,28 +3021,12 @@ var MSSQLStore = class extends MastraStorage {
|
|
|
2157
3021
|
resourceWorkingMemory: true,
|
|
2158
3022
|
hasColumn: true,
|
|
2159
3023
|
createTable: true,
|
|
2160
|
-
deleteMessages: true
|
|
3024
|
+
deleteMessages: true,
|
|
3025
|
+
listScoresBySpan: true,
|
|
3026
|
+
observabilityInstance: true,
|
|
3027
|
+
indexManagement: true
|
|
2161
3028
|
};
|
|
2162
3029
|
}
|
|
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
3030
|
async createTable({
|
|
2183
3031
|
tableName,
|
|
2184
3032
|
schema
|
|
@@ -2213,15 +3061,6 @@ var MSSQLStore = class extends MastraStorage {
|
|
|
2213
3061
|
async getThreadById({ threadId }) {
|
|
2214
3062
|
return this.stores.memory.getThreadById({ threadId });
|
|
2215
3063
|
}
|
|
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
3064
|
async saveThread({ thread }) {
|
|
2226
3065
|
return this.stores.memory.saveThread({ thread });
|
|
2227
3066
|
}
|
|
@@ -2235,17 +3074,8 @@ var MSSQLStore = class extends MastraStorage {
|
|
|
2235
3074
|
async deleteThread({ threadId }) {
|
|
2236
3075
|
return this.stores.memory.deleteThread({ threadId });
|
|
2237
3076
|
}
|
|
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);
|
|
3077
|
+
async listMessagesById({ messageIds }) {
|
|
3078
|
+
return this.stores.memory.listMessagesById({ messageIds });
|
|
2249
3079
|
}
|
|
2250
3080
|
async saveMessages(args) {
|
|
2251
3081
|
return this.stores.memory.saveMessages(args);
|
|
@@ -2279,9 +3109,9 @@ var MSSQLStore = class extends MastraStorage {
|
|
|
2279
3109
|
runId,
|
|
2280
3110
|
stepId,
|
|
2281
3111
|
result,
|
|
2282
|
-
|
|
3112
|
+
requestContext
|
|
2283
3113
|
}) {
|
|
2284
|
-
return this.stores.workflows.updateWorkflowResults({ workflowName, runId, stepId, result,
|
|
3114
|
+
return this.stores.workflows.updateWorkflowResults({ workflowName, runId, stepId, result, requestContext });
|
|
2285
3115
|
}
|
|
2286
3116
|
async updateWorkflowState({
|
|
2287
3117
|
workflowName,
|
|
@@ -2293,9 +3123,10 @@ var MSSQLStore = class extends MastraStorage {
|
|
|
2293
3123
|
async persistWorkflowSnapshot({
|
|
2294
3124
|
workflowName,
|
|
2295
3125
|
runId,
|
|
3126
|
+
resourceId,
|
|
2296
3127
|
snapshot
|
|
2297
3128
|
}) {
|
|
2298
|
-
return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, snapshot });
|
|
3129
|
+
return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, resourceId, snapshot });
|
|
2299
3130
|
}
|
|
2300
3131
|
async loadWorkflowSnapshot({
|
|
2301
3132
|
workflowName,
|
|
@@ -2303,15 +3134,15 @@ var MSSQLStore = class extends MastraStorage {
|
|
|
2303
3134
|
}) {
|
|
2304
3135
|
return this.stores.workflows.loadWorkflowSnapshot({ workflowName, runId });
|
|
2305
3136
|
}
|
|
2306
|
-
async
|
|
3137
|
+
async listWorkflowRuns({
|
|
2307
3138
|
workflowName,
|
|
2308
3139
|
fromDate,
|
|
2309
3140
|
toDate,
|
|
2310
|
-
|
|
2311
|
-
|
|
3141
|
+
perPage,
|
|
3142
|
+
page,
|
|
2312
3143
|
resourceId
|
|
2313
3144
|
} = {}) {
|
|
2314
|
-
return this.stores.workflows.
|
|
3145
|
+
return this.stores.workflows.listWorkflowRuns({ workflowName, fromDate, toDate, perPage, page, resourceId });
|
|
2315
3146
|
}
|
|
2316
3147
|
async getWorkflowRunById({
|
|
2317
3148
|
runId,
|
|
@@ -2322,38 +3153,108 @@ var MSSQLStore = class extends MastraStorage {
|
|
|
2322
3153
|
async close() {
|
|
2323
3154
|
await this.pool.close();
|
|
2324
3155
|
}
|
|
3156
|
+
/**
|
|
3157
|
+
* Index Management
|
|
3158
|
+
*/
|
|
3159
|
+
async createIndex(options) {
|
|
3160
|
+
return this.stores.operations.createIndex(options);
|
|
3161
|
+
}
|
|
3162
|
+
async listIndexes(tableName) {
|
|
3163
|
+
return this.stores.operations.listIndexes(tableName);
|
|
3164
|
+
}
|
|
3165
|
+
async describeIndex(indexName) {
|
|
3166
|
+
return this.stores.operations.describeIndex(indexName);
|
|
3167
|
+
}
|
|
3168
|
+
async dropIndex(indexName) {
|
|
3169
|
+
return this.stores.operations.dropIndex(indexName);
|
|
3170
|
+
}
|
|
3171
|
+
/**
|
|
3172
|
+
* Tracing / Observability
|
|
3173
|
+
*/
|
|
3174
|
+
getObservabilityStore() {
|
|
3175
|
+
if (!this.stores.observability) {
|
|
3176
|
+
throw new MastraError({
|
|
3177
|
+
id: "MSSQL_STORE_OBSERVABILITY_NOT_INITIALIZED",
|
|
3178
|
+
domain: ErrorDomain.STORAGE,
|
|
3179
|
+
category: ErrorCategory.SYSTEM,
|
|
3180
|
+
text: "Observability storage is not initialized"
|
|
3181
|
+
});
|
|
3182
|
+
}
|
|
3183
|
+
return this.stores.observability;
|
|
3184
|
+
}
|
|
3185
|
+
async createSpan(span) {
|
|
3186
|
+
return this.getObservabilityStore().createSpan(span);
|
|
3187
|
+
}
|
|
3188
|
+
async updateSpan({
|
|
3189
|
+
spanId,
|
|
3190
|
+
traceId,
|
|
3191
|
+
updates
|
|
3192
|
+
}) {
|
|
3193
|
+
return this.getObservabilityStore().updateSpan({ spanId, traceId, updates });
|
|
3194
|
+
}
|
|
3195
|
+
async getAITrace(traceId) {
|
|
3196
|
+
return this.getObservabilityStore().getAITrace(traceId);
|
|
3197
|
+
}
|
|
3198
|
+
async getAITracesPaginated(args) {
|
|
3199
|
+
return this.getObservabilityStore().getAITracesPaginated(args);
|
|
3200
|
+
}
|
|
3201
|
+
async batchCreateSpans(args) {
|
|
3202
|
+
return this.getObservabilityStore().batchCreateSpans(args);
|
|
3203
|
+
}
|
|
3204
|
+
async batchUpdateSpans(args) {
|
|
3205
|
+
return this.getObservabilityStore().batchUpdateSpans(args);
|
|
3206
|
+
}
|
|
3207
|
+
async batchDeleteAITraces(args) {
|
|
3208
|
+
return this.getObservabilityStore().batchDeleteAITraces(args);
|
|
3209
|
+
}
|
|
2325
3210
|
/**
|
|
2326
3211
|
* Scorers
|
|
2327
3212
|
*/
|
|
2328
3213
|
async getScoreById({ id: _id }) {
|
|
2329
3214
|
return this.stores.scores.getScoreById({ id: _id });
|
|
2330
3215
|
}
|
|
2331
|
-
async
|
|
3216
|
+
async listScoresByScorerId({
|
|
2332
3217
|
scorerId: _scorerId,
|
|
2333
|
-
pagination: _pagination
|
|
3218
|
+
pagination: _pagination,
|
|
3219
|
+
entityId: _entityId,
|
|
3220
|
+
entityType: _entityType,
|
|
3221
|
+
source: _source
|
|
2334
3222
|
}) {
|
|
2335
|
-
return this.stores.scores.
|
|
3223
|
+
return this.stores.scores.listScoresByScorerId({
|
|
3224
|
+
scorerId: _scorerId,
|
|
3225
|
+
pagination: _pagination,
|
|
3226
|
+
entityId: _entityId,
|
|
3227
|
+
entityType: _entityType,
|
|
3228
|
+
source: _source
|
|
3229
|
+
});
|
|
2336
3230
|
}
|
|
2337
3231
|
async saveScore(_score) {
|
|
2338
3232
|
return this.stores.scores.saveScore(_score);
|
|
2339
3233
|
}
|
|
2340
|
-
async
|
|
3234
|
+
async listScoresByRunId({
|
|
2341
3235
|
runId: _runId,
|
|
2342
3236
|
pagination: _pagination
|
|
2343
3237
|
}) {
|
|
2344
|
-
return this.stores.scores.
|
|
3238
|
+
return this.stores.scores.listScoresByRunId({ runId: _runId, pagination: _pagination });
|
|
2345
3239
|
}
|
|
2346
|
-
async
|
|
3240
|
+
async listScoresByEntityId({
|
|
2347
3241
|
entityId: _entityId,
|
|
2348
3242
|
entityType: _entityType,
|
|
2349
3243
|
pagination: _pagination
|
|
2350
3244
|
}) {
|
|
2351
|
-
return this.stores.scores.
|
|
3245
|
+
return this.stores.scores.listScoresByEntityId({
|
|
2352
3246
|
entityId: _entityId,
|
|
2353
3247
|
entityType: _entityType,
|
|
2354
3248
|
pagination: _pagination
|
|
2355
3249
|
});
|
|
2356
3250
|
}
|
|
3251
|
+
async listScoresBySpan({
|
|
3252
|
+
traceId,
|
|
3253
|
+
spanId,
|
|
3254
|
+
pagination: _pagination
|
|
3255
|
+
}) {
|
|
3256
|
+
return this.stores.scores.listScoresBySpan({ traceId, spanId, pagination: _pagination });
|
|
3257
|
+
}
|
|
2357
3258
|
};
|
|
2358
3259
|
|
|
2359
3260
|
export { MSSQLStore };
|