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