@mastra/mssql 1.0.0-beta.8 → 1.0.0
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 +921 -0
- 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 +293 -35
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +291 -37
- package/dist/index.js.map +1 -1
- package/dist/storage/db/index.d.ts +45 -0
- package/dist/storage/db/index.d.ts.map +1 -1
- package/dist/storage/domains/memory/index.d.ts +2 -2
- package/dist/storage/domains/memory/index.d.ts.map +1 -1
- package/dist/storage/domains/observability/index.d.ts +23 -0
- package/dist/storage/domains/observability/index.d.ts.map +1 -1
- package/dist/storage/domains/utils.d.ts.map +1 -1
- package/dist/storage/index.d.ts +9 -4
- package/dist/storage/index.d.ts.map +1 -1
- package/package.json +10 -9
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# @mastra/mssql Documentation
|
|
2
|
+
|
|
3
|
+
> Embedded documentation for coding agents
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Read the skill overview
|
|
9
|
+
cat docs/SKILL.md
|
|
10
|
+
|
|
11
|
+
# Get the source map
|
|
12
|
+
cat docs/SOURCE_MAP.json
|
|
13
|
+
|
|
14
|
+
# Read topic documentation
|
|
15
|
+
cat docs/<topic>/01-overview.md
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Structure
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
docs/
|
|
22
|
+
├── SKILL.md # Entry point
|
|
23
|
+
├── README.md # This file
|
|
24
|
+
├── SOURCE_MAP.json # Export index
|
|
25
|
+
├── storage/ (1 files)
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Version
|
|
29
|
+
|
|
30
|
+
Package: @mastra/mssql
|
|
31
|
+
Version: 1.0.0
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mastra-mssql-docs
|
|
3
|
+
description: Documentation for @mastra/mssql. Includes links to type definitions and readable implementation code in dist/.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# @mastra/mssql Documentation
|
|
7
|
+
|
|
8
|
+
> **Version**: 1.0.0
|
|
9
|
+
> **Package**: @mastra/mssql
|
|
10
|
+
|
|
11
|
+
## Quick Navigation
|
|
12
|
+
|
|
13
|
+
Use SOURCE_MAP.json to find any export:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
cat docs/SOURCE_MAP.json
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Each export maps to:
|
|
20
|
+
- **types**: `.d.ts` file with JSDoc and API signatures
|
|
21
|
+
- **implementation**: `.js` chunk file with readable source
|
|
22
|
+
- **docs**: Conceptual documentation in `docs/`
|
|
23
|
+
|
|
24
|
+
## Top Exports
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
See SOURCE_MAP.json for the complete list.
|
|
29
|
+
|
|
30
|
+
## Available Topics
|
|
31
|
+
|
|
32
|
+
- [Storage](storage/) - 1 file(s)
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# Storage API Reference
|
|
2
|
+
|
|
3
|
+
> API reference for storage - 1 entries
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Reference: MSSQL Storage
|
|
9
|
+
|
|
10
|
+
> Documentation for the MSSQL storage implementation in Mastra.
|
|
11
|
+
|
|
12
|
+
The MSSQL storage implementation provides a production-ready storage solution using Microsoft SQL Server databases.
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @mastra/mssql@beta
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
import { MSSQLStore } from "@mastra/mssql";
|
|
24
|
+
|
|
25
|
+
const storage = new MSSQLStore({
|
|
26
|
+
id: 'mssql-storage',
|
|
27
|
+
connectionString: process.env.DATABASE_URL,
|
|
28
|
+
});
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Parameters
|
|
32
|
+
|
|
33
|
+
## Constructor Examples
|
|
34
|
+
|
|
35
|
+
You can instantiate `MSSQLStore` in the following ways:
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
import { MSSQLStore } from "@mastra/mssql";
|
|
39
|
+
|
|
40
|
+
// Using a connection string only
|
|
41
|
+
const store1 = new MSSQLStore({
|
|
42
|
+
id: 'mssql-storage-1',
|
|
43
|
+
connectionString: "Server=localhost,1433;Database=mydb;User Id=sa;Password=password;Encrypt=true;TrustServerCertificate=true",
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// Using a connection string with a custom schema name
|
|
47
|
+
const store2 = new MSSQLStore({
|
|
48
|
+
id: 'mssql-storage-2',
|
|
49
|
+
connectionString: "Server=localhost,1433;Database=mydb;User Id=sa;Password=password;Encrypt=true;TrustServerCertificate=true",
|
|
50
|
+
schemaName: "custom_schema", // optional
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// Using individual connection parameters
|
|
54
|
+
const store4 = new MSSQLStore({
|
|
55
|
+
id: 'mssql-storage-3',
|
|
56
|
+
server: "localhost",
|
|
57
|
+
port: 1433,
|
|
58
|
+
database: "mydb",
|
|
59
|
+
user: "user",
|
|
60
|
+
password: "password",
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// Individual parameters with schemaName
|
|
64
|
+
const store5 = new MSSQLStore({
|
|
65
|
+
id: 'mssql-storage-4',
|
|
66
|
+
server: "localhost",
|
|
67
|
+
port: 1433,
|
|
68
|
+
database: "mydb",
|
|
69
|
+
user: "user",
|
|
70
|
+
password: "password",
|
|
71
|
+
schemaName: "custom_schema", // optional
|
|
72
|
+
});
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Additional Notes
|
|
76
|
+
|
|
77
|
+
### Schema Management
|
|
78
|
+
|
|
79
|
+
The storage implementation handles schema creation and updates automatically. It creates the following tables:
|
|
80
|
+
|
|
81
|
+
- `mastra_workflow_snapshot`: Stores workflow state and execution data
|
|
82
|
+
- `mastra_evals`: Stores evaluation results and metadata
|
|
83
|
+
- `mastra_threads`: Stores conversation threads
|
|
84
|
+
- `mastra_messages`: Stores individual messages
|
|
85
|
+
- `mastra_traces`: Stores telemetry and tracing data
|
|
86
|
+
- `mastra_scorers`: Stores scoring and evaluation data
|
|
87
|
+
- `mastra_resources`: Stores resource working memory data
|
|
88
|
+
|
|
89
|
+
### Initialization
|
|
90
|
+
|
|
91
|
+
When you pass storage to the Mastra class, `init()` is called automatically before any storage operation:
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
import { Mastra } from "@mastra/core";
|
|
95
|
+
import { MSSQLStore } from "@mastra/mssql";
|
|
96
|
+
|
|
97
|
+
const storage = new MSSQLStore({
|
|
98
|
+
connectionString: process.env.DATABASE_URL,
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
const mastra = new Mastra({
|
|
102
|
+
storage, // init() is called automatically
|
|
103
|
+
});
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
If you're using storage directly without Mastra, you must call `init()` explicitly to create the tables:
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
import { MSSQLStore } from "@mastra/mssql";
|
|
110
|
+
|
|
111
|
+
const storage = new MSSQLStore({
|
|
112
|
+
id: 'mssql-storage',
|
|
113
|
+
connectionString: process.env.DATABASE_URL,
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// Required when using storage directly
|
|
117
|
+
await storage.init();
|
|
118
|
+
|
|
119
|
+
// Access domain-specific stores via getStore()
|
|
120
|
+
const memoryStore = await storage.getStore('memory');
|
|
121
|
+
const thread = await memoryStore?.getThreadById({ threadId: "..." });
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
> **Note:**
|
|
125
|
+
If `init()` is not called, tables won't be created and storage operations will fail silently or throw errors.
|
|
126
|
+
|
|
127
|
+
### Direct Database and Pool Access
|
|
128
|
+
|
|
129
|
+
`MSSQLStore` exposes the mssql connection pool as public fields:
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
store.pool; // mssql connection pool instance
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
This enables direct queries and custom transaction management. When using these fields:
|
|
136
|
+
|
|
137
|
+
- You are responsible for proper connection and transaction handling.
|
|
138
|
+
- Closing the store (`store.close()`) will destroy the associated connection pool.
|
|
139
|
+
- Direct access bypasses any additional logic or validation provided by MSSQLStore methods.
|
|
140
|
+
|
|
141
|
+
This approach is intended for advanced scenarios where low-level access is required.
|
package/dist/index.cjs
CHANGED
|
@@ -340,15 +340,49 @@ ${columns}
|
|
|
340
340
|
);
|
|
341
341
|
const pkExists = Array.isArray(pkResult.recordset) && pkResult.recordset.length > 0;
|
|
342
342
|
if (!pkExists) {
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
343
|
+
const duplicateInfo = await this.checkForDuplicateSpans();
|
|
344
|
+
if (duplicateInfo.hasDuplicates) {
|
|
345
|
+
const errorMessage = `
|
|
346
|
+
===========================================================================
|
|
347
|
+
MIGRATION REQUIRED: Duplicate spans detected in ${duplicateInfo.tableName}
|
|
348
|
+
===========================================================================
|
|
349
|
+
|
|
350
|
+
Found ${duplicateInfo.duplicateCount} duplicate (traceId, spanId) combinations.
|
|
351
|
+
|
|
352
|
+
The spans table requires a unique constraint on (traceId, spanId), but your
|
|
353
|
+
database contains duplicate entries that must be resolved first.
|
|
354
|
+
|
|
355
|
+
To fix this, run the manual migration command:
|
|
356
|
+
|
|
357
|
+
npx mastra migrate
|
|
358
|
+
|
|
359
|
+
This command will:
|
|
360
|
+
1. Remove duplicate spans (keeping the most complete/recent version)
|
|
361
|
+
2. Add the required unique constraint
|
|
362
|
+
|
|
363
|
+
Note: This migration may take some time for large tables.
|
|
364
|
+
===========================================================================
|
|
365
|
+
`;
|
|
366
|
+
throw new error.MastraError({
|
|
367
|
+
id: storage.createStorageErrorId("MSSQL", "MIGRATION_REQUIRED", "DUPLICATE_SPANS"),
|
|
368
|
+
domain: error.ErrorDomain.STORAGE,
|
|
369
|
+
category: error.ErrorCategory.USER,
|
|
370
|
+
text: errorMessage
|
|
371
|
+
});
|
|
372
|
+
} else {
|
|
373
|
+
try {
|
|
374
|
+
const addPkSql = `ALTER TABLE ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} ADD CONSTRAINT [${pkConstraintName}] PRIMARY KEY ([traceId], [spanId])`;
|
|
375
|
+
await this.pool.request().query(addPkSql);
|
|
376
|
+
} catch (pkError) {
|
|
377
|
+
this.logger?.warn?.(`Failed to add composite primary key to spans table:`, pkError);
|
|
378
|
+
}
|
|
348
379
|
}
|
|
349
380
|
}
|
|
350
381
|
}
|
|
351
382
|
} catch (error$1) {
|
|
383
|
+
if (error$1 instanceof error.MastraError) {
|
|
384
|
+
throw error$1;
|
|
385
|
+
}
|
|
352
386
|
throw new error.MastraError(
|
|
353
387
|
{
|
|
354
388
|
id: storage.createStorageErrorId("MSSQL", "CREATE_TABLE", "FAILED"),
|
|
@@ -390,6 +424,154 @@ ${columns}
|
|
|
390
424
|
this.logger?.warn?.(`Failed to migrate spans table ${fullTableName}:`, error);
|
|
391
425
|
}
|
|
392
426
|
}
|
|
427
|
+
/**
|
|
428
|
+
* Deduplicates spans with the same (traceId, spanId) combination.
|
|
429
|
+
* This is needed for databases that existed before the unique constraint was added.
|
|
430
|
+
*
|
|
431
|
+
* Priority for keeping spans:
|
|
432
|
+
* 1. Completed spans (endedAt IS NOT NULL) over incomplete spans
|
|
433
|
+
* 2. Most recent updatedAt
|
|
434
|
+
* 3. Most recent createdAt (as tiebreaker)
|
|
435
|
+
*
|
|
436
|
+
* Note: This prioritizes migration completion over perfect data preservation.
|
|
437
|
+
* Old trace data may be lost, which is acceptable for this use case.
|
|
438
|
+
*/
|
|
439
|
+
async deduplicateSpans() {
|
|
440
|
+
const fullTableName = getTableName({ indexName: storage.TABLE_SPANS, schemaName: getSchemaName(this.schemaName) });
|
|
441
|
+
try {
|
|
442
|
+
const duplicateCheck = await this.pool.request().query(`
|
|
443
|
+
SELECT TOP 1 1 as has_duplicates
|
|
444
|
+
FROM ${fullTableName}
|
|
445
|
+
GROUP BY [traceId], [spanId]
|
|
446
|
+
HAVING COUNT(*) > 1
|
|
447
|
+
`);
|
|
448
|
+
if (!duplicateCheck.recordset || duplicateCheck.recordset.length === 0) {
|
|
449
|
+
this.logger?.debug?.(`No duplicate spans found in ${fullTableName}`);
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
this.logger?.info?.(`Duplicate spans detected in ${fullTableName}, starting deduplication...`);
|
|
453
|
+
const result = await this.pool.request().query(`
|
|
454
|
+
WITH RankedSpans AS (
|
|
455
|
+
SELECT *, ROW_NUMBER() OVER (
|
|
456
|
+
PARTITION BY [traceId], [spanId]
|
|
457
|
+
ORDER BY
|
|
458
|
+
CASE WHEN [endedAt] IS NOT NULL THEN 0 ELSE 1 END,
|
|
459
|
+
[updatedAt] DESC,
|
|
460
|
+
[createdAt] DESC
|
|
461
|
+
) as rn
|
|
462
|
+
FROM ${fullTableName}
|
|
463
|
+
)
|
|
464
|
+
DELETE FROM RankedSpans WHERE rn > 1
|
|
465
|
+
`);
|
|
466
|
+
this.logger?.info?.(
|
|
467
|
+
`Deduplication complete: removed ${result.rowsAffected?.[0] ?? 0} duplicate spans from ${fullTableName}`
|
|
468
|
+
);
|
|
469
|
+
} catch (error) {
|
|
470
|
+
this.logger?.warn?.("Failed to deduplicate spans:", error);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* Checks for duplicate (traceId, spanId) combinations in the spans table.
|
|
475
|
+
* Returns information about duplicates for logging/CLI purposes.
|
|
476
|
+
*/
|
|
477
|
+
async checkForDuplicateSpans() {
|
|
478
|
+
const fullTableName = getTableName({ indexName: storage.TABLE_SPANS, schemaName: getSchemaName(this.schemaName) });
|
|
479
|
+
try {
|
|
480
|
+
const result = await this.pool.request().query(`
|
|
481
|
+
SELECT COUNT(*) as duplicate_count
|
|
482
|
+
FROM (
|
|
483
|
+
SELECT [traceId], [spanId]
|
|
484
|
+
FROM ${fullTableName}
|
|
485
|
+
GROUP BY [traceId], [spanId]
|
|
486
|
+
HAVING COUNT(*) > 1
|
|
487
|
+
) duplicates
|
|
488
|
+
`);
|
|
489
|
+
const duplicateCount = result.recordset?.[0]?.duplicate_count ?? 0;
|
|
490
|
+
return {
|
|
491
|
+
hasDuplicates: duplicateCount > 0,
|
|
492
|
+
duplicateCount,
|
|
493
|
+
tableName: fullTableName
|
|
494
|
+
};
|
|
495
|
+
} catch (error) {
|
|
496
|
+
this.logger?.debug?.(`Could not check for duplicates: ${error}`);
|
|
497
|
+
return { hasDuplicates: false, duplicateCount: 0, tableName: fullTableName };
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
/**
|
|
501
|
+
* Checks if the PRIMARY KEY constraint on (traceId, spanId) already exists on the spans table.
|
|
502
|
+
*/
|
|
503
|
+
async spansPrimaryKeyExists() {
|
|
504
|
+
const schemaPrefix = this.schemaName ? `${utils.parseSqlIdentifier(this.schemaName, "schema name")}_` : "";
|
|
505
|
+
const pkConstraintName = `${schemaPrefix}mastra_ai_spans_traceid_spanid_pk`;
|
|
506
|
+
const checkPkRequest = this.pool.request();
|
|
507
|
+
checkPkRequest.input("constraintName", pkConstraintName);
|
|
508
|
+
const pkResult = await checkPkRequest.query(
|
|
509
|
+
`SELECT 1 AS found FROM sys.key_constraints WHERE name = @constraintName`
|
|
510
|
+
);
|
|
511
|
+
return Array.isArray(pkResult.recordset) && pkResult.recordset.length > 0;
|
|
512
|
+
}
|
|
513
|
+
/**
|
|
514
|
+
* Manually run the spans migration to deduplicate and add the unique constraint.
|
|
515
|
+
* This is intended to be called from the CLI when duplicates are detected.
|
|
516
|
+
*
|
|
517
|
+
* @returns Migration result with status and details
|
|
518
|
+
*/
|
|
519
|
+
async migrateSpans() {
|
|
520
|
+
const fullTableName = getTableName({ indexName: storage.TABLE_SPANS, schemaName: getSchemaName(this.schemaName) });
|
|
521
|
+
const pkExists = await this.spansPrimaryKeyExists();
|
|
522
|
+
if (pkExists) {
|
|
523
|
+
return {
|
|
524
|
+
success: true,
|
|
525
|
+
alreadyMigrated: true,
|
|
526
|
+
duplicatesRemoved: 0,
|
|
527
|
+
message: `Migration already complete. PRIMARY KEY constraint exists on ${fullTableName}.`
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
const duplicateInfo = await this.checkForDuplicateSpans();
|
|
531
|
+
if (duplicateInfo.hasDuplicates) {
|
|
532
|
+
this.logger?.info?.(
|
|
533
|
+
`Found ${duplicateInfo.duplicateCount} duplicate (traceId, spanId) combinations. Starting deduplication...`
|
|
534
|
+
);
|
|
535
|
+
await this.deduplicateSpans();
|
|
536
|
+
} else {
|
|
537
|
+
this.logger?.info?.(`No duplicate spans found.`);
|
|
538
|
+
}
|
|
539
|
+
const schemaPrefix = this.schemaName ? `${utils.parseSqlIdentifier(this.schemaName, "schema name")}_` : "";
|
|
540
|
+
const pkConstraintName = `${schemaPrefix}mastra_ai_spans_traceid_spanid_pk`;
|
|
541
|
+
const addPkSql = `ALTER TABLE ${fullTableName} ADD CONSTRAINT [${pkConstraintName}] PRIMARY KEY ([traceId], [spanId])`;
|
|
542
|
+
await this.pool.request().query(addPkSql);
|
|
543
|
+
return {
|
|
544
|
+
success: true,
|
|
545
|
+
alreadyMigrated: false,
|
|
546
|
+
duplicatesRemoved: duplicateInfo.duplicateCount,
|
|
547
|
+
message: duplicateInfo.hasDuplicates ? `Migration complete. Removed duplicates and added PRIMARY KEY constraint to ${fullTableName}.` : `Migration complete. Added PRIMARY KEY constraint to ${fullTableName}.`
|
|
548
|
+
};
|
|
549
|
+
}
|
|
550
|
+
/**
|
|
551
|
+
* Check migration status for the spans table.
|
|
552
|
+
* Returns information about whether migration is needed.
|
|
553
|
+
*/
|
|
554
|
+
async checkSpansMigrationStatus() {
|
|
555
|
+
const fullTableName = getTableName({ indexName: storage.TABLE_SPANS, schemaName: getSchemaName(this.schemaName) });
|
|
556
|
+
const pkExists = await this.spansPrimaryKeyExists();
|
|
557
|
+
if (pkExists) {
|
|
558
|
+
return {
|
|
559
|
+
needsMigration: false,
|
|
560
|
+
hasDuplicates: false,
|
|
561
|
+
duplicateCount: 0,
|
|
562
|
+
constraintExists: true,
|
|
563
|
+
tableName: fullTableName
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
const duplicateInfo = await this.checkForDuplicateSpans();
|
|
567
|
+
return {
|
|
568
|
+
needsMigration: true,
|
|
569
|
+
hasDuplicates: duplicateInfo.hasDuplicates,
|
|
570
|
+
duplicateCount: duplicateInfo.duplicateCount,
|
|
571
|
+
constraintExists: false,
|
|
572
|
+
tableName: fullTableName
|
|
573
|
+
};
|
|
574
|
+
}
|
|
393
575
|
/**
|
|
394
576
|
* Alters table schema to add columns if they don't exist
|
|
395
577
|
* @param tableName Name of the table
|
|
@@ -1016,10 +1198,12 @@ function getTableName2({ indexName, schemaName }) {
|
|
|
1016
1198
|
function buildDateRangeFilter(dateRange, fieldName) {
|
|
1017
1199
|
const filters = {};
|
|
1018
1200
|
if (dateRange?.start) {
|
|
1019
|
-
|
|
1201
|
+
const suffix = dateRange.startExclusive ? "_gt" : "_gte";
|
|
1202
|
+
filters[`${fieldName}${suffix}`] = dateRange.start;
|
|
1020
1203
|
}
|
|
1021
1204
|
if (dateRange?.end) {
|
|
1022
|
-
|
|
1205
|
+
const suffix = dateRange.endExclusive ? "_lt" : "_lte";
|
|
1206
|
+
filters[`${fieldName}${suffix}`] = dateRange.end;
|
|
1023
1207
|
}
|
|
1024
1208
|
return filters;
|
|
1025
1209
|
}
|
|
@@ -1037,11 +1221,21 @@ function prepareWhereClause(filters, _schema) {
|
|
|
1037
1221
|
const fieldName = key.slice(0, -4);
|
|
1038
1222
|
conditions.push(`[${utils.parseSqlIdentifier(fieldName, "field name")}] >= @${paramName}`);
|
|
1039
1223
|
params[paramName] = value instanceof Date ? value.toISOString() : value;
|
|
1224
|
+
} else if (key.endsWith("_gt")) {
|
|
1225
|
+
const paramName = `p${paramIndex++}`;
|
|
1226
|
+
const fieldName = key.slice(0, -3);
|
|
1227
|
+
conditions.push(`[${utils.parseSqlIdentifier(fieldName, "field name")}] > @${paramName}`);
|
|
1228
|
+
params[paramName] = value instanceof Date ? value.toISOString() : value;
|
|
1040
1229
|
} else if (key.endsWith("_lte")) {
|
|
1041
1230
|
const paramName = `p${paramIndex++}`;
|
|
1042
1231
|
const fieldName = key.slice(0, -4);
|
|
1043
1232
|
conditions.push(`[${utils.parseSqlIdentifier(fieldName, "field name")}] <= @${paramName}`);
|
|
1044
1233
|
params[paramName] = value instanceof Date ? value.toISOString() : value;
|
|
1234
|
+
} else if (key.endsWith("_lt")) {
|
|
1235
|
+
const paramName = `p${paramIndex++}`;
|
|
1236
|
+
const fieldName = key.slice(0, -3);
|
|
1237
|
+
conditions.push(`[${utils.parseSqlIdentifier(fieldName, "field name")}] < @${paramName}`);
|
|
1238
|
+
params[paramName] = value instanceof Date ? value.toISOString() : value;
|
|
1045
1239
|
} else if (value === null) {
|
|
1046
1240
|
conditions.push(`[${utils.parseSqlIdentifier(key, "field name")}] IS NULL`);
|
|
1047
1241
|
} else if (isInOperator(value)) {
|
|
@@ -1253,28 +1447,76 @@ var MemoryMSSQL = class _MemoryMSSQL extends storage.MemoryStorage {
|
|
|
1253
1447
|
);
|
|
1254
1448
|
}
|
|
1255
1449
|
}
|
|
1256
|
-
async
|
|
1257
|
-
const {
|
|
1258
|
-
|
|
1450
|
+
async listThreads(args) {
|
|
1451
|
+
const { page = 0, perPage: perPageInput, orderBy, filter } = args;
|
|
1452
|
+
try {
|
|
1453
|
+
this.validatePaginationInput(page, perPageInput ?? 100);
|
|
1454
|
+
} catch (error$1) {
|
|
1259
1455
|
throw new error.MastraError({
|
|
1260
|
-
id: storage.createStorageErrorId("MSSQL", "
|
|
1456
|
+
id: storage.createStorageErrorId("MSSQL", "LIST_THREADS", "INVALID_PAGE"),
|
|
1261
1457
|
domain: error.ErrorDomain.STORAGE,
|
|
1262
1458
|
category: error.ErrorCategory.USER,
|
|
1263
|
-
text:
|
|
1264
|
-
details: {
|
|
1265
|
-
resourceId,
|
|
1266
|
-
page
|
|
1267
|
-
}
|
|
1459
|
+
text: error$1 instanceof Error ? error$1.message : "Invalid pagination parameters",
|
|
1460
|
+
details: { page, ...perPageInput !== void 0 && { perPage: perPageInput } }
|
|
1268
1461
|
});
|
|
1269
1462
|
}
|
|
1270
1463
|
const perPage = storage.normalizePerPage(perPageInput, 100);
|
|
1464
|
+
try {
|
|
1465
|
+
this.validateMetadataKeys(filter?.metadata);
|
|
1466
|
+
} catch (error$1) {
|
|
1467
|
+
throw new error.MastraError({
|
|
1468
|
+
id: storage.createStorageErrorId("MSSQL", "LIST_THREADS", "INVALID_METADATA_KEY"),
|
|
1469
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1470
|
+
category: error.ErrorCategory.USER,
|
|
1471
|
+
text: error$1 instanceof Error ? error$1.message : "Invalid metadata key",
|
|
1472
|
+
details: { metadataKeys: filter?.metadata ? Object.keys(filter.metadata).join(", ") : "" }
|
|
1473
|
+
});
|
|
1474
|
+
}
|
|
1271
1475
|
const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
1272
1476
|
const { field, direction } = this.parseOrderBy(orderBy);
|
|
1273
1477
|
try {
|
|
1274
|
-
const
|
|
1478
|
+
const tableName = getTableName2({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName2(this.schema) });
|
|
1479
|
+
const whereClauses = [];
|
|
1480
|
+
const params = {};
|
|
1481
|
+
if (filter?.resourceId) {
|
|
1482
|
+
whereClauses.push("[resourceId] = @resourceId");
|
|
1483
|
+
params.resourceId = filter.resourceId;
|
|
1484
|
+
}
|
|
1485
|
+
if (filter?.metadata && Object.keys(filter.metadata).length > 0) {
|
|
1486
|
+
let metadataIndex = 0;
|
|
1487
|
+
for (const [key, value] of Object.entries(filter.metadata)) {
|
|
1488
|
+
if (value !== null && typeof value === "object") {
|
|
1489
|
+
throw new error.MastraError({
|
|
1490
|
+
id: storage.createStorageErrorId("MSSQL", "LIST_THREADS", "INVALID_METADATA_VALUE"),
|
|
1491
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1492
|
+
category: error.ErrorCategory.USER,
|
|
1493
|
+
text: `Metadata filter value for key "${key}" must be a scalar type (string, number, boolean, or null), got ${Array.isArray(value) ? "array" : "object"}`,
|
|
1494
|
+
details: { key, valueType: Array.isArray(value) ? "array" : "object" }
|
|
1495
|
+
});
|
|
1496
|
+
}
|
|
1497
|
+
if (value === null) {
|
|
1498
|
+
whereClauses.push(`JSON_VALUE(metadata, '$.${key}') IS NULL`);
|
|
1499
|
+
} else {
|
|
1500
|
+
const paramName = `metadata${metadataIndex}`;
|
|
1501
|
+
whereClauses.push(`JSON_VALUE(metadata, '$.${key}') = @${paramName}`);
|
|
1502
|
+
if (typeof value === "string") {
|
|
1503
|
+
params[paramName] = value;
|
|
1504
|
+
} else if (typeof value === "boolean") {
|
|
1505
|
+
params[paramName] = value ? "true" : "false";
|
|
1506
|
+
} else {
|
|
1507
|
+
params[paramName] = String(value);
|
|
1508
|
+
}
|
|
1509
|
+
}
|
|
1510
|
+
metadataIndex++;
|
|
1511
|
+
}
|
|
1512
|
+
}
|
|
1513
|
+
const whereClause = whereClauses.length > 0 ? `WHERE ${whereClauses.join(" AND ")}` : "";
|
|
1514
|
+
const baseQuery = `FROM ${tableName} ${whereClause}`;
|
|
1275
1515
|
const countQuery = `SELECT COUNT(*) as count ${baseQuery}`;
|
|
1276
1516
|
const countRequest = this.pool.request();
|
|
1277
|
-
|
|
1517
|
+
for (const [key, value] of Object.entries(params)) {
|
|
1518
|
+
countRequest.input(key, value);
|
|
1519
|
+
}
|
|
1278
1520
|
const countResult = await countRequest.query(countQuery);
|
|
1279
1521
|
const total = parseInt(countResult.recordset[0]?.count ?? "0", 10);
|
|
1280
1522
|
if (total === 0) {
|
|
@@ -1291,7 +1533,9 @@ var MemoryMSSQL = class _MemoryMSSQL extends storage.MemoryStorage {
|
|
|
1291
1533
|
const limitValue = perPageInput === false ? total : perPage;
|
|
1292
1534
|
const dataQuery = `SELECT id, [resourceId], title, metadata, [createdAt], [updatedAt] ${baseQuery} ORDER BY ${orderByField} ${dir} OFFSET @offset ROWS FETCH NEXT @perPage ROWS ONLY`;
|
|
1293
1535
|
const dataRequest = this.pool.request();
|
|
1294
|
-
|
|
1536
|
+
for (const [key, value] of Object.entries(params)) {
|
|
1537
|
+
dataRequest.input(key, value);
|
|
1538
|
+
}
|
|
1295
1539
|
dataRequest.input("offset", offset);
|
|
1296
1540
|
if (limitValue > 2147483647) {
|
|
1297
1541
|
dataRequest.input("perPage", sql__default.default.BigInt, limitValue);
|
|
@@ -1314,13 +1558,17 @@ var MemoryMSSQL = class _MemoryMSSQL extends storage.MemoryStorage {
|
|
|
1314
1558
|
hasMore: perPageInput === false ? false : offset + perPage < total
|
|
1315
1559
|
};
|
|
1316
1560
|
} catch (error$1) {
|
|
1561
|
+
if (error$1 instanceof error.MastraError && error$1.category === error.ErrorCategory.USER) {
|
|
1562
|
+
throw error$1;
|
|
1563
|
+
}
|
|
1317
1564
|
const mastraError = new error.MastraError(
|
|
1318
1565
|
{
|
|
1319
|
-
id: storage.createStorageErrorId("MSSQL", "
|
|
1566
|
+
id: storage.createStorageErrorId("MSSQL", "LIST_THREADS", "FAILED"),
|
|
1320
1567
|
domain: error.ErrorDomain.STORAGE,
|
|
1321
1568
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1322
1569
|
details: {
|
|
1323
|
-
resourceId,
|
|
1570
|
+
...filter?.resourceId && { resourceId: filter.resourceId },
|
|
1571
|
+
hasMetadataFilter: !!filter?.metadata,
|
|
1324
1572
|
page
|
|
1325
1573
|
}
|
|
1326
1574
|
},
|
|
@@ -2202,6 +2450,22 @@ var ObservabilityMSSQL = class _ObservabilityMSSQL extends storage.Observability
|
|
|
2202
2450
|
async dangerouslyClearAll() {
|
|
2203
2451
|
await this.db.clearTable({ tableName: storage.TABLE_SPANS });
|
|
2204
2452
|
}
|
|
2453
|
+
/**
|
|
2454
|
+
* Manually run the spans migration to deduplicate and add the unique constraint.
|
|
2455
|
+
* This is intended to be called from the CLI when duplicates are detected.
|
|
2456
|
+
*
|
|
2457
|
+
* @returns Migration result with status and details
|
|
2458
|
+
*/
|
|
2459
|
+
async migrateSpans() {
|
|
2460
|
+
return this.db.migrateSpans();
|
|
2461
|
+
}
|
|
2462
|
+
/**
|
|
2463
|
+
* Check migration status for the spans table.
|
|
2464
|
+
* Returns information about whether migration is needed.
|
|
2465
|
+
*/
|
|
2466
|
+
async checkSpansMigrationStatus() {
|
|
2467
|
+
return this.db.checkSpansMigrationStatus();
|
|
2468
|
+
}
|
|
2205
2469
|
get tracingStrategy() {
|
|
2206
2470
|
return {
|
|
2207
2471
|
preferred: "batch-with-updates",
|
|
@@ -3601,7 +3865,7 @@ var WorkflowsMSSQL = class _WorkflowsMSSQL extends storage.WorkflowsStorage {
|
|
|
3601
3865
|
var isPoolConfig = (config) => {
|
|
3602
3866
|
return "pool" in config;
|
|
3603
3867
|
};
|
|
3604
|
-
var MSSQLStore = class extends storage.
|
|
3868
|
+
var MSSQLStore = class extends storage.MastraCompositeStore {
|
|
3605
3869
|
pool;
|
|
3606
3870
|
schema;
|
|
3607
3871
|
isConnected = null;
|
|
@@ -3672,6 +3936,9 @@ var MSSQLStore = class extends storage.MastraStorage {
|
|
|
3672
3936
|
await super.init();
|
|
3673
3937
|
} catch (error$1) {
|
|
3674
3938
|
this.isConnected = null;
|
|
3939
|
+
if (error$1 instanceof error.MastraError) {
|
|
3940
|
+
throw error$1;
|
|
3941
|
+
}
|
|
3675
3942
|
throw new error.MastraError(
|
|
3676
3943
|
{
|
|
3677
3944
|
id: storage.createStorageErrorId("MSSQL", "INIT", "FAILED"),
|
|
@@ -3690,19 +3957,6 @@ var MSSQLStore = class extends storage.MastraStorage {
|
|
|
3690
3957
|
throw err;
|
|
3691
3958
|
}
|
|
3692
3959
|
}
|
|
3693
|
-
get supports() {
|
|
3694
|
-
return {
|
|
3695
|
-
selectByIncludeResourceScope: true,
|
|
3696
|
-
resourceWorkingMemory: true,
|
|
3697
|
-
hasColumn: true,
|
|
3698
|
-
createTable: true,
|
|
3699
|
-
deleteMessages: true,
|
|
3700
|
-
observability: true,
|
|
3701
|
-
indexManagement: true,
|
|
3702
|
-
listScoresBySpan: true,
|
|
3703
|
-
agents: false
|
|
3704
|
-
};
|
|
3705
|
-
}
|
|
3706
3960
|
/**
|
|
3707
3961
|
* Closes the MSSQL connection pool.
|
|
3708
3962
|
*
|
|
@@ -3714,5 +3968,9 @@ var MSSQLStore = class extends storage.MastraStorage {
|
|
|
3714
3968
|
};
|
|
3715
3969
|
|
|
3716
3970
|
exports.MSSQLStore = MSSQLStore;
|
|
3971
|
+
exports.MemoryMSSQL = MemoryMSSQL;
|
|
3972
|
+
exports.ObservabilityMSSQL = ObservabilityMSSQL;
|
|
3973
|
+
exports.ScoresMSSQL = ScoresMSSQL;
|
|
3974
|
+
exports.WorkflowsMSSQL = WorkflowsMSSQL;
|
|
3717
3975
|
//# sourceMappingURL=index.cjs.map
|
|
3718
3976
|
//# sourceMappingURL=index.cjs.map
|