@mastra/mssql 0.0.0-issue-7087-20250910004053 → 0.0.0-jail-fs-20260105160110
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 +1419 -3
- package/README.md +324 -37
- package/dist/docs/README.md +31 -0
- package/dist/docs/SKILL.md +32 -0
- package/dist/docs/SOURCE_MAP.json +6 -0
- package/dist/docs/storage/01-reference.md +141 -0
- package/dist/index.cjs +2500 -1146
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2497 -1147
- package/dist/index.js.map +1 -1
- package/dist/storage/db/index.d.ts +172 -0
- package/dist/storage/db/index.d.ts.map +1 -0
- package/dist/storage/db/utils.d.ts +21 -0
- package/dist/storage/db/utils.d.ts.map +1 -0
- package/dist/storage/domains/memory/index.d.ts +38 -52
- package/dist/storage/domains/memory/index.d.ts.map +1 -1
- package/dist/storage/domains/observability/index.d.ts +46 -0
- package/dist/storage/domains/observability/index.d.ts.map +1 -0
- package/dist/storage/domains/scores/index.d.ts +38 -25
- 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 +39 -28
- package/dist/storage/domains/workflows/index.d.ts.map +1 -1
- package/dist/storage/index.d.ts +115 -213
- package/dist/storage/index.d.ts.map +1 -1
- package/package.json +15 -10
- 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/operations/index.d.ts +0 -51
- package/dist/storage/domains/operations/index.d.ts.map +0 -1
- package/dist/storage/domains/traces/index.d.ts +0 -37
- package/dist/storage/domains/traces/index.d.ts.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -2,13 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
var error = require('@mastra/core/error');
|
|
4
4
|
var storage = require('@mastra/core/storage');
|
|
5
|
-
var
|
|
6
|
-
var utils = require('@mastra/core/utils');
|
|
5
|
+
var sql = require('mssql');
|
|
7
6
|
var agent = require('@mastra/core/agent');
|
|
7
|
+
var base = require('@mastra/core/base');
|
|
8
|
+
var utils = require('@mastra/core/utils');
|
|
9
|
+
var crypto = require('crypto');
|
|
10
|
+
var evals = require('@mastra/core/evals');
|
|
8
11
|
|
|
9
12
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
10
13
|
|
|
11
|
-
var
|
|
14
|
+
var sql__default = /*#__PURE__*/_interopDefault(sql);
|
|
12
15
|
|
|
13
16
|
// src/storage/index.ts
|
|
14
17
|
function getSchemaName(schema) {
|
|
@@ -21,157 +24,1119 @@ function getTableName({ indexName, schemaName }) {
|
|
|
21
24
|
return quotedSchemaName ? `${quotedSchemaName}.${quotedIndexName}` : quotedIndexName;
|
|
22
25
|
}
|
|
23
26
|
|
|
24
|
-
// src/storage/
|
|
25
|
-
function
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
// src/storage/db/index.ts
|
|
28
|
+
function resolveMssqlConfig(config) {
|
|
29
|
+
if ("pool" in config && !("server" in config)) {
|
|
30
|
+
return {
|
|
31
|
+
pool: config.pool,
|
|
32
|
+
schemaName: config.schemaName,
|
|
33
|
+
skipDefaultIndexes: config.skipDefaultIndexes,
|
|
34
|
+
indexes: config.indexes,
|
|
35
|
+
needsConnect: false
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
const restConfig = config;
|
|
39
|
+
const pool = new sql__default.default.ConnectionPool({
|
|
40
|
+
server: restConfig.server,
|
|
41
|
+
database: restConfig.database,
|
|
42
|
+
user: restConfig.user,
|
|
43
|
+
password: restConfig.password,
|
|
44
|
+
port: restConfig.port,
|
|
45
|
+
options: restConfig.options || { encrypt: true, trustServerCertificate: true }
|
|
46
|
+
});
|
|
47
|
+
return {
|
|
48
|
+
pool,
|
|
49
|
+
schemaName: restConfig.schemaName,
|
|
50
|
+
skipDefaultIndexes: restConfig.skipDefaultIndexes,
|
|
51
|
+
indexes: restConfig.indexes,
|
|
52
|
+
needsConnect: true
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
var MssqlDB = class extends base.MastraBase {
|
|
56
|
+
pool;
|
|
57
|
+
schemaName;
|
|
58
|
+
skipDefaultIndexes;
|
|
59
|
+
setupSchemaPromise = null;
|
|
60
|
+
schemaSetupComplete = void 0;
|
|
61
|
+
/**
|
|
62
|
+
* Columns that participate in composite indexes need smaller sizes (NVARCHAR(100)).
|
|
63
|
+
* MSSQL has a 900-byte index key limit, so composite indexes with NVARCHAR(400) columns fail.
|
|
64
|
+
* These are typically ID/type fields that don't need 400 chars.
|
|
65
|
+
*/
|
|
66
|
+
COMPOSITE_INDEX_COLUMNS = [
|
|
67
|
+
"traceId",
|
|
68
|
+
// Used in: PRIMARY KEY (traceId, spanId), index (traceId, spanId, seq_id)
|
|
69
|
+
"spanId",
|
|
70
|
+
// Used in: PRIMARY KEY (traceId, spanId), index (traceId, spanId, seq_id)
|
|
71
|
+
"parentSpanId",
|
|
72
|
+
// Used in: index (parentSpanId, startedAt)
|
|
73
|
+
"entityType",
|
|
74
|
+
// Used in: (entityType, entityId), (entityType, entityName)
|
|
75
|
+
"entityId",
|
|
76
|
+
// Used in: (entityType, entityId)
|
|
77
|
+
"entityName",
|
|
78
|
+
// Used in: (entityType, entityName)
|
|
79
|
+
"organizationId",
|
|
80
|
+
// Used in: (organizationId, userId)
|
|
81
|
+
"userId"
|
|
82
|
+
// Used in: (organizationId, userId)
|
|
83
|
+
];
|
|
84
|
+
/**
|
|
85
|
+
* Columns that store large amounts of data and should use NVARCHAR(MAX).
|
|
86
|
+
* Avoid listing columns that participate in indexes (resourceId, thread_id, agent_name, name, etc.)
|
|
87
|
+
*/
|
|
88
|
+
LARGE_DATA_COLUMNS = [
|
|
89
|
+
"workingMemory",
|
|
90
|
+
"snapshot",
|
|
91
|
+
"metadata",
|
|
92
|
+
"content",
|
|
93
|
+
// messages.content - can be very long conversation content
|
|
94
|
+
"input",
|
|
95
|
+
// evals.input - test input data
|
|
96
|
+
"output",
|
|
97
|
+
// evals.output - test output data
|
|
98
|
+
"instructions",
|
|
99
|
+
// evals.instructions - evaluation instructions
|
|
100
|
+
"other"
|
|
101
|
+
// traces.other - additional trace data
|
|
102
|
+
];
|
|
103
|
+
getSqlType(type, isPrimaryKey = false, useLargeStorage = false, useSmallStorage = false) {
|
|
104
|
+
switch (type) {
|
|
105
|
+
case "text":
|
|
106
|
+
if (useLargeStorage) {
|
|
107
|
+
return "NVARCHAR(MAX)";
|
|
108
|
+
}
|
|
109
|
+
if (useSmallStorage) {
|
|
110
|
+
return "NVARCHAR(100)";
|
|
111
|
+
}
|
|
112
|
+
return isPrimaryKey ? "NVARCHAR(255)" : "NVARCHAR(400)";
|
|
113
|
+
case "timestamp":
|
|
114
|
+
return "DATETIME2(7)";
|
|
115
|
+
case "uuid":
|
|
116
|
+
return "UNIQUEIDENTIFIER";
|
|
117
|
+
case "jsonb":
|
|
118
|
+
return "NVARCHAR(MAX)";
|
|
119
|
+
case "integer":
|
|
120
|
+
return "INT";
|
|
121
|
+
case "bigint":
|
|
122
|
+
return "BIGINT";
|
|
123
|
+
case "float":
|
|
124
|
+
return "FLOAT";
|
|
125
|
+
case "boolean":
|
|
126
|
+
return "BIT";
|
|
127
|
+
default:
|
|
128
|
+
throw new error.MastraError({
|
|
129
|
+
id: storage.createStorageErrorId("MSSQL", "TYPE", "NOT_SUPPORTED"),
|
|
130
|
+
domain: error.ErrorDomain.STORAGE,
|
|
131
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
constructor({
|
|
136
|
+
pool,
|
|
137
|
+
schemaName,
|
|
138
|
+
skipDefaultIndexes
|
|
139
|
+
}) {
|
|
140
|
+
super({ component: "STORAGE", name: "MssqlDB" });
|
|
141
|
+
this.pool = pool;
|
|
142
|
+
this.schemaName = schemaName;
|
|
143
|
+
this.skipDefaultIndexes = skipDefaultIndexes;
|
|
144
|
+
}
|
|
145
|
+
async hasColumn(table, column) {
|
|
146
|
+
const schema = this.schemaName || "dbo";
|
|
147
|
+
const request = this.pool.request();
|
|
148
|
+
request.input("schema", schema);
|
|
149
|
+
request.input("table", table);
|
|
150
|
+
request.input("column", column);
|
|
151
|
+
request.input("columnLower", column.toLowerCase());
|
|
152
|
+
const result = await request.query(
|
|
153
|
+
`SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = @schema AND TABLE_NAME = @table AND (COLUMN_NAME = @column OR COLUMN_NAME = @columnLower)`
|
|
154
|
+
);
|
|
155
|
+
return result.recordset.length > 0;
|
|
156
|
+
}
|
|
157
|
+
async setupSchema() {
|
|
158
|
+
if (!this.schemaName || this.schemaSetupComplete) {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
if (!this.setupSchemaPromise) {
|
|
162
|
+
this.setupSchemaPromise = (async () => {
|
|
163
|
+
try {
|
|
164
|
+
const checkRequest = this.pool.request();
|
|
165
|
+
checkRequest.input("schemaName", this.schemaName);
|
|
166
|
+
const checkResult = await checkRequest.query(`
|
|
167
|
+
SELECT 1 AS found FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = @schemaName
|
|
168
|
+
`);
|
|
169
|
+
const schemaExists = Array.isArray(checkResult.recordset) && checkResult.recordset.length > 0;
|
|
170
|
+
if (!schemaExists) {
|
|
171
|
+
try {
|
|
172
|
+
await this.pool.request().query(`CREATE SCHEMA [${this.schemaName}]`);
|
|
173
|
+
this.logger?.info?.(`Schema "${this.schemaName}" created successfully`);
|
|
174
|
+
} catch (error) {
|
|
175
|
+
this.logger?.error?.(`Failed to create schema "${this.schemaName}"`, { error });
|
|
176
|
+
throw new Error(
|
|
177
|
+
`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.`
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
this.schemaSetupComplete = true;
|
|
182
|
+
this.logger?.debug?.(`Schema "${this.schemaName}" is ready for use`);
|
|
183
|
+
} catch (error) {
|
|
184
|
+
this.schemaSetupComplete = void 0;
|
|
185
|
+
this.setupSchemaPromise = null;
|
|
186
|
+
throw error;
|
|
187
|
+
} finally {
|
|
188
|
+
this.setupSchemaPromise = null;
|
|
189
|
+
}
|
|
190
|
+
})();
|
|
191
|
+
}
|
|
192
|
+
await this.setupSchemaPromise;
|
|
193
|
+
}
|
|
194
|
+
async insert({
|
|
195
|
+
tableName,
|
|
196
|
+
record,
|
|
197
|
+
transaction
|
|
198
|
+
}) {
|
|
28
199
|
try {
|
|
29
|
-
|
|
30
|
-
|
|
200
|
+
const columns = Object.keys(record);
|
|
201
|
+
const parsedColumns = columns.map((col) => utils.parseSqlIdentifier(col, "column name"));
|
|
202
|
+
const paramNames = columns.map((_, i) => `@param${i}`);
|
|
203
|
+
const insertSql = `INSERT INTO ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} (${parsedColumns.map((c) => `[${c}]`).join(", ")}) VALUES (${paramNames.join(", ")})`;
|
|
204
|
+
const request = transaction ? transaction.request() : this.pool.request();
|
|
205
|
+
columns.forEach((col, i) => {
|
|
206
|
+
const value = record[col];
|
|
207
|
+
const preparedValue = this.prepareValue(value, col, tableName);
|
|
208
|
+
if (preparedValue instanceof Date) {
|
|
209
|
+
request.input(`param${i}`, sql__default.default.DateTime2, preparedValue);
|
|
210
|
+
} else if (preparedValue === null || preparedValue === void 0) {
|
|
211
|
+
request.input(`param${i}`, this.getMssqlType(tableName, col), null);
|
|
212
|
+
} else {
|
|
213
|
+
request.input(`param${i}`, preparedValue);
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
await request.query(insertSql);
|
|
217
|
+
} catch (error$1) {
|
|
218
|
+
throw new error.MastraError(
|
|
219
|
+
{
|
|
220
|
+
id: storage.createStorageErrorId("MSSQL", "INSERT", "FAILED"),
|
|
221
|
+
domain: error.ErrorDomain.STORAGE,
|
|
222
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
223
|
+
details: {
|
|
224
|
+
tableName
|
|
225
|
+
}
|
|
226
|
+
},
|
|
227
|
+
error$1
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
async clearTable({ tableName }) {
|
|
232
|
+
const fullTableName = getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) });
|
|
233
|
+
try {
|
|
234
|
+
try {
|
|
235
|
+
await this.pool.request().query(`TRUNCATE TABLE ${fullTableName}`);
|
|
236
|
+
} catch (truncateError) {
|
|
237
|
+
if (truncateError?.number === 4712) {
|
|
238
|
+
await this.pool.request().query(`DELETE FROM ${fullTableName}`);
|
|
239
|
+
} else {
|
|
240
|
+
throw truncateError;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
} catch (error$1) {
|
|
244
|
+
throw new error.MastraError(
|
|
245
|
+
{
|
|
246
|
+
id: storage.createStorageErrorId("MSSQL", "CLEAR_TABLE", "FAILED"),
|
|
247
|
+
domain: error.ErrorDomain.STORAGE,
|
|
248
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
249
|
+
details: {
|
|
250
|
+
tableName
|
|
251
|
+
}
|
|
252
|
+
},
|
|
253
|
+
error$1
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
getDefaultValue(type) {
|
|
258
|
+
switch (type) {
|
|
259
|
+
case "timestamp":
|
|
260
|
+
return "DEFAULT SYSUTCDATETIME()";
|
|
261
|
+
case "jsonb":
|
|
262
|
+
return "DEFAULT N'{}'";
|
|
263
|
+
case "boolean":
|
|
264
|
+
return "DEFAULT 0";
|
|
265
|
+
default:
|
|
266
|
+
return storage.getDefaultValue(type);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
async createTable({
|
|
270
|
+
tableName,
|
|
271
|
+
schema
|
|
272
|
+
}) {
|
|
273
|
+
try {
|
|
274
|
+
const uniqueConstraintColumns = tableName === storage.TABLE_WORKFLOW_SNAPSHOT ? ["workflow_name", "run_id"] : [];
|
|
275
|
+
const columns = Object.entries(schema).map(([name, def]) => {
|
|
276
|
+
const parsedName = utils.parseSqlIdentifier(name, "column name");
|
|
277
|
+
const constraints = [];
|
|
278
|
+
if (def.primaryKey) constraints.push("PRIMARY KEY");
|
|
279
|
+
if (!def.nullable) constraints.push("NOT NULL");
|
|
280
|
+
const isIndexed = !!def.primaryKey || uniqueConstraintColumns.includes(name);
|
|
281
|
+
const useLargeStorage = this.LARGE_DATA_COLUMNS.includes(name);
|
|
282
|
+
const useSmallStorage = this.COMPOSITE_INDEX_COLUMNS.includes(name);
|
|
283
|
+
return `[${parsedName}] ${this.getSqlType(def.type, isIndexed, useLargeStorage, useSmallStorage)} ${constraints.join(" ")}`.trim();
|
|
284
|
+
}).join(",\n");
|
|
285
|
+
if (this.schemaName) {
|
|
286
|
+
await this.setupSchema();
|
|
287
|
+
}
|
|
288
|
+
const checkTableRequest = this.pool.request();
|
|
289
|
+
checkTableRequest.input(
|
|
290
|
+
"tableName",
|
|
291
|
+
getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) }).replace(/[[\]]/g, "").split(".").pop()
|
|
292
|
+
);
|
|
293
|
+
const checkTableSql = `SELECT 1 AS found FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = @schema AND TABLE_NAME = @tableName`;
|
|
294
|
+
checkTableRequest.input("schema", this.schemaName || "dbo");
|
|
295
|
+
const checkTableResult = await checkTableRequest.query(checkTableSql);
|
|
296
|
+
const tableExists = Array.isArray(checkTableResult.recordset) && checkTableResult.recordset.length > 0;
|
|
297
|
+
if (!tableExists) {
|
|
298
|
+
const createSql = `CREATE TABLE ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} (
|
|
299
|
+
${columns}
|
|
300
|
+
)`;
|
|
301
|
+
await this.pool.request().query(createSql);
|
|
302
|
+
}
|
|
303
|
+
const columnCheckSql = `
|
|
304
|
+
SELECT 1 AS found
|
|
305
|
+
FROM INFORMATION_SCHEMA.COLUMNS
|
|
306
|
+
WHERE TABLE_SCHEMA = @schema AND TABLE_NAME = @tableName AND COLUMN_NAME = 'seq_id'
|
|
307
|
+
`;
|
|
308
|
+
const checkColumnRequest = this.pool.request();
|
|
309
|
+
checkColumnRequest.input("schema", this.schemaName || "dbo");
|
|
310
|
+
checkColumnRequest.input(
|
|
311
|
+
"tableName",
|
|
312
|
+
getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) }).replace(/[[\]]/g, "").split(".").pop()
|
|
313
|
+
);
|
|
314
|
+
const columnResult = await checkColumnRequest.query(columnCheckSql);
|
|
315
|
+
const columnExists = Array.isArray(columnResult.recordset) && columnResult.recordset.length > 0;
|
|
316
|
+
if (!columnExists) {
|
|
317
|
+
const alterSql = `ALTER TABLE ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} ADD seq_id BIGINT IDENTITY(1,1)`;
|
|
318
|
+
await this.pool.request().query(alterSql);
|
|
319
|
+
}
|
|
320
|
+
const schemaPrefix = this.schemaName ? `${this.schemaName}_` : "";
|
|
321
|
+
if (tableName === storage.TABLE_WORKFLOW_SNAPSHOT) {
|
|
322
|
+
const constraintName = `${schemaPrefix}mastra_workflow_snapshot_workflow_name_run_id_key`;
|
|
323
|
+
const checkConstraintSql = `SELECT 1 AS found FROM sys.key_constraints WHERE name = @constraintName`;
|
|
324
|
+
const checkConstraintRequest = this.pool.request();
|
|
325
|
+
checkConstraintRequest.input("constraintName", constraintName);
|
|
326
|
+
const constraintResult = await checkConstraintRequest.query(checkConstraintSql);
|
|
327
|
+
const constraintExists = Array.isArray(constraintResult.recordset) && constraintResult.recordset.length > 0;
|
|
328
|
+
if (!constraintExists) {
|
|
329
|
+
const addConstraintSql = `ALTER TABLE ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} ADD CONSTRAINT [${constraintName}] UNIQUE ([workflow_name], [run_id])`;
|
|
330
|
+
await this.pool.request().query(addConstraintSql);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
if (tableName === storage.TABLE_SPANS) {
|
|
334
|
+
await this.migrateSpansTable();
|
|
335
|
+
const pkConstraintName = `${schemaPrefix}mastra_ai_spans_traceid_spanid_pk`;
|
|
336
|
+
const checkPkRequest = this.pool.request();
|
|
337
|
+
checkPkRequest.input("constraintName", pkConstraintName);
|
|
338
|
+
const pkResult = await checkPkRequest.query(
|
|
339
|
+
`SELECT 1 AS found FROM sys.key_constraints WHERE name = @constraintName`
|
|
340
|
+
);
|
|
341
|
+
const pkExists = Array.isArray(pkResult.recordset) && pkResult.recordset.length > 0;
|
|
342
|
+
if (!pkExists) {
|
|
343
|
+
try {
|
|
344
|
+
const addPkSql = `ALTER TABLE ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} ADD CONSTRAINT [${pkConstraintName}] PRIMARY KEY ([traceId], [spanId])`;
|
|
345
|
+
await this.pool.request().query(addPkSql);
|
|
346
|
+
} catch (pkError) {
|
|
347
|
+
this.logger?.warn?.(`Failed to add composite primary key to spans table:`, pkError);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
} catch (error$1) {
|
|
352
|
+
throw new error.MastraError(
|
|
353
|
+
{
|
|
354
|
+
id: storage.createStorageErrorId("MSSQL", "CREATE_TABLE", "FAILED"),
|
|
355
|
+
domain: error.ErrorDomain.STORAGE,
|
|
356
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
357
|
+
details: {
|
|
358
|
+
tableName
|
|
359
|
+
}
|
|
360
|
+
},
|
|
361
|
+
error$1
|
|
362
|
+
);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Migrates the spans table schema from OLD_SPAN_SCHEMA to current SPAN_SCHEMA.
|
|
367
|
+
* This adds new columns that don't exist in old schema.
|
|
368
|
+
*/
|
|
369
|
+
async migrateSpansTable() {
|
|
370
|
+
const fullTableName = getTableName({ indexName: storage.TABLE_SPANS, schemaName: getSchemaName(this.schemaName) });
|
|
371
|
+
const schema = storage.TABLE_SCHEMAS[storage.TABLE_SPANS];
|
|
372
|
+
try {
|
|
373
|
+
for (const [columnName, columnDef] of Object.entries(schema)) {
|
|
374
|
+
const columnExists = await this.hasColumn(storage.TABLE_SPANS, columnName);
|
|
375
|
+
if (!columnExists) {
|
|
376
|
+
const parsedColumnName = utils.parseSqlIdentifier(columnName, "column name");
|
|
377
|
+
const useLargeStorage = this.LARGE_DATA_COLUMNS.includes(columnName);
|
|
378
|
+
const useSmallStorage = this.COMPOSITE_INDEX_COLUMNS.includes(columnName);
|
|
379
|
+
const isIndexed = !!columnDef.primaryKey;
|
|
380
|
+
const sqlType = this.getSqlType(columnDef.type, isIndexed, useLargeStorage, useSmallStorage);
|
|
381
|
+
const nullable = columnDef.nullable ? "" : "NOT NULL";
|
|
382
|
+
const defaultValue = !columnDef.nullable ? this.getDefaultValue(columnDef.type) : "";
|
|
383
|
+
const alterSql = `ALTER TABLE ${fullTableName} ADD [${parsedColumnName}] ${sqlType} ${nullable} ${defaultValue}`.trim();
|
|
384
|
+
await this.pool.request().query(alterSql);
|
|
385
|
+
this.logger?.debug?.(`Added column '${columnName}' to ${fullTableName}`);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
this.logger?.info?.(`Migration completed for ${fullTableName}`);
|
|
389
|
+
} catch (error) {
|
|
390
|
+
this.logger?.warn?.(`Failed to migrate spans table ${fullTableName}:`, error);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
/**
|
|
394
|
+
* Alters table schema to add columns if they don't exist
|
|
395
|
+
* @param tableName Name of the table
|
|
396
|
+
* @param schema Schema of the table
|
|
397
|
+
* @param ifNotExists Array of column names to add if they don't exist
|
|
398
|
+
*/
|
|
399
|
+
async alterTable({
|
|
400
|
+
tableName,
|
|
401
|
+
schema,
|
|
402
|
+
ifNotExists
|
|
403
|
+
}) {
|
|
404
|
+
const fullTableName = getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) });
|
|
405
|
+
try {
|
|
406
|
+
for (const columnName of ifNotExists) {
|
|
407
|
+
if (schema[columnName]) {
|
|
408
|
+
const columnCheckRequest = this.pool.request();
|
|
409
|
+
columnCheckRequest.input("tableName", fullTableName.replace(/[[\]]/g, "").split(".").pop());
|
|
410
|
+
columnCheckRequest.input("columnName", columnName);
|
|
411
|
+
columnCheckRequest.input("schema", this.schemaName || "dbo");
|
|
412
|
+
const checkSql = `SELECT 1 AS found FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = @schema AND TABLE_NAME = @tableName AND COLUMN_NAME = @columnName`;
|
|
413
|
+
const checkResult = await columnCheckRequest.query(checkSql);
|
|
414
|
+
const columnExists = Array.isArray(checkResult.recordset) && checkResult.recordset.length > 0;
|
|
415
|
+
if (!columnExists) {
|
|
416
|
+
const columnDef = schema[columnName];
|
|
417
|
+
const useLargeStorage = this.LARGE_DATA_COLUMNS.includes(columnName);
|
|
418
|
+
const useSmallStorage = this.COMPOSITE_INDEX_COLUMNS.includes(columnName);
|
|
419
|
+
const isIndexed = !!columnDef.primaryKey;
|
|
420
|
+
const sqlType = this.getSqlType(columnDef.type, isIndexed, useLargeStorage, useSmallStorage);
|
|
421
|
+
const nullable = columnDef.nullable ? "" : "NOT NULL";
|
|
422
|
+
const defaultValue = !columnDef.nullable ? this.getDefaultValue(columnDef.type) : "";
|
|
423
|
+
const parsedColumnName = utils.parseSqlIdentifier(columnName, "column name");
|
|
424
|
+
const alterSql = `ALTER TABLE ${fullTableName} ADD [${parsedColumnName}] ${sqlType} ${nullable} ${defaultValue}`.trim();
|
|
425
|
+
await this.pool.request().query(alterSql);
|
|
426
|
+
this.logger?.debug?.(`Ensured column ${parsedColumnName} exists in table ${fullTableName}`);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
} catch (error$1) {
|
|
431
|
+
throw new error.MastraError(
|
|
432
|
+
{
|
|
433
|
+
id: storage.createStorageErrorId("MSSQL", "ALTER_TABLE", "FAILED"),
|
|
434
|
+
domain: error.ErrorDomain.STORAGE,
|
|
435
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
436
|
+
details: {
|
|
437
|
+
tableName
|
|
438
|
+
}
|
|
439
|
+
},
|
|
440
|
+
error$1
|
|
441
|
+
);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
async load({ tableName, keys }) {
|
|
445
|
+
try {
|
|
446
|
+
const keyEntries = Object.entries(keys).map(([key, value]) => [utils.parseSqlIdentifier(key, "column name"), value]);
|
|
447
|
+
const conditions = keyEntries.map(([key], i) => `[${key}] = @param${i}`).join(" AND ");
|
|
448
|
+
const sqlQuery = `SELECT * FROM ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} WHERE ${conditions}`;
|
|
449
|
+
const request = this.pool.request();
|
|
450
|
+
keyEntries.forEach(([key, value], i) => {
|
|
451
|
+
const preparedValue = this.prepareValue(value, key, tableName);
|
|
452
|
+
if (preparedValue === null || preparedValue === void 0) {
|
|
453
|
+
request.input(`param${i}`, this.getMssqlType(tableName, key), null);
|
|
454
|
+
} else {
|
|
455
|
+
request.input(`param${i}`, preparedValue);
|
|
456
|
+
}
|
|
457
|
+
});
|
|
458
|
+
const resultSet = await request.query(sqlQuery);
|
|
459
|
+
const result = resultSet.recordset[0] || null;
|
|
460
|
+
if (!result) {
|
|
461
|
+
return null;
|
|
462
|
+
}
|
|
463
|
+
if (tableName === storage.TABLE_WORKFLOW_SNAPSHOT) {
|
|
464
|
+
const snapshot = result;
|
|
465
|
+
if (typeof snapshot.snapshot === "string") {
|
|
466
|
+
snapshot.snapshot = JSON.parse(snapshot.snapshot);
|
|
467
|
+
}
|
|
468
|
+
return snapshot;
|
|
469
|
+
}
|
|
470
|
+
return result;
|
|
471
|
+
} catch (error$1) {
|
|
472
|
+
throw new error.MastraError(
|
|
473
|
+
{
|
|
474
|
+
id: storage.createStorageErrorId("MSSQL", "LOAD", "FAILED"),
|
|
475
|
+
domain: error.ErrorDomain.STORAGE,
|
|
476
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
477
|
+
details: {
|
|
478
|
+
tableName
|
|
479
|
+
}
|
|
480
|
+
},
|
|
481
|
+
error$1
|
|
482
|
+
);
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
async batchInsert({ tableName, records }) {
|
|
486
|
+
const transaction = this.pool.transaction();
|
|
487
|
+
try {
|
|
488
|
+
await transaction.begin();
|
|
489
|
+
for (const record of records) {
|
|
490
|
+
await this.insert({ tableName, record, transaction });
|
|
491
|
+
}
|
|
492
|
+
await transaction.commit();
|
|
493
|
+
} catch (error$1) {
|
|
494
|
+
await transaction.rollback();
|
|
495
|
+
throw new error.MastraError(
|
|
496
|
+
{
|
|
497
|
+
id: storage.createStorageErrorId("MSSQL", "BATCH_INSERT", "FAILED"),
|
|
498
|
+
domain: error.ErrorDomain.STORAGE,
|
|
499
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
500
|
+
details: {
|
|
501
|
+
tableName,
|
|
502
|
+
numberOfRecords: records.length
|
|
503
|
+
}
|
|
504
|
+
},
|
|
505
|
+
error$1
|
|
506
|
+
);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
async dropTable({ tableName }) {
|
|
510
|
+
try {
|
|
511
|
+
const tableNameWithSchema = getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) });
|
|
512
|
+
await this.pool.request().query(`DROP TABLE IF EXISTS ${tableNameWithSchema}`);
|
|
513
|
+
} catch (error$1) {
|
|
514
|
+
throw new error.MastraError(
|
|
515
|
+
{
|
|
516
|
+
id: storage.createStorageErrorId("MSSQL", "DROP_TABLE", "FAILED"),
|
|
517
|
+
domain: error.ErrorDomain.STORAGE,
|
|
518
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
519
|
+
details: {
|
|
520
|
+
tableName
|
|
521
|
+
}
|
|
522
|
+
},
|
|
523
|
+
error$1
|
|
524
|
+
);
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
/**
|
|
528
|
+
* Prepares a value for database operations, handling Date objects and JSON serialization
|
|
529
|
+
*/
|
|
530
|
+
prepareValue(value, columnName, tableName) {
|
|
531
|
+
if (value === null || value === void 0) {
|
|
532
|
+
return value;
|
|
533
|
+
}
|
|
534
|
+
if (value instanceof Date) {
|
|
535
|
+
return value;
|
|
536
|
+
}
|
|
537
|
+
const schema = storage.TABLE_SCHEMAS[tableName];
|
|
538
|
+
const columnSchema = schema?.[columnName];
|
|
539
|
+
if (columnSchema?.type === "boolean") {
|
|
540
|
+
return value ? 1 : 0;
|
|
541
|
+
}
|
|
542
|
+
if (columnSchema?.type === "jsonb") {
|
|
543
|
+
if (typeof value === "string") {
|
|
544
|
+
const trimmed = value.trim();
|
|
545
|
+
if (trimmed.length > 0) {
|
|
546
|
+
try {
|
|
547
|
+
JSON.parse(trimmed);
|
|
548
|
+
return trimmed;
|
|
549
|
+
} catch {
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
return JSON.stringify(value);
|
|
553
|
+
}
|
|
554
|
+
if (typeof value === "bigint") {
|
|
555
|
+
return value.toString();
|
|
556
|
+
}
|
|
557
|
+
return JSON.stringify(value);
|
|
558
|
+
}
|
|
559
|
+
if (typeof value === "object") {
|
|
560
|
+
return JSON.stringify(value);
|
|
561
|
+
}
|
|
562
|
+
return value;
|
|
563
|
+
}
|
|
564
|
+
/**
|
|
565
|
+
* Maps TABLE_SCHEMAS types to mssql param types (used when value is null)
|
|
566
|
+
*/
|
|
567
|
+
getMssqlType(tableName, columnName) {
|
|
568
|
+
const col = storage.TABLE_SCHEMAS[tableName]?.[columnName];
|
|
569
|
+
switch (col?.type) {
|
|
570
|
+
case "text":
|
|
571
|
+
return sql__default.default.NVarChar;
|
|
572
|
+
case "timestamp":
|
|
573
|
+
return sql__default.default.DateTime2;
|
|
574
|
+
case "uuid":
|
|
575
|
+
return sql__default.default.UniqueIdentifier;
|
|
576
|
+
case "jsonb":
|
|
577
|
+
return sql__default.default.NVarChar;
|
|
578
|
+
case "integer":
|
|
579
|
+
return sql__default.default.Int;
|
|
580
|
+
case "bigint":
|
|
581
|
+
return sql__default.default.BigInt;
|
|
582
|
+
case "float":
|
|
583
|
+
return sql__default.default.Float;
|
|
584
|
+
case "boolean":
|
|
585
|
+
return sql__default.default.Bit;
|
|
586
|
+
default:
|
|
587
|
+
return sql__default.default.NVarChar;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
/**
|
|
591
|
+
* Update a single record in the database
|
|
592
|
+
*/
|
|
593
|
+
async update({
|
|
594
|
+
tableName,
|
|
595
|
+
keys,
|
|
596
|
+
data,
|
|
597
|
+
transaction
|
|
598
|
+
}) {
|
|
599
|
+
try {
|
|
600
|
+
if (!data || Object.keys(data).length === 0) {
|
|
601
|
+
throw new error.MastraError({
|
|
602
|
+
id: storage.createStorageErrorId("MSSQL", "UPDATE", "EMPTY_DATA"),
|
|
603
|
+
domain: error.ErrorDomain.STORAGE,
|
|
604
|
+
category: error.ErrorCategory.USER,
|
|
605
|
+
text: "Cannot update with empty data payload"
|
|
606
|
+
});
|
|
607
|
+
}
|
|
608
|
+
if (!keys || Object.keys(keys).length === 0) {
|
|
609
|
+
throw new error.MastraError({
|
|
610
|
+
id: storage.createStorageErrorId("MSSQL", "UPDATE", "EMPTY_KEYS"),
|
|
611
|
+
domain: error.ErrorDomain.STORAGE,
|
|
612
|
+
category: error.ErrorCategory.USER,
|
|
613
|
+
text: "Cannot update without keys to identify records"
|
|
614
|
+
});
|
|
615
|
+
}
|
|
616
|
+
const setClauses = [];
|
|
617
|
+
const request = transaction ? transaction.request() : this.pool.request();
|
|
618
|
+
let paramIndex = 0;
|
|
619
|
+
Object.entries(data).forEach(([key, value]) => {
|
|
620
|
+
const parsedKey = utils.parseSqlIdentifier(key, "column name");
|
|
621
|
+
const paramName = `set${paramIndex++}`;
|
|
622
|
+
setClauses.push(`[${parsedKey}] = @${paramName}`);
|
|
623
|
+
const preparedValue = this.prepareValue(value, key, tableName);
|
|
624
|
+
if (preparedValue === null || preparedValue === void 0) {
|
|
625
|
+
request.input(paramName, this.getMssqlType(tableName, key), null);
|
|
626
|
+
} else {
|
|
627
|
+
request.input(paramName, preparedValue);
|
|
628
|
+
}
|
|
629
|
+
});
|
|
630
|
+
const whereConditions = [];
|
|
631
|
+
Object.entries(keys).forEach(([key, value]) => {
|
|
632
|
+
const parsedKey = utils.parseSqlIdentifier(key, "column name");
|
|
633
|
+
const paramName = `where${paramIndex++}`;
|
|
634
|
+
whereConditions.push(`[${parsedKey}] = @${paramName}`);
|
|
635
|
+
const preparedValue = this.prepareValue(value, key, tableName);
|
|
636
|
+
if (preparedValue === null || preparedValue === void 0) {
|
|
637
|
+
request.input(paramName, this.getMssqlType(tableName, key), null);
|
|
638
|
+
} else {
|
|
639
|
+
request.input(paramName, preparedValue);
|
|
640
|
+
}
|
|
641
|
+
});
|
|
642
|
+
const tableName_ = getTableName({
|
|
643
|
+
indexName: tableName,
|
|
644
|
+
schemaName: getSchemaName(this.schemaName)
|
|
645
|
+
});
|
|
646
|
+
const updateSql = `UPDATE ${tableName_} SET ${setClauses.join(", ")} WHERE ${whereConditions.join(" AND ")}`;
|
|
647
|
+
await request.query(updateSql);
|
|
648
|
+
} catch (error$1) {
|
|
649
|
+
throw new error.MastraError(
|
|
650
|
+
{
|
|
651
|
+
id: storage.createStorageErrorId("MSSQL", "UPDATE", "FAILED"),
|
|
652
|
+
domain: error.ErrorDomain.STORAGE,
|
|
653
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
654
|
+
details: {
|
|
655
|
+
tableName
|
|
656
|
+
}
|
|
657
|
+
},
|
|
658
|
+
error$1
|
|
659
|
+
);
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
/**
|
|
663
|
+
* Update multiple records in a single batch transaction
|
|
664
|
+
*/
|
|
665
|
+
async batchUpdate({
|
|
666
|
+
tableName,
|
|
667
|
+
updates
|
|
668
|
+
}) {
|
|
669
|
+
const transaction = this.pool.transaction();
|
|
670
|
+
try {
|
|
671
|
+
await transaction.begin();
|
|
672
|
+
for (const { keys, data } of updates) {
|
|
673
|
+
await this.update({ tableName, keys, data, transaction });
|
|
674
|
+
}
|
|
675
|
+
await transaction.commit();
|
|
676
|
+
} catch (error$1) {
|
|
677
|
+
await transaction.rollback();
|
|
678
|
+
throw new error.MastraError(
|
|
679
|
+
{
|
|
680
|
+
id: storage.createStorageErrorId("MSSQL", "BATCH_UPDATE", "FAILED"),
|
|
681
|
+
domain: error.ErrorDomain.STORAGE,
|
|
682
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
683
|
+
details: {
|
|
684
|
+
tableName,
|
|
685
|
+
numberOfRecords: updates.length
|
|
686
|
+
}
|
|
687
|
+
},
|
|
688
|
+
error$1
|
|
689
|
+
);
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
/**
|
|
693
|
+
* Delete multiple records by keys
|
|
694
|
+
*/
|
|
695
|
+
async batchDelete({ tableName, keys }) {
|
|
696
|
+
if (keys.length === 0) {
|
|
697
|
+
return;
|
|
698
|
+
}
|
|
699
|
+
const tableName_ = getTableName({
|
|
700
|
+
indexName: tableName,
|
|
701
|
+
schemaName: getSchemaName(this.schemaName)
|
|
702
|
+
});
|
|
703
|
+
const transaction = this.pool.transaction();
|
|
704
|
+
try {
|
|
705
|
+
await transaction.begin();
|
|
706
|
+
for (const keySet of keys) {
|
|
707
|
+
const conditions = [];
|
|
708
|
+
const request = transaction.request();
|
|
709
|
+
let paramIndex = 0;
|
|
710
|
+
Object.entries(keySet).forEach(([key, value]) => {
|
|
711
|
+
const parsedKey = utils.parseSqlIdentifier(key, "column name");
|
|
712
|
+
const paramName = `p${paramIndex++}`;
|
|
713
|
+
conditions.push(`[${parsedKey}] = @${paramName}`);
|
|
714
|
+
const preparedValue = this.prepareValue(value, key, tableName);
|
|
715
|
+
if (preparedValue === null || preparedValue === void 0) {
|
|
716
|
+
request.input(paramName, this.getMssqlType(tableName, key), null);
|
|
717
|
+
} else {
|
|
718
|
+
request.input(paramName, preparedValue);
|
|
719
|
+
}
|
|
720
|
+
});
|
|
721
|
+
const deleteSql = `DELETE FROM ${tableName_} WHERE ${conditions.join(" AND ")}`;
|
|
722
|
+
await request.query(deleteSql);
|
|
723
|
+
}
|
|
724
|
+
await transaction.commit();
|
|
725
|
+
} catch (error$1) {
|
|
726
|
+
await transaction.rollback();
|
|
727
|
+
throw new error.MastraError(
|
|
728
|
+
{
|
|
729
|
+
id: storage.createStorageErrorId("MSSQL", "BATCH_DELETE", "FAILED"),
|
|
730
|
+
domain: error.ErrorDomain.STORAGE,
|
|
731
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
732
|
+
details: {
|
|
733
|
+
tableName,
|
|
734
|
+
numberOfRecords: keys.length
|
|
735
|
+
}
|
|
736
|
+
},
|
|
737
|
+
error$1
|
|
738
|
+
);
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
/**
|
|
742
|
+
* Create a new index on a table
|
|
743
|
+
*/
|
|
744
|
+
async createIndex(options) {
|
|
745
|
+
try {
|
|
746
|
+
const { name, table, columns, unique = false, where } = options;
|
|
747
|
+
const schemaName = this.schemaName || "dbo";
|
|
748
|
+
const fullTableName = getTableName({
|
|
749
|
+
indexName: table,
|
|
750
|
+
schemaName: getSchemaName(this.schemaName)
|
|
751
|
+
});
|
|
752
|
+
const indexNameSafe = utils.parseSqlIdentifier(name, "index name");
|
|
753
|
+
const checkRequest = this.pool.request();
|
|
754
|
+
checkRequest.input("indexName", indexNameSafe);
|
|
755
|
+
checkRequest.input("schemaName", schemaName);
|
|
756
|
+
checkRequest.input("tableName", table);
|
|
757
|
+
const indexExists = await checkRequest.query(`
|
|
758
|
+
SELECT 1 as found
|
|
759
|
+
FROM sys.indexes i
|
|
760
|
+
INNER JOIN sys.tables t ON i.object_id = t.object_id
|
|
761
|
+
INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
|
|
762
|
+
WHERE i.name = @indexName
|
|
763
|
+
AND s.name = @schemaName
|
|
764
|
+
AND t.name = @tableName
|
|
765
|
+
`);
|
|
766
|
+
if (indexExists.recordset && indexExists.recordset.length > 0) {
|
|
767
|
+
return;
|
|
768
|
+
}
|
|
769
|
+
const uniqueStr = unique ? "UNIQUE " : "";
|
|
770
|
+
const columnsStr = columns.map((col) => {
|
|
771
|
+
if (col.includes(" DESC") || col.includes(" ASC")) {
|
|
772
|
+
const [colName, ...modifiers] = col.split(" ");
|
|
773
|
+
if (!colName) {
|
|
774
|
+
throw new Error(`Invalid column specification: ${col}`);
|
|
775
|
+
}
|
|
776
|
+
return `[${utils.parseSqlIdentifier(colName, "column name")}] ${modifiers.join(" ")}`;
|
|
777
|
+
}
|
|
778
|
+
return `[${utils.parseSqlIdentifier(col, "column name")}]`;
|
|
779
|
+
}).join(", ");
|
|
780
|
+
const whereStr = where ? ` WHERE ${where}` : "";
|
|
781
|
+
const createIndexSql = `CREATE ${uniqueStr}INDEX [${indexNameSafe}] ON ${fullTableName} (${columnsStr})${whereStr}`;
|
|
782
|
+
await this.pool.request().query(createIndexSql);
|
|
783
|
+
} catch (error$1) {
|
|
784
|
+
throw new error.MastraError(
|
|
785
|
+
{
|
|
786
|
+
id: storage.createStorageErrorId("MSSQL", "INDEX_CREATE", "FAILED"),
|
|
787
|
+
domain: error.ErrorDomain.STORAGE,
|
|
788
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
789
|
+
details: {
|
|
790
|
+
indexName: options.name,
|
|
791
|
+
tableName: options.table
|
|
792
|
+
}
|
|
793
|
+
},
|
|
794
|
+
error$1
|
|
795
|
+
);
|
|
31
796
|
}
|
|
32
797
|
}
|
|
33
|
-
|
|
798
|
+
/**
|
|
799
|
+
* Drop an existing index
|
|
800
|
+
*/
|
|
801
|
+
async dropIndex(indexName) {
|
|
34
802
|
try {
|
|
35
|
-
|
|
36
|
-
|
|
803
|
+
const schemaName = this.schemaName || "dbo";
|
|
804
|
+
const indexNameSafe = utils.parseSqlIdentifier(indexName, "index name");
|
|
805
|
+
const checkRequest = this.pool.request();
|
|
806
|
+
checkRequest.input("indexName", indexNameSafe);
|
|
807
|
+
checkRequest.input("schemaName", schemaName);
|
|
808
|
+
const result = await checkRequest.query(`
|
|
809
|
+
SELECT t.name as table_name
|
|
810
|
+
FROM sys.indexes i
|
|
811
|
+
INNER JOIN sys.tables t ON i.object_id = t.object_id
|
|
812
|
+
INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
|
|
813
|
+
WHERE i.name = @indexName
|
|
814
|
+
AND s.name = @schemaName
|
|
815
|
+
`);
|
|
816
|
+
if (!result.recordset || result.recordset.length === 0) {
|
|
817
|
+
return;
|
|
818
|
+
}
|
|
819
|
+
if (result.recordset.length > 1) {
|
|
820
|
+
const tables = result.recordset.map((r) => r.table_name).join(", ");
|
|
821
|
+
throw new error.MastraError({
|
|
822
|
+
id: storage.createStorageErrorId("MSSQL", "INDEX", "AMBIGUOUS"),
|
|
823
|
+
domain: error.ErrorDomain.STORAGE,
|
|
824
|
+
category: error.ErrorCategory.USER,
|
|
825
|
+
text: `Index "${indexNameSafe}" exists on multiple tables (${tables}) in schema "${schemaName}". Please drop indexes manually or ensure unique index names.`
|
|
826
|
+
});
|
|
827
|
+
}
|
|
828
|
+
const tableName = result.recordset[0].table_name;
|
|
829
|
+
const fullTableName = getTableName({
|
|
830
|
+
indexName: tableName,
|
|
831
|
+
schemaName: getSchemaName(this.schemaName)
|
|
832
|
+
});
|
|
833
|
+
const dropSql = `DROP INDEX [${indexNameSafe}] ON ${fullTableName}`;
|
|
834
|
+
await this.pool.request().query(dropSql);
|
|
835
|
+
} catch (error$1) {
|
|
836
|
+
throw new error.MastraError(
|
|
837
|
+
{
|
|
838
|
+
id: storage.createStorageErrorId("MSSQL", "INDEX_DROP", "FAILED"),
|
|
839
|
+
domain: error.ErrorDomain.STORAGE,
|
|
840
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
841
|
+
details: {
|
|
842
|
+
indexName
|
|
843
|
+
}
|
|
844
|
+
},
|
|
845
|
+
error$1
|
|
846
|
+
);
|
|
37
847
|
}
|
|
38
848
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
result: resultValue,
|
|
44
|
-
metricName: row.metric_name,
|
|
45
|
-
instructions: row.instructions,
|
|
46
|
-
testInfo: testInfoValue,
|
|
47
|
-
globalRunId: row.global_run_id,
|
|
48
|
-
runId: row.run_id,
|
|
49
|
-
createdAt: row.created_at
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
var LegacyEvalsMSSQL = class extends storage.LegacyEvalsStorage {
|
|
53
|
-
pool;
|
|
54
|
-
schema;
|
|
55
|
-
constructor({ pool, schema }) {
|
|
56
|
-
super();
|
|
57
|
-
this.pool = pool;
|
|
58
|
-
this.schema = schema;
|
|
59
|
-
}
|
|
60
|
-
/** @deprecated use getEvals instead */
|
|
61
|
-
async getEvalsByAgentName(agentName, type) {
|
|
849
|
+
/**
|
|
850
|
+
* List indexes for a specific table or all tables
|
|
851
|
+
*/
|
|
852
|
+
async listIndexes(tableName) {
|
|
62
853
|
try {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
query += " AND test_info IS NOT NULL AND JSON_VALUE(test_info, '$.testPath') IS NOT NULL";
|
|
66
|
-
} else if (type === "live") {
|
|
67
|
-
query += " AND (test_info IS NULL OR JSON_VALUE(test_info, '$.testPath') IS NULL)";
|
|
68
|
-
}
|
|
69
|
-
query += " ORDER BY created_at DESC";
|
|
854
|
+
const schemaName = this.schemaName || "dbo";
|
|
855
|
+
let query;
|
|
70
856
|
const request = this.pool.request();
|
|
71
|
-
request.input("
|
|
857
|
+
request.input("schemaName", schemaName);
|
|
858
|
+
if (tableName) {
|
|
859
|
+
query = `
|
|
860
|
+
SELECT
|
|
861
|
+
i.name as name,
|
|
862
|
+
o.name as [table],
|
|
863
|
+
i.is_unique as is_unique,
|
|
864
|
+
CAST(SUM(s.used_page_count) * 8 / 1024.0 AS VARCHAR(50)) + ' MB' as size
|
|
865
|
+
FROM sys.indexes i
|
|
866
|
+
INNER JOIN sys.objects o ON i.object_id = o.object_id
|
|
867
|
+
INNER JOIN sys.schemas sch ON o.schema_id = sch.schema_id
|
|
868
|
+
LEFT JOIN sys.dm_db_partition_stats s ON i.object_id = s.object_id AND i.index_id = s.index_id
|
|
869
|
+
WHERE sch.name = @schemaName
|
|
870
|
+
AND o.name = @tableName
|
|
871
|
+
AND i.name IS NOT NULL
|
|
872
|
+
GROUP BY i.name, o.name, i.is_unique
|
|
873
|
+
`;
|
|
874
|
+
request.input("tableName", tableName);
|
|
875
|
+
} else {
|
|
876
|
+
query = `
|
|
877
|
+
SELECT
|
|
878
|
+
i.name as name,
|
|
879
|
+
o.name as [table],
|
|
880
|
+
i.is_unique as is_unique,
|
|
881
|
+
CAST(SUM(s.used_page_count) * 8 / 1024.0 AS VARCHAR(50)) + ' MB' as size
|
|
882
|
+
FROM sys.indexes i
|
|
883
|
+
INNER JOIN sys.objects o ON i.object_id = o.object_id
|
|
884
|
+
INNER JOIN sys.schemas sch ON o.schema_id = sch.schema_id
|
|
885
|
+
LEFT JOIN sys.dm_db_partition_stats s ON i.object_id = s.object_id AND i.index_id = s.index_id
|
|
886
|
+
WHERE sch.name = @schemaName
|
|
887
|
+
AND i.name IS NOT NULL
|
|
888
|
+
GROUP BY i.name, o.name, i.is_unique
|
|
889
|
+
`;
|
|
890
|
+
}
|
|
72
891
|
const result = await request.query(query);
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
892
|
+
const indexes = [];
|
|
893
|
+
for (const row of result.recordset) {
|
|
894
|
+
const colRequest = this.pool.request();
|
|
895
|
+
colRequest.input("indexName", row.name);
|
|
896
|
+
colRequest.input("schemaName", schemaName);
|
|
897
|
+
const colResult = await colRequest.query(`
|
|
898
|
+
SELECT c.name as column_name
|
|
899
|
+
FROM sys.indexes i
|
|
900
|
+
INNER JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
|
|
901
|
+
INNER JOIN sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id
|
|
902
|
+
INNER JOIN sys.objects o ON i.object_id = o.object_id
|
|
903
|
+
INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
|
|
904
|
+
WHERE i.name = @indexName
|
|
905
|
+
AND s.name = @schemaName
|
|
906
|
+
ORDER BY ic.key_ordinal
|
|
907
|
+
`);
|
|
908
|
+
indexes.push({
|
|
909
|
+
name: row.name,
|
|
910
|
+
table: row.table,
|
|
911
|
+
columns: colResult.recordset.map((c) => c.column_name),
|
|
912
|
+
unique: row.is_unique || false,
|
|
913
|
+
size: row.size || "0 MB",
|
|
914
|
+
definition: ""
|
|
915
|
+
// MSSQL doesn't store definition like PG
|
|
916
|
+
});
|
|
917
|
+
}
|
|
918
|
+
return indexes;
|
|
919
|
+
} catch (error$1) {
|
|
920
|
+
throw new error.MastraError(
|
|
921
|
+
{
|
|
922
|
+
id: storage.createStorageErrorId("MSSQL", "INDEX_LIST", "FAILED"),
|
|
923
|
+
domain: error.ErrorDomain.STORAGE,
|
|
924
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
925
|
+
details: tableName ? {
|
|
926
|
+
tableName
|
|
927
|
+
} : {}
|
|
928
|
+
},
|
|
929
|
+
error$1
|
|
930
|
+
);
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
/**
|
|
934
|
+
* Get detailed statistics for a specific index
|
|
935
|
+
*/
|
|
936
|
+
async describeIndex(indexName) {
|
|
111
937
|
try {
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
938
|
+
const schemaName = this.schemaName || "dbo";
|
|
939
|
+
const request = this.pool.request();
|
|
940
|
+
request.input("indexName", indexName);
|
|
941
|
+
request.input("schemaName", schemaName);
|
|
942
|
+
const query = `
|
|
943
|
+
SELECT
|
|
944
|
+
i.name as name,
|
|
945
|
+
o.name as [table],
|
|
946
|
+
i.is_unique as is_unique,
|
|
947
|
+
CAST(SUM(s.used_page_count) * 8 / 1024.0 AS VARCHAR(50)) + ' MB' as size,
|
|
948
|
+
i.type_desc as method,
|
|
949
|
+
ISNULL(us.user_scans, 0) as scans,
|
|
950
|
+
ISNULL(us.user_seeks + us.user_scans, 0) as tuples_read,
|
|
951
|
+
ISNULL(us.user_lookups, 0) as tuples_fetched
|
|
952
|
+
FROM sys.indexes i
|
|
953
|
+
INNER JOIN sys.objects o ON i.object_id = o.object_id
|
|
954
|
+
INNER JOIN sys.schemas sch ON o.schema_id = sch.schema_id
|
|
955
|
+
LEFT JOIN sys.dm_db_partition_stats s ON i.object_id = s.object_id AND i.index_id = s.index_id
|
|
956
|
+
LEFT JOIN sys.dm_db_index_usage_stats us ON i.object_id = us.object_id AND i.index_id = us.index_id
|
|
957
|
+
WHERE i.name = @indexName
|
|
958
|
+
AND sch.name = @schemaName
|
|
959
|
+
GROUP BY i.name, o.name, i.is_unique, i.type_desc, us.user_seeks, us.user_scans, us.user_lookups
|
|
960
|
+
`;
|
|
961
|
+
const result = await request.query(query);
|
|
962
|
+
if (!result.recordset || result.recordset.length === 0) {
|
|
963
|
+
throw new Error(`Index "${indexName}" not found in schema "${schemaName}"`);
|
|
130
964
|
}
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
965
|
+
const row = result.recordset[0];
|
|
966
|
+
const colRequest = this.pool.request();
|
|
967
|
+
colRequest.input("indexName", indexName);
|
|
968
|
+
colRequest.input("schemaName", schemaName);
|
|
969
|
+
const colResult = await colRequest.query(`
|
|
970
|
+
SELECT c.name as column_name
|
|
971
|
+
FROM sys.indexes i
|
|
972
|
+
INNER JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
|
|
973
|
+
INNER JOIN sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id
|
|
974
|
+
INNER JOIN sys.objects o ON i.object_id = o.object_id
|
|
975
|
+
INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
|
|
976
|
+
WHERE i.name = @indexName
|
|
977
|
+
AND s.name = @schemaName
|
|
978
|
+
ORDER BY ic.key_ordinal
|
|
979
|
+
`);
|
|
143
980
|
return {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
981
|
+
name: row.name,
|
|
982
|
+
table: row.table,
|
|
983
|
+
columns: colResult.recordset.map((c) => c.column_name),
|
|
984
|
+
unique: row.is_unique || false,
|
|
985
|
+
size: row.size || "0 MB",
|
|
986
|
+
definition: "",
|
|
987
|
+
method: row.method?.toLowerCase() || "nonclustered",
|
|
988
|
+
scans: Number(row.scans) || 0,
|
|
989
|
+
tuples_read: Number(row.tuples_read) || 0,
|
|
990
|
+
tuples_fetched: Number(row.tuples_fetched) || 0
|
|
149
991
|
};
|
|
150
992
|
} catch (error$1) {
|
|
151
|
-
|
|
993
|
+
throw new error.MastraError(
|
|
152
994
|
{
|
|
153
|
-
id: "
|
|
995
|
+
id: storage.createStorageErrorId("MSSQL", "INDEX_DESCRIBE", "FAILED"),
|
|
154
996
|
domain: error.ErrorDomain.STORAGE,
|
|
155
997
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
156
998
|
details: {
|
|
157
|
-
|
|
158
|
-
type: type || "all",
|
|
159
|
-
page,
|
|
160
|
-
perPage
|
|
999
|
+
indexName
|
|
161
1000
|
}
|
|
162
1001
|
},
|
|
163
1002
|
error$1
|
|
164
1003
|
);
|
|
165
|
-
this.logger?.error?.(mastraError.toString());
|
|
166
|
-
this.logger?.trackException(mastraError);
|
|
167
|
-
throw mastraError;
|
|
168
1004
|
}
|
|
169
1005
|
}
|
|
170
1006
|
};
|
|
171
|
-
|
|
1007
|
+
function getSchemaName2(schema) {
|
|
1008
|
+
return schema ? `[${utils.parseSqlIdentifier(schema, "schema name")}]` : void 0;
|
|
1009
|
+
}
|
|
1010
|
+
function getTableName2({ indexName, schemaName }) {
|
|
1011
|
+
const parsedIndexName = utils.parseSqlIdentifier(indexName, "index name");
|
|
1012
|
+
const quotedIndexName = `[${parsedIndexName}]`;
|
|
1013
|
+
const quotedSchemaName = schemaName;
|
|
1014
|
+
return quotedSchemaName ? `${quotedSchemaName}.${quotedIndexName}` : quotedIndexName;
|
|
1015
|
+
}
|
|
1016
|
+
function buildDateRangeFilter(dateRange, fieldName) {
|
|
1017
|
+
const filters = {};
|
|
1018
|
+
if (dateRange?.start) {
|
|
1019
|
+
const suffix = dateRange.startExclusive ? "_gt" : "_gte";
|
|
1020
|
+
filters[`${fieldName}${suffix}`] = dateRange.start;
|
|
1021
|
+
}
|
|
1022
|
+
if (dateRange?.end) {
|
|
1023
|
+
const suffix = dateRange.endExclusive ? "_lt" : "_lte";
|
|
1024
|
+
filters[`${fieldName}${suffix}`] = dateRange.end;
|
|
1025
|
+
}
|
|
1026
|
+
return filters;
|
|
1027
|
+
}
|
|
1028
|
+
function isInOperator(value) {
|
|
1029
|
+
return typeof value === "object" && value !== null && "$in" in value && Array.isArray(value.$in);
|
|
1030
|
+
}
|
|
1031
|
+
function prepareWhereClause(filters, _schema) {
|
|
1032
|
+
const conditions = [];
|
|
1033
|
+
const params = {};
|
|
1034
|
+
let paramIndex = 1;
|
|
1035
|
+
Object.entries(filters).forEach(([key, value]) => {
|
|
1036
|
+
if (value === void 0) return;
|
|
1037
|
+
if (key.endsWith("_gte")) {
|
|
1038
|
+
const paramName = `p${paramIndex++}`;
|
|
1039
|
+
const fieldName = key.slice(0, -4);
|
|
1040
|
+
conditions.push(`[${utils.parseSqlIdentifier(fieldName, "field name")}] >= @${paramName}`);
|
|
1041
|
+
params[paramName] = value instanceof Date ? value.toISOString() : value;
|
|
1042
|
+
} else if (key.endsWith("_gt")) {
|
|
1043
|
+
const paramName = `p${paramIndex++}`;
|
|
1044
|
+
const fieldName = key.slice(0, -3);
|
|
1045
|
+
conditions.push(`[${utils.parseSqlIdentifier(fieldName, "field name")}] > @${paramName}`);
|
|
1046
|
+
params[paramName] = value instanceof Date ? value.toISOString() : value;
|
|
1047
|
+
} else if (key.endsWith("_lte")) {
|
|
1048
|
+
const paramName = `p${paramIndex++}`;
|
|
1049
|
+
const fieldName = key.slice(0, -4);
|
|
1050
|
+
conditions.push(`[${utils.parseSqlIdentifier(fieldName, "field name")}] <= @${paramName}`);
|
|
1051
|
+
params[paramName] = value instanceof Date ? value.toISOString() : value;
|
|
1052
|
+
} else if (key.endsWith("_lt")) {
|
|
1053
|
+
const paramName = `p${paramIndex++}`;
|
|
1054
|
+
const fieldName = key.slice(0, -3);
|
|
1055
|
+
conditions.push(`[${utils.parseSqlIdentifier(fieldName, "field name")}] < @${paramName}`);
|
|
1056
|
+
params[paramName] = value instanceof Date ? value.toISOString() : value;
|
|
1057
|
+
} else if (value === null) {
|
|
1058
|
+
conditions.push(`[${utils.parseSqlIdentifier(key, "field name")}] IS NULL`);
|
|
1059
|
+
} else if (isInOperator(value)) {
|
|
1060
|
+
const inValues = value.$in;
|
|
1061
|
+
if (inValues.length === 0) {
|
|
1062
|
+
conditions.push("1 = 0");
|
|
1063
|
+
} else if (inValues.length === 1) {
|
|
1064
|
+
const paramName = `p${paramIndex++}`;
|
|
1065
|
+
conditions.push(`[${utils.parseSqlIdentifier(key, "field name")}] = @${paramName}`);
|
|
1066
|
+
params[paramName] = inValues[0] instanceof Date ? inValues[0].toISOString() : inValues[0];
|
|
1067
|
+
} else {
|
|
1068
|
+
const inParamNames = [];
|
|
1069
|
+
for (const item of inValues) {
|
|
1070
|
+
const paramName = `p${paramIndex++}`;
|
|
1071
|
+
inParamNames.push(`@${paramName}`);
|
|
1072
|
+
params[paramName] = item instanceof Date ? item.toISOString() : item;
|
|
1073
|
+
}
|
|
1074
|
+
conditions.push(`[${utils.parseSqlIdentifier(key, "field name")}] IN (${inParamNames.join(", ")})`);
|
|
1075
|
+
}
|
|
1076
|
+
} else if (Array.isArray(value)) {
|
|
1077
|
+
if (value.length === 0) {
|
|
1078
|
+
conditions.push("1 = 0");
|
|
1079
|
+
} else if (value.length === 1) {
|
|
1080
|
+
const paramName = `p${paramIndex++}`;
|
|
1081
|
+
conditions.push(`[${utils.parseSqlIdentifier(key, "field name")}] = @${paramName}`);
|
|
1082
|
+
params[paramName] = value[0] instanceof Date ? value[0].toISOString() : value[0];
|
|
1083
|
+
} else {
|
|
1084
|
+
const inParamNames = [];
|
|
1085
|
+
for (const item of value) {
|
|
1086
|
+
const paramName = `p${paramIndex++}`;
|
|
1087
|
+
inParamNames.push(`@${paramName}`);
|
|
1088
|
+
params[paramName] = item instanceof Date ? item.toISOString() : item;
|
|
1089
|
+
}
|
|
1090
|
+
conditions.push(`[${utils.parseSqlIdentifier(key, "field name")}] IN (${inParamNames.join(", ")})`);
|
|
1091
|
+
}
|
|
1092
|
+
} else {
|
|
1093
|
+
const paramName = `p${paramIndex++}`;
|
|
1094
|
+
conditions.push(`[${utils.parseSqlIdentifier(key, "field name")}] = @${paramName}`);
|
|
1095
|
+
params[paramName] = value instanceof Date ? value.toISOString() : value;
|
|
1096
|
+
}
|
|
1097
|
+
});
|
|
1098
|
+
return {
|
|
1099
|
+
sql: conditions.length > 0 ? ` WHERE ${conditions.join(" AND ")}` : "",
|
|
1100
|
+
params
|
|
1101
|
+
};
|
|
1102
|
+
}
|
|
1103
|
+
function transformFromSqlRow({
|
|
1104
|
+
tableName,
|
|
1105
|
+
sqlRow
|
|
1106
|
+
}) {
|
|
1107
|
+
const schema = storage.TABLE_SCHEMAS[tableName];
|
|
1108
|
+
const result = {};
|
|
1109
|
+
Object.entries(sqlRow).forEach(([key, value]) => {
|
|
1110
|
+
const columnSchema = schema?.[key];
|
|
1111
|
+
if (columnSchema?.type === "jsonb" && typeof value === "string") {
|
|
1112
|
+
try {
|
|
1113
|
+
result[key] = JSON.parse(value);
|
|
1114
|
+
} catch {
|
|
1115
|
+
result[key] = value;
|
|
1116
|
+
}
|
|
1117
|
+
} else if (columnSchema?.type === "timestamp" && value && typeof value === "string") {
|
|
1118
|
+
result[key] = new Date(value);
|
|
1119
|
+
} else if (columnSchema?.type === "timestamp" && value instanceof Date) {
|
|
1120
|
+
result[key] = value;
|
|
1121
|
+
} else if (columnSchema?.type === "boolean") {
|
|
1122
|
+
result[key] = Boolean(value);
|
|
1123
|
+
} else {
|
|
1124
|
+
result[key] = value;
|
|
1125
|
+
}
|
|
1126
|
+
});
|
|
1127
|
+
return result;
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
// src/storage/domains/memory/index.ts
|
|
1131
|
+
var MemoryMSSQL = class _MemoryMSSQL extends storage.MemoryStorage {
|
|
172
1132
|
pool;
|
|
173
1133
|
schema;
|
|
174
|
-
|
|
1134
|
+
db;
|
|
1135
|
+
needsConnect;
|
|
1136
|
+
skipDefaultIndexes;
|
|
1137
|
+
indexes;
|
|
1138
|
+
/** Tables managed by this domain */
|
|
1139
|
+
static MANAGED_TABLES = [storage.TABLE_THREADS, storage.TABLE_MESSAGES, storage.TABLE_RESOURCES];
|
|
175
1140
|
_parseAndFormatMessages(messages, format) {
|
|
176
1141
|
const messagesWithParsedContent = messages.map((message) => {
|
|
177
1142
|
if (typeof message.content === "string") {
|
|
@@ -185,32 +1150,97 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
185
1150
|
});
|
|
186
1151
|
const cleanMessages = messagesWithParsedContent.map(({ seq_id, ...rest }) => rest);
|
|
187
1152
|
const list = new agent.MessageList().add(cleanMessages, "memory");
|
|
188
|
-
return format === "v2" ? list.get.all.
|
|
1153
|
+
return format === "v2" ? list.get.all.db() : list.get.all.v1();
|
|
189
1154
|
}
|
|
190
|
-
constructor({
|
|
191
|
-
pool,
|
|
192
|
-
schema,
|
|
193
|
-
operations
|
|
194
|
-
}) {
|
|
1155
|
+
constructor(config) {
|
|
195
1156
|
super();
|
|
1157
|
+
const { pool, schemaName, skipDefaultIndexes, indexes, needsConnect } = resolveMssqlConfig(config);
|
|
196
1158
|
this.pool = pool;
|
|
197
|
-
this.schema =
|
|
198
|
-
this.
|
|
1159
|
+
this.schema = schemaName;
|
|
1160
|
+
this.db = new MssqlDB({ pool, schemaName, skipDefaultIndexes });
|
|
1161
|
+
this.needsConnect = needsConnect;
|
|
1162
|
+
this.skipDefaultIndexes = skipDefaultIndexes;
|
|
1163
|
+
this.indexes = indexes?.filter((idx) => _MemoryMSSQL.MANAGED_TABLES.includes(idx.table));
|
|
1164
|
+
}
|
|
1165
|
+
async init() {
|
|
1166
|
+
if (this.needsConnect) {
|
|
1167
|
+
await this.pool.connect();
|
|
1168
|
+
this.needsConnect = false;
|
|
1169
|
+
}
|
|
1170
|
+
await this.db.createTable({ tableName: storage.TABLE_THREADS, schema: storage.TABLE_SCHEMAS[storage.TABLE_THREADS] });
|
|
1171
|
+
await this.db.createTable({ tableName: storage.TABLE_MESSAGES, schema: storage.TABLE_SCHEMAS[storage.TABLE_MESSAGES] });
|
|
1172
|
+
await this.db.createTable({ tableName: storage.TABLE_RESOURCES, schema: storage.TABLE_SCHEMAS[storage.TABLE_RESOURCES] });
|
|
1173
|
+
await this.createDefaultIndexes();
|
|
1174
|
+
await this.createCustomIndexes();
|
|
1175
|
+
}
|
|
1176
|
+
/**
|
|
1177
|
+
* Returns default index definitions for the memory domain tables.
|
|
1178
|
+
* IMPORTANT: Uses seq_id DESC instead of createdAt DESC for MSSQL due to millisecond accuracy limitations
|
|
1179
|
+
*/
|
|
1180
|
+
getDefaultIndexDefinitions() {
|
|
1181
|
+
const schemaPrefix = this.schema ? `${this.schema}_` : "";
|
|
1182
|
+
return [
|
|
1183
|
+
{
|
|
1184
|
+
name: `${schemaPrefix}mastra_threads_resourceid_seqid_idx`,
|
|
1185
|
+
table: storage.TABLE_THREADS,
|
|
1186
|
+
columns: ["resourceId", "seq_id DESC"]
|
|
1187
|
+
},
|
|
1188
|
+
{
|
|
1189
|
+
name: `${schemaPrefix}mastra_messages_thread_id_seqid_idx`,
|
|
1190
|
+
table: storage.TABLE_MESSAGES,
|
|
1191
|
+
columns: ["thread_id", "seq_id DESC"]
|
|
1192
|
+
}
|
|
1193
|
+
];
|
|
1194
|
+
}
|
|
1195
|
+
/**
|
|
1196
|
+
* Creates default indexes for optimal query performance.
|
|
1197
|
+
*/
|
|
1198
|
+
async createDefaultIndexes() {
|
|
1199
|
+
if (this.skipDefaultIndexes) {
|
|
1200
|
+
return;
|
|
1201
|
+
}
|
|
1202
|
+
for (const indexDef of this.getDefaultIndexDefinitions()) {
|
|
1203
|
+
try {
|
|
1204
|
+
await this.db.createIndex(indexDef);
|
|
1205
|
+
} catch (error) {
|
|
1206
|
+
this.logger?.warn?.(`Failed to create index ${indexDef.name}:`, error);
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
/**
|
|
1211
|
+
* Creates custom user-defined indexes for this domain's tables.
|
|
1212
|
+
*/
|
|
1213
|
+
async createCustomIndexes() {
|
|
1214
|
+
if (!this.indexes || this.indexes.length === 0) {
|
|
1215
|
+
return;
|
|
1216
|
+
}
|
|
1217
|
+
for (const indexDef of this.indexes) {
|
|
1218
|
+
try {
|
|
1219
|
+
await this.db.createIndex(indexDef);
|
|
1220
|
+
} catch (error) {
|
|
1221
|
+
this.logger?.warn?.(`Failed to create custom index ${indexDef.name}:`, error);
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
async dangerouslyClearAll() {
|
|
1226
|
+
await this.db.clearTable({ tableName: storage.TABLE_MESSAGES });
|
|
1227
|
+
await this.db.clearTable({ tableName: storage.TABLE_THREADS });
|
|
1228
|
+
await this.db.clearTable({ tableName: storage.TABLE_RESOURCES });
|
|
199
1229
|
}
|
|
200
1230
|
async getThreadById({ threadId }) {
|
|
201
1231
|
try {
|
|
202
|
-
const
|
|
1232
|
+
const sql5 = `SELECT
|
|
203
1233
|
id,
|
|
204
1234
|
[resourceId],
|
|
205
1235
|
title,
|
|
206
1236
|
metadata,
|
|
207
1237
|
[createdAt],
|
|
208
1238
|
[updatedAt]
|
|
209
|
-
FROM ${
|
|
1239
|
+
FROM ${getTableName2({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName2(this.schema) })}
|
|
210
1240
|
WHERE id = @threadId`;
|
|
211
1241
|
const request = this.pool.request();
|
|
212
1242
|
request.input("threadId", threadId);
|
|
213
|
-
const resultSet = await request.query(
|
|
1243
|
+
const resultSet = await request.query(sql5);
|
|
214
1244
|
const thread = resultSet.recordset[0] || null;
|
|
215
1245
|
if (!thread) {
|
|
216
1246
|
return null;
|
|
@@ -224,7 +1254,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
224
1254
|
} catch (error$1) {
|
|
225
1255
|
throw new error.MastraError(
|
|
226
1256
|
{
|
|
227
|
-
id: "
|
|
1257
|
+
id: storage.createStorageErrorId("MSSQL", "GET_THREAD_BY_ID", "FAILED"),
|
|
228
1258
|
domain: error.ErrorDomain.STORAGE,
|
|
229
1259
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
230
1260
|
details: {
|
|
@@ -235,12 +1265,25 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
235
1265
|
);
|
|
236
1266
|
}
|
|
237
1267
|
}
|
|
238
|
-
async
|
|
239
|
-
const { resourceId, page = 0, perPage: perPageInput, orderBy
|
|
1268
|
+
async listThreadsByResourceId(args) {
|
|
1269
|
+
const { resourceId, page = 0, perPage: perPageInput, orderBy } = args;
|
|
1270
|
+
if (page < 0) {
|
|
1271
|
+
throw new error.MastraError({
|
|
1272
|
+
id: storage.createStorageErrorId("MSSQL", "LIST_THREADS_BY_RESOURCE_ID", "INVALID_PAGE"),
|
|
1273
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1274
|
+
category: error.ErrorCategory.USER,
|
|
1275
|
+
text: "Page number must be non-negative",
|
|
1276
|
+
details: {
|
|
1277
|
+
resourceId,
|
|
1278
|
+
page
|
|
1279
|
+
}
|
|
1280
|
+
});
|
|
1281
|
+
}
|
|
1282
|
+
const perPage = storage.normalizePerPage(perPageInput, 100);
|
|
1283
|
+
const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
1284
|
+
const { field, direction } = this.parseOrderBy(orderBy);
|
|
240
1285
|
try {
|
|
241
|
-
const
|
|
242
|
-
const currentOffset = page * perPage;
|
|
243
|
-
const baseQuery = `FROM ${getTableName({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName(this.schema) })} WHERE [resourceId] = @resourceId`;
|
|
1286
|
+
const baseQuery = `FROM ${getTableName2({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName2(this.schema) })} WHERE [resourceId] = @resourceId`;
|
|
244
1287
|
const countQuery = `SELECT COUNT(*) as count ${baseQuery}`;
|
|
245
1288
|
const countRequest = this.pool.request();
|
|
246
1289
|
countRequest.input("resourceId", resourceId);
|
|
@@ -251,16 +1294,22 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
251
1294
|
threads: [],
|
|
252
1295
|
total: 0,
|
|
253
1296
|
page,
|
|
254
|
-
perPage,
|
|
1297
|
+
perPage: perPageForResponse,
|
|
255
1298
|
hasMore: false
|
|
256
1299
|
};
|
|
257
1300
|
}
|
|
258
|
-
const orderByField =
|
|
259
|
-
const
|
|
1301
|
+
const orderByField = field === "createdAt" ? "[createdAt]" : "[updatedAt]";
|
|
1302
|
+
const dir = (direction || "DESC").toUpperCase() === "ASC" ? "ASC" : "DESC";
|
|
1303
|
+
const limitValue = perPageInput === false ? total : perPage;
|
|
1304
|
+
const dataQuery = `SELECT id, [resourceId], title, metadata, [createdAt], [updatedAt] ${baseQuery} ORDER BY ${orderByField} ${dir} OFFSET @offset ROWS FETCH NEXT @perPage ROWS ONLY`;
|
|
260
1305
|
const dataRequest = this.pool.request();
|
|
261
1306
|
dataRequest.input("resourceId", resourceId);
|
|
262
|
-
dataRequest.input("
|
|
263
|
-
|
|
1307
|
+
dataRequest.input("offset", offset);
|
|
1308
|
+
if (limitValue > 2147483647) {
|
|
1309
|
+
dataRequest.input("perPage", sql__default.default.BigInt, limitValue);
|
|
1310
|
+
} else {
|
|
1311
|
+
dataRequest.input("perPage", limitValue);
|
|
1312
|
+
}
|
|
264
1313
|
const rowsResult = await dataRequest.query(dataQuery);
|
|
265
1314
|
const rows = rowsResult.recordset || [];
|
|
266
1315
|
const threads = rows.map((thread) => ({
|
|
@@ -273,13 +1322,13 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
273
1322
|
threads,
|
|
274
1323
|
total,
|
|
275
1324
|
page,
|
|
276
|
-
perPage,
|
|
277
|
-
hasMore:
|
|
1325
|
+
perPage: perPageForResponse,
|
|
1326
|
+
hasMore: perPageInput === false ? false : offset + perPage < total
|
|
278
1327
|
};
|
|
279
1328
|
} catch (error$1) {
|
|
280
1329
|
const mastraError = new error.MastraError(
|
|
281
1330
|
{
|
|
282
|
-
id: "
|
|
1331
|
+
id: storage.createStorageErrorId("MSSQL", "LIST_THREADS_BY_RESOURCE_ID", "FAILED"),
|
|
283
1332
|
domain: error.ErrorDomain.STORAGE,
|
|
284
1333
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
285
1334
|
details: {
|
|
@@ -291,12 +1340,18 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
291
1340
|
);
|
|
292
1341
|
this.logger?.error?.(mastraError.toString());
|
|
293
1342
|
this.logger?.trackException?.(mastraError);
|
|
294
|
-
return {
|
|
1343
|
+
return {
|
|
1344
|
+
threads: [],
|
|
1345
|
+
total: 0,
|
|
1346
|
+
page,
|
|
1347
|
+
perPage: perPageForResponse,
|
|
1348
|
+
hasMore: false
|
|
1349
|
+
};
|
|
295
1350
|
}
|
|
296
1351
|
}
|
|
297
1352
|
async saveThread({ thread }) {
|
|
298
1353
|
try {
|
|
299
|
-
const table =
|
|
1354
|
+
const table = getTableName2({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName2(this.schema) });
|
|
300
1355
|
const mergeSql = `MERGE INTO ${table} WITH (HOLDLOCK) AS target
|
|
301
1356
|
USING (SELECT @id AS id) AS source
|
|
302
1357
|
ON (target.id = source.id)
|
|
@@ -313,15 +1368,20 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
313
1368
|
req.input("id", thread.id);
|
|
314
1369
|
req.input("resourceId", thread.resourceId);
|
|
315
1370
|
req.input("title", thread.title);
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
1371
|
+
const metadata = thread.metadata ? JSON.stringify(thread.metadata) : null;
|
|
1372
|
+
if (metadata === null) {
|
|
1373
|
+
req.input("metadata", sql__default.default.NVarChar, null);
|
|
1374
|
+
} else {
|
|
1375
|
+
req.input("metadata", metadata);
|
|
1376
|
+
}
|
|
1377
|
+
req.input("createdAt", sql__default.default.DateTime2, thread.createdAt);
|
|
1378
|
+
req.input("updatedAt", sql__default.default.DateTime2, thread.updatedAt);
|
|
319
1379
|
await req.query(mergeSql);
|
|
320
1380
|
return thread;
|
|
321
1381
|
} catch (error$1) {
|
|
322
1382
|
throw new error.MastraError(
|
|
323
1383
|
{
|
|
324
|
-
id: "
|
|
1384
|
+
id: storage.createStorageErrorId("MSSQL", "SAVE_THREAD", "FAILED"),
|
|
325
1385
|
domain: error.ErrorDomain.STORAGE,
|
|
326
1386
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
327
1387
|
details: {
|
|
@@ -332,30 +1392,6 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
332
1392
|
);
|
|
333
1393
|
}
|
|
334
1394
|
}
|
|
335
|
-
/**
|
|
336
|
-
* @deprecated use getThreadsByResourceIdPaginated instead
|
|
337
|
-
*/
|
|
338
|
-
async getThreadsByResourceId(args) {
|
|
339
|
-
const { resourceId, orderBy = "createdAt", sortDirection = "DESC" } = args;
|
|
340
|
-
try {
|
|
341
|
-
const baseQuery = `FROM ${getTableName({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName(this.schema) })} WHERE [resourceId] = @resourceId`;
|
|
342
|
-
const orderByField = orderBy === "createdAt" ? "[createdAt]" : "[updatedAt]";
|
|
343
|
-
const dataQuery = `SELECT id, [resourceId], title, metadata, [createdAt], [updatedAt] ${baseQuery} ORDER BY ${orderByField} ${sortDirection}`;
|
|
344
|
-
const request = this.pool.request();
|
|
345
|
-
request.input("resourceId", resourceId);
|
|
346
|
-
const resultSet = await request.query(dataQuery);
|
|
347
|
-
const rows = resultSet.recordset || [];
|
|
348
|
-
return rows.map((thread) => ({
|
|
349
|
-
...thread,
|
|
350
|
-
metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
|
|
351
|
-
createdAt: thread.createdAt,
|
|
352
|
-
updatedAt: thread.updatedAt
|
|
353
|
-
}));
|
|
354
|
-
} catch (error) {
|
|
355
|
-
this.logger?.error?.(`Error getting threads for resource ${resourceId}:`, error);
|
|
356
|
-
return [];
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
1395
|
/**
|
|
360
1396
|
* Updates a thread's title and metadata, merging with existing metadata. Returns the updated thread.
|
|
361
1397
|
*/
|
|
@@ -367,7 +1403,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
367
1403
|
const existingThread = await this.getThreadById({ threadId: id });
|
|
368
1404
|
if (!existingThread) {
|
|
369
1405
|
throw new error.MastraError({
|
|
370
|
-
id: "
|
|
1406
|
+
id: storage.createStorageErrorId("MSSQL", "UPDATE_THREAD", "NOT_FOUND"),
|
|
371
1407
|
domain: error.ErrorDomain.STORAGE,
|
|
372
1408
|
category: error.ErrorCategory.USER,
|
|
373
1409
|
text: `Thread ${id} not found`,
|
|
@@ -382,8 +1418,8 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
382
1418
|
...metadata
|
|
383
1419
|
};
|
|
384
1420
|
try {
|
|
385
|
-
const table =
|
|
386
|
-
const
|
|
1421
|
+
const table = getTableName2({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName2(this.schema) });
|
|
1422
|
+
const sql5 = `UPDATE ${table}
|
|
387
1423
|
SET title = @title,
|
|
388
1424
|
metadata = @metadata,
|
|
389
1425
|
[updatedAt] = @updatedAt
|
|
@@ -394,7 +1430,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
394
1430
|
req.input("title", title);
|
|
395
1431
|
req.input("metadata", JSON.stringify(mergedMetadata));
|
|
396
1432
|
req.input("updatedAt", /* @__PURE__ */ new Date());
|
|
397
|
-
const result = await req.query(
|
|
1433
|
+
const result = await req.query(sql5);
|
|
398
1434
|
let thread = result.recordset && result.recordset[0];
|
|
399
1435
|
if (thread && "seq_id" in thread) {
|
|
400
1436
|
const { seq_id, ...rest } = thread;
|
|
@@ -402,7 +1438,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
402
1438
|
}
|
|
403
1439
|
if (!thread) {
|
|
404
1440
|
throw new error.MastraError({
|
|
405
|
-
id: "
|
|
1441
|
+
id: storage.createStorageErrorId("MSSQL", "UPDATE_THREAD", "NOT_FOUND"),
|
|
406
1442
|
domain: error.ErrorDomain.STORAGE,
|
|
407
1443
|
category: error.ErrorCategory.USER,
|
|
408
1444
|
text: `Thread ${id} not found after update`,
|
|
@@ -421,7 +1457,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
421
1457
|
} catch (error$1) {
|
|
422
1458
|
throw new error.MastraError(
|
|
423
1459
|
{
|
|
424
|
-
id: "
|
|
1460
|
+
id: storage.createStorageErrorId("MSSQL", "UPDATE_THREAD", "FAILED"),
|
|
425
1461
|
domain: error.ErrorDomain.STORAGE,
|
|
426
1462
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
427
1463
|
details: {
|
|
@@ -434,8 +1470,8 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
434
1470
|
}
|
|
435
1471
|
}
|
|
436
1472
|
async deleteThread({ threadId }) {
|
|
437
|
-
const messagesTable =
|
|
438
|
-
const threadsTable =
|
|
1473
|
+
const messagesTable = getTableName2({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName2(this.schema) });
|
|
1474
|
+
const threadsTable = getTableName2({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName2(this.schema) });
|
|
439
1475
|
const deleteMessagesSql = `DELETE FROM ${messagesTable} WHERE [thread_id] = @threadId`;
|
|
440
1476
|
const deleteThreadSql = `DELETE FROM ${threadsTable} WHERE id = @threadId`;
|
|
441
1477
|
const tx = this.pool.transaction();
|
|
@@ -451,7 +1487,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
451
1487
|
});
|
|
452
1488
|
throw new error.MastraError(
|
|
453
1489
|
{
|
|
454
|
-
id: "
|
|
1490
|
+
id: storage.createStorageErrorId("MSSQL", "DELETE_THREAD", "FAILED"),
|
|
455
1491
|
domain: error.ErrorDomain.STORAGE,
|
|
456
1492
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
457
1493
|
details: {
|
|
@@ -462,25 +1498,18 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
462
1498
|
);
|
|
463
1499
|
}
|
|
464
1500
|
}
|
|
465
|
-
async _getIncludedMessages({
|
|
466
|
-
|
|
467
|
-
selectBy,
|
|
468
|
-
orderByStatement
|
|
469
|
-
}) {
|
|
470
|
-
if (!threadId.trim()) throw new Error("threadId must be a non-empty string");
|
|
471
|
-
const include = selectBy?.include;
|
|
472
|
-
if (!include) return null;
|
|
1501
|
+
async _getIncludedMessages({ include }) {
|
|
1502
|
+
if (!include || include.length === 0) return null;
|
|
473
1503
|
const unionQueries = [];
|
|
474
1504
|
const paramValues = [];
|
|
475
1505
|
let paramIdx = 1;
|
|
476
1506
|
const paramNames = [];
|
|
1507
|
+
const tableName = getTableName2({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName2(this.schema) });
|
|
477
1508
|
for (const inc of include) {
|
|
478
1509
|
const { id, withPreviousMessages = 0, withNextMessages = 0 } = inc;
|
|
479
|
-
const
|
|
480
|
-
const
|
|
481
|
-
const
|
|
482
|
-
const pPrev = `@p${paramIdx + 2}`;
|
|
483
|
-
const pNext = `@p${paramIdx + 3}`;
|
|
1510
|
+
const pId = `@p${paramIdx}`;
|
|
1511
|
+
const pPrev = `@p${paramIdx + 1}`;
|
|
1512
|
+
const pNext = `@p${paramIdx + 2}`;
|
|
484
1513
|
unionQueries.push(
|
|
485
1514
|
`
|
|
486
1515
|
SELECT
|
|
@@ -493,30 +1522,32 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
493
1522
|
m.[resourceId],
|
|
494
1523
|
m.seq_id
|
|
495
1524
|
FROM (
|
|
496
|
-
SELECT *, ROW_NUMBER() OVER (
|
|
497
|
-
FROM ${
|
|
498
|
-
WHERE [thread_id] = ${
|
|
1525
|
+
SELECT *, ROW_NUMBER() OVER (ORDER BY [createdAt] ASC) as row_num
|
|
1526
|
+
FROM ${tableName}
|
|
1527
|
+
WHERE [thread_id] = (SELECT thread_id FROM ${tableName} WHERE id = ${pId})
|
|
499
1528
|
) AS m
|
|
500
1529
|
WHERE m.id = ${pId}
|
|
501
1530
|
OR EXISTS (
|
|
502
1531
|
SELECT 1
|
|
503
1532
|
FROM (
|
|
504
|
-
SELECT *, ROW_NUMBER() OVER (
|
|
505
|
-
FROM ${
|
|
506
|
-
WHERE [thread_id] = ${
|
|
1533
|
+
SELECT *, ROW_NUMBER() OVER (ORDER BY [createdAt] ASC) as row_num
|
|
1534
|
+
FROM ${tableName}
|
|
1535
|
+
WHERE [thread_id] = (SELECT thread_id FROM ${tableName} WHERE id = ${pId})
|
|
507
1536
|
) AS target
|
|
508
1537
|
WHERE target.id = ${pId}
|
|
509
1538
|
AND (
|
|
510
|
-
|
|
1539
|
+
-- Get previous messages (messages that come BEFORE the target)
|
|
1540
|
+
(m.row_num < target.row_num AND m.row_num >= target.row_num - ${pPrev})
|
|
511
1541
|
OR
|
|
512
|
-
|
|
1542
|
+
-- Get next messages (messages that come AFTER the target)
|
|
1543
|
+
(m.row_num > target.row_num AND m.row_num <= target.row_num + ${pNext})
|
|
513
1544
|
)
|
|
514
1545
|
)
|
|
515
1546
|
`
|
|
516
1547
|
);
|
|
517
|
-
paramValues.push(
|
|
518
|
-
paramNames.push(`p${paramIdx}`, `p${paramIdx + 1}`, `p${paramIdx + 2}
|
|
519
|
-
paramIdx +=
|
|
1548
|
+
paramValues.push(id, withPreviousMessages, withNextMessages);
|
|
1549
|
+
paramNames.push(`p${paramIdx}`, `p${paramIdx + 1}`, `p${paramIdx + 2}`);
|
|
1550
|
+
paramIdx += 3;
|
|
520
1551
|
}
|
|
521
1552
|
const finalQuery = `
|
|
522
1553
|
SELECT * FROM (
|
|
@@ -538,34 +1569,16 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
538
1569
|
});
|
|
539
1570
|
return dedupedRows;
|
|
540
1571
|
}
|
|
541
|
-
async
|
|
542
|
-
|
|
1572
|
+
async listMessagesById({ messageIds }) {
|
|
1573
|
+
if (messageIds.length === 0) return { messages: [] };
|
|
543
1574
|
const selectStatement = `SELECT seq_id, id, content, role, type, [createdAt], thread_id AS threadId, resourceId`;
|
|
544
1575
|
const orderByStatement = `ORDER BY [seq_id] DESC`;
|
|
545
|
-
const limit = storage.resolveMessageLimit({ last: selectBy?.last, defaultLimit: 40 });
|
|
546
1576
|
try {
|
|
547
|
-
if (!threadId.trim()) throw new Error("threadId must be a non-empty string");
|
|
548
1577
|
let rows = [];
|
|
549
|
-
|
|
550
|
-
if (include?.length) {
|
|
551
|
-
const includeMessages = await this._getIncludedMessages({ threadId, selectBy, orderByStatement });
|
|
552
|
-
if (includeMessages) {
|
|
553
|
-
rows.push(...includeMessages);
|
|
554
|
-
}
|
|
555
|
-
}
|
|
556
|
-
const excludeIds = rows.map((m) => m.id).filter(Boolean);
|
|
557
|
-
let query = `${selectStatement} FROM ${getTableName({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName(this.schema) })} WHERE [thread_id] = @threadId`;
|
|
1578
|
+
let query = `${selectStatement} FROM ${getTableName2({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName2(this.schema) })} WHERE [id] IN (${messageIds.map((_, i) => `@id${i}`).join(", ")})`;
|
|
558
1579
|
const request = this.pool.request();
|
|
559
|
-
request.input(
|
|
560
|
-
|
|
561
|
-
const excludeParams = excludeIds.map((_, idx) => `@id${idx}`);
|
|
562
|
-
query += ` AND id NOT IN (${excludeParams.join(", ")})`;
|
|
563
|
-
excludeIds.forEach((id, idx) => {
|
|
564
|
-
request.input(`id${idx}`, id);
|
|
565
|
-
});
|
|
566
|
-
}
|
|
567
|
-
query += ` ${orderByStatement} OFFSET 0 ROWS FETCH NEXT @limit ROWS ONLY`;
|
|
568
|
-
request.input("limit", limit);
|
|
1580
|
+
messageIds.forEach((id, i) => request.input(`id${i}`, id));
|
|
1581
|
+
query += ` ${orderByStatement}`;
|
|
569
1582
|
const result = await request.query(query);
|
|
570
1583
|
const remainingRows = result.recordset || [];
|
|
571
1584
|
rows.push(...remainingRows);
|
|
@@ -573,157 +1586,177 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
573
1586
|
const timeDiff = a.seq_id - b.seq_id;
|
|
574
1587
|
return timeDiff;
|
|
575
1588
|
});
|
|
576
|
-
|
|
577
|
-
|
|
1589
|
+
const messagesWithParsedContent = rows.map((row) => {
|
|
1590
|
+
if (typeof row.content === "string") {
|
|
1591
|
+
try {
|
|
1592
|
+
return { ...row, content: JSON.parse(row.content) };
|
|
1593
|
+
} catch {
|
|
1594
|
+
return row;
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1597
|
+
return row;
|
|
1598
|
+
});
|
|
1599
|
+
const cleanMessages = messagesWithParsedContent.map(({ seq_id, ...rest }) => rest);
|
|
1600
|
+
const list = new agent.MessageList().add(cleanMessages, "memory");
|
|
1601
|
+
return { messages: list.get.all.db() };
|
|
578
1602
|
} catch (error$1) {
|
|
579
1603
|
const mastraError = new error.MastraError(
|
|
580
1604
|
{
|
|
581
|
-
id: "
|
|
1605
|
+
id: storage.createStorageErrorId("MSSQL", "LIST_MESSAGES_BY_ID", "FAILED"),
|
|
582
1606
|
domain: error.ErrorDomain.STORAGE,
|
|
583
1607
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
584
1608
|
details: {
|
|
585
|
-
|
|
586
|
-
resourceId: resourceId ?? ""
|
|
1609
|
+
messageIds: JSON.stringify(messageIds)
|
|
587
1610
|
}
|
|
588
1611
|
},
|
|
589
1612
|
error$1
|
|
590
1613
|
);
|
|
591
1614
|
this.logger?.error?.(mastraError.toString());
|
|
592
|
-
this.logger?.trackException(mastraError);
|
|
593
|
-
return [];
|
|
1615
|
+
this.logger?.trackException?.(mastraError);
|
|
1616
|
+
return { messages: [] };
|
|
594
1617
|
}
|
|
595
1618
|
}
|
|
596
|
-
async
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
const selectStatement = `SELECT seq_id, id, content, role, type, [createdAt], thread_id AS threadId, resourceId`;
|
|
602
|
-
const orderByStatement = `ORDER BY [seq_id] DESC`;
|
|
603
|
-
try {
|
|
604
|
-
let rows = [];
|
|
605
|
-
let query = `${selectStatement} FROM ${getTableName({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName(this.schema) })} WHERE [id] IN (${messageIds.map((_, i) => `@id${i}`).join(", ")})`;
|
|
606
|
-
const request = this.pool.request();
|
|
607
|
-
messageIds.forEach((id, i) => request.input(`id${i}`, id));
|
|
608
|
-
query += ` ${orderByStatement}`;
|
|
609
|
-
const result = await request.query(query);
|
|
610
|
-
const remainingRows = result.recordset || [];
|
|
611
|
-
rows.push(...remainingRows);
|
|
612
|
-
rows.sort((a, b) => {
|
|
613
|
-
const timeDiff = a.seq_id - b.seq_id;
|
|
614
|
-
return timeDiff;
|
|
615
|
-
});
|
|
616
|
-
rows = rows.map(({ seq_id, ...rest }) => rest);
|
|
617
|
-
if (format === `v1`) return this._parseAndFormatMessages(rows, format);
|
|
618
|
-
return this._parseAndFormatMessages(rows, `v2`);
|
|
619
|
-
} catch (error$1) {
|
|
620
|
-
const mastraError = new error.MastraError(
|
|
1619
|
+
async listMessages(args) {
|
|
1620
|
+
const { threadId, resourceId, include, filter, perPage: perPageInput, page = 0, orderBy } = args;
|
|
1621
|
+
const threadIds = Array.isArray(threadId) ? threadId : [threadId];
|
|
1622
|
+
if (threadIds.length === 0 || threadIds.some((id) => !id.trim())) {
|
|
1623
|
+
throw new error.MastraError(
|
|
621
1624
|
{
|
|
622
|
-
id: "
|
|
1625
|
+
id: storage.createStorageErrorId("MSSQL", "LIST_MESSAGES", "INVALID_THREAD_ID"),
|
|
623
1626
|
domain: error.ErrorDomain.STORAGE,
|
|
624
1627
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
625
|
-
details: {
|
|
626
|
-
messageIds: JSON.stringify(messageIds)
|
|
627
|
-
}
|
|
1628
|
+
details: { threadId: Array.isArray(threadId) ? threadId.join(",") : threadId }
|
|
628
1629
|
},
|
|
629
|
-
|
|
1630
|
+
new Error("threadId must be a non-empty string or array of non-empty strings")
|
|
630
1631
|
);
|
|
631
|
-
this.logger?.error?.(mastraError.toString());
|
|
632
|
-
this.logger?.trackException(mastraError);
|
|
633
|
-
return [];
|
|
634
1632
|
}
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
1633
|
+
if (page < 0) {
|
|
1634
|
+
throw new error.MastraError({
|
|
1635
|
+
id: storage.createStorageErrorId("MSSQL", "LIST_MESSAGES", "INVALID_PAGE"),
|
|
1636
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1637
|
+
category: error.ErrorCategory.USER,
|
|
1638
|
+
text: "Page number must be non-negative",
|
|
1639
|
+
details: {
|
|
1640
|
+
threadId: Array.isArray(threadId) ? threadId.join(",") : threadId,
|
|
1641
|
+
page
|
|
1642
|
+
}
|
|
1643
|
+
});
|
|
1644
|
+
}
|
|
1645
|
+
const perPage = storage.normalizePerPage(perPageInput, 40);
|
|
1646
|
+
const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
639
1647
|
try {
|
|
640
|
-
|
|
641
|
-
const
|
|
642
|
-
const
|
|
643
|
-
const
|
|
644
|
-
const
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
const
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
request
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
request.input("fromDate", fromDate.toISOString());
|
|
658
|
-
}
|
|
659
|
-
if (toDate instanceof Date && !isNaN(toDate.getTime())) {
|
|
660
|
-
conditions.push("[createdAt] <= @toDate");
|
|
661
|
-
request.input("toDate", toDate.toISOString());
|
|
662
|
-
}
|
|
663
|
-
const whereClause = `WHERE ${conditions.join(" AND ")}`;
|
|
664
|
-
const countQuery = `SELECT COUNT(*) as total FROM ${getTableName({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName(this.schema) })} ${whereClause}`;
|
|
665
|
-
const countResult = await request.query(countQuery);
|
|
1648
|
+
const { field, direction } = this.parseOrderBy(orderBy, "ASC");
|
|
1649
|
+
const orderByStatement = `ORDER BY [${field}] ${direction}, [seq_id] ${direction}`;
|
|
1650
|
+
const tableName = getTableName2({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName2(this.schema) });
|
|
1651
|
+
const baseQuery = `SELECT seq_id, id, content, role, type, [createdAt], thread_id AS threadId, resourceId FROM ${tableName}`;
|
|
1652
|
+
const filters = {
|
|
1653
|
+
thread_id: threadIds.length === 1 ? threadIds[0] : { $in: threadIds },
|
|
1654
|
+
...resourceId ? { resourceId } : {},
|
|
1655
|
+
...buildDateRangeFilter(filter?.dateRange, "createdAt")
|
|
1656
|
+
};
|
|
1657
|
+
const { sql: actualWhereClause = "", params: whereParams } = prepareWhereClause(
|
|
1658
|
+
filters);
|
|
1659
|
+
const bindWhereParams = (req) => {
|
|
1660
|
+
Object.entries(whereParams).forEach(([paramName, paramValue]) => req.input(paramName, paramValue));
|
|
1661
|
+
};
|
|
1662
|
+
const countRequest = this.pool.request();
|
|
1663
|
+
bindWhereParams(countRequest);
|
|
1664
|
+
const countResult = await countRequest.query(`SELECT COUNT(*) as total FROM ${tableName}${actualWhereClause}`);
|
|
666
1665
|
const total = parseInt(countResult.recordset[0]?.total, 10) || 0;
|
|
667
|
-
|
|
668
|
-
const
|
|
1666
|
+
const fetchBaseMessages = async () => {
|
|
1667
|
+
const request = this.pool.request();
|
|
1668
|
+
bindWhereParams(request);
|
|
1669
|
+
if (perPageInput === false) {
|
|
1670
|
+
const result2 = await request.query(`${baseQuery}${actualWhereClause} ${orderByStatement}`);
|
|
1671
|
+
return result2.recordset || [];
|
|
1672
|
+
}
|
|
1673
|
+
request.input("offset", offset);
|
|
1674
|
+
request.input("limit", perPage > 2147483647 ? sql__default.default.BigInt : sql__default.default.Int, perPage);
|
|
1675
|
+
const result = await request.query(
|
|
1676
|
+
`${baseQuery}${actualWhereClause} ${orderByStatement} OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY`
|
|
1677
|
+
);
|
|
1678
|
+
return result.recordset || [];
|
|
1679
|
+
};
|
|
1680
|
+
const baseRows = perPage === 0 ? [] : await fetchBaseMessages();
|
|
1681
|
+
const messages = [...baseRows];
|
|
1682
|
+
const seqById = /* @__PURE__ */ new Map();
|
|
1683
|
+
messages.forEach((msg) => {
|
|
1684
|
+
if (typeof msg.seq_id === "number") seqById.set(msg.id, msg.seq_id);
|
|
1685
|
+
});
|
|
1686
|
+
if (total === 0 && messages.length === 0 && (!include || include.length === 0)) {
|
|
669
1687
|
return {
|
|
670
|
-
messages:
|
|
671
|
-
total:
|
|
1688
|
+
messages: [],
|
|
1689
|
+
total: 0,
|
|
672
1690
|
page,
|
|
673
|
-
perPage,
|
|
1691
|
+
perPage: perPageForResponse,
|
|
674
1692
|
hasMore: false
|
|
675
1693
|
};
|
|
676
1694
|
}
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
const
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
const
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
1695
|
+
if (include?.length) {
|
|
1696
|
+
const messageIds = new Set(messages.map((m) => m.id));
|
|
1697
|
+
const includeMessages = await this._getIncludedMessages({ include });
|
|
1698
|
+
includeMessages?.forEach((msg) => {
|
|
1699
|
+
if (!messageIds.has(msg.id)) {
|
|
1700
|
+
messages.push(msg);
|
|
1701
|
+
messageIds.add(msg.id);
|
|
1702
|
+
if (typeof msg.seq_id === "number") seqById.set(msg.id, msg.seq_id);
|
|
1703
|
+
}
|
|
1704
|
+
});
|
|
1705
|
+
}
|
|
1706
|
+
const parsed = this._parseAndFormatMessages(messages, "v2");
|
|
1707
|
+
const mult = direction === "ASC" ? 1 : -1;
|
|
1708
|
+
const finalMessages = parsed.sort((a, b) => {
|
|
1709
|
+
const aVal = field === "createdAt" ? new Date(a.createdAt).getTime() : a[field];
|
|
1710
|
+
const bVal = field === "createdAt" ? new Date(b.createdAt).getTime() : b[field];
|
|
1711
|
+
if (aVal == null || bVal == null) {
|
|
1712
|
+
return aVal == null && bVal == null ? a.id.localeCompare(b.id) : aVal == null ? 1 : -1;
|
|
1713
|
+
}
|
|
1714
|
+
const diff = (typeof aVal === "number" && typeof bVal === "number" ? aVal - bVal : String(aVal).localeCompare(String(bVal))) * mult;
|
|
1715
|
+
if (diff !== 0) return diff;
|
|
1716
|
+
const seqA = seqById.get(a.id);
|
|
1717
|
+
const seqB = seqById.get(b.id);
|
|
1718
|
+
return seqA != null && seqB != null ? (seqA - seqB) * mult : a.id.localeCompare(b.id);
|
|
1719
|
+
});
|
|
1720
|
+
const threadIdSet = new Set(threadIds);
|
|
1721
|
+
const returnedThreadMessageCount = finalMessages.filter((m) => m.threadId && threadIdSet.has(m.threadId)).length;
|
|
1722
|
+
const hasMore = perPageInput !== false && returnedThreadMessageCount < total && offset + perPage < total;
|
|
692
1723
|
return {
|
|
693
|
-
messages:
|
|
694
|
-
total
|
|
1724
|
+
messages: finalMessages,
|
|
1725
|
+
total,
|
|
695
1726
|
page,
|
|
696
|
-
perPage,
|
|
697
|
-
hasMore
|
|
1727
|
+
perPage: perPageForResponse,
|
|
1728
|
+
hasMore
|
|
698
1729
|
};
|
|
699
1730
|
} catch (error$1) {
|
|
700
1731
|
const mastraError = new error.MastraError(
|
|
701
1732
|
{
|
|
702
|
-
id: "
|
|
1733
|
+
id: storage.createStorageErrorId("MSSQL", "LIST_MESSAGES", "FAILED"),
|
|
703
1734
|
domain: error.ErrorDomain.STORAGE,
|
|
704
1735
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
705
1736
|
details: {
|
|
706
|
-
threadId,
|
|
707
|
-
resourceId: resourceId ?? ""
|
|
708
|
-
page
|
|
1737
|
+
threadId: Array.isArray(threadId) ? threadId.join(",") : threadId,
|
|
1738
|
+
resourceId: resourceId ?? ""
|
|
709
1739
|
}
|
|
710
1740
|
},
|
|
711
1741
|
error$1
|
|
712
1742
|
);
|
|
713
1743
|
this.logger?.error?.(mastraError.toString());
|
|
714
|
-
this.logger?.trackException(mastraError);
|
|
715
|
-
return {
|
|
1744
|
+
this.logger?.trackException?.(mastraError);
|
|
1745
|
+
return {
|
|
1746
|
+
messages: [],
|
|
1747
|
+
total: 0,
|
|
1748
|
+
page,
|
|
1749
|
+
perPage: perPageForResponse,
|
|
1750
|
+
hasMore: false
|
|
1751
|
+
};
|
|
716
1752
|
}
|
|
717
1753
|
}
|
|
718
|
-
async saveMessages({
|
|
719
|
-
messages
|
|
720
|
-
format
|
|
721
|
-
}) {
|
|
722
|
-
if (messages.length === 0) return messages;
|
|
1754
|
+
async saveMessages({ messages }) {
|
|
1755
|
+
if (messages.length === 0) return { messages: [] };
|
|
723
1756
|
const threadId = messages[0]?.threadId;
|
|
724
1757
|
if (!threadId) {
|
|
725
1758
|
throw new error.MastraError({
|
|
726
|
-
id: "
|
|
1759
|
+
id: storage.createStorageErrorId("MSSQL", "SAVE_MESSAGES", "INVALID_THREAD_ID"),
|
|
727
1760
|
domain: error.ErrorDomain.STORAGE,
|
|
728
1761
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
729
1762
|
text: `Thread ID is required`
|
|
@@ -732,15 +1765,15 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
732
1765
|
const thread = await this.getThreadById({ threadId });
|
|
733
1766
|
if (!thread) {
|
|
734
1767
|
throw new error.MastraError({
|
|
735
|
-
id: "
|
|
1768
|
+
id: storage.createStorageErrorId("MSSQL", "SAVE_MESSAGES", "THREAD_NOT_FOUND"),
|
|
736
1769
|
domain: error.ErrorDomain.STORAGE,
|
|
737
1770
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
738
1771
|
text: `Thread ${threadId} not found`,
|
|
739
1772
|
details: { threadId }
|
|
740
1773
|
});
|
|
741
1774
|
}
|
|
742
|
-
const tableMessages =
|
|
743
|
-
const tableThreads =
|
|
1775
|
+
const tableMessages = getTableName2({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName2(this.schema) });
|
|
1776
|
+
const tableThreads = getTableName2({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName2(this.schema) });
|
|
744
1777
|
try {
|
|
745
1778
|
const transaction = this.pool.transaction();
|
|
746
1779
|
await transaction.begin();
|
|
@@ -763,7 +1796,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
763
1796
|
"content",
|
|
764
1797
|
typeof message.content === "string" ? message.content : JSON.stringify(message.content)
|
|
765
1798
|
);
|
|
766
|
-
request.input("createdAt",
|
|
1799
|
+
request.input("createdAt", sql__default.default.DateTime2, message.createdAt);
|
|
767
1800
|
request.input("role", message.role);
|
|
768
1801
|
request.input("type", message.type || "v2");
|
|
769
1802
|
request.input("resourceId", message.resourceId);
|
|
@@ -782,7 +1815,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
782
1815
|
await request.query(mergeSql);
|
|
783
1816
|
}
|
|
784
1817
|
const threadReq = transaction.request();
|
|
785
|
-
threadReq.input("updatedAt",
|
|
1818
|
+
threadReq.input("updatedAt", sql__default.default.DateTime2, /* @__PURE__ */ new Date());
|
|
786
1819
|
threadReq.input("id", threadId);
|
|
787
1820
|
await threadReq.query(`UPDATE ${tableThreads} SET [updatedAt] = @updatedAt WHERE id = @id`);
|
|
788
1821
|
await transaction.commit();
|
|
@@ -801,12 +1834,11 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
801
1834
|
return message;
|
|
802
1835
|
});
|
|
803
1836
|
const list = new agent.MessageList().add(messagesWithParsedContent, "memory");
|
|
804
|
-
|
|
805
|
-
return list.get.all.v1();
|
|
1837
|
+
return { messages: list.get.all.db() };
|
|
806
1838
|
} catch (error$1) {
|
|
807
1839
|
throw new error.MastraError(
|
|
808
1840
|
{
|
|
809
|
-
id: "
|
|
1841
|
+
id: storage.createStorageErrorId("MSSQL", "SAVE_MESSAGES", "FAILED"),
|
|
810
1842
|
domain: error.ErrorDomain.STORAGE,
|
|
811
1843
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
812
1844
|
details: { threadId }
|
|
@@ -823,7 +1855,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
823
1855
|
}
|
|
824
1856
|
const messageIds = messages.map((m) => m.id);
|
|
825
1857
|
const idParams = messageIds.map((_, i) => `@id${i}`).join(", ");
|
|
826
|
-
let selectQuery = `SELECT id, content, role, type, createdAt, thread_id AS threadId, resourceId FROM ${
|
|
1858
|
+
let selectQuery = `SELECT id, content, role, type, createdAt, thread_id AS threadId, resourceId FROM ${getTableName2({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName2(this.schema) })}`;
|
|
827
1859
|
if (idParams.length > 0) {
|
|
828
1860
|
selectQuery += ` WHERE id IN (${idParams})`;
|
|
829
1861
|
} else {
|
|
@@ -880,7 +1912,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
880
1912
|
}
|
|
881
1913
|
}
|
|
882
1914
|
if (setClauses.length > 0) {
|
|
883
|
-
const updateSql = `UPDATE ${
|
|
1915
|
+
const updateSql = `UPDATE ${getTableName2({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName2(this.schema) })} SET ${setClauses.join(", ")} WHERE id = @id`;
|
|
884
1916
|
await req.query(updateSql);
|
|
885
1917
|
}
|
|
886
1918
|
}
|
|
@@ -889,7 +1921,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
889
1921
|
const threadReq = transaction.request();
|
|
890
1922
|
Array.from(threadIdsToUpdate).forEach((tid, i) => threadReq.input(`tid${i}`, tid));
|
|
891
1923
|
threadReq.input("updatedAt", (/* @__PURE__ */ new Date()).toISOString());
|
|
892
|
-
const threadSql = `UPDATE ${
|
|
1924
|
+
const threadSql = `UPDATE ${getTableName2({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName2(this.schema) })} SET updatedAt = @updatedAt WHERE id IN (${threadIdParams})`;
|
|
893
1925
|
await threadReq.query(threadSql);
|
|
894
1926
|
}
|
|
895
1927
|
await transaction.commit();
|
|
@@ -897,7 +1929,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
897
1929
|
await transaction.rollback();
|
|
898
1930
|
throw new error.MastraError(
|
|
899
1931
|
{
|
|
900
|
-
id: "
|
|
1932
|
+
id: storage.createStorageErrorId("MSSQL", "UPDATE_MESSAGES", "FAILED"),
|
|
901
1933
|
domain: error.ErrorDomain.STORAGE,
|
|
902
1934
|
category: error.ErrorCategory.THIRD_PARTY
|
|
903
1935
|
},
|
|
@@ -922,8 +1954,8 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
922
1954
|
return;
|
|
923
1955
|
}
|
|
924
1956
|
try {
|
|
925
|
-
const messageTableName =
|
|
926
|
-
const threadTableName =
|
|
1957
|
+
const messageTableName = getTableName2({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName2(this.schema) });
|
|
1958
|
+
const threadTableName = getTableName2({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName2(this.schema) });
|
|
927
1959
|
const placeholders = messageIds.map((_, idx) => `@p${idx + 1}`).join(",");
|
|
928
1960
|
const request = this.pool.request();
|
|
929
1961
|
messageIds.forEach((id, idx) => {
|
|
@@ -959,7 +1991,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
959
1991
|
} catch (error$1) {
|
|
960
1992
|
throw new error.MastraError(
|
|
961
1993
|
{
|
|
962
|
-
id: "
|
|
1994
|
+
id: storage.createStorageErrorId("MSSQL", "DELETE_MESSAGES", "FAILED"),
|
|
963
1995
|
domain: error.ErrorDomain.STORAGE,
|
|
964
1996
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
965
1997
|
details: { messageIds: messageIds.join(", ") }
|
|
@@ -969,7 +2001,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
969
2001
|
}
|
|
970
2002
|
}
|
|
971
2003
|
async getResourceById({ resourceId }) {
|
|
972
|
-
const tableName =
|
|
2004
|
+
const tableName = getTableName2({ indexName: storage.TABLE_RESOURCES, schemaName: getSchemaName2(this.schema) });
|
|
973
2005
|
try {
|
|
974
2006
|
const req = this.pool.request();
|
|
975
2007
|
req.input("resourceId", resourceId);
|
|
@@ -978,14 +2010,16 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
978
2010
|
return null;
|
|
979
2011
|
}
|
|
980
2012
|
return {
|
|
981
|
-
|
|
982
|
-
|
|
2013
|
+
id: result.id,
|
|
2014
|
+
createdAt: result.createdAt,
|
|
2015
|
+
updatedAt: result.updatedAt,
|
|
2016
|
+
workingMemory: result.workingMemory,
|
|
983
2017
|
metadata: typeof result.metadata === "string" ? JSON.parse(result.metadata) : result.metadata
|
|
984
2018
|
};
|
|
985
2019
|
} catch (error$1) {
|
|
986
2020
|
const mastraError = new error.MastraError(
|
|
987
2021
|
{
|
|
988
|
-
id: "
|
|
2022
|
+
id: storage.createStorageErrorId("MSSQL", "GET_RESOURCE_BY_ID", "FAILED"),
|
|
989
2023
|
domain: error.ErrorDomain.STORAGE,
|
|
990
2024
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
991
2025
|
details: { resourceId }
|
|
@@ -993,16 +2027,16 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
993
2027
|
error$1
|
|
994
2028
|
);
|
|
995
2029
|
this.logger?.error?.(mastraError.toString());
|
|
996
|
-
this.logger?.trackException(mastraError);
|
|
2030
|
+
this.logger?.trackException?.(mastraError);
|
|
997
2031
|
throw mastraError;
|
|
998
2032
|
}
|
|
999
2033
|
}
|
|
1000
2034
|
async saveResource({ resource }) {
|
|
1001
|
-
await this.
|
|
2035
|
+
await this.db.insert({
|
|
1002
2036
|
tableName: storage.TABLE_RESOURCES,
|
|
1003
2037
|
record: {
|
|
1004
2038
|
...resource,
|
|
1005
|
-
metadata:
|
|
2039
|
+
metadata: resource.metadata
|
|
1006
2040
|
}
|
|
1007
2041
|
});
|
|
1008
2042
|
return resource;
|
|
@@ -1033,7 +2067,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
1033
2067
|
},
|
|
1034
2068
|
updatedAt: /* @__PURE__ */ new Date()
|
|
1035
2069
|
};
|
|
1036
|
-
const tableName =
|
|
2070
|
+
const tableName = getTableName2({ indexName: storage.TABLE_RESOURCES, schemaName: getSchemaName2(this.schema) });
|
|
1037
2071
|
const updates = [];
|
|
1038
2072
|
const req = this.pool.request();
|
|
1039
2073
|
if (workingMemory !== void 0) {
|
|
@@ -1052,7 +2086,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
1052
2086
|
} catch (error$1) {
|
|
1053
2087
|
const mastraError = new error.MastraError(
|
|
1054
2088
|
{
|
|
1055
|
-
id: "
|
|
2089
|
+
id: storage.createStorageErrorId("MSSQL", "UPDATE_RESOURCE", "FAILED"),
|
|
1056
2090
|
domain: error.ErrorDomain.STORAGE,
|
|
1057
2091
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1058
2092
|
details: { resourceId }
|
|
@@ -1060,357 +2094,650 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
1060
2094
|
error$1
|
|
1061
2095
|
);
|
|
1062
2096
|
this.logger?.error?.(mastraError.toString());
|
|
1063
|
-
this.logger?.trackException(mastraError);
|
|
2097
|
+
this.logger?.trackException?.(mastraError);
|
|
1064
2098
|
throw mastraError;
|
|
1065
2099
|
}
|
|
1066
2100
|
}
|
|
1067
2101
|
};
|
|
1068
|
-
var
|
|
2102
|
+
var ObservabilityMSSQL = class _ObservabilityMSSQL extends storage.ObservabilityStorage {
|
|
1069
2103
|
pool;
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
return "DATETIME2(7)";
|
|
1079
|
-
case "uuid":
|
|
1080
|
-
return "UNIQUEIDENTIFIER";
|
|
1081
|
-
case "jsonb":
|
|
1082
|
-
return "NVARCHAR(MAX)";
|
|
1083
|
-
case "integer":
|
|
1084
|
-
return "INT";
|
|
1085
|
-
case "bigint":
|
|
1086
|
-
return "BIGINT";
|
|
1087
|
-
case "float":
|
|
1088
|
-
return "FLOAT";
|
|
1089
|
-
default:
|
|
1090
|
-
throw new error.MastraError({
|
|
1091
|
-
id: "MASTRA_STORAGE_MSSQL_STORE_TYPE_NOT_SUPPORTED",
|
|
1092
|
-
domain: error.ErrorDomain.STORAGE,
|
|
1093
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
1094
|
-
});
|
|
1095
|
-
}
|
|
1096
|
-
}
|
|
1097
|
-
constructor({ pool, schemaName }) {
|
|
2104
|
+
db;
|
|
2105
|
+
schema;
|
|
2106
|
+
needsConnect;
|
|
2107
|
+
skipDefaultIndexes;
|
|
2108
|
+
indexes;
|
|
2109
|
+
/** Tables managed by this domain */
|
|
2110
|
+
static MANAGED_TABLES = [storage.TABLE_SPANS];
|
|
2111
|
+
constructor(config) {
|
|
1098
2112
|
super();
|
|
2113
|
+
const { pool, schemaName, skipDefaultIndexes, indexes, needsConnect } = resolveMssqlConfig(config);
|
|
1099
2114
|
this.pool = pool;
|
|
1100
|
-
this.
|
|
2115
|
+
this.schema = schemaName;
|
|
2116
|
+
this.db = new MssqlDB({ pool, schemaName, skipDefaultIndexes });
|
|
2117
|
+
this.needsConnect = needsConnect;
|
|
2118
|
+
this.skipDefaultIndexes = skipDefaultIndexes;
|
|
2119
|
+
this.indexes = indexes?.filter((idx) => _ObservabilityMSSQL.MANAGED_TABLES.includes(idx.table));
|
|
1101
2120
|
}
|
|
1102
|
-
async
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
`SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = @schema AND TABLE_NAME = @table AND (COLUMN_NAME = @column OR COLUMN_NAME = @columnLower)`
|
|
1111
|
-
);
|
|
1112
|
-
return result.recordset.length > 0;
|
|
2121
|
+
async init() {
|
|
2122
|
+
if (this.needsConnect) {
|
|
2123
|
+
await this.pool.connect();
|
|
2124
|
+
this.needsConnect = false;
|
|
2125
|
+
}
|
|
2126
|
+
await this.db.createTable({ tableName: storage.TABLE_SPANS, schema: storage.SPAN_SCHEMA });
|
|
2127
|
+
await this.createDefaultIndexes();
|
|
2128
|
+
await this.createCustomIndexes();
|
|
1113
2129
|
}
|
|
1114
|
-
|
|
1115
|
-
|
|
2130
|
+
/**
|
|
2131
|
+
* Returns default index definitions for the observability domain tables.
|
|
2132
|
+
*/
|
|
2133
|
+
getDefaultIndexDefinitions() {
|
|
2134
|
+
const schemaPrefix = this.schema ? `${this.schema}_` : "";
|
|
2135
|
+
return [
|
|
2136
|
+
{
|
|
2137
|
+
name: `${schemaPrefix}mastra_ai_spans_traceid_startedat_idx`,
|
|
2138
|
+
table: storage.TABLE_SPANS,
|
|
2139
|
+
columns: ["traceId", "startedAt DESC"]
|
|
2140
|
+
},
|
|
2141
|
+
{
|
|
2142
|
+
name: `${schemaPrefix}mastra_ai_spans_parentspanid_startedat_idx`,
|
|
2143
|
+
table: storage.TABLE_SPANS,
|
|
2144
|
+
columns: ["parentSpanId", "startedAt DESC"]
|
|
2145
|
+
},
|
|
2146
|
+
{
|
|
2147
|
+
name: `${schemaPrefix}mastra_ai_spans_name_idx`,
|
|
2148
|
+
table: storage.TABLE_SPANS,
|
|
2149
|
+
columns: ["name"]
|
|
2150
|
+
},
|
|
2151
|
+
{
|
|
2152
|
+
name: `${schemaPrefix}mastra_ai_spans_spantype_startedat_idx`,
|
|
2153
|
+
table: storage.TABLE_SPANS,
|
|
2154
|
+
columns: ["spanType", "startedAt DESC"]
|
|
2155
|
+
},
|
|
2156
|
+
// Root spans filtered index - every listTraces query filters parentSpanId IS NULL
|
|
2157
|
+
{
|
|
2158
|
+
name: `${schemaPrefix}mastra_ai_spans_root_spans_idx`,
|
|
2159
|
+
table: storage.TABLE_SPANS,
|
|
2160
|
+
columns: ["startedAt DESC"],
|
|
2161
|
+
where: "[parentSpanId] IS NULL"
|
|
2162
|
+
},
|
|
2163
|
+
// Entity identification indexes - common filtering patterns
|
|
2164
|
+
{
|
|
2165
|
+
name: `${schemaPrefix}mastra_ai_spans_entitytype_entityid_idx`,
|
|
2166
|
+
table: storage.TABLE_SPANS,
|
|
2167
|
+
columns: ["entityType", "entityId"]
|
|
2168
|
+
},
|
|
2169
|
+
{
|
|
2170
|
+
name: `${schemaPrefix}mastra_ai_spans_entitytype_entityname_idx`,
|
|
2171
|
+
table: storage.TABLE_SPANS,
|
|
2172
|
+
columns: ["entityType", "entityName"]
|
|
2173
|
+
},
|
|
2174
|
+
// Multi-tenant filtering - organizationId + userId
|
|
2175
|
+
{
|
|
2176
|
+
name: `${schemaPrefix}mastra_ai_spans_orgid_userid_idx`,
|
|
2177
|
+
table: storage.TABLE_SPANS,
|
|
2178
|
+
columns: ["organizationId", "userId"]
|
|
2179
|
+
}
|
|
2180
|
+
// Note: MSSQL doesn't support GIN indexes for JSONB/array containment queries
|
|
2181
|
+
// Metadata and tags filtering will use full table scans on NVARCHAR(MAX) columns
|
|
2182
|
+
];
|
|
2183
|
+
}
|
|
2184
|
+
/**
|
|
2185
|
+
* Creates default indexes for optimal query performance.
|
|
2186
|
+
*/
|
|
2187
|
+
async createDefaultIndexes() {
|
|
2188
|
+
if (this.skipDefaultIndexes) {
|
|
1116
2189
|
return;
|
|
1117
2190
|
}
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
SELECT 1 AS found FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = @schemaName
|
|
1125
|
-
`);
|
|
1126
|
-
const schemaExists = Array.isArray(checkResult.recordset) && checkResult.recordset.length > 0;
|
|
1127
|
-
if (!schemaExists) {
|
|
1128
|
-
try {
|
|
1129
|
-
await this.pool.request().query(`CREATE SCHEMA [${this.schemaName}]`);
|
|
1130
|
-
this.logger?.info?.(`Schema "${this.schemaName}" created successfully`);
|
|
1131
|
-
} catch (error) {
|
|
1132
|
-
this.logger?.error?.(`Failed to create schema "${this.schemaName}"`, { error });
|
|
1133
|
-
throw new Error(
|
|
1134
|
-
`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.`
|
|
1135
|
-
);
|
|
1136
|
-
}
|
|
1137
|
-
}
|
|
1138
|
-
this.schemaSetupComplete = true;
|
|
1139
|
-
this.logger?.debug?.(`Schema "${this.schemaName}" is ready for use`);
|
|
1140
|
-
} catch (error) {
|
|
1141
|
-
this.schemaSetupComplete = void 0;
|
|
1142
|
-
this.setupSchemaPromise = null;
|
|
1143
|
-
throw error;
|
|
1144
|
-
} finally {
|
|
1145
|
-
this.setupSchemaPromise = null;
|
|
1146
|
-
}
|
|
1147
|
-
})();
|
|
2191
|
+
for (const indexDef of this.getDefaultIndexDefinitions()) {
|
|
2192
|
+
try {
|
|
2193
|
+
await this.db.createIndex(indexDef);
|
|
2194
|
+
} catch (error) {
|
|
2195
|
+
this.logger?.warn?.(`Failed to create index ${indexDef.name}:`, error);
|
|
2196
|
+
}
|
|
1148
2197
|
}
|
|
1149
|
-
await this.setupSchemaPromise;
|
|
1150
2198
|
}
|
|
1151
|
-
|
|
2199
|
+
/**
|
|
2200
|
+
* Creates custom user-defined indexes for this domain's tables.
|
|
2201
|
+
*/
|
|
2202
|
+
async createCustomIndexes() {
|
|
2203
|
+
if (!this.indexes || this.indexes.length === 0) {
|
|
2204
|
+
return;
|
|
2205
|
+
}
|
|
2206
|
+
for (const indexDef of this.indexes) {
|
|
2207
|
+
try {
|
|
2208
|
+
await this.db.createIndex(indexDef);
|
|
2209
|
+
} catch (error) {
|
|
2210
|
+
this.logger?.warn?.(`Failed to create custom index ${indexDef.name}:`, error);
|
|
2211
|
+
}
|
|
2212
|
+
}
|
|
2213
|
+
}
|
|
2214
|
+
async dangerouslyClearAll() {
|
|
2215
|
+
await this.db.clearTable({ tableName: storage.TABLE_SPANS });
|
|
2216
|
+
}
|
|
2217
|
+
get tracingStrategy() {
|
|
2218
|
+
return {
|
|
2219
|
+
preferred: "batch-with-updates",
|
|
2220
|
+
supported: ["batch-with-updates", "insert-only"]
|
|
2221
|
+
};
|
|
2222
|
+
}
|
|
2223
|
+
async createSpan(args) {
|
|
2224
|
+
const { span } = args;
|
|
1152
2225
|
try {
|
|
1153
|
-
const
|
|
1154
|
-
const
|
|
1155
|
-
const
|
|
1156
|
-
const
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
request.input(`param${i}`, value);
|
|
1165
|
-
}
|
|
1166
|
-
});
|
|
1167
|
-
await request.query(insertSql);
|
|
2226
|
+
const startedAt = span.startedAt instanceof Date ? span.startedAt.toISOString() : span.startedAt;
|
|
2227
|
+
const endedAt = span.endedAt instanceof Date ? span.endedAt.toISOString() : span.endedAt;
|
|
2228
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2229
|
+
const record = {
|
|
2230
|
+
...span,
|
|
2231
|
+
startedAt,
|
|
2232
|
+
endedAt,
|
|
2233
|
+
createdAt: now,
|
|
2234
|
+
updatedAt: now
|
|
2235
|
+
};
|
|
2236
|
+
return this.db.insert({ tableName: storage.TABLE_SPANS, record });
|
|
1168
2237
|
} catch (error$1) {
|
|
1169
2238
|
throw new error.MastraError(
|
|
1170
2239
|
{
|
|
1171
|
-
id: "
|
|
2240
|
+
id: storage.createStorageErrorId("MSSQL", "CREATE_SPAN", "FAILED"),
|
|
1172
2241
|
domain: error.ErrorDomain.STORAGE,
|
|
1173
|
-
category: error.ErrorCategory.
|
|
2242
|
+
category: error.ErrorCategory.USER,
|
|
1174
2243
|
details: {
|
|
1175
|
-
|
|
2244
|
+
spanId: span.spanId,
|
|
2245
|
+
traceId: span.traceId,
|
|
2246
|
+
spanType: span.spanType,
|
|
2247
|
+
name: span.name
|
|
1176
2248
|
}
|
|
1177
2249
|
},
|
|
1178
2250
|
error$1
|
|
1179
2251
|
);
|
|
1180
2252
|
}
|
|
1181
2253
|
}
|
|
1182
|
-
async
|
|
1183
|
-
const
|
|
2254
|
+
async getTrace(args) {
|
|
2255
|
+
const { traceId } = args;
|
|
1184
2256
|
try {
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
2257
|
+
const tableName = getTableName2({
|
|
2258
|
+
indexName: storage.TABLE_SPANS,
|
|
2259
|
+
schemaName: getSchemaName2(this.schema)
|
|
2260
|
+
});
|
|
2261
|
+
const request = this.pool.request();
|
|
2262
|
+
request.input("traceId", traceId);
|
|
2263
|
+
const result = await request.query(
|
|
2264
|
+
`SELECT
|
|
2265
|
+
[traceId], [spanId], [parentSpanId], [name],
|
|
2266
|
+
[entityType], [entityId], [entityName],
|
|
2267
|
+
[userId], [organizationId], [resourceId],
|
|
2268
|
+
[runId], [sessionId], [threadId], [requestId],
|
|
2269
|
+
[environment], [source], [serviceName], [scope],
|
|
2270
|
+
[spanType], [attributes], [metadata], [tags], [links],
|
|
2271
|
+
[input], [output], [error], [isEvent],
|
|
2272
|
+
[startedAt], [endedAt], [createdAt], [updatedAt]
|
|
2273
|
+
FROM ${tableName}
|
|
2274
|
+
WHERE [traceId] = @traceId
|
|
2275
|
+
ORDER BY [startedAt] ASC`
|
|
2276
|
+
);
|
|
2277
|
+
if (!result.recordset || result.recordset.length === 0) {
|
|
2278
|
+
return null;
|
|
1193
2279
|
}
|
|
2280
|
+
return {
|
|
2281
|
+
traceId,
|
|
2282
|
+
spans: result.recordset.map(
|
|
2283
|
+
(span) => transformFromSqlRow({
|
|
2284
|
+
tableName: storage.TABLE_SPANS,
|
|
2285
|
+
sqlRow: span
|
|
2286
|
+
})
|
|
2287
|
+
)
|
|
2288
|
+
};
|
|
1194
2289
|
} catch (error$1) {
|
|
1195
2290
|
throw new error.MastraError(
|
|
1196
2291
|
{
|
|
1197
|
-
id: "
|
|
2292
|
+
id: storage.createStorageErrorId("MSSQL", "GET_TRACE", "FAILED"),
|
|
1198
2293
|
domain: error.ErrorDomain.STORAGE,
|
|
1199
|
-
category: error.ErrorCategory.
|
|
2294
|
+
category: error.ErrorCategory.USER,
|
|
1200
2295
|
details: {
|
|
1201
|
-
|
|
2296
|
+
traceId
|
|
1202
2297
|
}
|
|
1203
2298
|
},
|
|
1204
2299
|
error$1
|
|
1205
2300
|
);
|
|
1206
2301
|
}
|
|
1207
2302
|
}
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
2303
|
+
async getSpan(args) {
|
|
2304
|
+
const { traceId, spanId } = args;
|
|
2305
|
+
try {
|
|
2306
|
+
const tableName = getTableName2({
|
|
2307
|
+
indexName: storage.TABLE_SPANS,
|
|
2308
|
+
schemaName: getSchemaName2(this.schema)
|
|
2309
|
+
});
|
|
2310
|
+
const request = this.pool.request();
|
|
2311
|
+
request.input("traceId", traceId);
|
|
2312
|
+
request.input("spanId", spanId);
|
|
2313
|
+
const result = await request.query(
|
|
2314
|
+
`SELECT
|
|
2315
|
+
[traceId], [spanId], [parentSpanId], [name],
|
|
2316
|
+
[entityType], [entityId], [entityName],
|
|
2317
|
+
[userId], [organizationId], [resourceId],
|
|
2318
|
+
[runId], [sessionId], [threadId], [requestId],
|
|
2319
|
+
[environment], [source], [serviceName], [scope],
|
|
2320
|
+
[spanType], [attributes], [metadata], [tags], [links],
|
|
2321
|
+
[input], [output], [error], [isEvent],
|
|
2322
|
+
[startedAt], [endedAt], [createdAt], [updatedAt]
|
|
2323
|
+
FROM ${tableName}
|
|
2324
|
+
WHERE [traceId] = @traceId AND [spanId] = @spanId`
|
|
2325
|
+
);
|
|
2326
|
+
if (!result.recordset || result.recordset.length === 0) {
|
|
2327
|
+
return null;
|
|
2328
|
+
}
|
|
2329
|
+
return {
|
|
2330
|
+
span: transformFromSqlRow({
|
|
2331
|
+
tableName: storage.TABLE_SPANS,
|
|
2332
|
+
sqlRow: result.recordset[0]
|
|
2333
|
+
})
|
|
2334
|
+
};
|
|
2335
|
+
} catch (error$1) {
|
|
2336
|
+
throw new error.MastraError(
|
|
2337
|
+
{
|
|
2338
|
+
id: storage.createStorageErrorId("MSSQL", "GET_SPAN", "FAILED"),
|
|
2339
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2340
|
+
category: error.ErrorCategory.USER,
|
|
2341
|
+
details: { traceId, spanId }
|
|
2342
|
+
},
|
|
2343
|
+
error$1
|
|
2344
|
+
);
|
|
1216
2345
|
}
|
|
1217
2346
|
}
|
|
1218
|
-
async
|
|
1219
|
-
|
|
1220
|
-
schema
|
|
1221
|
-
}) {
|
|
2347
|
+
async getRootSpan(args) {
|
|
2348
|
+
const { traceId } = args;
|
|
1222
2349
|
try {
|
|
1223
|
-
const
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
2350
|
+
const tableName = getTableName2({
|
|
2351
|
+
indexName: storage.TABLE_SPANS,
|
|
2352
|
+
schemaName: getSchemaName2(this.schema)
|
|
2353
|
+
});
|
|
2354
|
+
const request = this.pool.request();
|
|
2355
|
+
request.input("traceId", traceId);
|
|
2356
|
+
const result = await request.query(
|
|
2357
|
+
`SELECT
|
|
2358
|
+
[traceId], [spanId], [parentSpanId], [name],
|
|
2359
|
+
[entityType], [entityId], [entityName],
|
|
2360
|
+
[userId], [organizationId], [resourceId],
|
|
2361
|
+
[runId], [sessionId], [threadId], [requestId],
|
|
2362
|
+
[environment], [source], [serviceName], [scope],
|
|
2363
|
+
[spanType], [attributes], [metadata], [tags], [links],
|
|
2364
|
+
[input], [output], [error], [isEvent],
|
|
2365
|
+
[startedAt], [endedAt], [createdAt], [updatedAt]
|
|
2366
|
+
FROM ${tableName}
|
|
2367
|
+
WHERE [traceId] = @traceId AND [parentSpanId] IS NULL`
|
|
1239
2368
|
);
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
const checkTableResult = await checkTableRequest.query(checkTableSql);
|
|
1243
|
-
const tableExists = Array.isArray(checkTableResult.recordset) && checkTableResult.recordset.length > 0;
|
|
1244
|
-
if (!tableExists) {
|
|
1245
|
-
const createSql = `CREATE TABLE ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} (
|
|
1246
|
-
${columns}
|
|
1247
|
-
)`;
|
|
1248
|
-
await this.pool.request().query(createSql);
|
|
2369
|
+
if (!result.recordset || result.recordset.length === 0) {
|
|
2370
|
+
return null;
|
|
1249
2371
|
}
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
2372
|
+
return {
|
|
2373
|
+
span: transformFromSqlRow({
|
|
2374
|
+
tableName: storage.TABLE_SPANS,
|
|
2375
|
+
sqlRow: result.recordset[0]
|
|
2376
|
+
})
|
|
2377
|
+
};
|
|
2378
|
+
} catch (error$1) {
|
|
2379
|
+
throw new error.MastraError(
|
|
2380
|
+
{
|
|
2381
|
+
id: storage.createStorageErrorId("MSSQL", "GET_ROOT_SPAN", "FAILED"),
|
|
2382
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2383
|
+
category: error.ErrorCategory.USER,
|
|
2384
|
+
details: { traceId }
|
|
2385
|
+
},
|
|
2386
|
+
error$1
|
|
1260
2387
|
);
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
2388
|
+
}
|
|
2389
|
+
}
|
|
2390
|
+
async updateSpan(args) {
|
|
2391
|
+
const { traceId, spanId, updates } = args;
|
|
2392
|
+
try {
|
|
2393
|
+
const data = { ...updates };
|
|
2394
|
+
if (data.endedAt instanceof Date) {
|
|
2395
|
+
data.endedAt = data.endedAt.toISOString();
|
|
1266
2396
|
}
|
|
1267
|
-
if (
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
2397
|
+
if (data.startedAt instanceof Date) {
|
|
2398
|
+
data.startedAt = data.startedAt.toISOString();
|
|
2399
|
+
}
|
|
2400
|
+
data.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2401
|
+
await this.db.update({
|
|
2402
|
+
tableName: storage.TABLE_SPANS,
|
|
2403
|
+
keys: { spanId, traceId },
|
|
2404
|
+
data
|
|
2405
|
+
});
|
|
2406
|
+
} catch (error$1) {
|
|
2407
|
+
throw new error.MastraError(
|
|
2408
|
+
{
|
|
2409
|
+
id: storage.createStorageErrorId("MSSQL", "UPDATE_SPAN", "FAILED"),
|
|
2410
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2411
|
+
category: error.ErrorCategory.USER,
|
|
2412
|
+
details: {
|
|
2413
|
+
spanId,
|
|
2414
|
+
traceId
|
|
2415
|
+
}
|
|
2416
|
+
},
|
|
2417
|
+
error$1
|
|
2418
|
+
);
|
|
2419
|
+
}
|
|
2420
|
+
}
|
|
2421
|
+
async listTraces(args) {
|
|
2422
|
+
const { filters, pagination, orderBy } = storage.listTracesArgsSchema.parse(args);
|
|
2423
|
+
const { page, perPage } = pagination;
|
|
2424
|
+
const tableName = getTableName2({
|
|
2425
|
+
indexName: storage.TABLE_SPANS,
|
|
2426
|
+
schemaName: getSchemaName2(this.schema)
|
|
2427
|
+
});
|
|
2428
|
+
try {
|
|
2429
|
+
const conditions = ["r.[parentSpanId] IS NULL"];
|
|
2430
|
+
const params = {};
|
|
2431
|
+
let paramIndex = 1;
|
|
2432
|
+
if (filters) {
|
|
2433
|
+
if (filters.startedAt?.start) {
|
|
2434
|
+
const param = `p${paramIndex++}`;
|
|
2435
|
+
conditions.push(`r.[startedAt] >= @${param}`);
|
|
2436
|
+
params[param] = filters.startedAt.start.toISOString();
|
|
2437
|
+
}
|
|
2438
|
+
if (filters.startedAt?.end) {
|
|
2439
|
+
const param = `p${paramIndex++}`;
|
|
2440
|
+
conditions.push(`r.[startedAt] <= @${param}`);
|
|
2441
|
+
params[param] = filters.startedAt.end.toISOString();
|
|
2442
|
+
}
|
|
2443
|
+
if (filters.endedAt?.start) {
|
|
2444
|
+
const param = `p${paramIndex++}`;
|
|
2445
|
+
conditions.push(`r.[endedAt] >= @${param}`);
|
|
2446
|
+
params[param] = filters.endedAt.start.toISOString();
|
|
2447
|
+
}
|
|
2448
|
+
if (filters.endedAt?.end) {
|
|
2449
|
+
const param = `p${paramIndex++}`;
|
|
2450
|
+
conditions.push(`r.[endedAt] <= @${param}`);
|
|
2451
|
+
params[param] = filters.endedAt.end.toISOString();
|
|
2452
|
+
}
|
|
2453
|
+
if (filters.spanType !== void 0) {
|
|
2454
|
+
const param = `p${paramIndex++}`;
|
|
2455
|
+
conditions.push(`r.[spanType] = @${param}`);
|
|
2456
|
+
params[param] = filters.spanType;
|
|
2457
|
+
}
|
|
2458
|
+
if (filters.entityType !== void 0) {
|
|
2459
|
+
const param = `p${paramIndex++}`;
|
|
2460
|
+
conditions.push(`r.[entityType] = @${param}`);
|
|
2461
|
+
params[param] = filters.entityType;
|
|
2462
|
+
}
|
|
2463
|
+
if (filters.entityId !== void 0) {
|
|
2464
|
+
const param = `p${paramIndex++}`;
|
|
2465
|
+
conditions.push(`r.[entityId] = @${param}`);
|
|
2466
|
+
params[param] = filters.entityId;
|
|
2467
|
+
}
|
|
2468
|
+
if (filters.entityName !== void 0) {
|
|
2469
|
+
const param = `p${paramIndex++}`;
|
|
2470
|
+
conditions.push(`r.[entityName] = @${param}`);
|
|
2471
|
+
params[param] = filters.entityName;
|
|
2472
|
+
}
|
|
2473
|
+
if (filters.userId !== void 0) {
|
|
2474
|
+
const param = `p${paramIndex++}`;
|
|
2475
|
+
conditions.push(`r.[userId] = @${param}`);
|
|
2476
|
+
params[param] = filters.userId;
|
|
2477
|
+
}
|
|
2478
|
+
if (filters.organizationId !== void 0) {
|
|
2479
|
+
const param = `p${paramIndex++}`;
|
|
2480
|
+
conditions.push(`r.[organizationId] = @${param}`);
|
|
2481
|
+
params[param] = filters.organizationId;
|
|
2482
|
+
}
|
|
2483
|
+
if (filters.resourceId !== void 0) {
|
|
2484
|
+
const param = `p${paramIndex++}`;
|
|
2485
|
+
conditions.push(`r.[resourceId] = @${param}`);
|
|
2486
|
+
params[param] = filters.resourceId;
|
|
2487
|
+
}
|
|
2488
|
+
if (filters.runId !== void 0) {
|
|
2489
|
+
const param = `p${paramIndex++}`;
|
|
2490
|
+
conditions.push(`r.[runId] = @${param}`);
|
|
2491
|
+
params[param] = filters.runId;
|
|
2492
|
+
}
|
|
2493
|
+
if (filters.sessionId !== void 0) {
|
|
2494
|
+
const param = `p${paramIndex++}`;
|
|
2495
|
+
conditions.push(`r.[sessionId] = @${param}`);
|
|
2496
|
+
params[param] = filters.sessionId;
|
|
2497
|
+
}
|
|
2498
|
+
if (filters.threadId !== void 0) {
|
|
2499
|
+
const param = `p${paramIndex++}`;
|
|
2500
|
+
conditions.push(`r.[threadId] = @${param}`);
|
|
2501
|
+
params[param] = filters.threadId;
|
|
2502
|
+
}
|
|
2503
|
+
if (filters.requestId !== void 0) {
|
|
2504
|
+
const param = `p${paramIndex++}`;
|
|
2505
|
+
conditions.push(`r.[requestId] = @${param}`);
|
|
2506
|
+
params[param] = filters.requestId;
|
|
2507
|
+
}
|
|
2508
|
+
if (filters.environment !== void 0) {
|
|
2509
|
+
const param = `p${paramIndex++}`;
|
|
2510
|
+
conditions.push(`r.[environment] = @${param}`);
|
|
2511
|
+
params[param] = filters.environment;
|
|
1277
2512
|
}
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
2513
|
+
if (filters.source !== void 0) {
|
|
2514
|
+
const param = `p${paramIndex++}`;
|
|
2515
|
+
conditions.push(`r.[source] = @${param}`);
|
|
2516
|
+
params[param] = filters.source;
|
|
2517
|
+
}
|
|
2518
|
+
if (filters.serviceName !== void 0) {
|
|
2519
|
+
const param = `p${paramIndex++}`;
|
|
2520
|
+
conditions.push(`r.[serviceName] = @${param}`);
|
|
2521
|
+
params[param] = filters.serviceName;
|
|
2522
|
+
}
|
|
2523
|
+
if (filters.scope != null) {
|
|
2524
|
+
for (const [key, value] of Object.entries(filters.scope)) {
|
|
2525
|
+
if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(key)) {
|
|
2526
|
+
throw new error.MastraError({
|
|
2527
|
+
id: storage.createStorageErrorId("MSSQL", "LIST_TRACES", "INVALID_FILTER_KEY"),
|
|
2528
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2529
|
+
category: error.ErrorCategory.USER,
|
|
2530
|
+
details: { key }
|
|
2531
|
+
});
|
|
2532
|
+
}
|
|
2533
|
+
const param = `p${paramIndex++}`;
|
|
2534
|
+
conditions.push(`JSON_VALUE(r.[scope], '$.${key}') = @${param}`);
|
|
2535
|
+
params[param] = typeof value === "string" ? value : JSON.stringify(value);
|
|
1287
2536
|
}
|
|
1288
|
-
}
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
columnCheckRequest.input("tableName", fullTableName.replace(/[[\]]/g, "").split(".").pop());
|
|
1310
|
-
columnCheckRequest.input("columnName", columnName);
|
|
1311
|
-
columnCheckRequest.input("schema", this.schemaName || "dbo");
|
|
1312
|
-
const checkSql = `SELECT 1 AS found FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = @schema AND TABLE_NAME = @tableName AND COLUMN_NAME = @columnName`;
|
|
1313
|
-
const checkResult = await columnCheckRequest.query(checkSql);
|
|
1314
|
-
const columnExists = Array.isArray(checkResult.recordset) && checkResult.recordset.length > 0;
|
|
1315
|
-
if (!columnExists) {
|
|
1316
|
-
const columnDef = schema[columnName];
|
|
1317
|
-
const sqlType = this.getSqlType(columnDef.type);
|
|
1318
|
-
const nullable = columnDef.nullable === false ? "NOT NULL" : "";
|
|
1319
|
-
const defaultValue = columnDef.nullable === false ? this.getDefaultValue(columnDef.type) : "";
|
|
1320
|
-
const parsedColumnName = utils.parseSqlIdentifier(columnName, "column name");
|
|
1321
|
-
const alterSql = `ALTER TABLE ${fullTableName} ADD [${parsedColumnName}] ${sqlType} ${nullable} ${defaultValue}`.trim();
|
|
1322
|
-
await this.pool.request().query(alterSql);
|
|
1323
|
-
this.logger?.debug?.(`Ensured column ${parsedColumnName} exists in table ${fullTableName}`);
|
|
2537
|
+
}
|
|
2538
|
+
if (filters.metadata != null) {
|
|
2539
|
+
for (const [key, value] of Object.entries(filters.metadata)) {
|
|
2540
|
+
if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(key)) {
|
|
2541
|
+
throw new error.MastraError({
|
|
2542
|
+
id: storage.createStorageErrorId("MSSQL", "LIST_TRACES", "INVALID_FILTER_KEY"),
|
|
2543
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2544
|
+
category: error.ErrorCategory.USER,
|
|
2545
|
+
details: { key }
|
|
2546
|
+
});
|
|
2547
|
+
}
|
|
2548
|
+
const param = `p${paramIndex++}`;
|
|
2549
|
+
conditions.push(`JSON_VALUE(r.[metadata], '$.${key}') = @${param}`);
|
|
2550
|
+
params[param] = typeof value === "string" ? value : JSON.stringify(value);
|
|
2551
|
+
}
|
|
2552
|
+
}
|
|
2553
|
+
if (filters.tags != null && filters.tags.length > 0) {
|
|
2554
|
+
for (const tag of filters.tags) {
|
|
2555
|
+
const param = `p${paramIndex++}`;
|
|
2556
|
+
conditions.push(`EXISTS (SELECT 1 FROM OPENJSON(r.[tags]) WHERE [value] = @${param})`);
|
|
2557
|
+
params[param] = tag;
|
|
1324
2558
|
}
|
|
1325
2559
|
}
|
|
2560
|
+
if (filters.status !== void 0) {
|
|
2561
|
+
switch (filters.status) {
|
|
2562
|
+
case storage.TraceStatus.ERROR:
|
|
2563
|
+
conditions.push(`r.[error] IS NOT NULL`);
|
|
2564
|
+
break;
|
|
2565
|
+
case storage.TraceStatus.RUNNING:
|
|
2566
|
+
conditions.push(`r.[endedAt] IS NULL AND r.[error] IS NULL`);
|
|
2567
|
+
break;
|
|
2568
|
+
case storage.TraceStatus.SUCCESS:
|
|
2569
|
+
conditions.push(`r.[endedAt] IS NOT NULL AND r.[error] IS NULL`);
|
|
2570
|
+
break;
|
|
2571
|
+
}
|
|
2572
|
+
}
|
|
2573
|
+
if (filters.hasChildError !== void 0) {
|
|
2574
|
+
if (filters.hasChildError) {
|
|
2575
|
+
conditions.push(`EXISTS (
|
|
2576
|
+
SELECT 1 FROM ${tableName} c
|
|
2577
|
+
WHERE c.[traceId] = r.[traceId] AND c.[error] IS NOT NULL
|
|
2578
|
+
)`);
|
|
2579
|
+
} else {
|
|
2580
|
+
conditions.push(`NOT EXISTS (
|
|
2581
|
+
SELECT 1 FROM ${tableName} c
|
|
2582
|
+
WHERE c.[traceId] = r.[traceId] AND c.[error] IS NOT NULL
|
|
2583
|
+
)`);
|
|
2584
|
+
}
|
|
2585
|
+
}
|
|
2586
|
+
}
|
|
2587
|
+
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
2588
|
+
const sortField = orderBy.field;
|
|
2589
|
+
const sortDirection = orderBy.direction;
|
|
2590
|
+
const countRequest = this.pool.request();
|
|
2591
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
2592
|
+
countRequest.input(key, value);
|
|
2593
|
+
});
|
|
2594
|
+
const countResult = await countRequest.query(
|
|
2595
|
+
`SELECT COUNT(*) as count FROM ${tableName} r ${whereClause}`
|
|
2596
|
+
);
|
|
2597
|
+
const count = countResult.recordset[0]?.count ?? 0;
|
|
2598
|
+
if (count === 0) {
|
|
2599
|
+
return {
|
|
2600
|
+
pagination: {
|
|
2601
|
+
total: 0,
|
|
2602
|
+
page,
|
|
2603
|
+
perPage,
|
|
2604
|
+
hasMore: false
|
|
2605
|
+
},
|
|
2606
|
+
spans: []
|
|
2607
|
+
};
|
|
1326
2608
|
}
|
|
2609
|
+
const dataRequest = this.pool.request();
|
|
2610
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
2611
|
+
dataRequest.input(key, value);
|
|
2612
|
+
});
|
|
2613
|
+
dataRequest.input("offset", page * perPage);
|
|
2614
|
+
dataRequest.input("limit", perPage);
|
|
2615
|
+
const result = await dataRequest.query(
|
|
2616
|
+
`SELECT
|
|
2617
|
+
r.[traceId], r.[spanId], r.[parentSpanId], r.[name],
|
|
2618
|
+
r.[entityType], r.[entityId], r.[entityName],
|
|
2619
|
+
r.[userId], r.[organizationId], r.[resourceId],
|
|
2620
|
+
r.[runId], r.[sessionId], r.[threadId], r.[requestId],
|
|
2621
|
+
r.[environment], r.[source], r.[serviceName], r.[scope],
|
|
2622
|
+
r.[spanType], r.[attributes], r.[metadata], r.[tags], r.[links],
|
|
2623
|
+
r.[input], r.[output], r.[error], r.[isEvent],
|
|
2624
|
+
r.[startedAt], r.[endedAt], r.[createdAt], r.[updatedAt]
|
|
2625
|
+
FROM ${tableName} r
|
|
2626
|
+
${whereClause}
|
|
2627
|
+
ORDER BY r.[${sortField}] ${sortDirection}
|
|
2628
|
+
OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY`
|
|
2629
|
+
);
|
|
2630
|
+
return {
|
|
2631
|
+
pagination: {
|
|
2632
|
+
total: count,
|
|
2633
|
+
page,
|
|
2634
|
+
perPage,
|
|
2635
|
+
hasMore: (page + 1) * perPage < count
|
|
2636
|
+
},
|
|
2637
|
+
spans: result.recordset.map(
|
|
2638
|
+
(span) => transformFromSqlRow({
|
|
2639
|
+
tableName: storage.TABLE_SPANS,
|
|
2640
|
+
sqlRow: span
|
|
2641
|
+
})
|
|
2642
|
+
)
|
|
2643
|
+
};
|
|
1327
2644
|
} catch (error$1) {
|
|
1328
2645
|
throw new error.MastraError(
|
|
1329
2646
|
{
|
|
1330
|
-
id: "
|
|
2647
|
+
id: storage.createStorageErrorId("MSSQL", "LIST_TRACES", "FAILED"),
|
|
1331
2648
|
domain: error.ErrorDomain.STORAGE,
|
|
1332
|
-
category: error.ErrorCategory.
|
|
1333
|
-
details: {
|
|
1334
|
-
tableName
|
|
1335
|
-
}
|
|
2649
|
+
category: error.ErrorCategory.USER
|
|
1336
2650
|
},
|
|
1337
2651
|
error$1
|
|
1338
2652
|
);
|
|
1339
2653
|
}
|
|
1340
2654
|
}
|
|
1341
|
-
async
|
|
2655
|
+
async batchCreateSpans(args) {
|
|
2656
|
+
if (!args.records || args.records.length === 0) {
|
|
2657
|
+
return;
|
|
2658
|
+
}
|
|
1342
2659
|
try {
|
|
1343
|
-
const
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
2660
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2661
|
+
await this.db.batchInsert({
|
|
2662
|
+
tableName: storage.TABLE_SPANS,
|
|
2663
|
+
records: args.records.map((span) => ({
|
|
2664
|
+
...span,
|
|
2665
|
+
startedAt: span.startedAt instanceof Date ? span.startedAt.toISOString() : span.startedAt,
|
|
2666
|
+
endedAt: span.endedAt instanceof Date ? span.endedAt.toISOString() : span.endedAt,
|
|
2667
|
+
createdAt: now,
|
|
2668
|
+
updatedAt: now
|
|
2669
|
+
}))
|
|
1350
2670
|
});
|
|
1351
|
-
const resultSet = await request.query(sql7);
|
|
1352
|
-
const result = resultSet.recordset[0] || null;
|
|
1353
|
-
if (!result) {
|
|
1354
|
-
return null;
|
|
1355
|
-
}
|
|
1356
|
-
if (tableName === storage.TABLE_WORKFLOW_SNAPSHOT) {
|
|
1357
|
-
const snapshot = result;
|
|
1358
|
-
if (typeof snapshot.snapshot === "string") {
|
|
1359
|
-
snapshot.snapshot = JSON.parse(snapshot.snapshot);
|
|
1360
|
-
}
|
|
1361
|
-
return snapshot;
|
|
1362
|
-
}
|
|
1363
|
-
return result;
|
|
1364
2671
|
} catch (error$1) {
|
|
1365
2672
|
throw new error.MastraError(
|
|
1366
2673
|
{
|
|
1367
|
-
id: "
|
|
2674
|
+
id: storage.createStorageErrorId("MSSQL", "BATCH_CREATE_SPANS", "FAILED"),
|
|
1368
2675
|
domain: error.ErrorDomain.STORAGE,
|
|
1369
|
-
category: error.ErrorCategory.
|
|
2676
|
+
category: error.ErrorCategory.USER,
|
|
1370
2677
|
details: {
|
|
1371
|
-
|
|
2678
|
+
count: args.records.length
|
|
1372
2679
|
}
|
|
1373
2680
|
},
|
|
1374
2681
|
error$1
|
|
1375
2682
|
);
|
|
1376
2683
|
}
|
|
1377
2684
|
}
|
|
1378
|
-
async
|
|
1379
|
-
|
|
2685
|
+
async batchUpdateSpans(args) {
|
|
2686
|
+
if (!args.records || args.records.length === 0) {
|
|
2687
|
+
return;
|
|
2688
|
+
}
|
|
2689
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1380
2690
|
try {
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
2691
|
+
const updates = args.records.map(({ traceId, spanId, updates: data }) => {
|
|
2692
|
+
const processedData = { ...data };
|
|
2693
|
+
if (processedData.endedAt instanceof Date) {
|
|
2694
|
+
processedData.endedAt = processedData.endedAt.toISOString();
|
|
2695
|
+
}
|
|
2696
|
+
if (processedData.startedAt instanceof Date) {
|
|
2697
|
+
processedData.startedAt = processedData.startedAt.toISOString();
|
|
2698
|
+
}
|
|
2699
|
+
processedData.updatedAt = now;
|
|
2700
|
+
return {
|
|
2701
|
+
keys: { spanId, traceId },
|
|
2702
|
+
data: processedData
|
|
2703
|
+
};
|
|
2704
|
+
});
|
|
2705
|
+
await this.db.batchUpdate({
|
|
2706
|
+
tableName: storage.TABLE_SPANS,
|
|
2707
|
+
updates
|
|
2708
|
+
});
|
|
1386
2709
|
} catch (error$1) {
|
|
1387
|
-
await transaction.rollback();
|
|
1388
2710
|
throw new error.MastraError(
|
|
1389
2711
|
{
|
|
1390
|
-
id: "
|
|
2712
|
+
id: storage.createStorageErrorId("MSSQL", "BATCH_UPDATE_SPANS", "FAILED"),
|
|
1391
2713
|
domain: error.ErrorDomain.STORAGE,
|
|
1392
|
-
category: error.ErrorCategory.
|
|
2714
|
+
category: error.ErrorCategory.USER,
|
|
1393
2715
|
details: {
|
|
1394
|
-
|
|
1395
|
-
numberOfRecords: records.length
|
|
2716
|
+
count: args.records.length
|
|
1396
2717
|
}
|
|
1397
2718
|
},
|
|
1398
2719
|
error$1
|
|
1399
2720
|
);
|
|
1400
2721
|
}
|
|
1401
2722
|
}
|
|
1402
|
-
async
|
|
2723
|
+
async batchDeleteTraces(args) {
|
|
2724
|
+
if (!args.traceIds || args.traceIds.length === 0) {
|
|
2725
|
+
return;
|
|
2726
|
+
}
|
|
1403
2727
|
try {
|
|
1404
|
-
const
|
|
1405
|
-
await this.
|
|
2728
|
+
const keys = args.traceIds.map((traceId) => ({ traceId }));
|
|
2729
|
+
await this.db.batchDelete({
|
|
2730
|
+
tableName: storage.TABLE_SPANS,
|
|
2731
|
+
keys
|
|
2732
|
+
});
|
|
1406
2733
|
} catch (error$1) {
|
|
1407
2734
|
throw new error.MastraError(
|
|
1408
2735
|
{
|
|
1409
|
-
id: "
|
|
2736
|
+
id: storage.createStorageErrorId("MSSQL", "BATCH_DELETE_TRACES", "FAILED"),
|
|
1410
2737
|
domain: error.ErrorDomain.STORAGE,
|
|
1411
|
-
category: error.ErrorCategory.
|
|
2738
|
+
category: error.ErrorCategory.USER,
|
|
1412
2739
|
details: {
|
|
1413
|
-
|
|
2740
|
+
count: args.traceIds.length
|
|
1414
2741
|
}
|
|
1415
2742
|
},
|
|
1416
2743
|
error$1
|
|
@@ -1418,49 +2745,92 @@ ${columns}
|
|
|
1418
2745
|
}
|
|
1419
2746
|
}
|
|
1420
2747
|
};
|
|
1421
|
-
function parseJSON(jsonString) {
|
|
1422
|
-
try {
|
|
1423
|
-
return JSON.parse(jsonString);
|
|
1424
|
-
} catch {
|
|
1425
|
-
return jsonString;
|
|
1426
|
-
}
|
|
1427
|
-
}
|
|
1428
2748
|
function transformScoreRow(row) {
|
|
1429
|
-
return {
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
scorer: parseJSON(row.scorer),
|
|
1433
|
-
preprocessStepResult: parseJSON(row.preprocessStepResult),
|
|
1434
|
-
analyzeStepResult: parseJSON(row.analyzeStepResult),
|
|
1435
|
-
metadata: parseJSON(row.metadata),
|
|
1436
|
-
output: parseJSON(row.output),
|
|
1437
|
-
additionalContext: parseJSON(row.additionalContext),
|
|
1438
|
-
runtimeContext: parseJSON(row.runtimeContext),
|
|
1439
|
-
entity: parseJSON(row.entity),
|
|
1440
|
-
createdAt: row.createdAt,
|
|
1441
|
-
updatedAt: row.updatedAt
|
|
1442
|
-
};
|
|
2749
|
+
return storage.transformScoreRow(row, {
|
|
2750
|
+
convertTimestamps: true
|
|
2751
|
+
});
|
|
1443
2752
|
}
|
|
1444
|
-
var ScoresMSSQL = class extends storage.ScoresStorage {
|
|
2753
|
+
var ScoresMSSQL = class _ScoresMSSQL extends storage.ScoresStorage {
|
|
1445
2754
|
pool;
|
|
1446
|
-
|
|
2755
|
+
db;
|
|
1447
2756
|
schema;
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
2757
|
+
needsConnect;
|
|
2758
|
+
skipDefaultIndexes;
|
|
2759
|
+
indexes;
|
|
2760
|
+
/** Tables managed by this domain */
|
|
2761
|
+
static MANAGED_TABLES = [storage.TABLE_SCORERS];
|
|
2762
|
+
constructor(config) {
|
|
1453
2763
|
super();
|
|
2764
|
+
const { pool, schemaName, skipDefaultIndexes, indexes, needsConnect } = resolveMssqlConfig(config);
|
|
1454
2765
|
this.pool = pool;
|
|
1455
|
-
this.
|
|
1456
|
-
this.
|
|
2766
|
+
this.schema = schemaName;
|
|
2767
|
+
this.db = new MssqlDB({ pool, schemaName, skipDefaultIndexes });
|
|
2768
|
+
this.needsConnect = needsConnect;
|
|
2769
|
+
this.skipDefaultIndexes = skipDefaultIndexes;
|
|
2770
|
+
this.indexes = indexes?.filter((idx) => _ScoresMSSQL.MANAGED_TABLES.includes(idx.table));
|
|
2771
|
+
}
|
|
2772
|
+
async init() {
|
|
2773
|
+
if (this.needsConnect) {
|
|
2774
|
+
await this.pool.connect();
|
|
2775
|
+
this.needsConnect = false;
|
|
2776
|
+
}
|
|
2777
|
+
await this.db.createTable({ tableName: storage.TABLE_SCORERS, schema: storage.TABLE_SCHEMAS[storage.TABLE_SCORERS] });
|
|
2778
|
+
await this.createDefaultIndexes();
|
|
2779
|
+
await this.createCustomIndexes();
|
|
2780
|
+
}
|
|
2781
|
+
/**
|
|
2782
|
+
* Returns default index definitions for the scores domain tables.
|
|
2783
|
+
* IMPORTANT: Uses seq_id DESC instead of createdAt DESC for MSSQL due to millisecond accuracy limitations
|
|
2784
|
+
*/
|
|
2785
|
+
getDefaultIndexDefinitions() {
|
|
2786
|
+
const schemaPrefix = this.schema ? `${this.schema}_` : "";
|
|
2787
|
+
return [
|
|
2788
|
+
{
|
|
2789
|
+
name: `${schemaPrefix}mastra_scores_trace_id_span_id_seqid_idx`,
|
|
2790
|
+
table: storage.TABLE_SCORERS,
|
|
2791
|
+
columns: ["traceId", "spanId", "seq_id DESC"]
|
|
2792
|
+
}
|
|
2793
|
+
];
|
|
2794
|
+
}
|
|
2795
|
+
/**
|
|
2796
|
+
* Creates default indexes for optimal query performance.
|
|
2797
|
+
*/
|
|
2798
|
+
async createDefaultIndexes() {
|
|
2799
|
+
if (this.skipDefaultIndexes) {
|
|
2800
|
+
return;
|
|
2801
|
+
}
|
|
2802
|
+
for (const indexDef of this.getDefaultIndexDefinitions()) {
|
|
2803
|
+
try {
|
|
2804
|
+
await this.db.createIndex(indexDef);
|
|
2805
|
+
} catch (error) {
|
|
2806
|
+
this.logger?.warn?.(`Failed to create index ${indexDef.name}:`, error);
|
|
2807
|
+
}
|
|
2808
|
+
}
|
|
2809
|
+
}
|
|
2810
|
+
/**
|
|
2811
|
+
* Creates custom user-defined indexes for this domain's tables.
|
|
2812
|
+
*/
|
|
2813
|
+
async createCustomIndexes() {
|
|
2814
|
+
if (!this.indexes || this.indexes.length === 0) {
|
|
2815
|
+
return;
|
|
2816
|
+
}
|
|
2817
|
+
for (const indexDef of this.indexes) {
|
|
2818
|
+
try {
|
|
2819
|
+
await this.db.createIndex(indexDef);
|
|
2820
|
+
} catch (error) {
|
|
2821
|
+
this.logger?.warn?.(`Failed to create custom index ${indexDef.name}:`, error);
|
|
2822
|
+
}
|
|
2823
|
+
}
|
|
2824
|
+
}
|
|
2825
|
+
async dangerouslyClearAll() {
|
|
2826
|
+
await this.db.clearTable({ tableName: storage.TABLE_SCORERS });
|
|
1457
2827
|
}
|
|
1458
2828
|
async getScoreById({ id }) {
|
|
1459
2829
|
try {
|
|
1460
2830
|
const request = this.pool.request();
|
|
1461
2831
|
request.input("p1", id);
|
|
1462
2832
|
const result = await request.query(
|
|
1463
|
-
`SELECT * FROM ${
|
|
2833
|
+
`SELECT * FROM ${getTableName2({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName2(this.schema) })} WHERE id = @p1`
|
|
1464
2834
|
);
|
|
1465
2835
|
if (result.recordset.length === 0) {
|
|
1466
2836
|
return null;
|
|
@@ -1469,7 +2839,7 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
|
|
|
1469
2839
|
} catch (error$1) {
|
|
1470
2840
|
throw new error.MastraError(
|
|
1471
2841
|
{
|
|
1472
|
-
id: "
|
|
2842
|
+
id: storage.createStorageErrorId("MSSQL", "GET_SCORE_BY_ID", "FAILED"),
|
|
1473
2843
|
domain: error.ErrorDomain.STORAGE,
|
|
1474
2844
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1475
2845
|
details: { id }
|
|
@@ -1479,8 +2849,29 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
|
|
|
1479
2849
|
}
|
|
1480
2850
|
}
|
|
1481
2851
|
async saveScore(score) {
|
|
2852
|
+
let validatedScore;
|
|
2853
|
+
try {
|
|
2854
|
+
validatedScore = evals.saveScorePayloadSchema.parse(score);
|
|
2855
|
+
} catch (error$1) {
|
|
2856
|
+
throw new error.MastraError(
|
|
2857
|
+
{
|
|
2858
|
+
id: storage.createStorageErrorId("MSSQL", "SAVE_SCORE", "VALIDATION_FAILED"),
|
|
2859
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2860
|
+
category: error.ErrorCategory.USER,
|
|
2861
|
+
details: {
|
|
2862
|
+
scorer: typeof score.scorer?.id === "string" ? score.scorer.id : String(score.scorer?.id ?? "unknown"),
|
|
2863
|
+
entityId: score.entityId ?? "unknown",
|
|
2864
|
+
entityType: score.entityType ?? "unknown",
|
|
2865
|
+
traceId: score.traceId ?? "",
|
|
2866
|
+
spanId: score.spanId ?? ""
|
|
2867
|
+
}
|
|
2868
|
+
},
|
|
2869
|
+
error$1
|
|
2870
|
+
);
|
|
2871
|
+
}
|
|
1482
2872
|
try {
|
|
1483
2873
|
const scoreId = crypto.randomUUID();
|
|
2874
|
+
const now = /* @__PURE__ */ new Date();
|
|
1484
2875
|
const {
|
|
1485
2876
|
scorer,
|
|
1486
2877
|
preprocessStepResult,
|
|
@@ -1489,34 +2880,33 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
|
|
|
1489
2880
|
input,
|
|
1490
2881
|
output,
|
|
1491
2882
|
additionalContext,
|
|
1492
|
-
|
|
2883
|
+
requestContext,
|
|
1493
2884
|
entity,
|
|
1494
2885
|
...rest
|
|
1495
|
-
} =
|
|
1496
|
-
await this.
|
|
2886
|
+
} = validatedScore;
|
|
2887
|
+
await this.db.insert({
|
|
1497
2888
|
tableName: storage.TABLE_SCORERS,
|
|
1498
2889
|
record: {
|
|
1499
2890
|
id: scoreId,
|
|
1500
2891
|
...rest,
|
|
1501
|
-
input:
|
|
1502
|
-
output:
|
|
1503
|
-
preprocessStepResult: preprocessStepResult
|
|
1504
|
-
analyzeStepResult: analyzeStepResult
|
|
1505
|
-
metadata: metadata
|
|
1506
|
-
additionalContext: additionalContext
|
|
1507
|
-
|
|
1508
|
-
entity: entity
|
|
1509
|
-
scorer: scorer
|
|
1510
|
-
createdAt:
|
|
1511
|
-
updatedAt:
|
|
2892
|
+
input: input || "",
|
|
2893
|
+
output: output || "",
|
|
2894
|
+
preprocessStepResult: preprocessStepResult || null,
|
|
2895
|
+
analyzeStepResult: analyzeStepResult || null,
|
|
2896
|
+
metadata: metadata || null,
|
|
2897
|
+
additionalContext: additionalContext || null,
|
|
2898
|
+
requestContext: requestContext || null,
|
|
2899
|
+
entity: entity || null,
|
|
2900
|
+
scorer: scorer || null,
|
|
2901
|
+
createdAt: now.toISOString(),
|
|
2902
|
+
updatedAt: now.toISOString()
|
|
1512
2903
|
}
|
|
1513
2904
|
});
|
|
1514
|
-
|
|
1515
|
-
return { score: scoreFromDb };
|
|
2905
|
+
return { score: { ...validatedScore, id: scoreId, createdAt: now, updatedAt: now } };
|
|
1516
2906
|
} catch (error$1) {
|
|
1517
2907
|
throw new error.MastraError(
|
|
1518
2908
|
{
|
|
1519
|
-
id: "
|
|
2909
|
+
id: storage.createStorageErrorId("MSSQL", "SAVE_SCORE", "FAILED"),
|
|
1520
2910
|
domain: error.ErrorDomain.STORAGE,
|
|
1521
2911
|
category: error.ErrorCategory.THIRD_PARTY
|
|
1522
2912
|
},
|
|
@@ -1524,48 +2914,77 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
|
|
|
1524
2914
|
);
|
|
1525
2915
|
}
|
|
1526
2916
|
}
|
|
1527
|
-
async
|
|
2917
|
+
async listScoresByScorerId({
|
|
1528
2918
|
scorerId,
|
|
1529
|
-
pagination
|
|
2919
|
+
pagination,
|
|
2920
|
+
entityId,
|
|
2921
|
+
entityType,
|
|
2922
|
+
source
|
|
1530
2923
|
}) {
|
|
1531
2924
|
try {
|
|
1532
|
-
const
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
2925
|
+
const conditions = ["[scorerId] = @p1"];
|
|
2926
|
+
const params = { p1: scorerId };
|
|
2927
|
+
let paramIndex = 2;
|
|
2928
|
+
if (entityId) {
|
|
2929
|
+
conditions.push(`[entityId] = @p${paramIndex}`);
|
|
2930
|
+
params[`p${paramIndex}`] = entityId;
|
|
2931
|
+
paramIndex++;
|
|
2932
|
+
}
|
|
2933
|
+
if (entityType) {
|
|
2934
|
+
conditions.push(`[entityType] = @p${paramIndex}`);
|
|
2935
|
+
params[`p${paramIndex}`] = entityType;
|
|
2936
|
+
paramIndex++;
|
|
2937
|
+
}
|
|
2938
|
+
if (source) {
|
|
2939
|
+
conditions.push(`[source] = @p${paramIndex}`);
|
|
2940
|
+
params[`p${paramIndex}`] = source;
|
|
2941
|
+
paramIndex++;
|
|
2942
|
+
}
|
|
2943
|
+
const whereClause = conditions.join(" AND ");
|
|
2944
|
+
const tableName = getTableName2({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName2(this.schema) });
|
|
2945
|
+
const countRequest = this.pool.request();
|
|
2946
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
2947
|
+
countRequest.input(key, value);
|
|
2948
|
+
});
|
|
2949
|
+
const totalResult = await countRequest.query(`SELECT COUNT(*) as count FROM ${tableName} WHERE ${whereClause}`);
|
|
1537
2950
|
const total = totalResult.recordset[0]?.count || 0;
|
|
2951
|
+
const { page, perPage: perPageInput } = pagination;
|
|
1538
2952
|
if (total === 0) {
|
|
1539
2953
|
return {
|
|
1540
2954
|
pagination: {
|
|
1541
2955
|
total: 0,
|
|
1542
|
-
page
|
|
1543
|
-
perPage:
|
|
2956
|
+
page,
|
|
2957
|
+
perPage: perPageInput,
|
|
1544
2958
|
hasMore: false
|
|
1545
2959
|
},
|
|
1546
2960
|
scores: []
|
|
1547
2961
|
};
|
|
1548
2962
|
}
|
|
2963
|
+
const perPage = storage.normalizePerPage(perPageInput, 100);
|
|
2964
|
+
const { offset: start, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
2965
|
+
const limitValue = perPageInput === false ? total : perPage;
|
|
2966
|
+
const end = perPageInput === false ? total : start + perPage;
|
|
1549
2967
|
const dataRequest = this.pool.request();
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
2968
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
2969
|
+
dataRequest.input(key, value);
|
|
2970
|
+
});
|
|
2971
|
+
dataRequest.input("perPage", limitValue);
|
|
2972
|
+
dataRequest.input("offset", start);
|
|
2973
|
+
const dataQuery = `SELECT * FROM ${tableName} WHERE ${whereClause} ORDER BY [createdAt] DESC OFFSET @offset ROWS FETCH NEXT @perPage ROWS ONLY`;
|
|
2974
|
+
const result = await dataRequest.query(dataQuery);
|
|
1556
2975
|
return {
|
|
1557
2976
|
pagination: {
|
|
1558
2977
|
total: Number(total),
|
|
1559
|
-
page
|
|
1560
|
-
perPage:
|
|
1561
|
-
hasMore:
|
|
2978
|
+
page,
|
|
2979
|
+
perPage: perPageForResponse,
|
|
2980
|
+
hasMore: end < total
|
|
1562
2981
|
},
|
|
1563
2982
|
scores: result.recordset.map((row) => transformScoreRow(row))
|
|
1564
2983
|
};
|
|
1565
2984
|
} catch (error$1) {
|
|
1566
2985
|
throw new error.MastraError(
|
|
1567
2986
|
{
|
|
1568
|
-
id: "
|
|
2987
|
+
id: storage.createStorageErrorId("MSSQL", "LIST_SCORES_BY_SCORER_ID", "FAILED"),
|
|
1569
2988
|
domain: error.ErrorDomain.STORAGE,
|
|
1570
2989
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1571
2990
|
details: { scorerId }
|
|
@@ -1574,7 +2993,7 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
|
|
|
1574
2993
|
);
|
|
1575
2994
|
}
|
|
1576
2995
|
}
|
|
1577
|
-
async
|
|
2996
|
+
async listScoresByRunId({
|
|
1578
2997
|
runId,
|
|
1579
2998
|
pagination
|
|
1580
2999
|
}) {
|
|
@@ -1582,40 +3001,45 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
|
|
|
1582
3001
|
const request = this.pool.request();
|
|
1583
3002
|
request.input("p1", runId);
|
|
1584
3003
|
const totalResult = await request.query(
|
|
1585
|
-
`SELECT COUNT(*) as count FROM ${
|
|
3004
|
+
`SELECT COUNT(*) as count FROM ${getTableName2({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName2(this.schema) })} WHERE [runId] = @p1`
|
|
1586
3005
|
);
|
|
1587
3006
|
const total = totalResult.recordset[0]?.count || 0;
|
|
3007
|
+
const { page, perPage: perPageInput } = pagination;
|
|
1588
3008
|
if (total === 0) {
|
|
1589
3009
|
return {
|
|
1590
3010
|
pagination: {
|
|
1591
3011
|
total: 0,
|
|
1592
|
-
page
|
|
1593
|
-
perPage:
|
|
3012
|
+
page,
|
|
3013
|
+
perPage: perPageInput,
|
|
1594
3014
|
hasMore: false
|
|
1595
3015
|
},
|
|
1596
3016
|
scores: []
|
|
1597
3017
|
};
|
|
1598
3018
|
}
|
|
3019
|
+
const perPage = storage.normalizePerPage(perPageInput, 100);
|
|
3020
|
+
const { offset: start, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
3021
|
+
const limitValue = perPageInput === false ? total : perPage;
|
|
3022
|
+
const end = perPageInput === false ? total : start + perPage;
|
|
1599
3023
|
const dataRequest = this.pool.request();
|
|
1600
3024
|
dataRequest.input("p1", runId);
|
|
1601
|
-
dataRequest.input("p2",
|
|
1602
|
-
dataRequest.input("p3",
|
|
3025
|
+
dataRequest.input("p2", limitValue);
|
|
3026
|
+
dataRequest.input("p3", start);
|
|
1603
3027
|
const result = await dataRequest.query(
|
|
1604
|
-
`SELECT * FROM ${
|
|
3028
|
+
`SELECT * FROM ${getTableName2({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName2(this.schema) })} WHERE [runId] = @p1 ORDER BY [createdAt] DESC OFFSET @p3 ROWS FETCH NEXT @p2 ROWS ONLY`
|
|
1605
3029
|
);
|
|
1606
3030
|
return {
|
|
1607
3031
|
pagination: {
|
|
1608
3032
|
total: Number(total),
|
|
1609
|
-
page
|
|
1610
|
-
perPage:
|
|
1611
|
-
hasMore:
|
|
3033
|
+
page,
|
|
3034
|
+
perPage: perPageForResponse,
|
|
3035
|
+
hasMore: end < total
|
|
1612
3036
|
},
|
|
1613
3037
|
scores: result.recordset.map((row) => transformScoreRow(row))
|
|
1614
3038
|
};
|
|
1615
3039
|
} catch (error$1) {
|
|
1616
3040
|
throw new error.MastraError(
|
|
1617
3041
|
{
|
|
1618
|
-
id: "
|
|
3042
|
+
id: storage.createStorageErrorId("MSSQL", "LIST_SCORES_BY_RUN_ID", "FAILED"),
|
|
1619
3043
|
domain: error.ErrorDomain.STORAGE,
|
|
1620
3044
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1621
3045
|
details: { runId }
|
|
@@ -1624,7 +3048,7 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
|
|
|
1624
3048
|
);
|
|
1625
3049
|
}
|
|
1626
3050
|
}
|
|
1627
|
-
async
|
|
3051
|
+
async listScoresByEntityId({
|
|
1628
3052
|
entityId,
|
|
1629
3053
|
entityType,
|
|
1630
3054
|
pagination
|
|
@@ -1634,41 +3058,46 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
|
|
|
1634
3058
|
request.input("p1", entityId);
|
|
1635
3059
|
request.input("p2", entityType);
|
|
1636
3060
|
const totalResult = await request.query(
|
|
1637
|
-
`SELECT COUNT(*) as count FROM ${
|
|
3061
|
+
`SELECT COUNT(*) as count FROM ${getTableName2({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName2(this.schema) })} WHERE [entityId] = @p1 AND [entityType] = @p2`
|
|
1638
3062
|
);
|
|
1639
3063
|
const total = totalResult.recordset[0]?.count || 0;
|
|
3064
|
+
const { page, perPage: perPageInput } = pagination;
|
|
3065
|
+
const perPage = storage.normalizePerPage(perPageInput, 100);
|
|
3066
|
+
const { offset: start, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
1640
3067
|
if (total === 0) {
|
|
1641
3068
|
return {
|
|
1642
3069
|
pagination: {
|
|
1643
3070
|
total: 0,
|
|
1644
|
-
page
|
|
1645
|
-
perPage:
|
|
3071
|
+
page,
|
|
3072
|
+
perPage: perPageForResponse,
|
|
1646
3073
|
hasMore: false
|
|
1647
3074
|
},
|
|
1648
3075
|
scores: []
|
|
1649
3076
|
};
|
|
1650
3077
|
}
|
|
3078
|
+
const limitValue = perPageInput === false ? total : perPage;
|
|
3079
|
+
const end = perPageInput === false ? total : start + perPage;
|
|
1651
3080
|
const dataRequest = this.pool.request();
|
|
1652
3081
|
dataRequest.input("p1", entityId);
|
|
1653
3082
|
dataRequest.input("p2", entityType);
|
|
1654
|
-
dataRequest.input("p3",
|
|
1655
|
-
dataRequest.input("p4",
|
|
3083
|
+
dataRequest.input("p3", limitValue);
|
|
3084
|
+
dataRequest.input("p4", start);
|
|
1656
3085
|
const result = await dataRequest.query(
|
|
1657
|
-
`SELECT * FROM ${
|
|
3086
|
+
`SELECT * FROM ${getTableName2({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName2(this.schema) })} WHERE [entityId] = @p1 AND [entityType] = @p2 ORDER BY [createdAt] DESC OFFSET @p4 ROWS FETCH NEXT @p3 ROWS ONLY`
|
|
1658
3087
|
);
|
|
1659
3088
|
return {
|
|
1660
3089
|
pagination: {
|
|
1661
3090
|
total: Number(total),
|
|
1662
|
-
page
|
|
1663
|
-
perPage:
|
|
1664
|
-
hasMore:
|
|
3091
|
+
page,
|
|
3092
|
+
perPage: perPageForResponse,
|
|
3093
|
+
hasMore: end < total
|
|
1665
3094
|
},
|
|
1666
3095
|
scores: result.recordset.map((row) => transformScoreRow(row))
|
|
1667
3096
|
};
|
|
1668
3097
|
} catch (error$1) {
|
|
1669
3098
|
throw new error.MastraError(
|
|
1670
3099
|
{
|
|
1671
|
-
id: "
|
|
3100
|
+
id: storage.createStorageErrorId("MSSQL", "LIST_SCORES_BY_ENTITY_ID", "FAILED"),
|
|
1672
3101
|
domain: error.ErrorDomain.STORAGE,
|
|
1673
3102
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1674
3103
|
details: { entityId, entityType }
|
|
@@ -1677,249 +3106,317 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
|
|
|
1677
3106
|
);
|
|
1678
3107
|
}
|
|
1679
3108
|
}
|
|
3109
|
+
async listScoresBySpan({
|
|
3110
|
+
traceId,
|
|
3111
|
+
spanId,
|
|
3112
|
+
pagination
|
|
3113
|
+
}) {
|
|
3114
|
+
try {
|
|
3115
|
+
const request = this.pool.request();
|
|
3116
|
+
request.input("p1", traceId);
|
|
3117
|
+
request.input("p2", spanId);
|
|
3118
|
+
const totalResult = await request.query(
|
|
3119
|
+
`SELECT COUNT(*) as count FROM ${getTableName2({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName2(this.schema) })} WHERE [traceId] = @p1 AND [spanId] = @p2`
|
|
3120
|
+
);
|
|
3121
|
+
const total = totalResult.recordset[0]?.count || 0;
|
|
3122
|
+
const { page, perPage: perPageInput } = pagination;
|
|
3123
|
+
const perPage = storage.normalizePerPage(perPageInput, 100);
|
|
3124
|
+
const { offset: start, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
3125
|
+
if (total === 0) {
|
|
3126
|
+
return {
|
|
3127
|
+
pagination: {
|
|
3128
|
+
total: 0,
|
|
3129
|
+
page,
|
|
3130
|
+
perPage: perPageForResponse,
|
|
3131
|
+
hasMore: false
|
|
3132
|
+
},
|
|
3133
|
+
scores: []
|
|
3134
|
+
};
|
|
3135
|
+
}
|
|
3136
|
+
const limitValue = perPageInput === false ? total : perPage;
|
|
3137
|
+
const end = perPageInput === false ? total : start + perPage;
|
|
3138
|
+
const dataRequest = this.pool.request();
|
|
3139
|
+
dataRequest.input("p1", traceId);
|
|
3140
|
+
dataRequest.input("p2", spanId);
|
|
3141
|
+
dataRequest.input("p3", limitValue);
|
|
3142
|
+
dataRequest.input("p4", start);
|
|
3143
|
+
const result = await dataRequest.query(
|
|
3144
|
+
`SELECT * FROM ${getTableName2({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName2(this.schema) })} WHERE [traceId] = @p1 AND [spanId] = @p2 ORDER BY [createdAt] DESC OFFSET @p4 ROWS FETCH NEXT @p3 ROWS ONLY`
|
|
3145
|
+
);
|
|
3146
|
+
return {
|
|
3147
|
+
pagination: {
|
|
3148
|
+
total: Number(total),
|
|
3149
|
+
page,
|
|
3150
|
+
perPage: perPageForResponse,
|
|
3151
|
+
hasMore: end < total
|
|
3152
|
+
},
|
|
3153
|
+
scores: result.recordset.map((row) => transformScoreRow(row))
|
|
3154
|
+
};
|
|
3155
|
+
} catch (error$1) {
|
|
3156
|
+
throw new error.MastraError(
|
|
3157
|
+
{
|
|
3158
|
+
id: storage.createStorageErrorId("MSSQL", "LIST_SCORES_BY_SPAN", "FAILED"),
|
|
3159
|
+
domain: error.ErrorDomain.STORAGE,
|
|
3160
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
3161
|
+
details: { traceId, spanId }
|
|
3162
|
+
},
|
|
3163
|
+
error$1
|
|
3164
|
+
);
|
|
3165
|
+
}
|
|
3166
|
+
}
|
|
1680
3167
|
};
|
|
1681
|
-
var
|
|
3168
|
+
var WorkflowsMSSQL = class _WorkflowsMSSQL extends storage.WorkflowsStorage {
|
|
1682
3169
|
pool;
|
|
1683
|
-
|
|
3170
|
+
db;
|
|
1684
3171
|
schema;
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
3172
|
+
needsConnect;
|
|
3173
|
+
skipDefaultIndexes;
|
|
3174
|
+
indexes;
|
|
3175
|
+
/** Tables managed by this domain */
|
|
3176
|
+
static MANAGED_TABLES = [storage.TABLE_WORKFLOW_SNAPSHOT];
|
|
3177
|
+
constructor(config) {
|
|
1690
3178
|
super();
|
|
3179
|
+
const { pool, schemaName, skipDefaultIndexes, indexes, needsConnect } = resolveMssqlConfig(config);
|
|
1691
3180
|
this.pool = pool;
|
|
1692
|
-
this.
|
|
1693
|
-
this.
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
const paramMap = {};
|
|
1713
|
-
const conditions = [];
|
|
1714
|
-
let paramIndex = 1;
|
|
1715
|
-
if (name) {
|
|
1716
|
-
const paramName = `p${paramIndex++}`;
|
|
1717
|
-
conditions.push(`[name] LIKE @${paramName}`);
|
|
1718
|
-
paramMap[paramName] = `${name}%`;
|
|
1719
|
-
}
|
|
1720
|
-
if (scope) {
|
|
1721
|
-
const paramName = `p${paramIndex++}`;
|
|
1722
|
-
conditions.push(`[scope] = @${paramName}`);
|
|
1723
|
-
paramMap[paramName] = scope;
|
|
3181
|
+
this.schema = schemaName;
|
|
3182
|
+
this.db = new MssqlDB({ pool, schemaName, skipDefaultIndexes });
|
|
3183
|
+
this.needsConnect = needsConnect;
|
|
3184
|
+
this.skipDefaultIndexes = skipDefaultIndexes;
|
|
3185
|
+
this.indexes = indexes?.filter((idx) => _WorkflowsMSSQL.MANAGED_TABLES.includes(idx.table));
|
|
3186
|
+
}
|
|
3187
|
+
/**
|
|
3188
|
+
* Returns default index definitions for the workflows domain tables.
|
|
3189
|
+
* Currently no default indexes are defined for workflows.
|
|
3190
|
+
*/
|
|
3191
|
+
getDefaultIndexDefinitions() {
|
|
3192
|
+
return [];
|
|
3193
|
+
}
|
|
3194
|
+
/**
|
|
3195
|
+
* Creates default indexes for optimal query performance.
|
|
3196
|
+
* Currently no default indexes are defined for workflows.
|
|
3197
|
+
*/
|
|
3198
|
+
async createDefaultIndexes() {
|
|
3199
|
+
if (this.skipDefaultIndexes) {
|
|
3200
|
+
return;
|
|
1724
3201
|
}
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
paramMap[paramName] = value;
|
|
1731
|
-
});
|
|
3202
|
+
}
|
|
3203
|
+
async init() {
|
|
3204
|
+
if (this.needsConnect) {
|
|
3205
|
+
await this.pool.connect();
|
|
3206
|
+
this.needsConnect = false;
|
|
1732
3207
|
}
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
3208
|
+
await this.db.createTable({ tableName: storage.TABLE_WORKFLOW_SNAPSHOT, schema: storage.TABLE_SCHEMAS[storage.TABLE_WORKFLOW_SNAPSHOT] });
|
|
3209
|
+
await this.createDefaultIndexes();
|
|
3210
|
+
await this.createCustomIndexes();
|
|
3211
|
+
}
|
|
3212
|
+
/**
|
|
3213
|
+
* Creates custom user-defined indexes for this domain's tables.
|
|
3214
|
+
*/
|
|
3215
|
+
async createCustomIndexes() {
|
|
3216
|
+
if (!this.indexes || this.indexes.length === 0) {
|
|
3217
|
+
return;
|
|
1740
3218
|
}
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
3219
|
+
for (const indexDef of this.indexes) {
|
|
3220
|
+
try {
|
|
3221
|
+
await this.db.createIndex(indexDef);
|
|
3222
|
+
} catch (error) {
|
|
3223
|
+
this.logger?.warn?.(`Failed to create custom index ${indexDef.name}:`, error);
|
|
3224
|
+
}
|
|
1745
3225
|
}
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
3226
|
+
}
|
|
3227
|
+
async dangerouslyClearAll() {
|
|
3228
|
+
await this.db.clearTable({ tableName: storage.TABLE_WORKFLOW_SNAPSHOT });
|
|
3229
|
+
}
|
|
3230
|
+
parseWorkflowRun(row) {
|
|
3231
|
+
let parsedSnapshot = row.snapshot;
|
|
3232
|
+
if (typeof parsedSnapshot === "string") {
|
|
3233
|
+
try {
|
|
3234
|
+
parsedSnapshot = JSON.parse(row.snapshot);
|
|
3235
|
+
} catch (e) {
|
|
3236
|
+
this.logger?.warn?.(`Failed to parse snapshot for workflow ${row.workflow_name}:`, e);
|
|
3237
|
+
}
|
|
1750
3238
|
}
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
3239
|
+
return {
|
|
3240
|
+
workflowName: row.workflow_name,
|
|
3241
|
+
runId: row.run_id,
|
|
3242
|
+
snapshot: parsedSnapshot,
|
|
3243
|
+
createdAt: row.createdAt,
|
|
3244
|
+
updatedAt: row.updatedAt,
|
|
3245
|
+
resourceId: row.resourceId
|
|
3246
|
+
};
|
|
3247
|
+
}
|
|
3248
|
+
async updateWorkflowResults({
|
|
3249
|
+
workflowName,
|
|
3250
|
+
runId,
|
|
3251
|
+
stepId,
|
|
3252
|
+
result,
|
|
3253
|
+
requestContext
|
|
3254
|
+
}) {
|
|
3255
|
+
const table = getTableName2({ indexName: storage.TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName2(this.schema) });
|
|
3256
|
+
const transaction = this.pool.transaction();
|
|
1754
3257
|
try {
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
3258
|
+
await transaction.begin();
|
|
3259
|
+
const selectRequest = new sql__default.default.Request(transaction);
|
|
3260
|
+
selectRequest.input("workflow_name", workflowName);
|
|
3261
|
+
selectRequest.input("run_id", runId);
|
|
3262
|
+
const existingSnapshotResult = await selectRequest.query(
|
|
3263
|
+
`SELECT snapshot FROM ${table} WITH (UPDLOCK, HOLDLOCK) WHERE workflow_name = @workflow_name AND run_id = @run_id`
|
|
3264
|
+
);
|
|
3265
|
+
let snapshot;
|
|
3266
|
+
if (!existingSnapshotResult.recordset || existingSnapshotResult.recordset.length === 0) {
|
|
3267
|
+
snapshot = {
|
|
3268
|
+
context: {},
|
|
3269
|
+
activePaths: [],
|
|
3270
|
+
activeStepsPath: {},
|
|
3271
|
+
timestamp: Date.now(),
|
|
3272
|
+
suspendedPaths: {},
|
|
3273
|
+
resumeLabels: {},
|
|
3274
|
+
serializedStepGraph: [],
|
|
3275
|
+
status: "pending",
|
|
3276
|
+
value: {},
|
|
3277
|
+
waitingPaths: {},
|
|
3278
|
+
runId,
|
|
3279
|
+
requestContext: {}
|
|
3280
|
+
};
|
|
3281
|
+
} else {
|
|
3282
|
+
const existingSnapshot = existingSnapshotResult.recordset[0].snapshot;
|
|
3283
|
+
snapshot = typeof existingSnapshot === "string" ? JSON.parse(existingSnapshot) : existingSnapshot;
|
|
3284
|
+
}
|
|
3285
|
+
snapshot.context[stepId] = result;
|
|
3286
|
+
snapshot.requestContext = { ...snapshot.requestContext, ...requestContext };
|
|
3287
|
+
const upsertReq = new sql__default.default.Request(transaction);
|
|
3288
|
+
upsertReq.input("workflow_name", workflowName);
|
|
3289
|
+
upsertReq.input("run_id", runId);
|
|
3290
|
+
upsertReq.input("snapshot", JSON.stringify(snapshot));
|
|
3291
|
+
upsertReq.input("createdAt", sql__default.default.DateTime2, /* @__PURE__ */ new Date());
|
|
3292
|
+
upsertReq.input("updatedAt", sql__default.default.DateTime2, /* @__PURE__ */ new Date());
|
|
3293
|
+
await upsertReq.query(
|
|
3294
|
+
`MERGE ${table} AS target
|
|
3295
|
+
USING (SELECT @workflow_name AS workflow_name, @run_id AS run_id) AS src
|
|
3296
|
+
ON target.workflow_name = src.workflow_name AND target.run_id = src.run_id
|
|
3297
|
+
WHEN MATCHED THEN UPDATE SET snapshot = @snapshot, [updatedAt] = @updatedAt
|
|
3298
|
+
WHEN NOT MATCHED THEN INSERT (workflow_name, run_id, snapshot, [createdAt], [updatedAt])
|
|
3299
|
+
VALUES (@workflow_name, @run_id, @snapshot, @createdAt, @updatedAt);`
|
|
3300
|
+
);
|
|
3301
|
+
await transaction.commit();
|
|
3302
|
+
return snapshot.context;
|
|
1765
3303
|
} catch (error$1) {
|
|
3304
|
+
try {
|
|
3305
|
+
await transaction.rollback();
|
|
3306
|
+
} catch {
|
|
3307
|
+
}
|
|
1766
3308
|
throw new error.MastraError(
|
|
1767
3309
|
{
|
|
1768
|
-
id: "
|
|
3310
|
+
id: storage.createStorageErrorId("MSSQL", "UPDATE_WORKFLOW_RESULTS", "FAILED"),
|
|
1769
3311
|
domain: error.ErrorDomain.STORAGE,
|
|
1770
3312
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1771
3313
|
details: {
|
|
1772
|
-
|
|
1773
|
-
|
|
3314
|
+
workflowName,
|
|
3315
|
+
runId,
|
|
3316
|
+
stepId
|
|
1774
3317
|
}
|
|
1775
3318
|
},
|
|
1776
3319
|
error$1
|
|
1777
3320
|
);
|
|
1778
3321
|
}
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
}
|
|
1788
|
-
const dataQuery = `SELECT * FROM ${getTableName({ indexName: storage.TABLE_TRACES, schemaName: getSchemaName(this.schema) })} ${whereClause} ORDER BY [seq_id] DESC OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY`;
|
|
1789
|
-
const dataRequest = this.pool.request();
|
|
1790
|
-
Object.entries(paramMap).forEach(([key, value]) => {
|
|
1791
|
-
if (value instanceof Date) {
|
|
1792
|
-
dataRequest.input(key, sql2__default.default.DateTime, value);
|
|
1793
|
-
} else {
|
|
1794
|
-
dataRequest.input(key, value);
|
|
1795
|
-
}
|
|
1796
|
-
});
|
|
1797
|
-
dataRequest.input("offset", currentOffset);
|
|
1798
|
-
dataRequest.input("limit", perPage);
|
|
3322
|
+
}
|
|
3323
|
+
async updateWorkflowState({
|
|
3324
|
+
workflowName,
|
|
3325
|
+
runId,
|
|
3326
|
+
opts
|
|
3327
|
+
}) {
|
|
3328
|
+
const table = getTableName2({ indexName: storage.TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName2(this.schema) });
|
|
3329
|
+
const transaction = this.pool.transaction();
|
|
1799
3330
|
try {
|
|
1800
|
-
|
|
1801
|
-
const
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
3331
|
+
await transaction.begin();
|
|
3332
|
+
const selectRequest = new sql__default.default.Request(transaction);
|
|
3333
|
+
selectRequest.input("workflow_name", workflowName);
|
|
3334
|
+
selectRequest.input("run_id", runId);
|
|
3335
|
+
const existingSnapshotResult = await selectRequest.query(
|
|
3336
|
+
`SELECT snapshot FROM ${table} WITH (UPDLOCK, HOLDLOCK) WHERE workflow_name = @workflow_name AND run_id = @run_id`
|
|
3337
|
+
);
|
|
3338
|
+
if (!existingSnapshotResult.recordset || existingSnapshotResult.recordset.length === 0) {
|
|
3339
|
+
await transaction.rollback();
|
|
3340
|
+
return void 0;
|
|
3341
|
+
}
|
|
3342
|
+
const existingSnapshot = existingSnapshotResult.recordset[0].snapshot;
|
|
3343
|
+
const snapshot = typeof existingSnapshot === "string" ? JSON.parse(existingSnapshot) : existingSnapshot;
|
|
3344
|
+
if (!snapshot || !snapshot?.context) {
|
|
3345
|
+
await transaction.rollback();
|
|
3346
|
+
throw new error.MastraError(
|
|
3347
|
+
{
|
|
3348
|
+
id: storage.createStorageErrorId("MSSQL", "UPDATE_WORKFLOW_STATE", "SNAPSHOT_NOT_FOUND"),
|
|
3349
|
+
domain: error.ErrorDomain.STORAGE,
|
|
3350
|
+
category: error.ErrorCategory.SYSTEM,
|
|
3351
|
+
details: {
|
|
3352
|
+
workflowName,
|
|
3353
|
+
runId
|
|
3354
|
+
}
|
|
3355
|
+
},
|
|
3356
|
+
new Error(`Snapshot not found for runId ${runId}`)
|
|
3357
|
+
);
|
|
3358
|
+
}
|
|
3359
|
+
const updatedSnapshot = { ...snapshot, ...opts };
|
|
3360
|
+
const updateRequest = new sql__default.default.Request(transaction);
|
|
3361
|
+
updateRequest.input("snapshot", JSON.stringify(updatedSnapshot));
|
|
3362
|
+
updateRequest.input("workflow_name", workflowName);
|
|
3363
|
+
updateRequest.input("run_id", runId);
|
|
3364
|
+
updateRequest.input("updatedAt", sql__default.default.DateTime2, /* @__PURE__ */ new Date());
|
|
3365
|
+
await updateRequest.query(
|
|
3366
|
+
`UPDATE ${table} SET snapshot = @snapshot, [updatedAt] = @updatedAt WHERE workflow_name = @workflow_name AND run_id = @run_id`
|
|
3367
|
+
);
|
|
3368
|
+
await transaction.commit();
|
|
3369
|
+
return updatedSnapshot;
|
|
1825
3370
|
} catch (error$1) {
|
|
3371
|
+
try {
|
|
3372
|
+
await transaction.rollback();
|
|
3373
|
+
} catch {
|
|
3374
|
+
}
|
|
3375
|
+
if (error$1 instanceof error.MastraError) throw error$1;
|
|
1826
3376
|
throw new error.MastraError(
|
|
1827
3377
|
{
|
|
1828
|
-
id: "
|
|
3378
|
+
id: storage.createStorageErrorId("MSSQL", "UPDATE_WORKFLOW_STATE", "FAILED"),
|
|
1829
3379
|
domain: error.ErrorDomain.STORAGE,
|
|
1830
3380
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1831
3381
|
details: {
|
|
1832
|
-
|
|
1833
|
-
|
|
3382
|
+
workflowName,
|
|
3383
|
+
runId
|
|
1834
3384
|
}
|
|
1835
3385
|
},
|
|
1836
3386
|
error$1
|
|
1837
3387
|
);
|
|
1838
3388
|
}
|
|
1839
3389
|
}
|
|
1840
|
-
async batchTraceInsert({ records }) {
|
|
1841
|
-
this.logger.debug("Batch inserting traces", { count: records.length });
|
|
1842
|
-
await this.operations.batchInsert({
|
|
1843
|
-
tableName: storage.TABLE_TRACES,
|
|
1844
|
-
records
|
|
1845
|
-
});
|
|
1846
|
-
}
|
|
1847
|
-
};
|
|
1848
|
-
function parseWorkflowRun(row) {
|
|
1849
|
-
let parsedSnapshot = row.snapshot;
|
|
1850
|
-
if (typeof parsedSnapshot === "string") {
|
|
1851
|
-
try {
|
|
1852
|
-
parsedSnapshot = JSON.parse(row.snapshot);
|
|
1853
|
-
} catch (e) {
|
|
1854
|
-
console.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
|
|
1855
|
-
}
|
|
1856
|
-
}
|
|
1857
|
-
return {
|
|
1858
|
-
workflowName: row.workflow_name,
|
|
1859
|
-
runId: row.run_id,
|
|
1860
|
-
snapshot: parsedSnapshot,
|
|
1861
|
-
createdAt: row.createdAt,
|
|
1862
|
-
updatedAt: row.updatedAt,
|
|
1863
|
-
resourceId: row.resourceId
|
|
1864
|
-
};
|
|
1865
|
-
}
|
|
1866
|
-
var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
|
|
1867
|
-
pool;
|
|
1868
|
-
operations;
|
|
1869
|
-
schema;
|
|
1870
|
-
constructor({
|
|
1871
|
-
pool,
|
|
1872
|
-
operations,
|
|
1873
|
-
schema
|
|
1874
|
-
}) {
|
|
1875
|
-
super();
|
|
1876
|
-
this.pool = pool;
|
|
1877
|
-
this.operations = operations;
|
|
1878
|
-
this.schema = schema;
|
|
1879
|
-
}
|
|
1880
|
-
updateWorkflowResults({
|
|
1881
|
-
// workflowName,
|
|
1882
|
-
// runId,
|
|
1883
|
-
// stepId,
|
|
1884
|
-
// result,
|
|
1885
|
-
// runtimeContext,
|
|
1886
|
-
}) {
|
|
1887
|
-
throw new Error("Method not implemented.");
|
|
1888
|
-
}
|
|
1889
|
-
updateWorkflowState({
|
|
1890
|
-
// workflowName,
|
|
1891
|
-
// runId,
|
|
1892
|
-
// opts,
|
|
1893
|
-
}) {
|
|
1894
|
-
throw new Error("Method not implemented.");
|
|
1895
|
-
}
|
|
1896
3390
|
async persistWorkflowSnapshot({
|
|
1897
3391
|
workflowName,
|
|
1898
3392
|
runId,
|
|
3393
|
+
resourceId,
|
|
1899
3394
|
snapshot
|
|
1900
3395
|
}) {
|
|
1901
|
-
const table =
|
|
3396
|
+
const table = getTableName2({ indexName: storage.TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName2(this.schema) });
|
|
1902
3397
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1903
3398
|
try {
|
|
1904
3399
|
const request = this.pool.request();
|
|
1905
3400
|
request.input("workflow_name", workflowName);
|
|
1906
3401
|
request.input("run_id", runId);
|
|
3402
|
+
request.input("resourceId", resourceId);
|
|
1907
3403
|
request.input("snapshot", JSON.stringify(snapshot));
|
|
1908
|
-
request.input("createdAt",
|
|
1909
|
-
request.input("updatedAt",
|
|
3404
|
+
request.input("createdAt", sql__default.default.DateTime2, new Date(now));
|
|
3405
|
+
request.input("updatedAt", sql__default.default.DateTime2, new Date(now));
|
|
1910
3406
|
const mergeSql = `MERGE INTO ${table} AS target
|
|
1911
3407
|
USING (SELECT @workflow_name AS workflow_name, @run_id AS run_id) AS src
|
|
1912
3408
|
ON target.workflow_name = src.workflow_name AND target.run_id = src.run_id
|
|
1913
3409
|
WHEN MATCHED THEN UPDATE SET
|
|
3410
|
+
resourceId = @resourceId,
|
|
1914
3411
|
snapshot = @snapshot,
|
|
1915
3412
|
[updatedAt] = @updatedAt
|
|
1916
|
-
WHEN NOT MATCHED THEN INSERT (workflow_name, run_id, snapshot, [createdAt], [updatedAt])
|
|
1917
|
-
VALUES (@workflow_name, @run_id, @snapshot, @createdAt, @updatedAt);`;
|
|
3413
|
+
WHEN NOT MATCHED THEN INSERT (workflow_name, run_id, resourceId, snapshot, [createdAt], [updatedAt])
|
|
3414
|
+
VALUES (@workflow_name, @run_id, @resourceId, @snapshot, @createdAt, @updatedAt);`;
|
|
1918
3415
|
await request.query(mergeSql);
|
|
1919
3416
|
} catch (error$1) {
|
|
1920
3417
|
throw new error.MastraError(
|
|
1921
3418
|
{
|
|
1922
|
-
id: "
|
|
3419
|
+
id: storage.createStorageErrorId("MSSQL", "PERSIST_WORKFLOW_SNAPSHOT", "FAILED"),
|
|
1923
3420
|
domain: error.ErrorDomain.STORAGE,
|
|
1924
3421
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1925
3422
|
details: {
|
|
@@ -1936,7 +3433,7 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
|
|
|
1936
3433
|
runId
|
|
1937
3434
|
}) {
|
|
1938
3435
|
try {
|
|
1939
|
-
const result = await this.
|
|
3436
|
+
const result = await this.db.load({
|
|
1940
3437
|
tableName: storage.TABLE_WORKFLOW_SNAPSHOT,
|
|
1941
3438
|
keys: {
|
|
1942
3439
|
workflow_name: workflowName,
|
|
@@ -1950,7 +3447,7 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
|
|
|
1950
3447
|
} catch (error$1) {
|
|
1951
3448
|
throw new error.MastraError(
|
|
1952
3449
|
{
|
|
1953
|
-
id: "
|
|
3450
|
+
id: storage.createStorageErrorId("MSSQL", "LOAD_WORKFLOW_SNAPSHOT", "FAILED"),
|
|
1954
3451
|
domain: error.ErrorDomain.STORAGE,
|
|
1955
3452
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1956
3453
|
details: {
|
|
@@ -1978,7 +3475,7 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
|
|
|
1978
3475
|
paramMap["workflowName"] = workflowName;
|
|
1979
3476
|
}
|
|
1980
3477
|
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
1981
|
-
const tableName =
|
|
3478
|
+
const tableName = getTableName2({ indexName: storage.TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName2(this.schema) });
|
|
1982
3479
|
const query = `SELECT * FROM ${tableName} ${whereClause}`;
|
|
1983
3480
|
const request = this.pool.request();
|
|
1984
3481
|
Object.entries(paramMap).forEach(([key, value]) => request.input(key, value));
|
|
@@ -1986,11 +3483,11 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
|
|
|
1986
3483
|
if (!result.recordset || result.recordset.length === 0) {
|
|
1987
3484
|
return null;
|
|
1988
3485
|
}
|
|
1989
|
-
return parseWorkflowRun(result.recordset[0]);
|
|
3486
|
+
return this.parseWorkflowRun(result.recordset[0]);
|
|
1990
3487
|
} catch (error$1) {
|
|
1991
3488
|
throw new error.MastraError(
|
|
1992
3489
|
{
|
|
1993
|
-
id: "
|
|
3490
|
+
id: storage.createStorageErrorId("MSSQL", "GET_WORKFLOW_RUN_BY_ID", "FAILED"),
|
|
1994
3491
|
domain: error.ErrorDomain.STORAGE,
|
|
1995
3492
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1996
3493
|
details: {
|
|
@@ -2002,13 +3499,43 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
|
|
|
2002
3499
|
);
|
|
2003
3500
|
}
|
|
2004
3501
|
}
|
|
2005
|
-
async
|
|
3502
|
+
async deleteWorkflowRunById({ runId, workflowName }) {
|
|
3503
|
+
const table = getTableName2({ indexName: storage.TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName2(this.schema) });
|
|
3504
|
+
const transaction = this.pool.transaction();
|
|
3505
|
+
try {
|
|
3506
|
+
await transaction.begin();
|
|
3507
|
+
const deleteRequest = new sql__default.default.Request(transaction);
|
|
3508
|
+
deleteRequest.input("workflow_name", workflowName);
|
|
3509
|
+
deleteRequest.input("run_id", runId);
|
|
3510
|
+
await deleteRequest.query(`DELETE FROM ${table} WHERE workflow_name = @workflow_name AND run_id = @run_id`);
|
|
3511
|
+
await transaction.commit();
|
|
3512
|
+
} catch (error$1) {
|
|
3513
|
+
try {
|
|
3514
|
+
await transaction.rollback();
|
|
3515
|
+
} catch {
|
|
3516
|
+
}
|
|
3517
|
+
throw new error.MastraError(
|
|
3518
|
+
{
|
|
3519
|
+
id: storage.createStorageErrorId("MSSQL", "DELETE_WORKFLOW_RUN_BY_ID", "FAILED"),
|
|
3520
|
+
domain: error.ErrorDomain.STORAGE,
|
|
3521
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
3522
|
+
details: {
|
|
3523
|
+
runId,
|
|
3524
|
+
workflowName
|
|
3525
|
+
}
|
|
3526
|
+
},
|
|
3527
|
+
error$1
|
|
3528
|
+
);
|
|
3529
|
+
}
|
|
3530
|
+
}
|
|
3531
|
+
async listWorkflowRuns({
|
|
2006
3532
|
workflowName,
|
|
2007
3533
|
fromDate,
|
|
2008
3534
|
toDate,
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
resourceId
|
|
3535
|
+
page,
|
|
3536
|
+
perPage,
|
|
3537
|
+
resourceId,
|
|
3538
|
+
status
|
|
2012
3539
|
} = {}) {
|
|
2013
3540
|
try {
|
|
2014
3541
|
const conditions = [];
|
|
@@ -2017,13 +3544,17 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
|
|
|
2017
3544
|
conditions.push(`[workflow_name] = @workflowName`);
|
|
2018
3545
|
paramMap["workflowName"] = workflowName;
|
|
2019
3546
|
}
|
|
3547
|
+
if (status) {
|
|
3548
|
+
conditions.push(`JSON_VALUE([snapshot], '$.status') = @status`);
|
|
3549
|
+
paramMap["status"] = status;
|
|
3550
|
+
}
|
|
2020
3551
|
if (resourceId) {
|
|
2021
|
-
const hasResourceId = await this.
|
|
3552
|
+
const hasResourceId = await this.db.hasColumn(storage.TABLE_WORKFLOW_SNAPSHOT, "resourceId");
|
|
2022
3553
|
if (hasResourceId) {
|
|
2023
3554
|
conditions.push(`[resourceId] = @resourceId`);
|
|
2024
3555
|
paramMap["resourceId"] = resourceId;
|
|
2025
3556
|
} else {
|
|
2026
|
-
|
|
3557
|
+
this.logger?.warn?.(`[${storage.TABLE_WORKFLOW_SNAPSHOT}] resourceId column not found. Skipping resourceId filter.`);
|
|
2027
3558
|
}
|
|
2028
3559
|
}
|
|
2029
3560
|
if (fromDate instanceof Date && !isNaN(fromDate.getTime())) {
|
|
@@ -2036,33 +3567,36 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
|
|
|
2036
3567
|
}
|
|
2037
3568
|
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
2038
3569
|
let total = 0;
|
|
2039
|
-
const tableName =
|
|
3570
|
+
const tableName = getTableName2({ indexName: storage.TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName2(this.schema) });
|
|
2040
3571
|
const request = this.pool.request();
|
|
2041
3572
|
Object.entries(paramMap).forEach(([key, value]) => {
|
|
2042
3573
|
if (value instanceof Date) {
|
|
2043
|
-
request.input(key,
|
|
3574
|
+
request.input(key, sql__default.default.DateTime, value);
|
|
2044
3575
|
} else {
|
|
2045
3576
|
request.input(key, value);
|
|
2046
3577
|
}
|
|
2047
3578
|
});
|
|
2048
|
-
|
|
3579
|
+
const usePagination = typeof perPage === "number" && typeof page === "number";
|
|
3580
|
+
if (usePagination) {
|
|
2049
3581
|
const countQuery = `SELECT COUNT(*) as count FROM ${tableName} ${whereClause}`;
|
|
2050
3582
|
const countResult = await request.query(countQuery);
|
|
2051
3583
|
total = Number(countResult.recordset[0]?.count || 0);
|
|
2052
3584
|
}
|
|
2053
3585
|
let query = `SELECT * FROM ${tableName} ${whereClause} ORDER BY [seq_id] DESC`;
|
|
2054
|
-
if (
|
|
2055
|
-
|
|
2056
|
-
|
|
3586
|
+
if (usePagination) {
|
|
3587
|
+
const normalizedPerPage = storage.normalizePerPage(perPage, Number.MAX_SAFE_INTEGER);
|
|
3588
|
+
const offset = page * normalizedPerPage;
|
|
3589
|
+
query += ` OFFSET @offset ROWS FETCH NEXT @perPage ROWS ONLY`;
|
|
3590
|
+
request.input("perPage", normalizedPerPage);
|
|
2057
3591
|
request.input("offset", offset);
|
|
2058
3592
|
}
|
|
2059
3593
|
const result = await request.query(query);
|
|
2060
|
-
const runs = (result.recordset || []).map((row) => parseWorkflowRun(row));
|
|
3594
|
+
const runs = (result.recordset || []).map((row) => this.parseWorkflowRun(row));
|
|
2061
3595
|
return { runs, total: total || runs.length };
|
|
2062
3596
|
} catch (error$1) {
|
|
2063
3597
|
throw new error.MastraError(
|
|
2064
3598
|
{
|
|
2065
|
-
id: "
|
|
3599
|
+
id: storage.createStorageErrorId("MSSQL", "LIST_WORKFLOW_RUNS", "FAILED"),
|
|
2066
3600
|
domain: error.ErrorDomain.STORAGE,
|
|
2067
3601
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
2068
3602
|
details: {
|
|
@@ -2076,18 +3610,28 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
|
|
|
2076
3610
|
};
|
|
2077
3611
|
|
|
2078
3612
|
// src/storage/index.ts
|
|
3613
|
+
var isPoolConfig = (config) => {
|
|
3614
|
+
return "pool" in config;
|
|
3615
|
+
};
|
|
2079
3616
|
var MSSQLStore = class extends storage.MastraStorage {
|
|
2080
3617
|
pool;
|
|
2081
3618
|
schema;
|
|
2082
3619
|
isConnected = null;
|
|
2083
3620
|
stores;
|
|
2084
3621
|
constructor(config) {
|
|
2085
|
-
|
|
3622
|
+
if (!config.id || typeof config.id !== "string" || config.id.trim() === "") {
|
|
3623
|
+
throw new Error("MSSQLStore: id must be provided and cannot be empty.");
|
|
3624
|
+
}
|
|
3625
|
+
super({ id: config.id, name: "MSSQLStore", disableInit: config.disableInit });
|
|
2086
3626
|
try {
|
|
2087
|
-
|
|
3627
|
+
this.schema = config.schemaName || "dbo";
|
|
3628
|
+
if (isPoolConfig(config)) {
|
|
3629
|
+
this.pool = config.pool;
|
|
3630
|
+
} else if ("connectionString" in config) {
|
|
2088
3631
|
if (!config.connectionString || typeof config.connectionString !== "string" || config.connectionString.trim() === "") {
|
|
2089
3632
|
throw new Error("MSSQLStore: connectionString must be provided and cannot be empty.");
|
|
2090
3633
|
}
|
|
3634
|
+
this.pool = new sql__default.default.ConnectionPool(config.connectionString);
|
|
2091
3635
|
} else {
|
|
2092
3636
|
const required = ["server", "database", "user", "password"];
|
|
2093
3637
|
for (const key of required) {
|
|
@@ -2095,34 +3639,35 @@ var MSSQLStore = class extends storage.MastraStorage {
|
|
|
2095
3639
|
throw new Error(`MSSQLStore: ${key} must be provided and cannot be empty.`);
|
|
2096
3640
|
}
|
|
2097
3641
|
}
|
|
3642
|
+
this.pool = new sql__default.default.ConnectionPool({
|
|
3643
|
+
server: config.server,
|
|
3644
|
+
database: config.database,
|
|
3645
|
+
user: config.user,
|
|
3646
|
+
password: config.password,
|
|
3647
|
+
port: config.port,
|
|
3648
|
+
options: config.options || { encrypt: true, trustServerCertificate: true }
|
|
3649
|
+
});
|
|
2098
3650
|
}
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
const
|
|
2109
|
-
const operations = new StoreOperationsMSSQL({ pool: this.pool, schemaName: this.schema });
|
|
2110
|
-
const scores = new ScoresMSSQL({ pool: this.pool, operations, schema: this.schema });
|
|
2111
|
-
const traces = new TracesMSSQL({ pool: this.pool, operations, schema: this.schema });
|
|
2112
|
-
const workflows = new WorkflowsMSSQL({ pool: this.pool, operations, schema: this.schema });
|
|
2113
|
-
const memory = new MemoryMSSQL({ pool: this.pool, schema: this.schema, operations });
|
|
3651
|
+
const domainConfig = {
|
|
3652
|
+
pool: this.pool,
|
|
3653
|
+
schemaName: this.schema,
|
|
3654
|
+
skipDefaultIndexes: config.skipDefaultIndexes,
|
|
3655
|
+
indexes: config.indexes
|
|
3656
|
+
};
|
|
3657
|
+
const scores = new ScoresMSSQL(domainConfig);
|
|
3658
|
+
const workflows = new WorkflowsMSSQL(domainConfig);
|
|
3659
|
+
const memory = new MemoryMSSQL(domainConfig);
|
|
3660
|
+
const observability = new ObservabilityMSSQL(domainConfig);
|
|
2114
3661
|
this.stores = {
|
|
2115
|
-
operations,
|
|
2116
3662
|
scores,
|
|
2117
|
-
traces,
|
|
2118
3663
|
workflows,
|
|
2119
|
-
|
|
2120
|
-
|
|
3664
|
+
memory,
|
|
3665
|
+
observability
|
|
2121
3666
|
};
|
|
2122
3667
|
} catch (e) {
|
|
2123
3668
|
throw new error.MastraError(
|
|
2124
3669
|
{
|
|
2125
|
-
id: "
|
|
3670
|
+
id: storage.createStorageErrorId("MSSQL", "INITIALIZATION", "FAILED"),
|
|
2126
3671
|
domain: error.ErrorDomain.STORAGE,
|
|
2127
3672
|
category: error.ErrorCategory.USER
|
|
2128
3673
|
},
|
|
@@ -2141,7 +3686,7 @@ var MSSQLStore = class extends storage.MastraStorage {
|
|
|
2141
3686
|
this.isConnected = null;
|
|
2142
3687
|
throw new error.MastraError(
|
|
2143
3688
|
{
|
|
2144
|
-
id: "
|
|
3689
|
+
id: storage.createStorageErrorId("MSSQL", "INIT", "FAILED"),
|
|
2145
3690
|
domain: error.ErrorDomain.STORAGE,
|
|
2146
3691
|
category: error.ErrorCategory.THIRD_PARTY
|
|
2147
3692
|
},
|
|
@@ -2157,211 +3702,20 @@ var MSSQLStore = class extends storage.MastraStorage {
|
|
|
2157
3702
|
throw err;
|
|
2158
3703
|
}
|
|
2159
3704
|
}
|
|
2160
|
-
get supports() {
|
|
2161
|
-
return {
|
|
2162
|
-
selectByIncludeResourceScope: true,
|
|
2163
|
-
resourceWorkingMemory: true,
|
|
2164
|
-
hasColumn: true,
|
|
2165
|
-
createTable: true,
|
|
2166
|
-
deleteMessages: true
|
|
2167
|
-
};
|
|
2168
|
-
}
|
|
2169
|
-
/** @deprecated use getEvals instead */
|
|
2170
|
-
async getEvalsByAgentName(agentName, type) {
|
|
2171
|
-
return this.stores.legacyEvals.getEvalsByAgentName(agentName, type);
|
|
2172
|
-
}
|
|
2173
|
-
async getEvals(options = {}) {
|
|
2174
|
-
return this.stores.legacyEvals.getEvals(options);
|
|
2175
|
-
}
|
|
2176
|
-
/**
|
|
2177
|
-
* @deprecated use getTracesPaginated instead
|
|
2178
|
-
*/
|
|
2179
|
-
async getTraces(args) {
|
|
2180
|
-
return this.stores.traces.getTraces(args);
|
|
2181
|
-
}
|
|
2182
|
-
async getTracesPaginated(args) {
|
|
2183
|
-
return this.stores.traces.getTracesPaginated(args);
|
|
2184
|
-
}
|
|
2185
|
-
async batchTraceInsert({ records }) {
|
|
2186
|
-
return this.stores.traces.batchTraceInsert({ records });
|
|
2187
|
-
}
|
|
2188
|
-
async createTable({
|
|
2189
|
-
tableName,
|
|
2190
|
-
schema
|
|
2191
|
-
}) {
|
|
2192
|
-
return this.stores.operations.createTable({ tableName, schema });
|
|
2193
|
-
}
|
|
2194
|
-
async alterTable({
|
|
2195
|
-
tableName,
|
|
2196
|
-
schema,
|
|
2197
|
-
ifNotExists
|
|
2198
|
-
}) {
|
|
2199
|
-
return this.stores.operations.alterTable({ tableName, schema, ifNotExists });
|
|
2200
|
-
}
|
|
2201
|
-
async clearTable({ tableName }) {
|
|
2202
|
-
return this.stores.operations.clearTable({ tableName });
|
|
2203
|
-
}
|
|
2204
|
-
async dropTable({ tableName }) {
|
|
2205
|
-
return this.stores.operations.dropTable({ tableName });
|
|
2206
|
-
}
|
|
2207
|
-
async insert({ tableName, record }) {
|
|
2208
|
-
return this.stores.operations.insert({ tableName, record });
|
|
2209
|
-
}
|
|
2210
|
-
async batchInsert({ tableName, records }) {
|
|
2211
|
-
return this.stores.operations.batchInsert({ tableName, records });
|
|
2212
|
-
}
|
|
2213
|
-
async load({ tableName, keys }) {
|
|
2214
|
-
return this.stores.operations.load({ tableName, keys });
|
|
2215
|
-
}
|
|
2216
|
-
/**
|
|
2217
|
-
* Memory
|
|
2218
|
-
*/
|
|
2219
|
-
async getThreadById({ threadId }) {
|
|
2220
|
-
return this.stores.memory.getThreadById({ threadId });
|
|
2221
|
-
}
|
|
2222
|
-
/**
|
|
2223
|
-
* @deprecated use getThreadsByResourceIdPaginated instead
|
|
2224
|
-
*/
|
|
2225
|
-
async getThreadsByResourceId(args) {
|
|
2226
|
-
return this.stores.memory.getThreadsByResourceId(args);
|
|
2227
|
-
}
|
|
2228
|
-
async getThreadsByResourceIdPaginated(args) {
|
|
2229
|
-
return this.stores.memory.getThreadsByResourceIdPaginated(args);
|
|
2230
|
-
}
|
|
2231
|
-
async saveThread({ thread }) {
|
|
2232
|
-
return this.stores.memory.saveThread({ thread });
|
|
2233
|
-
}
|
|
2234
|
-
async updateThread({
|
|
2235
|
-
id,
|
|
2236
|
-
title,
|
|
2237
|
-
metadata
|
|
2238
|
-
}) {
|
|
2239
|
-
return this.stores.memory.updateThread({ id, title, metadata });
|
|
2240
|
-
}
|
|
2241
|
-
async deleteThread({ threadId }) {
|
|
2242
|
-
return this.stores.memory.deleteThread({ threadId });
|
|
2243
|
-
}
|
|
2244
|
-
async getMessages(args) {
|
|
2245
|
-
return this.stores.memory.getMessages(args);
|
|
2246
|
-
}
|
|
2247
|
-
async getMessagesById({
|
|
2248
|
-
messageIds,
|
|
2249
|
-
format
|
|
2250
|
-
}) {
|
|
2251
|
-
return this.stores.memory.getMessagesById({ messageIds, format });
|
|
2252
|
-
}
|
|
2253
|
-
async getMessagesPaginated(args) {
|
|
2254
|
-
return this.stores.memory.getMessagesPaginated(args);
|
|
2255
|
-
}
|
|
2256
|
-
async saveMessages(args) {
|
|
2257
|
-
return this.stores.memory.saveMessages(args);
|
|
2258
|
-
}
|
|
2259
|
-
async updateMessages({
|
|
2260
|
-
messages
|
|
2261
|
-
}) {
|
|
2262
|
-
return this.stores.memory.updateMessages({ messages });
|
|
2263
|
-
}
|
|
2264
|
-
async deleteMessages(messageIds) {
|
|
2265
|
-
return this.stores.memory.deleteMessages(messageIds);
|
|
2266
|
-
}
|
|
2267
|
-
async getResourceById({ resourceId }) {
|
|
2268
|
-
return this.stores.memory.getResourceById({ resourceId });
|
|
2269
|
-
}
|
|
2270
|
-
async saveResource({ resource }) {
|
|
2271
|
-
return this.stores.memory.saveResource({ resource });
|
|
2272
|
-
}
|
|
2273
|
-
async updateResource({
|
|
2274
|
-
resourceId,
|
|
2275
|
-
workingMemory,
|
|
2276
|
-
metadata
|
|
2277
|
-
}) {
|
|
2278
|
-
return this.stores.memory.updateResource({ resourceId, workingMemory, metadata });
|
|
2279
|
-
}
|
|
2280
3705
|
/**
|
|
2281
|
-
*
|
|
3706
|
+
* Closes the MSSQL connection pool.
|
|
3707
|
+
*
|
|
3708
|
+
* This will close the connection pool, including pre-configured pools.
|
|
2282
3709
|
*/
|
|
2283
|
-
async updateWorkflowResults({
|
|
2284
|
-
workflowName,
|
|
2285
|
-
runId,
|
|
2286
|
-
stepId,
|
|
2287
|
-
result,
|
|
2288
|
-
runtimeContext
|
|
2289
|
-
}) {
|
|
2290
|
-
return this.stores.workflows.updateWorkflowResults({ workflowName, runId, stepId, result, runtimeContext });
|
|
2291
|
-
}
|
|
2292
|
-
async updateWorkflowState({
|
|
2293
|
-
workflowName,
|
|
2294
|
-
runId,
|
|
2295
|
-
opts
|
|
2296
|
-
}) {
|
|
2297
|
-
return this.stores.workflows.updateWorkflowState({ workflowName, runId, opts });
|
|
2298
|
-
}
|
|
2299
|
-
async persistWorkflowSnapshot({
|
|
2300
|
-
workflowName,
|
|
2301
|
-
runId,
|
|
2302
|
-
snapshot
|
|
2303
|
-
}) {
|
|
2304
|
-
return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, snapshot });
|
|
2305
|
-
}
|
|
2306
|
-
async loadWorkflowSnapshot({
|
|
2307
|
-
workflowName,
|
|
2308
|
-
runId
|
|
2309
|
-
}) {
|
|
2310
|
-
return this.stores.workflows.loadWorkflowSnapshot({ workflowName, runId });
|
|
2311
|
-
}
|
|
2312
|
-
async getWorkflowRuns({
|
|
2313
|
-
workflowName,
|
|
2314
|
-
fromDate,
|
|
2315
|
-
toDate,
|
|
2316
|
-
limit,
|
|
2317
|
-
offset,
|
|
2318
|
-
resourceId
|
|
2319
|
-
} = {}) {
|
|
2320
|
-
return this.stores.workflows.getWorkflowRuns({ workflowName, fromDate, toDate, limit, offset, resourceId });
|
|
2321
|
-
}
|
|
2322
|
-
async getWorkflowRunById({
|
|
2323
|
-
runId,
|
|
2324
|
-
workflowName
|
|
2325
|
-
}) {
|
|
2326
|
-
return this.stores.workflows.getWorkflowRunById({ runId, workflowName });
|
|
2327
|
-
}
|
|
2328
3710
|
async close() {
|
|
2329
3711
|
await this.pool.close();
|
|
2330
3712
|
}
|
|
2331
|
-
/**
|
|
2332
|
-
* Scorers
|
|
2333
|
-
*/
|
|
2334
|
-
async getScoreById({ id: _id }) {
|
|
2335
|
-
return this.stores.scores.getScoreById({ id: _id });
|
|
2336
|
-
}
|
|
2337
|
-
async getScoresByScorerId({
|
|
2338
|
-
scorerId: _scorerId,
|
|
2339
|
-
pagination: _pagination
|
|
2340
|
-
}) {
|
|
2341
|
-
return this.stores.scores.getScoresByScorerId({ scorerId: _scorerId, pagination: _pagination });
|
|
2342
|
-
}
|
|
2343
|
-
async saveScore(_score) {
|
|
2344
|
-
return this.stores.scores.saveScore(_score);
|
|
2345
|
-
}
|
|
2346
|
-
async getScoresByRunId({
|
|
2347
|
-
runId: _runId,
|
|
2348
|
-
pagination: _pagination
|
|
2349
|
-
}) {
|
|
2350
|
-
return this.stores.scores.getScoresByRunId({ runId: _runId, pagination: _pagination });
|
|
2351
|
-
}
|
|
2352
|
-
async getScoresByEntityId({
|
|
2353
|
-
entityId: _entityId,
|
|
2354
|
-
entityType: _entityType,
|
|
2355
|
-
pagination: _pagination
|
|
2356
|
-
}) {
|
|
2357
|
-
return this.stores.scores.getScoresByEntityId({
|
|
2358
|
-
entityId: _entityId,
|
|
2359
|
-
entityType: _entityType,
|
|
2360
|
-
pagination: _pagination
|
|
2361
|
-
});
|
|
2362
|
-
}
|
|
2363
3713
|
};
|
|
2364
3714
|
|
|
2365
3715
|
exports.MSSQLStore = MSSQLStore;
|
|
3716
|
+
exports.MemoryMSSQL = MemoryMSSQL;
|
|
3717
|
+
exports.ObservabilityMSSQL = ObservabilityMSSQL;
|
|
3718
|
+
exports.ScoresMSSQL = ScoresMSSQL;
|
|
3719
|
+
exports.WorkflowsMSSQL = WorkflowsMSSQL;
|
|
2366
3720
|
//# sourceMappingURL=index.cjs.map
|
|
2367
3721
|
//# sourceMappingURL=index.cjs.map
|