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