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