@mastra/mssql 0.0.0-fix-writer-workflow-resumestream-20251022161252 → 0.0.0-fix-multi-modal-for-cloud-20251028082043
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 +32 -3
- package/README.md +315 -36
- package/dist/index.cjs +1326 -314
- 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 +1327 -315
- package/dist/index.js.map +1 -1
- 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 +3 -2
- 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 +3 -2
- package/dist/storage/domains/workflows/index.d.ts.map +1 -1
- package/dist/storage/index.d.ts +43 -14
- package/dist/storage/index.d.ts.map +1 -1
- package/package.json +6 -6
- 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
|
@@ -2,14 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
var error = require('@mastra/core/error');
|
|
4
4
|
var storage = require('@mastra/core/storage');
|
|
5
|
-
var
|
|
5
|
+
var sql3 = require('mssql');
|
|
6
6
|
var utils = require('@mastra/core/utils');
|
|
7
7
|
var agent = require('@mastra/core/agent');
|
|
8
|
+
var crypto = require('crypto');
|
|
8
9
|
var scores = require('@mastra/core/scores');
|
|
9
10
|
|
|
10
11
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
11
12
|
|
|
12
|
-
var
|
|
13
|
+
var sql3__default = /*#__PURE__*/_interopDefault(sql3);
|
|
13
14
|
|
|
14
15
|
// src/storage/index.ts
|
|
15
16
|
function getSchemaName(schema) {
|
|
@@ -21,6 +22,69 @@ function getTableName({ indexName, schemaName }) {
|
|
|
21
22
|
const quotedSchemaName = schemaName;
|
|
22
23
|
return quotedSchemaName ? `${quotedSchemaName}.${quotedIndexName}` : quotedIndexName;
|
|
23
24
|
}
|
|
25
|
+
function buildDateRangeFilter(dateRange, fieldName) {
|
|
26
|
+
const filters = {};
|
|
27
|
+
if (dateRange?.start) {
|
|
28
|
+
filters[`${fieldName}_gte`] = dateRange.start;
|
|
29
|
+
}
|
|
30
|
+
if (dateRange?.end) {
|
|
31
|
+
filters[`${fieldName}_lte`] = dateRange.end;
|
|
32
|
+
}
|
|
33
|
+
return filters;
|
|
34
|
+
}
|
|
35
|
+
function prepareWhereClause(filters, _schema) {
|
|
36
|
+
const conditions = [];
|
|
37
|
+
const params = {};
|
|
38
|
+
let paramIndex = 1;
|
|
39
|
+
Object.entries(filters).forEach(([key, value]) => {
|
|
40
|
+
if (value === void 0) return;
|
|
41
|
+
const paramName = `p${paramIndex++}`;
|
|
42
|
+
if (key.endsWith("_gte")) {
|
|
43
|
+
const fieldName = key.slice(0, -4);
|
|
44
|
+
conditions.push(`[${utils.parseSqlIdentifier(fieldName, "field name")}] >= @${paramName}`);
|
|
45
|
+
params[paramName] = value instanceof Date ? value.toISOString() : value;
|
|
46
|
+
} else if (key.endsWith("_lte")) {
|
|
47
|
+
const fieldName = key.slice(0, -4);
|
|
48
|
+
conditions.push(`[${utils.parseSqlIdentifier(fieldName, "field name")}] <= @${paramName}`);
|
|
49
|
+
params[paramName] = value instanceof Date ? value.toISOString() : value;
|
|
50
|
+
} else if (value === null) {
|
|
51
|
+
conditions.push(`[${utils.parseSqlIdentifier(key, "field name")}] IS NULL`);
|
|
52
|
+
} else {
|
|
53
|
+
conditions.push(`[${utils.parseSqlIdentifier(key, "field name")}] = @${paramName}`);
|
|
54
|
+
params[paramName] = value instanceof Date ? value.toISOString() : value;
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
return {
|
|
58
|
+
sql: conditions.length > 0 ? ` WHERE ${conditions.join(" AND ")}` : "",
|
|
59
|
+
params
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
function transformFromSqlRow({
|
|
63
|
+
tableName,
|
|
64
|
+
sqlRow
|
|
65
|
+
}) {
|
|
66
|
+
const schema = storage.TABLE_SCHEMAS[tableName];
|
|
67
|
+
const result = {};
|
|
68
|
+
Object.entries(sqlRow).forEach(([key, value]) => {
|
|
69
|
+
const columnSchema = schema?.[key];
|
|
70
|
+
if (columnSchema?.type === "jsonb" && typeof value === "string") {
|
|
71
|
+
try {
|
|
72
|
+
result[key] = JSON.parse(value);
|
|
73
|
+
} catch {
|
|
74
|
+
result[key] = value;
|
|
75
|
+
}
|
|
76
|
+
} else if (columnSchema?.type === "timestamp" && value && typeof value === "string") {
|
|
77
|
+
result[key] = new Date(value);
|
|
78
|
+
} else if (columnSchema?.type === "timestamp" && value instanceof Date) {
|
|
79
|
+
result[key] = value;
|
|
80
|
+
} else if (columnSchema?.type === "boolean") {
|
|
81
|
+
result[key] = Boolean(value);
|
|
82
|
+
} else {
|
|
83
|
+
result[key] = value;
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
return result;
|
|
87
|
+
}
|
|
24
88
|
|
|
25
89
|
// src/storage/domains/legacy-evals/index.ts
|
|
26
90
|
function transformEvalRow(row) {
|
|
@@ -31,7 +95,7 @@ function transformEvalRow(row) {
|
|
|
31
95
|
} catch {
|
|
32
96
|
}
|
|
33
97
|
}
|
|
34
|
-
if (row.
|
|
98
|
+
if (row.result) {
|
|
35
99
|
try {
|
|
36
100
|
resultValue = typeof row.result === "string" ? JSON.parse(row.result) : row.result;
|
|
37
101
|
} catch {
|
|
@@ -77,7 +141,7 @@ var LegacyEvalsMSSQL = class extends storage.LegacyEvalsStorage {
|
|
|
77
141
|
if (error && error.number === 208 && error.message && error.message.includes("Invalid object name")) {
|
|
78
142
|
return [];
|
|
79
143
|
}
|
|
80
|
-
|
|
144
|
+
this.logger?.error?.("Failed to get evals for the specified agent:", error);
|
|
81
145
|
throw error;
|
|
82
146
|
}
|
|
83
147
|
}
|
|
@@ -113,7 +177,7 @@ var LegacyEvalsMSSQL = class extends storage.LegacyEvalsStorage {
|
|
|
113
177
|
const countReq = this.pool.request();
|
|
114
178
|
Object.entries(params).forEach(([key, value]) => {
|
|
115
179
|
if (value instanceof Date) {
|
|
116
|
-
countReq.input(key,
|
|
180
|
+
countReq.input(key, sql3__default.default.DateTime, value);
|
|
117
181
|
} else {
|
|
118
182
|
countReq.input(key, value);
|
|
119
183
|
}
|
|
@@ -132,7 +196,7 @@ var LegacyEvalsMSSQL = class extends storage.LegacyEvalsStorage {
|
|
|
132
196
|
const req = this.pool.request();
|
|
133
197
|
Object.entries(params).forEach(([key, value]) => {
|
|
134
198
|
if (value instanceof Date) {
|
|
135
|
-
req.input(key,
|
|
199
|
+
req.input(key, sql3__default.default.DateTime, value);
|
|
136
200
|
} else {
|
|
137
201
|
req.input(key, value);
|
|
138
202
|
}
|
|
@@ -164,7 +228,7 @@ var LegacyEvalsMSSQL = class extends storage.LegacyEvalsStorage {
|
|
|
164
228
|
error$1
|
|
165
229
|
);
|
|
166
230
|
this.logger?.error?.(mastraError.toString());
|
|
167
|
-
this.logger?.trackException(mastraError);
|
|
231
|
+
this.logger?.trackException?.(mastraError);
|
|
168
232
|
throw mastraError;
|
|
169
233
|
}
|
|
170
234
|
}
|
|
@@ -200,7 +264,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
200
264
|
}
|
|
201
265
|
async getThreadById({ threadId }) {
|
|
202
266
|
try {
|
|
203
|
-
const
|
|
267
|
+
const sql6 = `SELECT
|
|
204
268
|
id,
|
|
205
269
|
[resourceId],
|
|
206
270
|
title,
|
|
@@ -211,7 +275,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
211
275
|
WHERE id = @threadId`;
|
|
212
276
|
const request = this.pool.request();
|
|
213
277
|
request.input("threadId", threadId);
|
|
214
|
-
const resultSet = await request.query(
|
|
278
|
+
const resultSet = await request.query(sql6);
|
|
215
279
|
const thread = resultSet.recordset[0] || null;
|
|
216
280
|
if (!thread) {
|
|
217
281
|
return null;
|
|
@@ -257,7 +321,8 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
257
321
|
};
|
|
258
322
|
}
|
|
259
323
|
const orderByField = orderBy === "createdAt" ? "[createdAt]" : "[updatedAt]";
|
|
260
|
-
const
|
|
324
|
+
const dir = (sortDirection || "DESC").toUpperCase() === "ASC" ? "ASC" : "DESC";
|
|
325
|
+
const dataQuery = `SELECT id, [resourceId], title, metadata, [createdAt], [updatedAt] ${baseQuery} ORDER BY ${orderByField} ${dir} OFFSET @offset ROWS FETCH NEXT @perPage ROWS ONLY`;
|
|
261
326
|
const dataRequest = this.pool.request();
|
|
262
327
|
dataRequest.input("resourceId", resourceId);
|
|
263
328
|
dataRequest.input("perPage", perPage);
|
|
@@ -314,9 +379,14 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
314
379
|
req.input("id", thread.id);
|
|
315
380
|
req.input("resourceId", thread.resourceId);
|
|
316
381
|
req.input("title", thread.title);
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
382
|
+
const metadata = thread.metadata ? JSON.stringify(thread.metadata) : null;
|
|
383
|
+
if (metadata === null) {
|
|
384
|
+
req.input("metadata", sql3__default.default.NVarChar, null);
|
|
385
|
+
} else {
|
|
386
|
+
req.input("metadata", metadata);
|
|
387
|
+
}
|
|
388
|
+
req.input("createdAt", sql3__default.default.DateTime2, thread.createdAt);
|
|
389
|
+
req.input("updatedAt", sql3__default.default.DateTime2, thread.updatedAt);
|
|
320
390
|
await req.query(mergeSql);
|
|
321
391
|
return thread;
|
|
322
392
|
} catch (error$1) {
|
|
@@ -341,7 +411,8 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
341
411
|
try {
|
|
342
412
|
const baseQuery = `FROM ${getTableName({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName(this.schema) })} WHERE [resourceId] = @resourceId`;
|
|
343
413
|
const orderByField = orderBy === "createdAt" ? "[createdAt]" : "[updatedAt]";
|
|
344
|
-
const
|
|
414
|
+
const dir = (sortDirection || "DESC").toUpperCase() === "ASC" ? "ASC" : "DESC";
|
|
415
|
+
const dataQuery = `SELECT id, [resourceId], title, metadata, [createdAt], [updatedAt] ${baseQuery} ORDER BY ${orderByField} ${dir}`;
|
|
345
416
|
const request = this.pool.request();
|
|
346
417
|
request.input("resourceId", resourceId);
|
|
347
418
|
const resultSet = await request.query(dataQuery);
|
|
@@ -384,7 +455,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
384
455
|
};
|
|
385
456
|
try {
|
|
386
457
|
const table = getTableName({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName(this.schema) });
|
|
387
|
-
const
|
|
458
|
+
const sql6 = `UPDATE ${table}
|
|
388
459
|
SET title = @title,
|
|
389
460
|
metadata = @metadata,
|
|
390
461
|
[updatedAt] = @updatedAt
|
|
@@ -395,7 +466,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
395
466
|
req.input("title", title);
|
|
396
467
|
req.input("metadata", JSON.stringify(mergedMetadata));
|
|
397
468
|
req.input("updatedAt", /* @__PURE__ */ new Date());
|
|
398
|
-
const result = await req.query(
|
|
469
|
+
const result = await req.query(sql6);
|
|
399
470
|
let thread = result.recordset && result.recordset[0];
|
|
400
471
|
if (thread && "seq_id" in thread) {
|
|
401
472
|
const { seq_id, ...rest } = thread;
|
|
@@ -590,7 +661,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
590
661
|
error$1
|
|
591
662
|
);
|
|
592
663
|
this.logger?.error?.(mastraError.toString());
|
|
593
|
-
this.logger?.trackException(mastraError);
|
|
664
|
+
this.logger?.trackException?.(mastraError);
|
|
594
665
|
return [];
|
|
595
666
|
}
|
|
596
667
|
}
|
|
@@ -630,7 +701,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
630
701
|
error$1
|
|
631
702
|
);
|
|
632
703
|
this.logger?.error?.(mastraError.toString());
|
|
633
|
-
this.logger?.trackException(mastraError);
|
|
704
|
+
this.logger?.trackException?.(mastraError);
|
|
634
705
|
return [];
|
|
635
706
|
}
|
|
636
707
|
}
|
|
@@ -692,7 +763,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
692
763
|
const parsed = this._parseAndFormatMessages(messages, format);
|
|
693
764
|
return {
|
|
694
765
|
messages: parsed,
|
|
695
|
-
total
|
|
766
|
+
total,
|
|
696
767
|
page,
|
|
697
768
|
perPage,
|
|
698
769
|
hasMore: currentOffset + rows.length < total
|
|
@@ -712,7 +783,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
712
783
|
error$1
|
|
713
784
|
);
|
|
714
785
|
this.logger?.error?.(mastraError.toString());
|
|
715
|
-
this.logger?.trackException(mastraError);
|
|
786
|
+
this.logger?.trackException?.(mastraError);
|
|
716
787
|
return { messages: [], total: 0, page, perPage: perPageInput || 40, hasMore: false };
|
|
717
788
|
}
|
|
718
789
|
}
|
|
@@ -764,7 +835,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
764
835
|
"content",
|
|
765
836
|
typeof message.content === "string" ? message.content : JSON.stringify(message.content)
|
|
766
837
|
);
|
|
767
|
-
request.input("createdAt",
|
|
838
|
+
request.input("createdAt", sql3__default.default.DateTime2, message.createdAt);
|
|
768
839
|
request.input("role", message.role);
|
|
769
840
|
request.input("type", message.type || "v2");
|
|
770
841
|
request.input("resourceId", message.resourceId);
|
|
@@ -783,7 +854,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
783
854
|
await request.query(mergeSql);
|
|
784
855
|
}
|
|
785
856
|
const threadReq = transaction.request();
|
|
786
|
-
threadReq.input("updatedAt",
|
|
857
|
+
threadReq.input("updatedAt", sql3__default.default.DateTime2, /* @__PURE__ */ new Date());
|
|
787
858
|
threadReq.input("id", threadId);
|
|
788
859
|
await threadReq.query(`UPDATE ${tableThreads} SET [updatedAt] = @updatedAt WHERE id = @id`);
|
|
789
860
|
await transaction.commit();
|
|
@@ -979,8 +1050,10 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
979
1050
|
return null;
|
|
980
1051
|
}
|
|
981
1052
|
return {
|
|
982
|
-
|
|
983
|
-
|
|
1053
|
+
id: result.id,
|
|
1054
|
+
createdAt: result.createdAt,
|
|
1055
|
+
updatedAt: result.updatedAt,
|
|
1056
|
+
workingMemory: result.workingMemory,
|
|
984
1057
|
metadata: typeof result.metadata === "string" ? JSON.parse(result.metadata) : result.metadata
|
|
985
1058
|
};
|
|
986
1059
|
} catch (error$1) {
|
|
@@ -994,7 +1067,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
994
1067
|
error$1
|
|
995
1068
|
);
|
|
996
1069
|
this.logger?.error?.(mastraError.toString());
|
|
997
|
-
this.logger?.trackException(mastraError);
|
|
1070
|
+
this.logger?.trackException?.(mastraError);
|
|
998
1071
|
throw mastraError;
|
|
999
1072
|
}
|
|
1000
1073
|
}
|
|
@@ -1003,7 +1076,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
1003
1076
|
tableName: storage.TABLE_RESOURCES,
|
|
1004
1077
|
record: {
|
|
1005
1078
|
...resource,
|
|
1006
|
-
metadata:
|
|
1079
|
+
metadata: resource.metadata
|
|
1007
1080
|
}
|
|
1008
1081
|
});
|
|
1009
1082
|
return resource;
|
|
@@ -1061,20 +1134,337 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
1061
1134
|
error$1
|
|
1062
1135
|
);
|
|
1063
1136
|
this.logger?.error?.(mastraError.toString());
|
|
1064
|
-
this.logger?.trackException(mastraError);
|
|
1137
|
+
this.logger?.trackException?.(mastraError);
|
|
1065
1138
|
throw mastraError;
|
|
1066
1139
|
}
|
|
1067
1140
|
}
|
|
1068
1141
|
};
|
|
1142
|
+
var ObservabilityMSSQL = class extends storage.ObservabilityStorage {
|
|
1143
|
+
pool;
|
|
1144
|
+
operations;
|
|
1145
|
+
schema;
|
|
1146
|
+
constructor({
|
|
1147
|
+
pool,
|
|
1148
|
+
operations,
|
|
1149
|
+
schema
|
|
1150
|
+
}) {
|
|
1151
|
+
super();
|
|
1152
|
+
this.pool = pool;
|
|
1153
|
+
this.operations = operations;
|
|
1154
|
+
this.schema = schema;
|
|
1155
|
+
}
|
|
1156
|
+
get aiTracingStrategy() {
|
|
1157
|
+
return {
|
|
1158
|
+
preferred: "batch-with-updates",
|
|
1159
|
+
supported: ["batch-with-updates", "insert-only"]
|
|
1160
|
+
};
|
|
1161
|
+
}
|
|
1162
|
+
async createAISpan(span) {
|
|
1163
|
+
try {
|
|
1164
|
+
const startedAt = span.startedAt instanceof Date ? span.startedAt.toISOString() : span.startedAt;
|
|
1165
|
+
const endedAt = span.endedAt instanceof Date ? span.endedAt.toISOString() : span.endedAt;
|
|
1166
|
+
const record = {
|
|
1167
|
+
...span,
|
|
1168
|
+
startedAt,
|
|
1169
|
+
endedAt
|
|
1170
|
+
// Note: createdAt/updatedAt will be set by default values
|
|
1171
|
+
};
|
|
1172
|
+
return this.operations.insert({ tableName: storage.TABLE_AI_SPANS, record });
|
|
1173
|
+
} catch (error$1) {
|
|
1174
|
+
throw new error.MastraError(
|
|
1175
|
+
{
|
|
1176
|
+
id: "MSSQL_STORE_CREATE_AI_SPAN_FAILED",
|
|
1177
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1178
|
+
category: error.ErrorCategory.USER,
|
|
1179
|
+
details: {
|
|
1180
|
+
spanId: span.spanId,
|
|
1181
|
+
traceId: span.traceId,
|
|
1182
|
+
spanType: span.spanType,
|
|
1183
|
+
spanName: span.name
|
|
1184
|
+
}
|
|
1185
|
+
},
|
|
1186
|
+
error$1
|
|
1187
|
+
);
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
async getAITrace(traceId) {
|
|
1191
|
+
try {
|
|
1192
|
+
const tableName = getTableName({
|
|
1193
|
+
indexName: storage.TABLE_AI_SPANS,
|
|
1194
|
+
schemaName: getSchemaName(this.schema)
|
|
1195
|
+
});
|
|
1196
|
+
const request = this.pool.request();
|
|
1197
|
+
request.input("traceId", traceId);
|
|
1198
|
+
const result = await request.query(
|
|
1199
|
+
`SELECT
|
|
1200
|
+
[traceId], [spanId], [parentSpanId], [name], [scope], [spanType],
|
|
1201
|
+
[attributes], [metadata], [links], [input], [output], [error], [isEvent],
|
|
1202
|
+
[startedAt], [endedAt], [createdAt], [updatedAt]
|
|
1203
|
+
FROM ${tableName}
|
|
1204
|
+
WHERE [traceId] = @traceId
|
|
1205
|
+
ORDER BY [startedAt] DESC`
|
|
1206
|
+
);
|
|
1207
|
+
if (!result.recordset || result.recordset.length === 0) {
|
|
1208
|
+
return null;
|
|
1209
|
+
}
|
|
1210
|
+
return {
|
|
1211
|
+
traceId,
|
|
1212
|
+
spans: result.recordset.map(
|
|
1213
|
+
(span) => transformFromSqlRow({
|
|
1214
|
+
tableName: storage.TABLE_AI_SPANS,
|
|
1215
|
+
sqlRow: span
|
|
1216
|
+
})
|
|
1217
|
+
)
|
|
1218
|
+
};
|
|
1219
|
+
} catch (error$1) {
|
|
1220
|
+
throw new error.MastraError(
|
|
1221
|
+
{
|
|
1222
|
+
id: "MSSQL_STORE_GET_AI_TRACE_FAILED",
|
|
1223
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1224
|
+
category: error.ErrorCategory.USER,
|
|
1225
|
+
details: {
|
|
1226
|
+
traceId
|
|
1227
|
+
}
|
|
1228
|
+
},
|
|
1229
|
+
error$1
|
|
1230
|
+
);
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
async updateAISpan({
|
|
1234
|
+
spanId,
|
|
1235
|
+
traceId,
|
|
1236
|
+
updates
|
|
1237
|
+
}) {
|
|
1238
|
+
try {
|
|
1239
|
+
const data = { ...updates };
|
|
1240
|
+
if (data.endedAt instanceof Date) {
|
|
1241
|
+
data.endedAt = data.endedAt.toISOString();
|
|
1242
|
+
}
|
|
1243
|
+
if (data.startedAt instanceof Date) {
|
|
1244
|
+
data.startedAt = data.startedAt.toISOString();
|
|
1245
|
+
}
|
|
1246
|
+
await this.operations.update({
|
|
1247
|
+
tableName: storage.TABLE_AI_SPANS,
|
|
1248
|
+
keys: { spanId, traceId },
|
|
1249
|
+
data
|
|
1250
|
+
});
|
|
1251
|
+
} catch (error$1) {
|
|
1252
|
+
throw new error.MastraError(
|
|
1253
|
+
{
|
|
1254
|
+
id: "MSSQL_STORE_UPDATE_AI_SPAN_FAILED",
|
|
1255
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1256
|
+
category: error.ErrorCategory.USER,
|
|
1257
|
+
details: {
|
|
1258
|
+
spanId,
|
|
1259
|
+
traceId
|
|
1260
|
+
}
|
|
1261
|
+
},
|
|
1262
|
+
error$1
|
|
1263
|
+
);
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
async getAITracesPaginated({
|
|
1267
|
+
filters,
|
|
1268
|
+
pagination
|
|
1269
|
+
}) {
|
|
1270
|
+
const page = pagination?.page ?? 0;
|
|
1271
|
+
const perPage = pagination?.perPage ?? 10;
|
|
1272
|
+
const { entityId, entityType, ...actualFilters } = filters || {};
|
|
1273
|
+
const filtersWithDateRange = {
|
|
1274
|
+
...actualFilters,
|
|
1275
|
+
...buildDateRangeFilter(pagination?.dateRange, "startedAt"),
|
|
1276
|
+
parentSpanId: null
|
|
1277
|
+
// Only get root spans for traces
|
|
1278
|
+
};
|
|
1279
|
+
const whereClause = prepareWhereClause(filtersWithDateRange);
|
|
1280
|
+
let actualWhereClause = whereClause.sql;
|
|
1281
|
+
const params = { ...whereClause.params };
|
|
1282
|
+
let currentParamIndex = Object.keys(params).length + 1;
|
|
1283
|
+
if (entityId && entityType) {
|
|
1284
|
+
let name = "";
|
|
1285
|
+
if (entityType === "workflow") {
|
|
1286
|
+
name = `workflow run: '${entityId}'`;
|
|
1287
|
+
} else if (entityType === "agent") {
|
|
1288
|
+
name = `agent run: '${entityId}'`;
|
|
1289
|
+
} else {
|
|
1290
|
+
const error$1 = new error.MastraError({
|
|
1291
|
+
id: "MSSQL_STORE_GET_AI_TRACES_PAGINATED_FAILED",
|
|
1292
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1293
|
+
category: error.ErrorCategory.USER,
|
|
1294
|
+
details: {
|
|
1295
|
+
entityType
|
|
1296
|
+
},
|
|
1297
|
+
text: `Cannot filter by entity type: ${entityType}`
|
|
1298
|
+
});
|
|
1299
|
+
throw error$1;
|
|
1300
|
+
}
|
|
1301
|
+
const entityParam = `p${currentParamIndex++}`;
|
|
1302
|
+
if (actualWhereClause) {
|
|
1303
|
+
actualWhereClause += ` AND [name] = @${entityParam}`;
|
|
1304
|
+
} else {
|
|
1305
|
+
actualWhereClause = ` WHERE [name] = @${entityParam}`;
|
|
1306
|
+
}
|
|
1307
|
+
params[entityParam] = name;
|
|
1308
|
+
}
|
|
1309
|
+
const tableName = getTableName({
|
|
1310
|
+
indexName: storage.TABLE_AI_SPANS,
|
|
1311
|
+
schemaName: getSchemaName(this.schema)
|
|
1312
|
+
});
|
|
1313
|
+
try {
|
|
1314
|
+
const countRequest = this.pool.request();
|
|
1315
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
1316
|
+
countRequest.input(key, value);
|
|
1317
|
+
});
|
|
1318
|
+
const countResult = await countRequest.query(
|
|
1319
|
+
`SELECT COUNT(*) as count FROM ${tableName}${actualWhereClause}`
|
|
1320
|
+
);
|
|
1321
|
+
const total = countResult.recordset[0]?.count ?? 0;
|
|
1322
|
+
if (total === 0) {
|
|
1323
|
+
return {
|
|
1324
|
+
pagination: {
|
|
1325
|
+
total: 0,
|
|
1326
|
+
page,
|
|
1327
|
+
perPage,
|
|
1328
|
+
hasMore: false
|
|
1329
|
+
},
|
|
1330
|
+
spans: []
|
|
1331
|
+
};
|
|
1332
|
+
}
|
|
1333
|
+
const dataRequest = this.pool.request();
|
|
1334
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
1335
|
+
dataRequest.input(key, value);
|
|
1336
|
+
});
|
|
1337
|
+
dataRequest.input("offset", page * perPage);
|
|
1338
|
+
dataRequest.input("limit", perPage);
|
|
1339
|
+
const dataResult = await dataRequest.query(
|
|
1340
|
+
`SELECT * FROM ${tableName}${actualWhereClause} ORDER BY [startedAt] DESC OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY`
|
|
1341
|
+
);
|
|
1342
|
+
const spans = dataResult.recordset.map(
|
|
1343
|
+
(row) => transformFromSqlRow({
|
|
1344
|
+
tableName: storage.TABLE_AI_SPANS,
|
|
1345
|
+
sqlRow: row
|
|
1346
|
+
})
|
|
1347
|
+
);
|
|
1348
|
+
return {
|
|
1349
|
+
pagination: {
|
|
1350
|
+
total,
|
|
1351
|
+
page,
|
|
1352
|
+
perPage,
|
|
1353
|
+
hasMore: (page + 1) * perPage < total
|
|
1354
|
+
},
|
|
1355
|
+
spans
|
|
1356
|
+
};
|
|
1357
|
+
} catch (error$1) {
|
|
1358
|
+
throw new error.MastraError(
|
|
1359
|
+
{
|
|
1360
|
+
id: "MSSQL_STORE_GET_AI_TRACES_PAGINATED_FAILED",
|
|
1361
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1362
|
+
category: error.ErrorCategory.USER
|
|
1363
|
+
},
|
|
1364
|
+
error$1
|
|
1365
|
+
);
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
async batchCreateAISpans(args) {
|
|
1369
|
+
if (!args.records || args.records.length === 0) {
|
|
1370
|
+
return;
|
|
1371
|
+
}
|
|
1372
|
+
try {
|
|
1373
|
+
await this.operations.batchInsert({
|
|
1374
|
+
tableName: storage.TABLE_AI_SPANS,
|
|
1375
|
+
records: args.records.map((span) => ({
|
|
1376
|
+
...span,
|
|
1377
|
+
startedAt: span.startedAt instanceof Date ? span.startedAt.toISOString() : span.startedAt,
|
|
1378
|
+
endedAt: span.endedAt instanceof Date ? span.endedAt.toISOString() : span.endedAt
|
|
1379
|
+
}))
|
|
1380
|
+
});
|
|
1381
|
+
} catch (error$1) {
|
|
1382
|
+
throw new error.MastraError(
|
|
1383
|
+
{
|
|
1384
|
+
id: "MSSQL_STORE_BATCH_CREATE_AI_SPANS_FAILED",
|
|
1385
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1386
|
+
category: error.ErrorCategory.USER,
|
|
1387
|
+
details: {
|
|
1388
|
+
count: args.records.length
|
|
1389
|
+
}
|
|
1390
|
+
},
|
|
1391
|
+
error$1
|
|
1392
|
+
);
|
|
1393
|
+
}
|
|
1394
|
+
}
|
|
1395
|
+
async batchUpdateAISpans(args) {
|
|
1396
|
+
if (!args.records || args.records.length === 0) {
|
|
1397
|
+
return;
|
|
1398
|
+
}
|
|
1399
|
+
try {
|
|
1400
|
+
const updates = args.records.map(({ traceId, spanId, updates: data }) => {
|
|
1401
|
+
const processedData = { ...data };
|
|
1402
|
+
if (processedData.endedAt instanceof Date) {
|
|
1403
|
+
processedData.endedAt = processedData.endedAt.toISOString();
|
|
1404
|
+
}
|
|
1405
|
+
if (processedData.startedAt instanceof Date) {
|
|
1406
|
+
processedData.startedAt = processedData.startedAt.toISOString();
|
|
1407
|
+
}
|
|
1408
|
+
return {
|
|
1409
|
+
keys: { spanId, traceId },
|
|
1410
|
+
data: processedData
|
|
1411
|
+
};
|
|
1412
|
+
});
|
|
1413
|
+
await this.operations.batchUpdate({
|
|
1414
|
+
tableName: storage.TABLE_AI_SPANS,
|
|
1415
|
+
updates
|
|
1416
|
+
});
|
|
1417
|
+
} catch (error$1) {
|
|
1418
|
+
throw new error.MastraError(
|
|
1419
|
+
{
|
|
1420
|
+
id: "MSSQL_STORE_BATCH_UPDATE_AI_SPANS_FAILED",
|
|
1421
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1422
|
+
category: error.ErrorCategory.USER,
|
|
1423
|
+
details: {
|
|
1424
|
+
count: args.records.length
|
|
1425
|
+
}
|
|
1426
|
+
},
|
|
1427
|
+
error$1
|
|
1428
|
+
);
|
|
1429
|
+
}
|
|
1430
|
+
}
|
|
1431
|
+
async batchDeleteAITraces(args) {
|
|
1432
|
+
if (!args.traceIds || args.traceIds.length === 0) {
|
|
1433
|
+
return;
|
|
1434
|
+
}
|
|
1435
|
+
try {
|
|
1436
|
+
const keys = args.traceIds.map((traceId) => ({ traceId }));
|
|
1437
|
+
await this.operations.batchDelete({
|
|
1438
|
+
tableName: storage.TABLE_AI_SPANS,
|
|
1439
|
+
keys
|
|
1440
|
+
});
|
|
1441
|
+
} catch (error$1) {
|
|
1442
|
+
throw new error.MastraError(
|
|
1443
|
+
{
|
|
1444
|
+
id: "MSSQL_STORE_BATCH_DELETE_AI_TRACES_FAILED",
|
|
1445
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1446
|
+
category: error.ErrorCategory.USER,
|
|
1447
|
+
details: {
|
|
1448
|
+
count: args.traceIds.length
|
|
1449
|
+
}
|
|
1450
|
+
},
|
|
1451
|
+
error$1
|
|
1452
|
+
);
|
|
1453
|
+
}
|
|
1454
|
+
}
|
|
1455
|
+
};
|
|
1069
1456
|
var StoreOperationsMSSQL = class extends storage.StoreOperations {
|
|
1070
1457
|
pool;
|
|
1071
1458
|
schemaName;
|
|
1072
1459
|
setupSchemaPromise = null;
|
|
1073
1460
|
schemaSetupComplete = void 0;
|
|
1074
|
-
getSqlType(type, isPrimaryKey = false) {
|
|
1461
|
+
getSqlType(type, isPrimaryKey = false, useLargeStorage = false) {
|
|
1075
1462
|
switch (type) {
|
|
1076
1463
|
case "text":
|
|
1077
|
-
|
|
1464
|
+
if (useLargeStorage) {
|
|
1465
|
+
return "NVARCHAR(MAX)";
|
|
1466
|
+
}
|
|
1467
|
+
return isPrimaryKey ? "NVARCHAR(255)" : "NVARCHAR(400)";
|
|
1078
1468
|
case "timestamp":
|
|
1079
1469
|
return "DATETIME2(7)";
|
|
1080
1470
|
case "uuid":
|
|
@@ -1087,6 +1477,8 @@ var StoreOperationsMSSQL = class extends storage.StoreOperations {
|
|
|
1087
1477
|
return "BIGINT";
|
|
1088
1478
|
case "float":
|
|
1089
1479
|
return "FLOAT";
|
|
1480
|
+
case "boolean":
|
|
1481
|
+
return "BIT";
|
|
1090
1482
|
default:
|
|
1091
1483
|
throw new error.MastraError({
|
|
1092
1484
|
id: "MASTRA_STORAGE_MSSQL_STORE_TYPE_NOT_SUPPORTED",
|
|
@@ -1149,20 +1541,26 @@ var StoreOperationsMSSQL = class extends storage.StoreOperations {
|
|
|
1149
1541
|
}
|
|
1150
1542
|
await this.setupSchemaPromise;
|
|
1151
1543
|
}
|
|
1152
|
-
async insert({
|
|
1544
|
+
async insert({
|
|
1545
|
+
tableName,
|
|
1546
|
+
record,
|
|
1547
|
+
transaction
|
|
1548
|
+
}) {
|
|
1153
1549
|
try {
|
|
1154
|
-
const columns = Object.keys(record)
|
|
1155
|
-
const
|
|
1156
|
-
const paramNames =
|
|
1157
|
-
const insertSql = `INSERT INTO ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} (${
|
|
1158
|
-
const request = this.pool.request();
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
request.input(`param${i}`,
|
|
1550
|
+
const columns = Object.keys(record);
|
|
1551
|
+
const parsedColumns = columns.map((col) => utils.parseSqlIdentifier(col, "column name"));
|
|
1552
|
+
const paramNames = columns.map((_, i) => `@param${i}`);
|
|
1553
|
+
const insertSql = `INSERT INTO ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} (${parsedColumns.map((c) => `[${c}]`).join(", ")}) VALUES (${paramNames.join(", ")})`;
|
|
1554
|
+
const request = transaction ? transaction.request() : this.pool.request();
|
|
1555
|
+
columns.forEach((col, i) => {
|
|
1556
|
+
const value = record[col];
|
|
1557
|
+
const preparedValue = this.prepareValue(value, col, tableName);
|
|
1558
|
+
if (preparedValue instanceof Date) {
|
|
1559
|
+
request.input(`param${i}`, sql3__default.default.DateTime2, preparedValue);
|
|
1560
|
+
} else if (preparedValue === null || preparedValue === void 0) {
|
|
1561
|
+
request.input(`param${i}`, this.getMssqlType(tableName, col), null);
|
|
1164
1562
|
} else {
|
|
1165
|
-
request.input(`param${i}`,
|
|
1563
|
+
request.input(`param${i}`, preparedValue);
|
|
1166
1564
|
}
|
|
1167
1565
|
});
|
|
1168
1566
|
await request.query(insertSql);
|
|
@@ -1186,7 +1584,7 @@ var StoreOperationsMSSQL = class extends storage.StoreOperations {
|
|
|
1186
1584
|
try {
|
|
1187
1585
|
await this.pool.request().query(`TRUNCATE TABLE ${fullTableName}`);
|
|
1188
1586
|
} catch (truncateError) {
|
|
1189
|
-
if (truncateError
|
|
1587
|
+
if (truncateError?.number === 4712) {
|
|
1190
1588
|
await this.pool.request().query(`DELETE FROM ${fullTableName}`);
|
|
1191
1589
|
} else {
|
|
1192
1590
|
throw truncateError;
|
|
@@ -1209,9 +1607,11 @@ var StoreOperationsMSSQL = class extends storage.StoreOperations {
|
|
|
1209
1607
|
getDefaultValue(type) {
|
|
1210
1608
|
switch (type) {
|
|
1211
1609
|
case "timestamp":
|
|
1212
|
-
return "DEFAULT
|
|
1610
|
+
return "DEFAULT SYSUTCDATETIME()";
|
|
1213
1611
|
case "jsonb":
|
|
1214
1612
|
return "DEFAULT N'{}'";
|
|
1613
|
+
case "boolean":
|
|
1614
|
+
return "DEFAULT 0";
|
|
1215
1615
|
default:
|
|
1216
1616
|
return super.getDefaultValue(type);
|
|
1217
1617
|
}
|
|
@@ -1222,13 +1622,29 @@ var StoreOperationsMSSQL = class extends storage.StoreOperations {
|
|
|
1222
1622
|
}) {
|
|
1223
1623
|
try {
|
|
1224
1624
|
const uniqueConstraintColumns = tableName === storage.TABLE_WORKFLOW_SNAPSHOT ? ["workflow_name", "run_id"] : [];
|
|
1625
|
+
const largeDataColumns = [
|
|
1626
|
+
"workingMemory",
|
|
1627
|
+
"snapshot",
|
|
1628
|
+
"metadata",
|
|
1629
|
+
"content",
|
|
1630
|
+
// messages.content - can be very long conversation content
|
|
1631
|
+
"input",
|
|
1632
|
+
// evals.input - test input data
|
|
1633
|
+
"output",
|
|
1634
|
+
// evals.output - test output data
|
|
1635
|
+
"instructions",
|
|
1636
|
+
// evals.instructions - evaluation instructions
|
|
1637
|
+
"other"
|
|
1638
|
+
// traces.other - additional trace data
|
|
1639
|
+
];
|
|
1225
1640
|
const columns = Object.entries(schema).map(([name, def]) => {
|
|
1226
1641
|
const parsedName = utils.parseSqlIdentifier(name, "column name");
|
|
1227
1642
|
const constraints = [];
|
|
1228
1643
|
if (def.primaryKey) constraints.push("PRIMARY KEY");
|
|
1229
1644
|
if (!def.nullable) constraints.push("NOT NULL");
|
|
1230
1645
|
const isIndexed = !!def.primaryKey || uniqueConstraintColumns.includes(name);
|
|
1231
|
-
|
|
1646
|
+
const useLargeStorage = largeDataColumns.includes(name);
|
|
1647
|
+
return `[${parsedName}] ${this.getSqlType(def.type, isIndexed, useLargeStorage)} ${constraints.join(" ")}`.trim();
|
|
1232
1648
|
}).join(",\n");
|
|
1233
1649
|
if (this.schemaName) {
|
|
1234
1650
|
await this.setupSchema();
|
|
@@ -1315,7 +1731,19 @@ ${columns}
|
|
|
1315
1731
|
const columnExists = Array.isArray(checkResult.recordset) && checkResult.recordset.length > 0;
|
|
1316
1732
|
if (!columnExists) {
|
|
1317
1733
|
const columnDef = schema[columnName];
|
|
1318
|
-
const
|
|
1734
|
+
const largeDataColumns = [
|
|
1735
|
+
"workingMemory",
|
|
1736
|
+
"snapshot",
|
|
1737
|
+
"metadata",
|
|
1738
|
+
"content",
|
|
1739
|
+
"input",
|
|
1740
|
+
"output",
|
|
1741
|
+
"instructions",
|
|
1742
|
+
"other"
|
|
1743
|
+
];
|
|
1744
|
+
const useLargeStorage = largeDataColumns.includes(columnName);
|
|
1745
|
+
const isIndexed = !!columnDef.primaryKey;
|
|
1746
|
+
const sqlType = this.getSqlType(columnDef.type, isIndexed, useLargeStorage);
|
|
1319
1747
|
const nullable = columnDef.nullable === false ? "NOT NULL" : "";
|
|
1320
1748
|
const defaultValue = columnDef.nullable === false ? this.getDefaultValue(columnDef.type) : "";
|
|
1321
1749
|
const parsedColumnName = utils.parseSqlIdentifier(columnName, "column name");
|
|
@@ -1343,13 +1771,17 @@ ${columns}
|
|
|
1343
1771
|
try {
|
|
1344
1772
|
const keyEntries = Object.entries(keys).map(([key, value]) => [utils.parseSqlIdentifier(key, "column name"), value]);
|
|
1345
1773
|
const conditions = keyEntries.map(([key], i) => `[${key}] = @param${i}`).join(" AND ");
|
|
1346
|
-
const
|
|
1347
|
-
const sql7 = `SELECT * FROM ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} WHERE ${conditions}`;
|
|
1774
|
+
const sql6 = `SELECT * FROM ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} WHERE ${conditions}`;
|
|
1348
1775
|
const request = this.pool.request();
|
|
1349
|
-
|
|
1350
|
-
|
|
1776
|
+
keyEntries.forEach(([key, value], i) => {
|
|
1777
|
+
const preparedValue = this.prepareValue(value, key, tableName);
|
|
1778
|
+
if (preparedValue === null || preparedValue === void 0) {
|
|
1779
|
+
request.input(`param${i}`, this.getMssqlType(tableName, key), null);
|
|
1780
|
+
} else {
|
|
1781
|
+
request.input(`param${i}`, preparedValue);
|
|
1782
|
+
}
|
|
1351
1783
|
});
|
|
1352
|
-
const resultSet = await request.query(
|
|
1784
|
+
const resultSet = await request.query(sql6);
|
|
1353
1785
|
const result = resultSet.recordset[0] || null;
|
|
1354
1786
|
if (!result) {
|
|
1355
1787
|
return null;
|
|
@@ -1381,7 +1813,7 @@ ${columns}
|
|
|
1381
1813
|
try {
|
|
1382
1814
|
await transaction.begin();
|
|
1383
1815
|
for (const record of records) {
|
|
1384
|
-
await this.insert({ tableName, record });
|
|
1816
|
+
await this.insert({ tableName, record, transaction });
|
|
1385
1817
|
}
|
|
1386
1818
|
await transaction.commit();
|
|
1387
1819
|
} catch (error$1) {
|
|
@@ -1418,51 +1850,592 @@ ${columns}
|
|
|
1418
1850
|
);
|
|
1419
1851
|
}
|
|
1420
1852
|
}
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1853
|
+
/**
|
|
1854
|
+
* Prepares a value for database operations, handling Date objects and JSON serialization
|
|
1855
|
+
*/
|
|
1856
|
+
prepareValue(value, columnName, tableName) {
|
|
1857
|
+
if (value === null || value === void 0) {
|
|
1858
|
+
return value;
|
|
1859
|
+
}
|
|
1860
|
+
if (value instanceof Date) {
|
|
1861
|
+
return value;
|
|
1862
|
+
}
|
|
1863
|
+
const schema = storage.TABLE_SCHEMAS[tableName];
|
|
1864
|
+
const columnSchema = schema?.[columnName];
|
|
1865
|
+
if (columnSchema?.type === "boolean") {
|
|
1866
|
+
return value ? 1 : 0;
|
|
1867
|
+
}
|
|
1868
|
+
if (columnSchema?.type === "jsonb") {
|
|
1869
|
+
return JSON.stringify(value);
|
|
1870
|
+
}
|
|
1871
|
+
if (typeof value === "object") {
|
|
1872
|
+
return JSON.stringify(value);
|
|
1873
|
+
}
|
|
1874
|
+
return value;
|
|
1427
1875
|
}
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
}) {
|
|
1454
|
-
super();
|
|
1455
|
-
this.pool = pool;
|
|
1456
|
-
this.operations = operations;
|
|
1457
|
-
this.schema = schema;
|
|
1876
|
+
/**
|
|
1877
|
+
* Maps TABLE_SCHEMAS types to mssql param types (used when value is null)
|
|
1878
|
+
*/
|
|
1879
|
+
getMssqlType(tableName, columnName) {
|
|
1880
|
+
const col = storage.TABLE_SCHEMAS[tableName]?.[columnName];
|
|
1881
|
+
switch (col?.type) {
|
|
1882
|
+
case "text":
|
|
1883
|
+
return sql3__default.default.NVarChar;
|
|
1884
|
+
case "timestamp":
|
|
1885
|
+
return sql3__default.default.DateTime2;
|
|
1886
|
+
case "uuid":
|
|
1887
|
+
return sql3__default.default.UniqueIdentifier;
|
|
1888
|
+
case "jsonb":
|
|
1889
|
+
return sql3__default.default.NVarChar;
|
|
1890
|
+
case "integer":
|
|
1891
|
+
return sql3__default.default.Int;
|
|
1892
|
+
case "bigint":
|
|
1893
|
+
return sql3__default.default.BigInt;
|
|
1894
|
+
case "float":
|
|
1895
|
+
return sql3__default.default.Float;
|
|
1896
|
+
case "boolean":
|
|
1897
|
+
return sql3__default.default.Bit;
|
|
1898
|
+
default:
|
|
1899
|
+
return sql3__default.default.NVarChar;
|
|
1900
|
+
}
|
|
1458
1901
|
}
|
|
1459
|
-
|
|
1902
|
+
/**
|
|
1903
|
+
* Update a single record in the database
|
|
1904
|
+
*/
|
|
1905
|
+
async update({
|
|
1906
|
+
tableName,
|
|
1907
|
+
keys,
|
|
1908
|
+
data,
|
|
1909
|
+
transaction
|
|
1910
|
+
}) {
|
|
1460
1911
|
try {
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1912
|
+
if (!data || Object.keys(data).length === 0) {
|
|
1913
|
+
throw new error.MastraError({
|
|
1914
|
+
id: "MASTRA_STORAGE_MSSQL_UPDATE_EMPTY_DATA",
|
|
1915
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1916
|
+
category: error.ErrorCategory.USER,
|
|
1917
|
+
text: "Cannot update with empty data payload"
|
|
1918
|
+
});
|
|
1919
|
+
}
|
|
1920
|
+
if (!keys || Object.keys(keys).length === 0) {
|
|
1921
|
+
throw new error.MastraError({
|
|
1922
|
+
id: "MASTRA_STORAGE_MSSQL_UPDATE_EMPTY_KEYS",
|
|
1923
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1924
|
+
category: error.ErrorCategory.USER,
|
|
1925
|
+
text: "Cannot update without keys to identify records"
|
|
1926
|
+
});
|
|
1927
|
+
}
|
|
1928
|
+
const setClauses = [];
|
|
1929
|
+
const request = transaction ? transaction.request() : this.pool.request();
|
|
1930
|
+
let paramIndex = 0;
|
|
1931
|
+
Object.entries(data).forEach(([key, value]) => {
|
|
1932
|
+
const parsedKey = utils.parseSqlIdentifier(key, "column name");
|
|
1933
|
+
const paramName = `set${paramIndex++}`;
|
|
1934
|
+
setClauses.push(`[${parsedKey}] = @${paramName}`);
|
|
1935
|
+
const preparedValue = this.prepareValue(value, key, tableName);
|
|
1936
|
+
if (preparedValue === null || preparedValue === void 0) {
|
|
1937
|
+
request.input(paramName, this.getMssqlType(tableName, key), null);
|
|
1938
|
+
} else {
|
|
1939
|
+
request.input(paramName, preparedValue);
|
|
1940
|
+
}
|
|
1941
|
+
});
|
|
1942
|
+
const whereConditions = [];
|
|
1943
|
+
Object.entries(keys).forEach(([key, value]) => {
|
|
1944
|
+
const parsedKey = utils.parseSqlIdentifier(key, "column name");
|
|
1945
|
+
const paramName = `where${paramIndex++}`;
|
|
1946
|
+
whereConditions.push(`[${parsedKey}] = @${paramName}`);
|
|
1947
|
+
const preparedValue = this.prepareValue(value, key, tableName);
|
|
1948
|
+
if (preparedValue === null || preparedValue === void 0) {
|
|
1949
|
+
request.input(paramName, this.getMssqlType(tableName, key), null);
|
|
1950
|
+
} else {
|
|
1951
|
+
request.input(paramName, preparedValue);
|
|
1952
|
+
}
|
|
1953
|
+
});
|
|
1954
|
+
const tableName_ = getTableName({
|
|
1955
|
+
indexName: tableName,
|
|
1956
|
+
schemaName: getSchemaName(this.schemaName)
|
|
1957
|
+
});
|
|
1958
|
+
const updateSql = `UPDATE ${tableName_} SET ${setClauses.join(", ")} WHERE ${whereConditions.join(" AND ")}`;
|
|
1959
|
+
await request.query(updateSql);
|
|
1960
|
+
} catch (error$1) {
|
|
1961
|
+
throw new error.MastraError(
|
|
1962
|
+
{
|
|
1963
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_UPDATE_FAILED",
|
|
1964
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1965
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1966
|
+
details: {
|
|
1967
|
+
tableName
|
|
1968
|
+
}
|
|
1969
|
+
},
|
|
1970
|
+
error$1
|
|
1971
|
+
);
|
|
1972
|
+
}
|
|
1973
|
+
}
|
|
1974
|
+
/**
|
|
1975
|
+
* Update multiple records in a single batch transaction
|
|
1976
|
+
*/
|
|
1977
|
+
async batchUpdate({
|
|
1978
|
+
tableName,
|
|
1979
|
+
updates
|
|
1980
|
+
}) {
|
|
1981
|
+
const transaction = this.pool.transaction();
|
|
1982
|
+
try {
|
|
1983
|
+
await transaction.begin();
|
|
1984
|
+
for (const { keys, data } of updates) {
|
|
1985
|
+
await this.update({ tableName, keys, data, transaction });
|
|
1986
|
+
}
|
|
1987
|
+
await transaction.commit();
|
|
1988
|
+
} catch (error$1) {
|
|
1989
|
+
await transaction.rollback();
|
|
1990
|
+
throw new error.MastraError(
|
|
1991
|
+
{
|
|
1992
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_BATCH_UPDATE_FAILED",
|
|
1993
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1994
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1995
|
+
details: {
|
|
1996
|
+
tableName,
|
|
1997
|
+
numberOfRecords: updates.length
|
|
1998
|
+
}
|
|
1999
|
+
},
|
|
2000
|
+
error$1
|
|
2001
|
+
);
|
|
2002
|
+
}
|
|
2003
|
+
}
|
|
2004
|
+
/**
|
|
2005
|
+
* Delete multiple records by keys
|
|
2006
|
+
*/
|
|
2007
|
+
async batchDelete({ tableName, keys }) {
|
|
2008
|
+
if (keys.length === 0) {
|
|
2009
|
+
return;
|
|
2010
|
+
}
|
|
2011
|
+
const tableName_ = getTableName({
|
|
2012
|
+
indexName: tableName,
|
|
2013
|
+
schemaName: getSchemaName(this.schemaName)
|
|
2014
|
+
});
|
|
2015
|
+
const transaction = this.pool.transaction();
|
|
2016
|
+
try {
|
|
2017
|
+
await transaction.begin();
|
|
2018
|
+
for (const keySet of keys) {
|
|
2019
|
+
const conditions = [];
|
|
2020
|
+
const request = transaction.request();
|
|
2021
|
+
let paramIndex = 0;
|
|
2022
|
+
Object.entries(keySet).forEach(([key, value]) => {
|
|
2023
|
+
const parsedKey = utils.parseSqlIdentifier(key, "column name");
|
|
2024
|
+
const paramName = `p${paramIndex++}`;
|
|
2025
|
+
conditions.push(`[${parsedKey}] = @${paramName}`);
|
|
2026
|
+
const preparedValue = this.prepareValue(value, key, tableName);
|
|
2027
|
+
if (preparedValue === null || preparedValue === void 0) {
|
|
2028
|
+
request.input(paramName, this.getMssqlType(tableName, key), null);
|
|
2029
|
+
} else {
|
|
2030
|
+
request.input(paramName, preparedValue);
|
|
2031
|
+
}
|
|
2032
|
+
});
|
|
2033
|
+
const deleteSql = `DELETE FROM ${tableName_} WHERE ${conditions.join(" AND ")}`;
|
|
2034
|
+
await request.query(deleteSql);
|
|
2035
|
+
}
|
|
2036
|
+
await transaction.commit();
|
|
2037
|
+
} catch (error$1) {
|
|
2038
|
+
await transaction.rollback();
|
|
2039
|
+
throw new error.MastraError(
|
|
2040
|
+
{
|
|
2041
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_BATCH_DELETE_FAILED",
|
|
2042
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2043
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
2044
|
+
details: {
|
|
2045
|
+
tableName,
|
|
2046
|
+
numberOfRecords: keys.length
|
|
2047
|
+
}
|
|
2048
|
+
},
|
|
2049
|
+
error$1
|
|
2050
|
+
);
|
|
2051
|
+
}
|
|
2052
|
+
}
|
|
2053
|
+
/**
|
|
2054
|
+
* Create a new index on a table
|
|
2055
|
+
*/
|
|
2056
|
+
async createIndex(options) {
|
|
2057
|
+
try {
|
|
2058
|
+
const { name, table, columns, unique = false, where } = options;
|
|
2059
|
+
const schemaName = this.schemaName || "dbo";
|
|
2060
|
+
const fullTableName = getTableName({
|
|
2061
|
+
indexName: table,
|
|
2062
|
+
schemaName: getSchemaName(this.schemaName)
|
|
2063
|
+
});
|
|
2064
|
+
const indexNameSafe = utils.parseSqlIdentifier(name, "index name");
|
|
2065
|
+
const checkRequest = this.pool.request();
|
|
2066
|
+
checkRequest.input("indexName", indexNameSafe);
|
|
2067
|
+
checkRequest.input("schemaName", schemaName);
|
|
2068
|
+
checkRequest.input("tableName", table);
|
|
2069
|
+
const indexExists = await checkRequest.query(`
|
|
2070
|
+
SELECT 1 as found
|
|
2071
|
+
FROM sys.indexes i
|
|
2072
|
+
INNER JOIN sys.tables t ON i.object_id = t.object_id
|
|
2073
|
+
INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
|
|
2074
|
+
WHERE i.name = @indexName
|
|
2075
|
+
AND s.name = @schemaName
|
|
2076
|
+
AND t.name = @tableName
|
|
2077
|
+
`);
|
|
2078
|
+
if (indexExists.recordset && indexExists.recordset.length > 0) {
|
|
2079
|
+
return;
|
|
2080
|
+
}
|
|
2081
|
+
const uniqueStr = unique ? "UNIQUE " : "";
|
|
2082
|
+
const columnsStr = columns.map((col) => {
|
|
2083
|
+
if (col.includes(" DESC") || col.includes(" ASC")) {
|
|
2084
|
+
const [colName, ...modifiers] = col.split(" ");
|
|
2085
|
+
if (!colName) {
|
|
2086
|
+
throw new Error(`Invalid column specification: ${col}`);
|
|
2087
|
+
}
|
|
2088
|
+
return `[${utils.parseSqlIdentifier(colName, "column name")}] ${modifiers.join(" ")}`;
|
|
2089
|
+
}
|
|
2090
|
+
return `[${utils.parseSqlIdentifier(col, "column name")}]`;
|
|
2091
|
+
}).join(", ");
|
|
2092
|
+
const whereStr = where ? ` WHERE ${where}` : "";
|
|
2093
|
+
const createIndexSql = `CREATE ${uniqueStr}INDEX [${indexNameSafe}] ON ${fullTableName} (${columnsStr})${whereStr}`;
|
|
2094
|
+
await this.pool.request().query(createIndexSql);
|
|
2095
|
+
} catch (error$1) {
|
|
2096
|
+
throw new error.MastraError(
|
|
2097
|
+
{
|
|
2098
|
+
id: "MASTRA_STORAGE_MSSQL_INDEX_CREATE_FAILED",
|
|
2099
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2100
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
2101
|
+
details: {
|
|
2102
|
+
indexName: options.name,
|
|
2103
|
+
tableName: options.table
|
|
2104
|
+
}
|
|
2105
|
+
},
|
|
2106
|
+
error$1
|
|
2107
|
+
);
|
|
2108
|
+
}
|
|
2109
|
+
}
|
|
2110
|
+
/**
|
|
2111
|
+
* Drop an existing index
|
|
2112
|
+
*/
|
|
2113
|
+
async dropIndex(indexName) {
|
|
2114
|
+
try {
|
|
2115
|
+
const schemaName = this.schemaName || "dbo";
|
|
2116
|
+
const indexNameSafe = utils.parseSqlIdentifier(indexName, "index name");
|
|
2117
|
+
const checkRequest = this.pool.request();
|
|
2118
|
+
checkRequest.input("indexName", indexNameSafe);
|
|
2119
|
+
checkRequest.input("schemaName", schemaName);
|
|
2120
|
+
const result = await checkRequest.query(`
|
|
2121
|
+
SELECT t.name as table_name
|
|
2122
|
+
FROM sys.indexes i
|
|
2123
|
+
INNER JOIN sys.tables t ON i.object_id = t.object_id
|
|
2124
|
+
INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
|
|
2125
|
+
WHERE i.name = @indexName
|
|
2126
|
+
AND s.name = @schemaName
|
|
2127
|
+
`);
|
|
2128
|
+
if (!result.recordset || result.recordset.length === 0) {
|
|
2129
|
+
return;
|
|
2130
|
+
}
|
|
2131
|
+
if (result.recordset.length > 1) {
|
|
2132
|
+
const tables = result.recordset.map((r) => r.table_name).join(", ");
|
|
2133
|
+
throw new error.MastraError({
|
|
2134
|
+
id: "MASTRA_STORAGE_MSSQL_INDEX_AMBIGUOUS",
|
|
2135
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2136
|
+
category: error.ErrorCategory.USER,
|
|
2137
|
+
text: `Index "${indexNameSafe}" exists on multiple tables (${tables}) in schema "${schemaName}". Please drop indexes manually or ensure unique index names.`
|
|
2138
|
+
});
|
|
2139
|
+
}
|
|
2140
|
+
const tableName = result.recordset[0].table_name;
|
|
2141
|
+
const fullTableName = getTableName({
|
|
2142
|
+
indexName: tableName,
|
|
2143
|
+
schemaName: getSchemaName(this.schemaName)
|
|
2144
|
+
});
|
|
2145
|
+
const dropSql = `DROP INDEX [${indexNameSafe}] ON ${fullTableName}`;
|
|
2146
|
+
await this.pool.request().query(dropSql);
|
|
2147
|
+
} catch (error$1) {
|
|
2148
|
+
throw new error.MastraError(
|
|
2149
|
+
{
|
|
2150
|
+
id: "MASTRA_STORAGE_MSSQL_INDEX_DROP_FAILED",
|
|
2151
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2152
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
2153
|
+
details: {
|
|
2154
|
+
indexName
|
|
2155
|
+
}
|
|
2156
|
+
},
|
|
2157
|
+
error$1
|
|
2158
|
+
);
|
|
2159
|
+
}
|
|
2160
|
+
}
|
|
2161
|
+
/**
|
|
2162
|
+
* List indexes for a specific table or all tables
|
|
2163
|
+
*/
|
|
2164
|
+
async listIndexes(tableName) {
|
|
2165
|
+
try {
|
|
2166
|
+
const schemaName = this.schemaName || "dbo";
|
|
2167
|
+
let query;
|
|
2168
|
+
const request = this.pool.request();
|
|
2169
|
+
request.input("schemaName", schemaName);
|
|
2170
|
+
if (tableName) {
|
|
2171
|
+
query = `
|
|
2172
|
+
SELECT
|
|
2173
|
+
i.name as name,
|
|
2174
|
+
o.name as [table],
|
|
2175
|
+
i.is_unique as is_unique,
|
|
2176
|
+
CAST(SUM(s.used_page_count) * 8 / 1024.0 AS VARCHAR(50)) + ' MB' as size
|
|
2177
|
+
FROM sys.indexes i
|
|
2178
|
+
INNER JOIN sys.objects o ON i.object_id = o.object_id
|
|
2179
|
+
INNER JOIN sys.schemas sch ON o.schema_id = sch.schema_id
|
|
2180
|
+
LEFT JOIN sys.dm_db_partition_stats s ON i.object_id = s.object_id AND i.index_id = s.index_id
|
|
2181
|
+
WHERE sch.name = @schemaName
|
|
2182
|
+
AND o.name = @tableName
|
|
2183
|
+
AND i.name IS NOT NULL
|
|
2184
|
+
GROUP BY i.name, o.name, i.is_unique
|
|
2185
|
+
`;
|
|
2186
|
+
request.input("tableName", tableName);
|
|
2187
|
+
} else {
|
|
2188
|
+
query = `
|
|
2189
|
+
SELECT
|
|
2190
|
+
i.name as name,
|
|
2191
|
+
o.name as [table],
|
|
2192
|
+
i.is_unique as is_unique,
|
|
2193
|
+
CAST(SUM(s.used_page_count) * 8 / 1024.0 AS VARCHAR(50)) + ' MB' as size
|
|
2194
|
+
FROM sys.indexes i
|
|
2195
|
+
INNER JOIN sys.objects o ON i.object_id = o.object_id
|
|
2196
|
+
INNER JOIN sys.schemas sch ON o.schema_id = sch.schema_id
|
|
2197
|
+
LEFT JOIN sys.dm_db_partition_stats s ON i.object_id = s.object_id AND i.index_id = s.index_id
|
|
2198
|
+
WHERE sch.name = @schemaName
|
|
2199
|
+
AND i.name IS NOT NULL
|
|
2200
|
+
GROUP BY i.name, o.name, i.is_unique
|
|
2201
|
+
`;
|
|
2202
|
+
}
|
|
2203
|
+
const result = await request.query(query);
|
|
2204
|
+
const indexes = [];
|
|
2205
|
+
for (const row of result.recordset) {
|
|
2206
|
+
const colRequest = this.pool.request();
|
|
2207
|
+
colRequest.input("indexName", row.name);
|
|
2208
|
+
colRequest.input("schemaName", schemaName);
|
|
2209
|
+
const colResult = await colRequest.query(`
|
|
2210
|
+
SELECT c.name as column_name
|
|
2211
|
+
FROM sys.indexes i
|
|
2212
|
+
INNER JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
|
|
2213
|
+
INNER JOIN sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id
|
|
2214
|
+
INNER JOIN sys.objects o ON i.object_id = o.object_id
|
|
2215
|
+
INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
|
|
2216
|
+
WHERE i.name = @indexName
|
|
2217
|
+
AND s.name = @schemaName
|
|
2218
|
+
ORDER BY ic.key_ordinal
|
|
2219
|
+
`);
|
|
2220
|
+
indexes.push({
|
|
2221
|
+
name: row.name,
|
|
2222
|
+
table: row.table,
|
|
2223
|
+
columns: colResult.recordset.map((c) => c.column_name),
|
|
2224
|
+
unique: row.is_unique || false,
|
|
2225
|
+
size: row.size || "0 MB",
|
|
2226
|
+
definition: ""
|
|
2227
|
+
// MSSQL doesn't store definition like PG
|
|
2228
|
+
});
|
|
2229
|
+
}
|
|
2230
|
+
return indexes;
|
|
2231
|
+
} catch (error$1) {
|
|
2232
|
+
throw new error.MastraError(
|
|
2233
|
+
{
|
|
2234
|
+
id: "MASTRA_STORAGE_MSSQL_INDEX_LIST_FAILED",
|
|
2235
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2236
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
2237
|
+
details: tableName ? {
|
|
2238
|
+
tableName
|
|
2239
|
+
} : {}
|
|
2240
|
+
},
|
|
2241
|
+
error$1
|
|
2242
|
+
);
|
|
2243
|
+
}
|
|
2244
|
+
}
|
|
2245
|
+
/**
|
|
2246
|
+
* Get detailed statistics for a specific index
|
|
2247
|
+
*/
|
|
2248
|
+
async describeIndex(indexName) {
|
|
2249
|
+
try {
|
|
2250
|
+
const schemaName = this.schemaName || "dbo";
|
|
2251
|
+
const request = this.pool.request();
|
|
2252
|
+
request.input("indexName", indexName);
|
|
2253
|
+
request.input("schemaName", schemaName);
|
|
2254
|
+
const query = `
|
|
2255
|
+
SELECT
|
|
2256
|
+
i.name as name,
|
|
2257
|
+
o.name as [table],
|
|
2258
|
+
i.is_unique as is_unique,
|
|
2259
|
+
CAST(SUM(s.used_page_count) * 8 / 1024.0 AS VARCHAR(50)) + ' MB' as size,
|
|
2260
|
+
i.type_desc as method,
|
|
2261
|
+
ISNULL(us.user_scans, 0) as scans,
|
|
2262
|
+
ISNULL(us.user_seeks + us.user_scans, 0) as tuples_read,
|
|
2263
|
+
ISNULL(us.user_lookups, 0) as tuples_fetched
|
|
2264
|
+
FROM sys.indexes i
|
|
2265
|
+
INNER JOIN sys.objects o ON i.object_id = o.object_id
|
|
2266
|
+
INNER JOIN sys.schemas sch ON o.schema_id = sch.schema_id
|
|
2267
|
+
LEFT JOIN sys.dm_db_partition_stats s ON i.object_id = s.object_id AND i.index_id = s.index_id
|
|
2268
|
+
LEFT JOIN sys.dm_db_index_usage_stats us ON i.object_id = us.object_id AND i.index_id = us.index_id
|
|
2269
|
+
WHERE i.name = @indexName
|
|
2270
|
+
AND sch.name = @schemaName
|
|
2271
|
+
GROUP BY i.name, o.name, i.is_unique, i.type_desc, us.user_seeks, us.user_scans, us.user_lookups
|
|
2272
|
+
`;
|
|
2273
|
+
const result = await request.query(query);
|
|
2274
|
+
if (!result.recordset || result.recordset.length === 0) {
|
|
2275
|
+
throw new Error(`Index "${indexName}" not found in schema "${schemaName}"`);
|
|
2276
|
+
}
|
|
2277
|
+
const row = result.recordset[0];
|
|
2278
|
+
const colRequest = this.pool.request();
|
|
2279
|
+
colRequest.input("indexName", indexName);
|
|
2280
|
+
colRequest.input("schemaName", schemaName);
|
|
2281
|
+
const colResult = await colRequest.query(`
|
|
2282
|
+
SELECT c.name as column_name
|
|
2283
|
+
FROM sys.indexes i
|
|
2284
|
+
INNER JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
|
|
2285
|
+
INNER JOIN sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id
|
|
2286
|
+
INNER JOIN sys.objects o ON i.object_id = o.object_id
|
|
2287
|
+
INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
|
|
2288
|
+
WHERE i.name = @indexName
|
|
2289
|
+
AND s.name = @schemaName
|
|
2290
|
+
ORDER BY ic.key_ordinal
|
|
2291
|
+
`);
|
|
2292
|
+
return {
|
|
2293
|
+
name: row.name,
|
|
2294
|
+
table: row.table,
|
|
2295
|
+
columns: colResult.recordset.map((c) => c.column_name),
|
|
2296
|
+
unique: row.is_unique || false,
|
|
2297
|
+
size: row.size || "0 MB",
|
|
2298
|
+
definition: "",
|
|
2299
|
+
method: row.method?.toLowerCase() || "nonclustered",
|
|
2300
|
+
scans: Number(row.scans) || 0,
|
|
2301
|
+
tuples_read: Number(row.tuples_read) || 0,
|
|
2302
|
+
tuples_fetched: Number(row.tuples_fetched) || 0
|
|
2303
|
+
};
|
|
2304
|
+
} catch (error$1) {
|
|
2305
|
+
throw new error.MastraError(
|
|
2306
|
+
{
|
|
2307
|
+
id: "MASTRA_STORAGE_MSSQL_INDEX_DESCRIBE_FAILED",
|
|
2308
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2309
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
2310
|
+
details: {
|
|
2311
|
+
indexName
|
|
2312
|
+
}
|
|
2313
|
+
},
|
|
2314
|
+
error$1
|
|
2315
|
+
);
|
|
2316
|
+
}
|
|
2317
|
+
}
|
|
2318
|
+
/**
|
|
2319
|
+
* Returns definitions for automatic performance indexes
|
|
2320
|
+
* IMPORTANT: Uses seq_id DESC instead of createdAt DESC for MSSQL due to millisecond accuracy limitations
|
|
2321
|
+
* NOTE: Using NVARCHAR(400) for text columns (800 bytes) leaves room for composite indexes
|
|
2322
|
+
*/
|
|
2323
|
+
getAutomaticIndexDefinitions() {
|
|
2324
|
+
const schemaPrefix = this.schemaName ? `${this.schemaName}_` : "";
|
|
2325
|
+
return [
|
|
2326
|
+
// Composite indexes for optimal filtering + sorting performance
|
|
2327
|
+
// NVARCHAR(400) = 800 bytes, plus BIGINT (8 bytes) = 808 bytes total (under 900-byte limit)
|
|
2328
|
+
{
|
|
2329
|
+
name: `${schemaPrefix}mastra_threads_resourceid_seqid_idx`,
|
|
2330
|
+
table: storage.TABLE_THREADS,
|
|
2331
|
+
columns: ["resourceId", "seq_id DESC"]
|
|
2332
|
+
},
|
|
2333
|
+
{
|
|
2334
|
+
name: `${schemaPrefix}mastra_messages_thread_id_seqid_idx`,
|
|
2335
|
+
table: storage.TABLE_MESSAGES,
|
|
2336
|
+
columns: ["thread_id", "seq_id DESC"]
|
|
2337
|
+
},
|
|
2338
|
+
{
|
|
2339
|
+
name: `${schemaPrefix}mastra_traces_name_seqid_idx`,
|
|
2340
|
+
table: storage.TABLE_TRACES,
|
|
2341
|
+
columns: ["name", "seq_id DESC"]
|
|
2342
|
+
},
|
|
2343
|
+
{
|
|
2344
|
+
name: `${schemaPrefix}mastra_evals_agent_name_seqid_idx`,
|
|
2345
|
+
table: storage.TABLE_EVALS,
|
|
2346
|
+
columns: ["agent_name", "seq_id DESC"]
|
|
2347
|
+
},
|
|
2348
|
+
{
|
|
2349
|
+
name: `${schemaPrefix}mastra_scores_trace_id_span_id_seqid_idx`,
|
|
2350
|
+
table: storage.TABLE_SCORERS,
|
|
2351
|
+
columns: ["traceId", "spanId", "seq_id DESC"]
|
|
2352
|
+
},
|
|
2353
|
+
// AI Spans indexes for optimal trace querying
|
|
2354
|
+
{
|
|
2355
|
+
name: `${schemaPrefix}mastra_ai_spans_traceid_startedat_idx`,
|
|
2356
|
+
table: storage.TABLE_AI_SPANS,
|
|
2357
|
+
columns: ["traceId", "startedAt DESC"]
|
|
2358
|
+
},
|
|
2359
|
+
{
|
|
2360
|
+
name: `${schemaPrefix}mastra_ai_spans_parentspanid_startedat_idx`,
|
|
2361
|
+
table: storage.TABLE_AI_SPANS,
|
|
2362
|
+
columns: ["parentSpanId", "startedAt DESC"]
|
|
2363
|
+
},
|
|
2364
|
+
{
|
|
2365
|
+
name: `${schemaPrefix}mastra_ai_spans_name_idx`,
|
|
2366
|
+
table: storage.TABLE_AI_SPANS,
|
|
2367
|
+
columns: ["name"]
|
|
2368
|
+
},
|
|
2369
|
+
{
|
|
2370
|
+
name: `${schemaPrefix}mastra_ai_spans_spantype_startedat_idx`,
|
|
2371
|
+
table: storage.TABLE_AI_SPANS,
|
|
2372
|
+
columns: ["spanType", "startedAt DESC"]
|
|
2373
|
+
}
|
|
2374
|
+
];
|
|
2375
|
+
}
|
|
2376
|
+
/**
|
|
2377
|
+
* Creates automatic indexes for optimal query performance
|
|
2378
|
+
* Uses getAutomaticIndexDefinitions() to determine which indexes to create
|
|
2379
|
+
*/
|
|
2380
|
+
async createAutomaticIndexes() {
|
|
2381
|
+
try {
|
|
2382
|
+
const indexes = this.getAutomaticIndexDefinitions();
|
|
2383
|
+
for (const indexOptions of indexes) {
|
|
2384
|
+
try {
|
|
2385
|
+
await this.createIndex(indexOptions);
|
|
2386
|
+
} catch (error) {
|
|
2387
|
+
this.logger?.warn?.(`Failed to create index ${indexOptions.name}:`, error);
|
|
2388
|
+
}
|
|
2389
|
+
}
|
|
2390
|
+
} catch (error$1) {
|
|
2391
|
+
throw new error.MastraError(
|
|
2392
|
+
{
|
|
2393
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_CREATE_PERFORMANCE_INDEXES_FAILED",
|
|
2394
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2395
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
2396
|
+
},
|
|
2397
|
+
error$1
|
|
2398
|
+
);
|
|
2399
|
+
}
|
|
2400
|
+
}
|
|
2401
|
+
};
|
|
2402
|
+
function transformScoreRow(row) {
|
|
2403
|
+
return {
|
|
2404
|
+
...row,
|
|
2405
|
+
input: storage.safelyParseJSON(row.input),
|
|
2406
|
+
scorer: storage.safelyParseJSON(row.scorer),
|
|
2407
|
+
preprocessStepResult: storage.safelyParseJSON(row.preprocessStepResult),
|
|
2408
|
+
analyzeStepResult: storage.safelyParseJSON(row.analyzeStepResult),
|
|
2409
|
+
metadata: storage.safelyParseJSON(row.metadata),
|
|
2410
|
+
output: storage.safelyParseJSON(row.output),
|
|
2411
|
+
additionalContext: storage.safelyParseJSON(row.additionalContext),
|
|
2412
|
+
runtimeContext: storage.safelyParseJSON(row.runtimeContext),
|
|
2413
|
+
entity: storage.safelyParseJSON(row.entity),
|
|
2414
|
+
createdAt: row.createdAt,
|
|
2415
|
+
updatedAt: row.updatedAt
|
|
2416
|
+
};
|
|
2417
|
+
}
|
|
2418
|
+
var ScoresMSSQL = class extends storage.ScoresStorage {
|
|
2419
|
+
pool;
|
|
2420
|
+
operations;
|
|
2421
|
+
schema;
|
|
2422
|
+
constructor({
|
|
2423
|
+
pool,
|
|
2424
|
+
operations,
|
|
2425
|
+
schema
|
|
2426
|
+
}) {
|
|
2427
|
+
super();
|
|
2428
|
+
this.pool = pool;
|
|
2429
|
+
this.operations = operations;
|
|
2430
|
+
this.schema = schema;
|
|
2431
|
+
}
|
|
2432
|
+
async getScoreById({ id }) {
|
|
2433
|
+
try {
|
|
2434
|
+
const request = this.pool.request();
|
|
2435
|
+
request.input("p1", id);
|
|
2436
|
+
const result = await request.query(
|
|
2437
|
+
`SELECT * FROM ${getTableName({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName(this.schema) })} WHERE id = @p1`
|
|
2438
|
+
);
|
|
1466
2439
|
if (result.recordset.length === 0) {
|
|
1467
2440
|
return null;
|
|
1468
2441
|
}
|
|
@@ -1512,15 +2485,15 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
|
|
|
1512
2485
|
record: {
|
|
1513
2486
|
id: scoreId,
|
|
1514
2487
|
...rest,
|
|
1515
|
-
input:
|
|
1516
|
-
output:
|
|
1517
|
-
preprocessStepResult: preprocessStepResult
|
|
1518
|
-
analyzeStepResult: analyzeStepResult
|
|
1519
|
-
metadata: metadata
|
|
1520
|
-
additionalContext: additionalContext
|
|
1521
|
-
runtimeContext: runtimeContext
|
|
1522
|
-
entity: entity
|
|
1523
|
-
scorer: scorer
|
|
2488
|
+
input: input || "",
|
|
2489
|
+
output: output || "",
|
|
2490
|
+
preprocessStepResult: preprocessStepResult || null,
|
|
2491
|
+
analyzeStepResult: analyzeStepResult || null,
|
|
2492
|
+
metadata: metadata || null,
|
|
2493
|
+
additionalContext: additionalContext || null,
|
|
2494
|
+
runtimeContext: runtimeContext || null,
|
|
2495
|
+
entity: entity || null,
|
|
2496
|
+
scorer: scorer || null,
|
|
1524
2497
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1525
2498
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1526
2499
|
}
|
|
@@ -1540,14 +2513,37 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
|
|
|
1540
2513
|
}
|
|
1541
2514
|
async getScoresByScorerId({
|
|
1542
2515
|
scorerId,
|
|
1543
|
-
pagination
|
|
2516
|
+
pagination,
|
|
2517
|
+
entityId,
|
|
2518
|
+
entityType,
|
|
2519
|
+
source
|
|
1544
2520
|
}) {
|
|
1545
2521
|
try {
|
|
1546
|
-
const
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
2522
|
+
const conditions = ["[scorerId] = @p1"];
|
|
2523
|
+
const params = { p1: scorerId };
|
|
2524
|
+
let paramIndex = 2;
|
|
2525
|
+
if (entityId) {
|
|
2526
|
+
conditions.push(`[entityId] = @p${paramIndex}`);
|
|
2527
|
+
params[`p${paramIndex}`] = entityId;
|
|
2528
|
+
paramIndex++;
|
|
2529
|
+
}
|
|
2530
|
+
if (entityType) {
|
|
2531
|
+
conditions.push(`[entityType] = @p${paramIndex}`);
|
|
2532
|
+
params[`p${paramIndex}`] = entityType;
|
|
2533
|
+
paramIndex++;
|
|
2534
|
+
}
|
|
2535
|
+
if (source) {
|
|
2536
|
+
conditions.push(`[source] = @p${paramIndex}`);
|
|
2537
|
+
params[`p${paramIndex}`] = source;
|
|
2538
|
+
paramIndex++;
|
|
2539
|
+
}
|
|
2540
|
+
const whereClause = conditions.join(" AND ");
|
|
2541
|
+
const tableName = getTableName({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName(this.schema) });
|
|
2542
|
+
const countRequest = this.pool.request();
|
|
2543
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
2544
|
+
countRequest.input(key, value);
|
|
2545
|
+
});
|
|
2546
|
+
const totalResult = await countRequest.query(`SELECT COUNT(*) as count FROM ${tableName} WHERE ${whereClause}`);
|
|
1551
2547
|
const total = totalResult.recordset[0]?.count || 0;
|
|
1552
2548
|
if (total === 0) {
|
|
1553
2549
|
return {
|
|
@@ -1561,12 +2557,13 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
|
|
|
1561
2557
|
};
|
|
1562
2558
|
}
|
|
1563
2559
|
const dataRequest = this.pool.request();
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
2560
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
2561
|
+
dataRequest.input(key, value);
|
|
2562
|
+
});
|
|
2563
|
+
dataRequest.input("perPage", pagination.perPage);
|
|
2564
|
+
dataRequest.input("offset", pagination.page * pagination.perPage);
|
|
2565
|
+
const dataQuery = `SELECT * FROM ${tableName} WHERE ${whereClause} ORDER BY [createdAt] DESC OFFSET @offset ROWS FETCH NEXT @perPage ROWS ONLY`;
|
|
2566
|
+
const result = await dataRequest.query(dataQuery);
|
|
1570
2567
|
return {
|
|
1571
2568
|
pagination: {
|
|
1572
2569
|
total: Number(total),
|
|
@@ -1746,7 +2743,7 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
|
|
|
1746
2743
|
}
|
|
1747
2744
|
}
|
|
1748
2745
|
};
|
|
1749
|
-
var
|
|
2746
|
+
var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
|
|
1750
2747
|
pool;
|
|
1751
2748
|
operations;
|
|
1752
2749
|
schema;
|
|
@@ -1760,207 +2757,164 @@ var TracesMSSQL = class extends storage.TracesStorage {
|
|
|
1760
2757
|
this.operations = operations;
|
|
1761
2758
|
this.schema = schema;
|
|
1762
2759
|
}
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
if (
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
2760
|
+
parseWorkflowRun(row) {
|
|
2761
|
+
let parsedSnapshot = row.snapshot;
|
|
2762
|
+
if (typeof parsedSnapshot === "string") {
|
|
2763
|
+
try {
|
|
2764
|
+
parsedSnapshot = JSON.parse(row.snapshot);
|
|
2765
|
+
} catch (e) {
|
|
2766
|
+
this.logger?.warn?.(`Failed to parse snapshot for workflow ${row.workflow_name}:`, e);
|
|
2767
|
+
}
|
|
1770
2768
|
}
|
|
1771
|
-
|
|
1772
|
-
|
|
2769
|
+
return {
|
|
2770
|
+
workflowName: row.workflow_name,
|
|
2771
|
+
runId: row.run_id,
|
|
2772
|
+
snapshot: parsedSnapshot,
|
|
2773
|
+
createdAt: row.createdAt,
|
|
2774
|
+
updatedAt: row.updatedAt,
|
|
2775
|
+
resourceId: row.resourceId
|
|
2776
|
+
};
|
|
1773
2777
|
}
|
|
1774
|
-
async
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
const
|
|
1782
|
-
|
|
1783
|
-
if (name) {
|
|
1784
|
-
const paramName = `p${paramIndex++}`;
|
|
1785
|
-
conditions.push(`[name] LIKE @${paramName}`);
|
|
1786
|
-
paramMap[paramName] = `${name}%`;
|
|
1787
|
-
}
|
|
1788
|
-
if (scope) {
|
|
1789
|
-
const paramName = `p${paramIndex++}`;
|
|
1790
|
-
conditions.push(`[scope] = @${paramName}`);
|
|
1791
|
-
paramMap[paramName] = scope;
|
|
1792
|
-
}
|
|
1793
|
-
if (attributes) {
|
|
1794
|
-
Object.entries(attributes).forEach(([key, value]) => {
|
|
1795
|
-
const parsedKey = utils.parseFieldKey(key);
|
|
1796
|
-
const paramName = `p${paramIndex++}`;
|
|
1797
|
-
conditions.push(`JSON_VALUE([attributes], '$.${parsedKey}') = @${paramName}`);
|
|
1798
|
-
paramMap[paramName] = value;
|
|
1799
|
-
});
|
|
1800
|
-
}
|
|
1801
|
-
if (filters) {
|
|
1802
|
-
Object.entries(filters).forEach(([key, value]) => {
|
|
1803
|
-
const parsedKey = utils.parseFieldKey(key);
|
|
1804
|
-
const paramName = `p${paramIndex++}`;
|
|
1805
|
-
conditions.push(`[${parsedKey}] = @${paramName}`);
|
|
1806
|
-
paramMap[paramName] = value;
|
|
1807
|
-
});
|
|
1808
|
-
}
|
|
1809
|
-
if (fromDate instanceof Date && !isNaN(fromDate.getTime())) {
|
|
1810
|
-
const paramName = `p${paramIndex++}`;
|
|
1811
|
-
conditions.push(`[createdAt] >= @${paramName}`);
|
|
1812
|
-
paramMap[paramName] = fromDate.toISOString();
|
|
1813
|
-
}
|
|
1814
|
-
if (toDate instanceof Date && !isNaN(toDate.getTime())) {
|
|
1815
|
-
const paramName = `p${paramIndex++}`;
|
|
1816
|
-
conditions.push(`[createdAt] <= @${paramName}`);
|
|
1817
|
-
paramMap[paramName] = toDate.toISOString();
|
|
1818
|
-
}
|
|
1819
|
-
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
1820
|
-
const countQuery = `SELECT COUNT(*) as total FROM ${getTableName({ indexName: storage.TABLE_TRACES, schemaName: getSchemaName(this.schema) })} ${whereClause}`;
|
|
1821
|
-
let total = 0;
|
|
2778
|
+
async updateWorkflowResults({
|
|
2779
|
+
workflowName,
|
|
2780
|
+
runId,
|
|
2781
|
+
stepId,
|
|
2782
|
+
result,
|
|
2783
|
+
runtimeContext
|
|
2784
|
+
}) {
|
|
2785
|
+
const table = getTableName({ indexName: storage.TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName(this.schema) });
|
|
2786
|
+
const transaction = this.pool.transaction();
|
|
1822
2787
|
try {
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
2788
|
+
await transaction.begin();
|
|
2789
|
+
const selectRequest = new sql3__default.default.Request(transaction);
|
|
2790
|
+
selectRequest.input("workflow_name", workflowName);
|
|
2791
|
+
selectRequest.input("run_id", runId);
|
|
2792
|
+
const existingSnapshotResult = await selectRequest.query(
|
|
2793
|
+
`SELECT snapshot FROM ${table} WITH (UPDLOCK, HOLDLOCK) WHERE workflow_name = @workflow_name AND run_id = @run_id`
|
|
2794
|
+
);
|
|
2795
|
+
let snapshot;
|
|
2796
|
+
if (!existingSnapshotResult.recordset || existingSnapshotResult.recordset.length === 0) {
|
|
2797
|
+
snapshot = {
|
|
2798
|
+
context: {},
|
|
2799
|
+
activePaths: [],
|
|
2800
|
+
timestamp: Date.now(),
|
|
2801
|
+
suspendedPaths: {},
|
|
2802
|
+
resumeLabels: {},
|
|
2803
|
+
serializedStepGraph: [],
|
|
2804
|
+
value: {},
|
|
2805
|
+
waitingPaths: {},
|
|
2806
|
+
status: "pending",
|
|
2807
|
+
runId,
|
|
2808
|
+
runtimeContext: {}
|
|
2809
|
+
};
|
|
2810
|
+
} else {
|
|
2811
|
+
const existingSnapshot = existingSnapshotResult.recordset[0].snapshot;
|
|
2812
|
+
snapshot = typeof existingSnapshot === "string" ? JSON.parse(existingSnapshot) : existingSnapshot;
|
|
2813
|
+
}
|
|
2814
|
+
snapshot.context[stepId] = result;
|
|
2815
|
+
snapshot.runtimeContext = { ...snapshot.runtimeContext, ...runtimeContext };
|
|
2816
|
+
const upsertReq = new sql3__default.default.Request(transaction);
|
|
2817
|
+
upsertReq.input("workflow_name", workflowName);
|
|
2818
|
+
upsertReq.input("run_id", runId);
|
|
2819
|
+
upsertReq.input("snapshot", JSON.stringify(snapshot));
|
|
2820
|
+
upsertReq.input("createdAt", sql3__default.default.DateTime2, /* @__PURE__ */ new Date());
|
|
2821
|
+
upsertReq.input("updatedAt", sql3__default.default.DateTime2, /* @__PURE__ */ new Date());
|
|
2822
|
+
await upsertReq.query(
|
|
2823
|
+
`MERGE ${table} AS target
|
|
2824
|
+
USING (SELECT @workflow_name AS workflow_name, @run_id AS run_id) AS src
|
|
2825
|
+
ON target.workflow_name = src.workflow_name AND target.run_id = src.run_id
|
|
2826
|
+
WHEN MATCHED THEN UPDATE SET snapshot = @snapshot, [updatedAt] = @updatedAt
|
|
2827
|
+
WHEN NOT MATCHED THEN INSERT (workflow_name, run_id, snapshot, [createdAt], [updatedAt])
|
|
2828
|
+
VALUES (@workflow_name, @run_id, @snapshot, @createdAt, @updatedAt);`
|
|
2829
|
+
);
|
|
2830
|
+
await transaction.commit();
|
|
2831
|
+
return snapshot.context;
|
|
1833
2832
|
} catch (error$1) {
|
|
2833
|
+
try {
|
|
2834
|
+
await transaction.rollback();
|
|
2835
|
+
} catch {
|
|
2836
|
+
}
|
|
1834
2837
|
throw new error.MastraError(
|
|
1835
2838
|
{
|
|
1836
|
-
id: "
|
|
2839
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_UPDATE_WORKFLOW_RESULTS_FAILED",
|
|
1837
2840
|
domain: error.ErrorDomain.STORAGE,
|
|
1838
2841
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1839
2842
|
details: {
|
|
1840
|
-
|
|
1841
|
-
|
|
2843
|
+
workflowName,
|
|
2844
|
+
runId,
|
|
2845
|
+
stepId
|
|
1842
2846
|
}
|
|
1843
2847
|
},
|
|
1844
2848
|
error$1
|
|
1845
2849
|
);
|
|
1846
2850
|
}
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
}
|
|
1856
|
-
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`;
|
|
1857
|
-
const dataRequest = this.pool.request();
|
|
1858
|
-
Object.entries(paramMap).forEach(([key, value]) => {
|
|
1859
|
-
if (value instanceof Date) {
|
|
1860
|
-
dataRequest.input(key, sql2__default.default.DateTime, value);
|
|
1861
|
-
} else {
|
|
1862
|
-
dataRequest.input(key, value);
|
|
1863
|
-
}
|
|
1864
|
-
});
|
|
1865
|
-
dataRequest.input("offset", currentOffset);
|
|
1866
|
-
dataRequest.input("limit", perPage);
|
|
2851
|
+
}
|
|
2852
|
+
async updateWorkflowState({
|
|
2853
|
+
workflowName,
|
|
2854
|
+
runId,
|
|
2855
|
+
opts
|
|
2856
|
+
}) {
|
|
2857
|
+
const table = getTableName({ indexName: storage.TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName(this.schema) });
|
|
2858
|
+
const transaction = this.pool.transaction();
|
|
1867
2859
|
try {
|
|
1868
|
-
|
|
1869
|
-
const
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
2860
|
+
await transaction.begin();
|
|
2861
|
+
const selectRequest = new sql3__default.default.Request(transaction);
|
|
2862
|
+
selectRequest.input("workflow_name", workflowName);
|
|
2863
|
+
selectRequest.input("run_id", runId);
|
|
2864
|
+
const existingSnapshotResult = await selectRequest.query(
|
|
2865
|
+
`SELECT snapshot FROM ${table} WITH (UPDLOCK, HOLDLOCK) WHERE workflow_name = @workflow_name AND run_id = @run_id`
|
|
2866
|
+
);
|
|
2867
|
+
if (!existingSnapshotResult.recordset || existingSnapshotResult.recordset.length === 0) {
|
|
2868
|
+
await transaction.rollback();
|
|
2869
|
+
return void 0;
|
|
2870
|
+
}
|
|
2871
|
+
const existingSnapshot = existingSnapshotResult.recordset[0].snapshot;
|
|
2872
|
+
const snapshot = typeof existingSnapshot === "string" ? JSON.parse(existingSnapshot) : existingSnapshot;
|
|
2873
|
+
if (!snapshot || !snapshot?.context) {
|
|
2874
|
+
await transaction.rollback();
|
|
2875
|
+
throw new error.MastraError(
|
|
2876
|
+
{
|
|
2877
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_UPDATE_WORKFLOW_STATE_SNAPSHOT_NOT_FOUND",
|
|
2878
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2879
|
+
category: error.ErrorCategory.SYSTEM,
|
|
2880
|
+
details: {
|
|
2881
|
+
workflowName,
|
|
2882
|
+
runId
|
|
2883
|
+
}
|
|
2884
|
+
},
|
|
2885
|
+
new Error(`Snapshot not found for runId ${runId}`)
|
|
2886
|
+
);
|
|
2887
|
+
}
|
|
2888
|
+
const updatedSnapshot = { ...snapshot, ...opts };
|
|
2889
|
+
const updateRequest = new sql3__default.default.Request(transaction);
|
|
2890
|
+
updateRequest.input("snapshot", JSON.stringify(updatedSnapshot));
|
|
2891
|
+
updateRequest.input("workflow_name", workflowName);
|
|
2892
|
+
updateRequest.input("run_id", runId);
|
|
2893
|
+
updateRequest.input("updatedAt", sql3__default.default.DateTime2, /* @__PURE__ */ new Date());
|
|
2894
|
+
await updateRequest.query(
|
|
2895
|
+
`UPDATE ${table} SET snapshot = @snapshot, [updatedAt] = @updatedAt WHERE workflow_name = @workflow_name AND run_id = @run_id`
|
|
2896
|
+
);
|
|
2897
|
+
await transaction.commit();
|
|
2898
|
+
return updatedSnapshot;
|
|
1893
2899
|
} catch (error$1) {
|
|
2900
|
+
try {
|
|
2901
|
+
await transaction.rollback();
|
|
2902
|
+
} catch {
|
|
2903
|
+
}
|
|
1894
2904
|
throw new error.MastraError(
|
|
1895
2905
|
{
|
|
1896
|
-
id: "
|
|
2906
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_UPDATE_WORKFLOW_STATE_FAILED",
|
|
1897
2907
|
domain: error.ErrorDomain.STORAGE,
|
|
1898
2908
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1899
2909
|
details: {
|
|
1900
|
-
|
|
1901
|
-
|
|
2910
|
+
workflowName,
|
|
2911
|
+
runId
|
|
1902
2912
|
}
|
|
1903
2913
|
},
|
|
1904
2914
|
error$1
|
|
1905
2915
|
);
|
|
1906
2916
|
}
|
|
1907
2917
|
}
|
|
1908
|
-
async batchTraceInsert({ records }) {
|
|
1909
|
-
this.logger.debug("Batch inserting traces", { count: records.length });
|
|
1910
|
-
await this.operations.batchInsert({
|
|
1911
|
-
tableName: storage.TABLE_TRACES,
|
|
1912
|
-
records
|
|
1913
|
-
});
|
|
1914
|
-
}
|
|
1915
|
-
};
|
|
1916
|
-
function parseWorkflowRun(row) {
|
|
1917
|
-
let parsedSnapshot = row.snapshot;
|
|
1918
|
-
if (typeof parsedSnapshot === "string") {
|
|
1919
|
-
try {
|
|
1920
|
-
parsedSnapshot = JSON.parse(row.snapshot);
|
|
1921
|
-
} catch (e) {
|
|
1922
|
-
console.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
|
|
1923
|
-
}
|
|
1924
|
-
}
|
|
1925
|
-
return {
|
|
1926
|
-
workflowName: row.workflow_name,
|
|
1927
|
-
runId: row.run_id,
|
|
1928
|
-
snapshot: parsedSnapshot,
|
|
1929
|
-
createdAt: row.createdAt,
|
|
1930
|
-
updatedAt: row.updatedAt,
|
|
1931
|
-
resourceId: row.resourceId
|
|
1932
|
-
};
|
|
1933
|
-
}
|
|
1934
|
-
var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
|
|
1935
|
-
pool;
|
|
1936
|
-
operations;
|
|
1937
|
-
schema;
|
|
1938
|
-
constructor({
|
|
1939
|
-
pool,
|
|
1940
|
-
operations,
|
|
1941
|
-
schema
|
|
1942
|
-
}) {
|
|
1943
|
-
super();
|
|
1944
|
-
this.pool = pool;
|
|
1945
|
-
this.operations = operations;
|
|
1946
|
-
this.schema = schema;
|
|
1947
|
-
}
|
|
1948
|
-
updateWorkflowResults({
|
|
1949
|
-
// workflowName,
|
|
1950
|
-
// runId,
|
|
1951
|
-
// stepId,
|
|
1952
|
-
// result,
|
|
1953
|
-
// runtimeContext,
|
|
1954
|
-
}) {
|
|
1955
|
-
throw new Error("Method not implemented.");
|
|
1956
|
-
}
|
|
1957
|
-
updateWorkflowState({
|
|
1958
|
-
// workflowName,
|
|
1959
|
-
// runId,
|
|
1960
|
-
// opts,
|
|
1961
|
-
}) {
|
|
1962
|
-
throw new Error("Method not implemented.");
|
|
1963
|
-
}
|
|
1964
2918
|
async persistWorkflowSnapshot({
|
|
1965
2919
|
workflowName,
|
|
1966
2920
|
runId,
|
|
@@ -1975,8 +2929,8 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
|
|
|
1975
2929
|
request.input("run_id", runId);
|
|
1976
2930
|
request.input("resourceId", resourceId);
|
|
1977
2931
|
request.input("snapshot", JSON.stringify(snapshot));
|
|
1978
|
-
request.input("createdAt",
|
|
1979
|
-
request.input("updatedAt",
|
|
2932
|
+
request.input("createdAt", sql3__default.default.DateTime2, new Date(now));
|
|
2933
|
+
request.input("updatedAt", sql3__default.default.DateTime2, new Date(now));
|
|
1980
2934
|
const mergeSql = `MERGE INTO ${table} AS target
|
|
1981
2935
|
USING (SELECT @workflow_name AS workflow_name, @run_id AS run_id) AS src
|
|
1982
2936
|
ON target.workflow_name = src.workflow_name AND target.run_id = src.run_id
|
|
@@ -2057,7 +3011,7 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
|
|
|
2057
3011
|
if (!result.recordset || result.recordset.length === 0) {
|
|
2058
3012
|
return null;
|
|
2059
3013
|
}
|
|
2060
|
-
return parseWorkflowRun(result.recordset[0]);
|
|
3014
|
+
return this.parseWorkflowRun(result.recordset[0]);
|
|
2061
3015
|
} catch (error$1) {
|
|
2062
3016
|
throw new error.MastraError(
|
|
2063
3017
|
{
|
|
@@ -2094,7 +3048,7 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
|
|
|
2094
3048
|
conditions.push(`[resourceId] = @resourceId`);
|
|
2095
3049
|
paramMap["resourceId"] = resourceId;
|
|
2096
3050
|
} else {
|
|
2097
|
-
|
|
3051
|
+
this.logger?.warn?.(`[${storage.TABLE_WORKFLOW_SNAPSHOT}] resourceId column not found. Skipping resourceId filter.`);
|
|
2098
3052
|
}
|
|
2099
3053
|
}
|
|
2100
3054
|
if (fromDate instanceof Date && !isNaN(fromDate.getTime())) {
|
|
@@ -2111,7 +3065,7 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
|
|
|
2111
3065
|
const request = this.pool.request();
|
|
2112
3066
|
Object.entries(paramMap).forEach(([key, value]) => {
|
|
2113
3067
|
if (value instanceof Date) {
|
|
2114
|
-
request.input(key,
|
|
3068
|
+
request.input(key, sql3__default.default.DateTime, value);
|
|
2115
3069
|
} else {
|
|
2116
3070
|
request.input(key, value);
|
|
2117
3071
|
}
|
|
@@ -2128,7 +3082,7 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
|
|
|
2128
3082
|
request.input("offset", offset);
|
|
2129
3083
|
}
|
|
2130
3084
|
const result = await request.query(query);
|
|
2131
|
-
const runs = (result.recordset || []).map((row) => parseWorkflowRun(row));
|
|
3085
|
+
const runs = (result.recordset || []).map((row) => this.parseWorkflowRun(row));
|
|
2132
3086
|
return { runs, total: total || runs.length };
|
|
2133
3087
|
} catch (error$1) {
|
|
2134
3088
|
throw new error.MastraError(
|
|
@@ -2168,7 +3122,7 @@ var MSSQLStore = class extends storage.MastraStorage {
|
|
|
2168
3122
|
}
|
|
2169
3123
|
}
|
|
2170
3124
|
this.schema = config.schemaName || "dbo";
|
|
2171
|
-
this.pool = "connectionString" in config ? new
|
|
3125
|
+
this.pool = "connectionString" in config ? new sql3__default.default.ConnectionPool(config.connectionString) : new sql3__default.default.ConnectionPool({
|
|
2172
3126
|
server: config.server,
|
|
2173
3127
|
database: config.database,
|
|
2174
3128
|
user: config.user,
|
|
@@ -2179,16 +3133,16 @@ var MSSQLStore = class extends storage.MastraStorage {
|
|
|
2179
3133
|
const legacyEvals = new LegacyEvalsMSSQL({ pool: this.pool, schema: this.schema });
|
|
2180
3134
|
const operations = new StoreOperationsMSSQL({ pool: this.pool, schemaName: this.schema });
|
|
2181
3135
|
const scores = new ScoresMSSQL({ pool: this.pool, operations, schema: this.schema });
|
|
2182
|
-
const traces = new TracesMSSQL({ pool: this.pool, operations, schema: this.schema });
|
|
2183
3136
|
const workflows = new WorkflowsMSSQL({ pool: this.pool, operations, schema: this.schema });
|
|
2184
3137
|
const memory = new MemoryMSSQL({ pool: this.pool, schema: this.schema, operations });
|
|
3138
|
+
const observability = new ObservabilityMSSQL({ pool: this.pool, operations, schema: this.schema });
|
|
2185
3139
|
this.stores = {
|
|
2186
3140
|
operations,
|
|
2187
3141
|
scores,
|
|
2188
|
-
traces,
|
|
2189
3142
|
workflows,
|
|
2190
3143
|
legacyEvals,
|
|
2191
|
-
memory
|
|
3144
|
+
memory,
|
|
3145
|
+
observability
|
|
2192
3146
|
};
|
|
2193
3147
|
} catch (e) {
|
|
2194
3148
|
throw new error.MastraError(
|
|
@@ -2208,6 +3162,11 @@ var MSSQLStore = class extends storage.MastraStorage {
|
|
|
2208
3162
|
try {
|
|
2209
3163
|
await this.isConnected;
|
|
2210
3164
|
await super.init();
|
|
3165
|
+
try {
|
|
3166
|
+
await this.stores.operations.createAutomaticIndexes();
|
|
3167
|
+
} catch (indexError) {
|
|
3168
|
+
this.logger?.warn?.("Failed to create indexes:", indexError);
|
|
3169
|
+
}
|
|
2211
3170
|
} catch (error$1) {
|
|
2212
3171
|
this.isConnected = null;
|
|
2213
3172
|
throw new error.MastraError(
|
|
@@ -2235,7 +3194,9 @@ var MSSQLStore = class extends storage.MastraStorage {
|
|
|
2235
3194
|
hasColumn: true,
|
|
2236
3195
|
createTable: true,
|
|
2237
3196
|
deleteMessages: true,
|
|
2238
|
-
getScoresBySpan: true
|
|
3197
|
+
getScoresBySpan: true,
|
|
3198
|
+
aiTracing: true,
|
|
3199
|
+
indexManagement: true
|
|
2239
3200
|
};
|
|
2240
3201
|
}
|
|
2241
3202
|
/** @deprecated use getEvals instead */
|
|
@@ -2245,18 +3206,6 @@ var MSSQLStore = class extends storage.MastraStorage {
|
|
|
2245
3206
|
async getEvals(options = {}) {
|
|
2246
3207
|
return this.stores.legacyEvals.getEvals(options);
|
|
2247
3208
|
}
|
|
2248
|
-
/**
|
|
2249
|
-
* @deprecated use getTracesPaginated instead
|
|
2250
|
-
*/
|
|
2251
|
-
async getTraces(args) {
|
|
2252
|
-
return this.stores.traces.getTraces(args);
|
|
2253
|
-
}
|
|
2254
|
-
async getTracesPaginated(args) {
|
|
2255
|
-
return this.stores.traces.getTracesPaginated(args);
|
|
2256
|
-
}
|
|
2257
|
-
async batchTraceInsert({ records }) {
|
|
2258
|
-
return this.stores.traces.batchTraceInsert({ records });
|
|
2259
|
-
}
|
|
2260
3209
|
async createTable({
|
|
2261
3210
|
tableName,
|
|
2262
3211
|
schema
|
|
@@ -2401,6 +3350,60 @@ var MSSQLStore = class extends storage.MastraStorage {
|
|
|
2401
3350
|
async close() {
|
|
2402
3351
|
await this.pool.close();
|
|
2403
3352
|
}
|
|
3353
|
+
/**
|
|
3354
|
+
* Index Management
|
|
3355
|
+
*/
|
|
3356
|
+
async createIndex(options) {
|
|
3357
|
+
return this.stores.operations.createIndex(options);
|
|
3358
|
+
}
|
|
3359
|
+
async listIndexes(tableName) {
|
|
3360
|
+
return this.stores.operations.listIndexes(tableName);
|
|
3361
|
+
}
|
|
3362
|
+
async describeIndex(indexName) {
|
|
3363
|
+
return this.stores.operations.describeIndex(indexName);
|
|
3364
|
+
}
|
|
3365
|
+
async dropIndex(indexName) {
|
|
3366
|
+
return this.stores.operations.dropIndex(indexName);
|
|
3367
|
+
}
|
|
3368
|
+
/**
|
|
3369
|
+
* AI Tracing / Observability
|
|
3370
|
+
*/
|
|
3371
|
+
getObservabilityStore() {
|
|
3372
|
+
if (!this.stores.observability) {
|
|
3373
|
+
throw new error.MastraError({
|
|
3374
|
+
id: "MSSQL_STORE_OBSERVABILITY_NOT_INITIALIZED",
|
|
3375
|
+
domain: error.ErrorDomain.STORAGE,
|
|
3376
|
+
category: error.ErrorCategory.SYSTEM,
|
|
3377
|
+
text: "Observability storage is not initialized"
|
|
3378
|
+
});
|
|
3379
|
+
}
|
|
3380
|
+
return this.stores.observability;
|
|
3381
|
+
}
|
|
3382
|
+
async createAISpan(span) {
|
|
3383
|
+
return this.getObservabilityStore().createAISpan(span);
|
|
3384
|
+
}
|
|
3385
|
+
async updateAISpan({
|
|
3386
|
+
spanId,
|
|
3387
|
+
traceId,
|
|
3388
|
+
updates
|
|
3389
|
+
}) {
|
|
3390
|
+
return this.getObservabilityStore().updateAISpan({ spanId, traceId, updates });
|
|
3391
|
+
}
|
|
3392
|
+
async getAITrace(traceId) {
|
|
3393
|
+
return this.getObservabilityStore().getAITrace(traceId);
|
|
3394
|
+
}
|
|
3395
|
+
async getAITracesPaginated(args) {
|
|
3396
|
+
return this.getObservabilityStore().getAITracesPaginated(args);
|
|
3397
|
+
}
|
|
3398
|
+
async batchCreateAISpans(args) {
|
|
3399
|
+
return this.getObservabilityStore().batchCreateAISpans(args);
|
|
3400
|
+
}
|
|
3401
|
+
async batchUpdateAISpans(args) {
|
|
3402
|
+
return this.getObservabilityStore().batchUpdateAISpans(args);
|
|
3403
|
+
}
|
|
3404
|
+
async batchDeleteAITraces(args) {
|
|
3405
|
+
return this.getObservabilityStore().batchDeleteAITraces(args);
|
|
3406
|
+
}
|
|
2404
3407
|
/**
|
|
2405
3408
|
* Scorers
|
|
2406
3409
|
*/
|
|
@@ -2409,9 +3412,18 @@ var MSSQLStore = class extends storage.MastraStorage {
|
|
|
2409
3412
|
}
|
|
2410
3413
|
async getScoresByScorerId({
|
|
2411
3414
|
scorerId: _scorerId,
|
|
2412
|
-
pagination: _pagination
|
|
3415
|
+
pagination: _pagination,
|
|
3416
|
+
entityId: _entityId,
|
|
3417
|
+
entityType: _entityType,
|
|
3418
|
+
source: _source
|
|
2413
3419
|
}) {
|
|
2414
|
-
return this.stores.scores.getScoresByScorerId({
|
|
3420
|
+
return this.stores.scores.getScoresByScorerId({
|
|
3421
|
+
scorerId: _scorerId,
|
|
3422
|
+
pagination: _pagination,
|
|
3423
|
+
entityId: _entityId,
|
|
3424
|
+
entityType: _entityType,
|
|
3425
|
+
source: _source
|
|
3426
|
+
});
|
|
2415
3427
|
}
|
|
2416
3428
|
async saveScore(_score) {
|
|
2417
3429
|
return this.stores.scores.saveScore(_score);
|