@mastra/mssql 1.0.0-beta.0 → 1.0.0-beta.2

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 CHANGED
@@ -1,5 +1,30 @@
1
1
  # @mastra/mssql
2
2
 
3
+ ## 1.0.0-beta.2
4
+
5
+ ### Patch Changes
6
+
7
+ - Add restart method to workflow run that allows restarting an active workflow run ([#9750](https://github.com/mastra-ai/mastra/pull/9750))
8
+ Add status filter to `listWorkflowRuns`
9
+ Add automatic restart to restart active workflow runs when server starts
10
+ - Updated dependencies [[`2319326`](https://github.com/mastra-ai/mastra/commit/2319326f8c64e503a09bbcf14be2dd65405445e0), [`d629361`](https://github.com/mastra-ai/mastra/commit/d629361a60f6565b5bfb11976fdaf7308af858e2), [`08c31c1`](https://github.com/mastra-ai/mastra/commit/08c31c188ebccd598acaf55e888b6397d01f7eae), [`fd3d338`](https://github.com/mastra-ai/mastra/commit/fd3d338a2c362174ed5b383f1f011ad9fb0302aa), [`c30400a`](https://github.com/mastra-ai/mastra/commit/c30400a49b994b1b97256fe785eb6c906fc2b232), [`69e0a87`](https://github.com/mastra-ai/mastra/commit/69e0a878896a2da9494945d86e056a5f8f05b851), [`01f8878`](https://github.com/mastra-ai/mastra/commit/01f88783de25e4de048c1c8aace43e26373c6ea5), [`4c77209`](https://github.com/mastra-ai/mastra/commit/4c77209e6c11678808b365d545845918c40045c8), [`d827d08`](https://github.com/mastra-ai/mastra/commit/d827d0808ffe1f3553a84e975806cc989b9735dd), [`23c10a1`](https://github.com/mastra-ai/mastra/commit/23c10a1efdd9a693c405511ab2dc8a1236603162), [`676ccc7`](https://github.com/mastra-ai/mastra/commit/676ccc7fe92468d2d45d39c31a87825c89fd1ea0), [`c10398d`](https://github.com/mastra-ai/mastra/commit/c10398d5b88f1d4af556f4267ff06f1d11e89179), [`00c2387`](https://github.com/mastra-ai/mastra/commit/00c2387f5f04a365316f851e58666ac43f8c4edf), [`ad6250d`](https://github.com/mastra-ai/mastra/commit/ad6250dbdaad927e29f74a27b83f6c468b50a705), [`3a73998`](https://github.com/mastra-ai/mastra/commit/3a73998fa4ebeb7f3dc9301afe78095fc63e7999), [`e16d553`](https://github.com/mastra-ai/mastra/commit/e16d55338403c7553531cc568125c63d53653dff), [`4d59f58`](https://github.com/mastra-ai/mastra/commit/4d59f58de2d90d6e2810a19d4518e38ddddb9038), [`e1bb9c9`](https://github.com/mastra-ai/mastra/commit/e1bb9c94b4eb68b019ae275981be3feb769b5365), [`351a11f`](https://github.com/mastra-ai/mastra/commit/351a11fcaf2ed1008977fa9b9a489fc422e51cd4)]:
11
+ - @mastra/core@1.0.0-beta.3
12
+
13
+ ## 1.0.0-beta.1
14
+
15
+ ### Patch Changes
16
+
17
+ - Fixes MSSQL store test configuration and pagination issues: ([#9905](https://github.com/mastra-ai/mastra/pull/9905))
18
+
19
+ Adds missing id parameter to test configuration and updates documentation
20
+ Implements page validation to handle negative page numbers
21
+ Fixes sorting and pagination bugs in message listing (improves ORDER BY with seq_id secondary sort and corrects hasMore calculation)
22
+
23
+ - Prevents double stringification for MSSQL jsonb columns by reusing incoming strings that already contain valid JSON while still stringifying other inputs as needed. ([#9901](https://github.com/mastra-ai/mastra/pull/9901))
24
+
25
+ - Updated dependencies [[`465ac05`](https://github.com/mastra-ai/mastra/commit/465ac0526a91d175542091c675181f1a96c98c46)]:
26
+ - @mastra/core@1.0.0-beta.2
27
+
3
28
  ## 1.0.0-beta.0
4
29
 
5
30
  ### Major Changes
package/README.md CHANGED
@@ -27,6 +27,7 @@ MSSQLStore supports multiple connection methods:
27
27
  import { MSSQLStore } from '@mastra/mssql';
28
28
 
29
29
  const store = new MSSQLStore({
30
+ id: 'mssql-storage',
30
31
  connectionString:
31
32
  'Server=localhost,1433;Database=mastra;User Id=sa;Password=yourPassword;Encrypt=true;TrustServerCertificate=true',
32
33
  });
@@ -36,6 +37,7 @@ const store = new MSSQLStore({
36
37
 
37
38
  ```typescript
38
39
  const store = new MSSQLStore({
40
+ id: 'mssql-storage',
39
41
  server: 'localhost',
40
42
  port: 1433,
41
43
  database: 'mastra',
@@ -49,6 +51,7 @@ const store = new MSSQLStore({
49
51
 
50
52
  ```typescript
51
53
  const store = new MSSQLStore({
54
+ id: 'mssql-storage',
52
55
  connectionString:
53
56
  'Server=localhost,1433;Database=mastra;User Id=sa;Password=yourPassword;Encrypt=true;TrustServerCertificate=true',
54
57
  schemaName: 'custom_schema', // Use custom schema (default: dbo)
@@ -103,6 +106,10 @@ const messages = await store.listMessages({ threadId: 'thread-123' });
103
106
 
104
107
  ## Configuration
105
108
 
109
+ ### Identifier
110
+
111
+ - `id`: Unique identifier for this store instance (required)
112
+
106
113
  ### Connection Methods
107
114
 
108
115
  MSSQLStore supports multiple connection methods:
@@ -111,6 +118,7 @@ MSSQLStore supports multiple connection methods:
111
118
 
112
119
  ```typescript
113
120
  {
121
+ id: 'mssql-storage',
114
122
  connectionString: 'Server=localhost,1433;Database=mastra;User Id=sa;Password=yourPassword;Encrypt=true;TrustServerCertificate=true';
115
123
  }
116
124
  ```
@@ -118,6 +126,7 @@ MSSQLStore supports multiple connection methods:
118
126
  2. **Server/Port/Database**
119
127
  ```typescript
120
128
  {
129
+ id: 'mssql-storage',
121
130
  server: 'localhost',
122
131
  port: 1433,
123
132
  database: 'mastra',
package/dist/index.cjs CHANGED
@@ -156,6 +156,18 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
156
156
  }
157
157
  async listThreadsByResourceId(args) {
158
158
  const { resourceId, page = 0, perPage: perPageInput, orderBy } = args;
159
+ if (page < 0) {
160
+ throw new error.MastraError({
161
+ id: "MASTRA_STORAGE_MSSQL_STORE_INVALID_PAGE",
162
+ domain: error.ErrorDomain.STORAGE,
163
+ category: error.ErrorCategory.USER,
164
+ text: "Page number must be non-negative",
165
+ details: {
166
+ resourceId,
167
+ page
168
+ }
169
+ });
170
+ }
159
171
  const perPage = storage.normalizePerPage(perPageInput, 100);
160
172
  const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
161
173
  const { field, direction } = this.parseOrderBy(orderBy);
@@ -511,43 +523,59 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
511
523
  new Error("threadId must be a non-empty string")
512
524
  );
513
525
  }
526
+ if (page < 0) {
527
+ throw new error.MastraError({
528
+ id: "MASTRA_STORAGE_MSSQL_STORE_INVALID_PAGE",
529
+ domain: error.ErrorDomain.STORAGE,
530
+ category: error.ErrorCategory.USER,
531
+ text: "Page number must be non-negative",
532
+ details: {
533
+ threadId,
534
+ page
535
+ }
536
+ });
537
+ }
514
538
  const perPage = storage.normalizePerPage(perPageInput, 40);
515
539
  const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
516
540
  try {
517
541
  const { field, direction } = this.parseOrderBy(orderBy, "ASC");
518
- const orderByStatement = `ORDER BY [${field}] ${direction}`;
519
- const selectStatement = `SELECT seq_id, id, content, role, type, [createdAt], thread_id AS threadId, resourceId`;
542
+ const orderByStatement = `ORDER BY [${field}] ${direction}, [seq_id] ${direction}`;
520
543
  const tableName = getTableName({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName(this.schema) });
521
- const conditions = ["[thread_id] = @threadId"];
522
- const request = this.pool.request();
523
- request.input("threadId", threadId);
524
- if (resourceId) {
525
- conditions.push("[resourceId] = @resourceId");
526
- request.input("resourceId", resourceId);
527
- }
528
- if (filter?.dateRange?.start) {
529
- conditions.push("[createdAt] >= @fromDate");
530
- request.input("fromDate", filter.dateRange.start);
531
- }
532
- if (filter?.dateRange?.end) {
533
- conditions.push("[createdAt] <= @toDate");
534
- request.input("toDate", filter.dateRange.end);
535
- }
536
- const whereClause = `WHERE ${conditions.join(" AND ")}`;
537
- const countQuery = `SELECT COUNT(*) as total FROM ${tableName} ${whereClause}`;
538
- const countResult = await request.query(countQuery);
544
+ const baseQuery = `SELECT seq_id, id, content, role, type, [createdAt], thread_id AS threadId, resourceId FROM ${tableName}`;
545
+ const filters = {
546
+ thread_id: threadId,
547
+ ...resourceId ? { resourceId } : {},
548
+ ...buildDateRangeFilter(filter?.dateRange, "createdAt")
549
+ };
550
+ const { sql: actualWhereClause = "", params: whereParams } = prepareWhereClause(
551
+ filters);
552
+ const bindWhereParams = (req) => {
553
+ Object.entries(whereParams).forEach(([paramName, paramValue]) => req.input(paramName, paramValue));
554
+ };
555
+ const countRequest = this.pool.request();
556
+ bindWhereParams(countRequest);
557
+ const countResult = await countRequest.query(`SELECT COUNT(*) as total FROM ${tableName}${actualWhereClause}`);
539
558
  const total = parseInt(countResult.recordset[0]?.total, 10) || 0;
540
- const limitValue = perPageInput === false ? total : perPage;
541
- const dataQuery = `${selectStatement} FROM ${tableName} ${whereClause} ${orderByStatement} OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY`;
542
- request.input("offset", offset);
543
- if (limitValue > 2147483647) {
544
- request.input("limit", sql2__default.default.BigInt, limitValue);
545
- } else {
546
- request.input("limit", limitValue);
547
- }
548
- const rowsResult = await request.query(dataQuery);
549
- const rows = rowsResult.recordset || [];
550
- const messages = [...rows];
559
+ const fetchBaseMessages = async () => {
560
+ const request = this.pool.request();
561
+ bindWhereParams(request);
562
+ if (perPageInput === false) {
563
+ const result2 = await request.query(`${baseQuery}${actualWhereClause} ${orderByStatement}`);
564
+ return result2.recordset || [];
565
+ }
566
+ request.input("offset", offset);
567
+ request.input("limit", perPage > 2147483647 ? sql2__default.default.BigInt : sql2__default.default.Int, perPage);
568
+ const result = await request.query(
569
+ `${baseQuery}${actualWhereClause} ${orderByStatement} OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY`
570
+ );
571
+ return result.recordset || [];
572
+ };
573
+ const baseRows = perPage === 0 ? [] : await fetchBaseMessages();
574
+ const messages = [...baseRows];
575
+ const seqById = /* @__PURE__ */ new Map();
576
+ messages.forEach((msg) => {
577
+ if (typeof msg.seq_id === "number") seqById.set(msg.id, msg.seq_id);
578
+ });
551
579
  if (total === 0 && messages.length === 0 && (!include || include.length === 0)) {
552
580
  return {
553
581
  messages: [],
@@ -557,28 +585,33 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
557
585
  hasMore: false
558
586
  };
559
587
  }
560
- const messageIds = new Set(messages.map((m) => m.id));
561
- if (include && include.length > 0) {
588
+ if (include?.length) {
589
+ const messageIds = new Set(messages.map((m) => m.id));
562
590
  const includeMessages = await this._getIncludedMessages({ threadId, include });
563
- if (includeMessages) {
564
- for (const includeMsg of includeMessages) {
565
- if (!messageIds.has(includeMsg.id)) {
566
- messages.push(includeMsg);
567
- messageIds.add(includeMsg.id);
568
- }
591
+ includeMessages?.forEach((msg) => {
592
+ if (!messageIds.has(msg.id)) {
593
+ messages.push(msg);
594
+ messageIds.add(msg.id);
595
+ if (typeof msg.seq_id === "number") seqById.set(msg.id, msg.seq_id);
569
596
  }
570
- }
597
+ });
571
598
  }
572
599
  const parsed = this._parseAndFormatMessages(messages, "v2");
573
- let finalMessages = parsed;
574
- finalMessages = finalMessages.sort((a, b) => {
575
- const aValue = field === "createdAt" ? new Date(a.createdAt).getTime() : a[field];
576
- const bValue = field === "createdAt" ? new Date(b.createdAt).getTime() : b[field];
577
- return direction === "ASC" ? aValue - bValue : bValue - aValue;
600
+ const mult = direction === "ASC" ? 1 : -1;
601
+ const finalMessages = parsed.sort((a, b) => {
602
+ const aVal = field === "createdAt" ? new Date(a.createdAt).getTime() : a[field];
603
+ const bVal = field === "createdAt" ? new Date(b.createdAt).getTime() : b[field];
604
+ if (aVal == null || bVal == null) {
605
+ return aVal == null && bVal == null ? a.id.localeCompare(b.id) : aVal == null ? 1 : -1;
606
+ }
607
+ const diff = (typeof aVal === "number" && typeof bVal === "number" ? aVal - bVal : String(aVal).localeCompare(String(bVal))) * mult;
608
+ if (diff !== 0) return diff;
609
+ const seqA = seqById.get(a.id);
610
+ const seqB = seqById.get(b.id);
611
+ return seqA != null && seqB != null ? (seqA - seqB) * mult : a.id.localeCompare(b.id);
578
612
  });
579
- const returnedThreadMessageIds = new Set(finalMessages.filter((m) => m.threadId === threadId).map((m) => m.id));
580
- const allThreadMessagesReturned = returnedThreadMessageIds.size >= total;
581
- const hasMore = perPageInput !== false && !allThreadMessagesReturned && offset + perPage < total;
613
+ const returnedThreadMessageCount = finalMessages.filter((m) => m.threadId === threadId).length;
614
+ const hasMore = perPageInput !== false && returnedThreadMessageCount < total && offset + perPage < total;
582
615
  return {
583
616
  messages: finalMessages,
584
617
  total,
@@ -1685,6 +1718,20 @@ ${columns}
1685
1718
  return value ? 1 : 0;
1686
1719
  }
1687
1720
  if (columnSchema?.type === "jsonb") {
1721
+ if (typeof value === "string") {
1722
+ const trimmed = value.trim();
1723
+ if (trimmed.length > 0) {
1724
+ try {
1725
+ JSON.parse(trimmed);
1726
+ return trimmed;
1727
+ } catch {
1728
+ }
1729
+ }
1730
+ return JSON.stringify(value);
1731
+ }
1732
+ if (typeof value === "bigint") {
1733
+ return value.toString();
1734
+ }
1688
1735
  return JSON.stringify(value);
1689
1736
  }
1690
1737
  if (typeof value === "object") {
@@ -2630,13 +2677,14 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
2630
2677
  snapshot = {
2631
2678
  context: {},
2632
2679
  activePaths: [],
2680
+ activeStepsPath: {},
2633
2681
  timestamp: Date.now(),
2634
2682
  suspendedPaths: {},
2635
2683
  resumeLabels: {},
2636
2684
  serializedStepGraph: [],
2685
+ status: "pending",
2637
2686
  value: {},
2638
2687
  waitingPaths: {},
2639
- status: "pending",
2640
2688
  runId,
2641
2689
  requestContext: {}
2642
2690
  };
@@ -2866,7 +2914,8 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
2866
2914
  toDate,
2867
2915
  page,
2868
2916
  perPage,
2869
- resourceId
2917
+ resourceId,
2918
+ status
2870
2919
  } = {}) {
2871
2920
  try {
2872
2921
  const conditions = [];
@@ -2875,6 +2924,10 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
2875
2924
  conditions.push(`[workflow_name] = @workflowName`);
2876
2925
  paramMap["workflowName"] = workflowName;
2877
2926
  }
2927
+ if (status) {
2928
+ conditions.push(`JSON_VALUE([snapshot], '$.status') = @status`);
2929
+ paramMap["status"] = status;
2930
+ }
2878
2931
  if (resourceId) {
2879
2932
  const hasResourceId = await this.operations.hasColumn(storage.TABLE_WORKFLOW_SNAPSHOT, "resourceId");
2880
2933
  if (hasResourceId) {
@@ -3143,15 +3196,8 @@ var MSSQLStore = class extends storage.MastraStorage {
3143
3196
  }) {
3144
3197
  return this.stores.workflows.loadWorkflowSnapshot({ workflowName, runId });
3145
3198
  }
3146
- async listWorkflowRuns({
3147
- workflowName,
3148
- fromDate,
3149
- toDate,
3150
- perPage,
3151
- page,
3152
- resourceId
3153
- } = {}) {
3154
- return this.stores.workflows.listWorkflowRuns({ workflowName, fromDate, toDate, perPage, page, resourceId });
3199
+ async listWorkflowRuns(args = {}) {
3200
+ return this.stores.workflows.listWorkflowRuns(args);
3155
3201
  }
3156
3202
  async getWorkflowRunById({
3157
3203
  runId,