@mastra/mongodb 0.0.0-vnextAgentNetwork-20250602134426 → 0.0.0-workflow-deno-20250616130925
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/.turbo/turbo-build.log +23 -0
- package/CHANGELOG.md +112 -2
- package/dist/_tsup-dts-rollup.d.cts +34 -1
- package/dist/_tsup-dts-rollup.d.ts +34 -1
- package/dist/index.cjs +32 -4
- package/dist/index.js +32 -4
- package/package.json +13 -12
- package/src/storage/index.test.ts +258 -17
- package/src/storage/index.ts +64 -5
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
|
|
2
|
+
> @mastra/mongodb@0.11.0-alpha.1 build /home/runner/work/mastra/mastra/stores/mongodb
|
|
3
|
+
> tsup src/index.ts --format esm,cjs --experimental-dts --clean --treeshake=smallest --splitting
|
|
4
|
+
|
|
5
|
+
[34mCLI[39m Building entry: src/index.ts
|
|
6
|
+
[34mCLI[39m Using tsconfig: tsconfig.json
|
|
7
|
+
[34mCLI[39m tsup v8.5.0
|
|
8
|
+
[34mTSC[39m Build start
|
|
9
|
+
[32mTSC[39m ⚡️ Build success in 9462ms
|
|
10
|
+
[34mDTS[39m Build start
|
|
11
|
+
[34mCLI[39m Target: es2022
|
|
12
|
+
Analysis will use the bundled TypeScript version 5.8.3
|
|
13
|
+
[36mWriting package typings: /home/runner/work/mastra/mastra/stores/mongodb/dist/_tsup-dts-rollup.d.ts[39m
|
|
14
|
+
Analysis will use the bundled TypeScript version 5.8.3
|
|
15
|
+
[36mWriting package typings: /home/runner/work/mastra/mastra/stores/mongodb/dist/_tsup-dts-rollup.d.cts[39m
|
|
16
|
+
[32mDTS[39m ⚡️ Build success in 11575ms
|
|
17
|
+
[34mCLI[39m Cleaning output folder
|
|
18
|
+
[34mESM[39m Build start
|
|
19
|
+
[34mCJS[39m Build start
|
|
20
|
+
[32mESM[39m [1mdist/index.js [22m[32m33.93 KB[39m
|
|
21
|
+
[32mESM[39m ⚡️ Build success in 1213ms
|
|
22
|
+
[32mCJS[39m [1mdist/index.cjs [22m[32m34.07 KB[39m
|
|
23
|
+
[32mCJS[39m ⚡️ Build success in 1213ms
|
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,109 @@
|
|
|
1
1
|
# @mastra/mongodb
|
|
2
2
|
|
|
3
|
-
## 0.0.0-
|
|
3
|
+
## 0.0.0-workflow-deno-20250616130925
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 704d1ca: Thread Timestamp Auto-Update Enhancement
|
|
8
|
+
Added automatic thread updatedAt timestamp updates when messages are saved across all storage providers
|
|
9
|
+
Enhanced user experience: Threads now accurately reflect their latest activity with automatic timestamp updates when new messages are added
|
|
10
|
+
Universal implementation: Consistent behavior across all 7 storage backends (ClickHouse, Cloudflare D1, DynamoDB, MongoDB, PostgreSQL, Upstash, LibSQL)
|
|
11
|
+
Performance optimized: Updates execute in parallel with message saving operations for minimal performance impact
|
|
12
|
+
Backwards compatible: No breaking changes - existing code continues to work unchanged
|
|
13
|
+
Improved conversation ordering: Chat interfaces can now properly sort threads by actual last activity
|
|
14
|
+
This enhancement resolves the issue where active conversations appeared stale due to outdated thread timestamps, providing better conversation management and user experience in chat applications.
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- 63f6b7d: dependencies updates:
|
|
19
|
+
- Updated dependency [`cloudflare@^4.3.0` ↗︎](https://www.npmjs.com/package/cloudflare/v/4.3.0) (from `^4.1.0`, in `dependencies`)
|
|
20
|
+
- Updated dependency [`mongodb@^6.17.0` ↗︎](https://www.npmjs.com/package/mongodb/v/6.17.0) (from `^6.15.0`, in `dependencies`)
|
|
21
|
+
- Updated dependencies [63f6b7d]
|
|
22
|
+
- Updated dependencies [ee9af57]
|
|
23
|
+
- Updated dependencies [36f1c36]
|
|
24
|
+
- Updated dependencies [10d352e]
|
|
25
|
+
- Updated dependencies [3ca9a67]
|
|
26
|
+
- Updated dependencies [53d3c37]
|
|
27
|
+
- Updated dependencies [577ce3a]
|
|
28
|
+
- Updated dependencies [9260b3a]
|
|
29
|
+
- @mastra/core@0.0.0-workflow-deno-20250616130925
|
|
30
|
+
|
|
31
|
+
## 0.11.0-alpha.1
|
|
32
|
+
|
|
33
|
+
### Minor Changes
|
|
34
|
+
|
|
35
|
+
- 704d1ca: Thread Timestamp Auto-Update Enhancement
|
|
36
|
+
Added automatic thread updatedAt timestamp updates when messages are saved across all storage providers
|
|
37
|
+
Enhanced user experience: Threads now accurately reflect their latest activity with automatic timestamp updates when new messages are added
|
|
38
|
+
Universal implementation: Consistent behavior across all 7 storage backends (ClickHouse, Cloudflare D1, DynamoDB, MongoDB, PostgreSQL, Upstash, LibSQL)
|
|
39
|
+
Performance optimized: Updates execute in parallel with message saving operations for minimal performance impact
|
|
40
|
+
Backwards compatible: No breaking changes - existing code continues to work unchanged
|
|
41
|
+
Improved conversation ordering: Chat interfaces can now properly sort threads by actual last activity
|
|
42
|
+
This enhancement resolves the issue where active conversations appeared stale due to outdated thread timestamps, providing better conversation management and user experience in chat applications.
|
|
43
|
+
|
|
44
|
+
## 0.10.4-alpha.0
|
|
45
|
+
|
|
46
|
+
### Patch Changes
|
|
47
|
+
|
|
48
|
+
- 63f6b7d: dependencies updates:
|
|
49
|
+
- Updated dependency [`cloudflare@^4.3.0` ↗︎](https://www.npmjs.com/package/cloudflare/v/4.3.0) (from `^4.1.0`, in `dependencies`)
|
|
50
|
+
- Updated dependency [`mongodb@^6.17.0` ↗︎](https://www.npmjs.com/package/mongodb/v/6.17.0) (from `^6.15.0`, in `dependencies`)
|
|
51
|
+
- Updated dependencies [63f6b7d]
|
|
52
|
+
- Updated dependencies [36f1c36]
|
|
53
|
+
- Updated dependencies [10d352e]
|
|
54
|
+
- Updated dependencies [53d3c37]
|
|
55
|
+
- @mastra/core@0.10.6-alpha.0
|
|
56
|
+
|
|
57
|
+
## 0.10.3
|
|
58
|
+
|
|
59
|
+
### Patch Changes
|
|
60
|
+
|
|
61
|
+
- dffb67b: updated stores to add alter table and change tests
|
|
62
|
+
- 925ab94: added paginated functions to base class and added boilerplate and updated imports
|
|
63
|
+
- e030ea3: Added missing format compatibility to MongoDB getMessages() method
|
|
64
|
+
- 66f4424: Update peerdeps
|
|
65
|
+
- Updated dependencies [d1ed912]
|
|
66
|
+
- Updated dependencies [f6fd25f]
|
|
67
|
+
- Updated dependencies [dffb67b]
|
|
68
|
+
- Updated dependencies [f1f1f1b]
|
|
69
|
+
- Updated dependencies [925ab94]
|
|
70
|
+
- Updated dependencies [f9816ae]
|
|
71
|
+
- Updated dependencies [82090c1]
|
|
72
|
+
- Updated dependencies [1b443fd]
|
|
73
|
+
- Updated dependencies [ce97900]
|
|
74
|
+
- Updated dependencies [f1309d3]
|
|
75
|
+
- Updated dependencies [14a2566]
|
|
76
|
+
- Updated dependencies [f7f8293]
|
|
77
|
+
- Updated dependencies [48eddb9]
|
|
78
|
+
- @mastra/core@0.10.4
|
|
79
|
+
|
|
80
|
+
## 0.10.3-alpha.2
|
|
81
|
+
|
|
82
|
+
### Patch Changes
|
|
83
|
+
|
|
84
|
+
- 66f4424: Update peerdeps
|
|
85
|
+
|
|
86
|
+
## 0.10.3-alpha.1
|
|
87
|
+
|
|
88
|
+
### Patch Changes
|
|
89
|
+
|
|
90
|
+
- 925ab94: added paginated functions to base class and added boilerplate and updated imports
|
|
91
|
+
- Updated dependencies [925ab94]
|
|
92
|
+
- @mastra/core@0.10.4-alpha.3
|
|
93
|
+
|
|
94
|
+
## 0.10.3-alpha.0
|
|
95
|
+
|
|
96
|
+
### Patch Changes
|
|
97
|
+
|
|
98
|
+
- dffb67b: updated stores to add alter table and change tests
|
|
99
|
+
- e030ea3: Added missing format compatibility to MongoDB getMessages() method
|
|
100
|
+
- Updated dependencies [f6fd25f]
|
|
101
|
+
- Updated dependencies [dffb67b]
|
|
102
|
+
- Updated dependencies [f1309d3]
|
|
103
|
+
- Updated dependencies [f7f8293]
|
|
104
|
+
- @mastra/core@0.10.4-alpha.1
|
|
105
|
+
|
|
106
|
+
## 0.10.2
|
|
4
107
|
|
|
5
108
|
### Patch Changes
|
|
6
109
|
|
|
@@ -11,12 +114,19 @@
|
|
|
11
114
|
- Updated dependencies [e5dc18d]
|
|
12
115
|
- Updated dependencies [ab5adbe]
|
|
13
116
|
- Updated dependencies [1e8bb40]
|
|
117
|
+
- Updated dependencies [1b5fc55]
|
|
14
118
|
- Updated dependencies [195c428]
|
|
15
119
|
- Updated dependencies [f73e11b]
|
|
120
|
+
- Updated dependencies [37643b8]
|
|
121
|
+
- Updated dependencies [99fd6cf]
|
|
16
122
|
- Updated dependencies [c5bf1ce]
|
|
123
|
+
- Updated dependencies [add596e]
|
|
124
|
+
- Updated dependencies [8dc94d8]
|
|
125
|
+
- Updated dependencies [ecebbeb]
|
|
126
|
+
- Updated dependencies [79d5145]
|
|
17
127
|
- Updated dependencies [12b7002]
|
|
18
128
|
- Updated dependencies [2901125]
|
|
19
|
-
- @mastra/core@0.
|
|
129
|
+
- @mastra/core@0.10.2
|
|
20
130
|
|
|
21
131
|
## 0.10.2-alpha.1
|
|
22
132
|
|
|
@@ -11,11 +11,15 @@ import { MastraStorage } from '@mastra/core/storage';
|
|
|
11
11
|
import { MastraVector } from '@mastra/core/vector';
|
|
12
12
|
import type { MongoClientOptions } from 'mongodb';
|
|
13
13
|
import type { OperatorSupport } from '@mastra/core/vector/filter';
|
|
14
|
+
import type { PaginationInfo } from '@mastra/core/storage';
|
|
14
15
|
import type { QueryResult } from '@mastra/core/vector';
|
|
15
16
|
import type { QueryVectorParams } from '@mastra/core/vector';
|
|
17
|
+
import type { StorageColumn } from '@mastra/core/storage';
|
|
16
18
|
import type { StorageGetMessagesArg } from '@mastra/core/storage';
|
|
19
|
+
import type { StorageGetTracesArg } from '@mastra/core/storage';
|
|
17
20
|
import type { StorageThreadType } from '@mastra/core/memory';
|
|
18
21
|
import type { TABLE_NAMES } from '@mastra/core/storage';
|
|
22
|
+
import type { Trace } from '@mastra/core/telemetry';
|
|
19
23
|
import type { UpdateVectorParams } from '@mastra/core/vector';
|
|
20
24
|
import type { UpsertVectorParams } from '@mastra/core/vector';
|
|
21
25
|
import type { VectorFilter } from '@mastra/core/vector/filter';
|
|
@@ -71,6 +75,17 @@ declare class MongoDBStore extends MastraStorage {
|
|
|
71
75
|
private getConnection;
|
|
72
76
|
private getCollection;
|
|
73
77
|
createTable(): Promise<void>;
|
|
78
|
+
/**
|
|
79
|
+
* No-op: This backend is schemaless and does not require schema changes.
|
|
80
|
+
* @param tableName Name of the table
|
|
81
|
+
* @param schema Schema of the table
|
|
82
|
+
* @param ifNotExists Array of column names to add if they don't exist
|
|
83
|
+
*/
|
|
84
|
+
alterTable(_args: {
|
|
85
|
+
tableName: TABLE_NAMES;
|
|
86
|
+
schema: Record<string, StorageColumn>;
|
|
87
|
+
ifNotExists: string[];
|
|
88
|
+
}): Promise<void>;
|
|
74
89
|
clearTable({ tableName }: {
|
|
75
90
|
tableName: TABLE_NAMES;
|
|
76
91
|
}): Promise<void>;
|
|
@@ -103,7 +118,12 @@ declare class MongoDBStore extends MastraStorage {
|
|
|
103
118
|
deleteThread({ threadId }: {
|
|
104
119
|
threadId: string;
|
|
105
120
|
}): Promise<void>;
|
|
106
|
-
getMessages
|
|
121
|
+
getMessages(args: StorageGetMessagesArg & {
|
|
122
|
+
format?: 'v1';
|
|
123
|
+
}): Promise<MastraMessageV1[]>;
|
|
124
|
+
getMessages(args: StorageGetMessagesArg & {
|
|
125
|
+
format: 'v2';
|
|
126
|
+
}): Promise<MastraMessageV2[]>;
|
|
107
127
|
saveMessages(args: {
|
|
108
128
|
messages: MastraMessageV1[];
|
|
109
129
|
format?: undefined | 'v1';
|
|
@@ -153,6 +173,19 @@ declare class MongoDBStore extends MastraStorage {
|
|
|
153
173
|
private parseWorkflowRun;
|
|
154
174
|
private parseRow;
|
|
155
175
|
private transformEvalRow;
|
|
176
|
+
getTracesPaginated(_args: StorageGetTracesArg): Promise<PaginationInfo & {
|
|
177
|
+
traces: Trace[];
|
|
178
|
+
}>;
|
|
179
|
+
getThreadsByResourceIdPaginated(_args: {
|
|
180
|
+
resourceId: string;
|
|
181
|
+
page?: number;
|
|
182
|
+
perPage?: number;
|
|
183
|
+
}): Promise<PaginationInfo & {
|
|
184
|
+
threads: StorageThreadType[];
|
|
185
|
+
}>;
|
|
186
|
+
getMessagesPaginated(_args: StorageGetMessagesArg): Promise<PaginationInfo & {
|
|
187
|
+
messages: MastraMessageV1[] | MastraMessageV2[];
|
|
188
|
+
}>;
|
|
156
189
|
close(): Promise<void>;
|
|
157
190
|
}
|
|
158
191
|
export { MongoDBStore }
|
|
@@ -11,11 +11,15 @@ import { MastraStorage } from '@mastra/core/storage';
|
|
|
11
11
|
import { MastraVector } from '@mastra/core/vector';
|
|
12
12
|
import type { MongoClientOptions } from 'mongodb';
|
|
13
13
|
import type { OperatorSupport } from '@mastra/core/vector/filter';
|
|
14
|
+
import type { PaginationInfo } from '@mastra/core/storage';
|
|
14
15
|
import type { QueryResult } from '@mastra/core/vector';
|
|
15
16
|
import type { QueryVectorParams } from '@mastra/core/vector';
|
|
17
|
+
import type { StorageColumn } from '@mastra/core/storage';
|
|
16
18
|
import type { StorageGetMessagesArg } from '@mastra/core/storage';
|
|
19
|
+
import type { StorageGetTracesArg } from '@mastra/core/storage';
|
|
17
20
|
import type { StorageThreadType } from '@mastra/core/memory';
|
|
18
21
|
import type { TABLE_NAMES } from '@mastra/core/storage';
|
|
22
|
+
import type { Trace } from '@mastra/core/telemetry';
|
|
19
23
|
import type { UpdateVectorParams } from '@mastra/core/vector';
|
|
20
24
|
import type { UpsertVectorParams } from '@mastra/core/vector';
|
|
21
25
|
import type { VectorFilter } from '@mastra/core/vector/filter';
|
|
@@ -71,6 +75,17 @@ declare class MongoDBStore extends MastraStorage {
|
|
|
71
75
|
private getConnection;
|
|
72
76
|
private getCollection;
|
|
73
77
|
createTable(): Promise<void>;
|
|
78
|
+
/**
|
|
79
|
+
* No-op: This backend is schemaless and does not require schema changes.
|
|
80
|
+
* @param tableName Name of the table
|
|
81
|
+
* @param schema Schema of the table
|
|
82
|
+
* @param ifNotExists Array of column names to add if they don't exist
|
|
83
|
+
*/
|
|
84
|
+
alterTable(_args: {
|
|
85
|
+
tableName: TABLE_NAMES;
|
|
86
|
+
schema: Record<string, StorageColumn>;
|
|
87
|
+
ifNotExists: string[];
|
|
88
|
+
}): Promise<void>;
|
|
74
89
|
clearTable({ tableName }: {
|
|
75
90
|
tableName: TABLE_NAMES;
|
|
76
91
|
}): Promise<void>;
|
|
@@ -103,7 +118,12 @@ declare class MongoDBStore extends MastraStorage {
|
|
|
103
118
|
deleteThread({ threadId }: {
|
|
104
119
|
threadId: string;
|
|
105
120
|
}): Promise<void>;
|
|
106
|
-
getMessages
|
|
121
|
+
getMessages(args: StorageGetMessagesArg & {
|
|
122
|
+
format?: 'v1';
|
|
123
|
+
}): Promise<MastraMessageV1[]>;
|
|
124
|
+
getMessages(args: StorageGetMessagesArg & {
|
|
125
|
+
format: 'v2';
|
|
126
|
+
}): Promise<MastraMessageV2[]>;
|
|
107
127
|
saveMessages(args: {
|
|
108
128
|
messages: MastraMessageV1[];
|
|
109
129
|
format?: undefined | 'v1';
|
|
@@ -153,6 +173,19 @@ declare class MongoDBStore extends MastraStorage {
|
|
|
153
173
|
private parseWorkflowRun;
|
|
154
174
|
private parseRow;
|
|
155
175
|
private transformEvalRow;
|
|
176
|
+
getTracesPaginated(_args: StorageGetTracesArg): Promise<PaginationInfo & {
|
|
177
|
+
traces: Trace[];
|
|
178
|
+
}>;
|
|
179
|
+
getThreadsByResourceIdPaginated(_args: {
|
|
180
|
+
resourceId: string;
|
|
181
|
+
page?: number;
|
|
182
|
+
perPage?: number;
|
|
183
|
+
}): Promise<PaginationInfo & {
|
|
184
|
+
threads: StorageThreadType[];
|
|
185
|
+
}>;
|
|
186
|
+
getMessagesPaginated(_args: StorageGetMessagesArg): Promise<PaginationInfo & {
|
|
187
|
+
messages: MastraMessageV1[] | MastraMessageV2[];
|
|
188
|
+
}>;
|
|
156
189
|
close(): Promise<void>;
|
|
157
190
|
}
|
|
158
191
|
export { MongoDBStore }
|
package/dist/index.cjs
CHANGED
|
@@ -447,6 +447,14 @@ var MongoDBStore = class extends storage.MastraStorage {
|
|
|
447
447
|
}
|
|
448
448
|
async createTable() {
|
|
449
449
|
}
|
|
450
|
+
/**
|
|
451
|
+
* No-op: This backend is schemaless and does not require schema changes.
|
|
452
|
+
* @param tableName Name of the table
|
|
453
|
+
* @param schema Schema of the table
|
|
454
|
+
* @param ifNotExists Array of column names to add if they don't exist
|
|
455
|
+
*/
|
|
456
|
+
async alterTable(_args) {
|
|
457
|
+
}
|
|
450
458
|
async clearTable({ tableName }) {
|
|
451
459
|
try {
|
|
452
460
|
const collection = await this.getCollection(tableName);
|
|
@@ -584,7 +592,11 @@ var MongoDBStore = class extends storage.MastraStorage {
|
|
|
584
592
|
throw error;
|
|
585
593
|
}
|
|
586
594
|
}
|
|
587
|
-
async getMessages({
|
|
595
|
+
async getMessages({
|
|
596
|
+
threadId,
|
|
597
|
+
selectBy,
|
|
598
|
+
format
|
|
599
|
+
}) {
|
|
588
600
|
try {
|
|
589
601
|
const limit = typeof selectBy?.last === "number" ? selectBy.last : 40;
|
|
590
602
|
const include = selectBy?.include || [];
|
|
@@ -623,7 +635,9 @@ var MongoDBStore = class extends storage.MastraStorage {
|
|
|
623
635
|
}
|
|
624
636
|
}
|
|
625
637
|
messages.sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime());
|
|
626
|
-
|
|
638
|
+
const list = new agent.MessageList().add(messages.slice(0, limit), "memory");
|
|
639
|
+
if (format === `v2`) return list.get.all.v2();
|
|
640
|
+
return list.get.all.v1();
|
|
627
641
|
} catch (error) {
|
|
628
642
|
this.logger.error("Error getting messages:", error);
|
|
629
643
|
throw error;
|
|
@@ -655,7 +669,11 @@ var MongoDBStore = class extends storage.MastraStorage {
|
|
|
655
669
|
};
|
|
656
670
|
});
|
|
657
671
|
const collection = await this.getCollection(storage.TABLE_MESSAGES);
|
|
658
|
-
await
|
|
672
|
+
const threadsCollection = await this.getCollection(storage.TABLE_THREADS);
|
|
673
|
+
await Promise.all([
|
|
674
|
+
collection.insertMany(messagesToInsert),
|
|
675
|
+
threadsCollection.updateOne({ id: threadId }, { $set: { updatedAt: /* @__PURE__ */ new Date() } })
|
|
676
|
+
]);
|
|
659
677
|
const list = new agent.MessageList().add(messages, "memory");
|
|
660
678
|
if (format === `v2`) return list.get.all.v2();
|
|
661
679
|
return list.get.all.v1();
|
|
@@ -898,7 +916,8 @@ var MongoDBStore = class extends storage.MastraStorage {
|
|
|
898
916
|
role: row.role,
|
|
899
917
|
type: row.type,
|
|
900
918
|
createdAt: new Date(row.createdAt),
|
|
901
|
-
threadId: row.thread_id
|
|
919
|
+
threadId: row.thread_id,
|
|
920
|
+
resourceId: row.resourceId
|
|
902
921
|
};
|
|
903
922
|
}
|
|
904
923
|
transformEvalRow(row) {
|
|
@@ -923,6 +942,15 @@ var MongoDBStore = class extends storage.MastraStorage {
|
|
|
923
942
|
createdAt: row.created_at
|
|
924
943
|
};
|
|
925
944
|
}
|
|
945
|
+
async getTracesPaginated(_args) {
|
|
946
|
+
throw new Error("Method not implemented.");
|
|
947
|
+
}
|
|
948
|
+
async getThreadsByResourceIdPaginated(_args) {
|
|
949
|
+
throw new Error("Method not implemented.");
|
|
950
|
+
}
|
|
951
|
+
async getMessagesPaginated(_args) {
|
|
952
|
+
throw new Error("Method not implemented.");
|
|
953
|
+
}
|
|
926
954
|
async close() {
|
|
927
955
|
await this.#client.close();
|
|
928
956
|
}
|
package/dist/index.js
CHANGED
|
@@ -445,6 +445,14 @@ var MongoDBStore = class extends MastraStorage {
|
|
|
445
445
|
}
|
|
446
446
|
async createTable() {
|
|
447
447
|
}
|
|
448
|
+
/**
|
|
449
|
+
* No-op: This backend is schemaless and does not require schema changes.
|
|
450
|
+
* @param tableName Name of the table
|
|
451
|
+
* @param schema Schema of the table
|
|
452
|
+
* @param ifNotExists Array of column names to add if they don't exist
|
|
453
|
+
*/
|
|
454
|
+
async alterTable(_args) {
|
|
455
|
+
}
|
|
448
456
|
async clearTable({ tableName }) {
|
|
449
457
|
try {
|
|
450
458
|
const collection = await this.getCollection(tableName);
|
|
@@ -582,7 +590,11 @@ var MongoDBStore = class extends MastraStorage {
|
|
|
582
590
|
throw error;
|
|
583
591
|
}
|
|
584
592
|
}
|
|
585
|
-
async getMessages({
|
|
593
|
+
async getMessages({
|
|
594
|
+
threadId,
|
|
595
|
+
selectBy,
|
|
596
|
+
format
|
|
597
|
+
}) {
|
|
586
598
|
try {
|
|
587
599
|
const limit = typeof selectBy?.last === "number" ? selectBy.last : 40;
|
|
588
600
|
const include = selectBy?.include || [];
|
|
@@ -621,7 +633,9 @@ var MongoDBStore = class extends MastraStorage {
|
|
|
621
633
|
}
|
|
622
634
|
}
|
|
623
635
|
messages.sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime());
|
|
624
|
-
|
|
636
|
+
const list = new MessageList().add(messages.slice(0, limit), "memory");
|
|
637
|
+
if (format === `v2`) return list.get.all.v2();
|
|
638
|
+
return list.get.all.v1();
|
|
625
639
|
} catch (error) {
|
|
626
640
|
this.logger.error("Error getting messages:", error);
|
|
627
641
|
throw error;
|
|
@@ -653,7 +667,11 @@ var MongoDBStore = class extends MastraStorage {
|
|
|
653
667
|
};
|
|
654
668
|
});
|
|
655
669
|
const collection = await this.getCollection(TABLE_MESSAGES);
|
|
656
|
-
await
|
|
670
|
+
const threadsCollection = await this.getCollection(TABLE_THREADS);
|
|
671
|
+
await Promise.all([
|
|
672
|
+
collection.insertMany(messagesToInsert),
|
|
673
|
+
threadsCollection.updateOne({ id: threadId }, { $set: { updatedAt: /* @__PURE__ */ new Date() } })
|
|
674
|
+
]);
|
|
657
675
|
const list = new MessageList().add(messages, "memory");
|
|
658
676
|
if (format === `v2`) return list.get.all.v2();
|
|
659
677
|
return list.get.all.v1();
|
|
@@ -896,7 +914,8 @@ var MongoDBStore = class extends MastraStorage {
|
|
|
896
914
|
role: row.role,
|
|
897
915
|
type: row.type,
|
|
898
916
|
createdAt: new Date(row.createdAt),
|
|
899
|
-
threadId: row.thread_id
|
|
917
|
+
threadId: row.thread_id,
|
|
918
|
+
resourceId: row.resourceId
|
|
900
919
|
};
|
|
901
920
|
}
|
|
902
921
|
transformEvalRow(row) {
|
|
@@ -921,6 +940,15 @@ var MongoDBStore = class extends MastraStorage {
|
|
|
921
940
|
createdAt: row.created_at
|
|
922
941
|
};
|
|
923
942
|
}
|
|
943
|
+
async getTracesPaginated(_args) {
|
|
944
|
+
throw new Error("Method not implemented.");
|
|
945
|
+
}
|
|
946
|
+
async getThreadsByResourceIdPaginated(_args) {
|
|
947
|
+
throw new Error("Method not implemented.");
|
|
948
|
+
}
|
|
949
|
+
async getMessagesPaginated(_args) {
|
|
950
|
+
throw new Error("Method not implemented.");
|
|
951
|
+
}
|
|
924
952
|
async close() {
|
|
925
953
|
await this.#client.close();
|
|
926
954
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mastra/mongodb",
|
|
3
|
-
"version": "0.0.0-
|
|
3
|
+
"version": "0.0.0-workflow-deno-20250616130925",
|
|
4
4
|
"description": "MongoDB provider for Mastra - includes vector store capabilities",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -20,22 +20,23 @@
|
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"@types/mongodb": "^4.0.7",
|
|
23
|
-
"cloudflare": "^4.
|
|
24
|
-
"mongodb": "^6.
|
|
23
|
+
"cloudflare": "^4.3.0",
|
|
24
|
+
"mongodb": "^6.17.0",
|
|
25
25
|
"uuid": "^11.1.0"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
|
-
"@microsoft/api-extractor": "^7.52.
|
|
29
|
-
"@types/node": "^20.
|
|
30
|
-
"eslint": "^9.
|
|
31
|
-
"tsup": "^8.
|
|
32
|
-
"typescript": "^5.8.
|
|
33
|
-
"vitest": "^3.
|
|
34
|
-
"@
|
|
35
|
-
"@
|
|
28
|
+
"@microsoft/api-extractor": "^7.52.8",
|
|
29
|
+
"@types/node": "^20.19.0",
|
|
30
|
+
"eslint": "^9.28.0",
|
|
31
|
+
"tsup": "^8.5.0",
|
|
32
|
+
"typescript": "^5.8.3",
|
|
33
|
+
"vitest": "^3.2.3",
|
|
34
|
+
"@internal/lint": "0.0.0-workflow-deno-20250616130925",
|
|
35
|
+
"@mastra/core": "0.0.0-workflow-deno-20250616130925",
|
|
36
|
+
"@internal/storage-test-utils": "0.0.0-workflow-deno-20250616130925"
|
|
36
37
|
},
|
|
37
38
|
"peerDependencies": {
|
|
38
|
-
"@mastra/core": "
|
|
39
|
+
"@mastra/core": ">=0.10.4-0 <0.11.0"
|
|
39
40
|
},
|
|
40
41
|
"scripts": {
|
|
41
42
|
"build": "tsup src/index.ts --format esm,cjs --experimental-dts --clean --treeshake=smallest --splitting",
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { randomUUID } from 'crypto';
|
|
2
|
-
import type { MastraMessageV1, MetricResult, WorkflowRunState } from '@mastra/core';
|
|
2
|
+
import type { MastraMessageV1, MastraMessageV2, MetricResult, WorkflowRunState } from '@mastra/core';
|
|
3
|
+
import type { TABLE_NAMES } from '@mastra/core/storage';
|
|
3
4
|
import { TABLE_EVALS, TABLE_MESSAGES, TABLE_THREADS, TABLE_WORKFLOW_SNAPSHOT } from '@mastra/core/storage';
|
|
4
|
-
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
|
|
5
|
+
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it } from 'vitest';
|
|
5
6
|
import type { MongoDBConfig } from './index';
|
|
6
7
|
import { MongoDBStore } from './index';
|
|
7
8
|
|
|
@@ -40,15 +41,46 @@ class Test {
|
|
|
40
41
|
};
|
|
41
42
|
}
|
|
42
43
|
|
|
43
|
-
|
|
44
|
+
generateSampleMessageV1({
|
|
45
|
+
threadId,
|
|
46
|
+
resourceId = randomUUID(),
|
|
47
|
+
content = 'Hello',
|
|
48
|
+
}: {
|
|
49
|
+
threadId: string;
|
|
50
|
+
resourceId?: string;
|
|
51
|
+
content?: string;
|
|
52
|
+
}): MastraMessageV1 {
|
|
44
53
|
return {
|
|
45
54
|
id: `msg-${randomUUID()}`,
|
|
46
55
|
role: 'user',
|
|
47
56
|
type: 'text',
|
|
48
57
|
threadId,
|
|
49
|
-
content: [{ type: 'text', text:
|
|
58
|
+
content: [{ type: 'text', text: content }],
|
|
50
59
|
createdAt: new Date(),
|
|
51
|
-
resourceId
|
|
60
|
+
resourceId,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
generateSampleMessageV2({
|
|
65
|
+
threadId,
|
|
66
|
+
resourceId = randomUUID(),
|
|
67
|
+
content = 'Hello',
|
|
68
|
+
}: {
|
|
69
|
+
threadId: string;
|
|
70
|
+
resourceId?: string;
|
|
71
|
+
content?: string;
|
|
72
|
+
}): MastraMessageV2 {
|
|
73
|
+
return {
|
|
74
|
+
id: `msg-${randomUUID()}`,
|
|
75
|
+
role: 'user',
|
|
76
|
+
type: 'text',
|
|
77
|
+
threadId,
|
|
78
|
+
content: {
|
|
79
|
+
format: 2,
|
|
80
|
+
parts: [{ type: 'text', text: content }],
|
|
81
|
+
},
|
|
82
|
+
createdAt: new Date(),
|
|
83
|
+
resourceId,
|
|
52
84
|
};
|
|
53
85
|
}
|
|
54
86
|
|
|
@@ -93,6 +125,7 @@ class Test {
|
|
|
93
125
|
suspendedPaths: {},
|
|
94
126
|
runId,
|
|
95
127
|
timestamp: timestamp.getTime(),
|
|
128
|
+
status: options.status,
|
|
96
129
|
} as WorkflowRunState;
|
|
97
130
|
return { snapshot, runId, stepId };
|
|
98
131
|
}
|
|
@@ -201,7 +234,10 @@ describe('MongoDBStore', () => {
|
|
|
201
234
|
await store.saveThread({ thread });
|
|
202
235
|
|
|
203
236
|
// Add some messages
|
|
204
|
-
const messages = [
|
|
237
|
+
const messages = [
|
|
238
|
+
test.generateSampleMessageV1({ threadId: thread.id }),
|
|
239
|
+
test.generateSampleMessageV1({ threadId: thread.id }),
|
|
240
|
+
];
|
|
205
241
|
await store.saveMessages({ messages });
|
|
206
242
|
|
|
207
243
|
await store.deleteThread({ threadId: thread.id });
|
|
@@ -236,6 +272,27 @@ describe('MongoDBStore', () => {
|
|
|
236
272
|
expect(retrievedThread?.title).toBe('Updated Title');
|
|
237
273
|
expect(retrievedThread?.metadata).toEqual({ key: 'newValue' });
|
|
238
274
|
});
|
|
275
|
+
|
|
276
|
+
it('should update thread updatedAt when a message is saved to it', async () => {
|
|
277
|
+
const test = new Test(store).build();
|
|
278
|
+
await test.clearTables();
|
|
279
|
+
|
|
280
|
+
const thread = test.generateSampleThread();
|
|
281
|
+
await store.saveThread({ thread });
|
|
282
|
+
|
|
283
|
+
const initialThread = await store.getThreadById({ threadId: thread.id });
|
|
284
|
+
expect(initialThread).toBeDefined();
|
|
285
|
+
const originalUpdatedAt = initialThread!.updatedAt;
|
|
286
|
+
|
|
287
|
+
await new Promise(resolve => setTimeout(resolve, 10));
|
|
288
|
+
|
|
289
|
+
const message = test.generateSampleMessageV1({ threadId: thread.id });
|
|
290
|
+
await store.saveMessages({ messages: [message] });
|
|
291
|
+
|
|
292
|
+
const updatedThread = await store.getThreadById({ threadId: thread.id });
|
|
293
|
+
expect(updatedThread).toBeDefined();
|
|
294
|
+
expect(updatedThread!.updatedAt.getTime()).toBeGreaterThan(originalUpdatedAt.getTime());
|
|
295
|
+
});
|
|
239
296
|
});
|
|
240
297
|
|
|
241
298
|
describe('Message Operations', () => {
|
|
@@ -246,8 +303,8 @@ describe('MongoDBStore', () => {
|
|
|
246
303
|
await store.saveThread({ thread });
|
|
247
304
|
|
|
248
305
|
const messages = [
|
|
249
|
-
test.
|
|
250
|
-
{ ...test.
|
|
306
|
+
test.generateSampleMessageV1({ threadId: thread.id }),
|
|
307
|
+
{ ...test.generateSampleMessageV1({ threadId: thread.id }), role: 'assistant' as const },
|
|
251
308
|
];
|
|
252
309
|
|
|
253
310
|
// Save messages
|
|
@@ -277,29 +334,129 @@ describe('MongoDBStore', () => {
|
|
|
277
334
|
|
|
278
335
|
const messages = [
|
|
279
336
|
{
|
|
280
|
-
...test.
|
|
281
|
-
content: [{ type: 'text', text: 'First' }] as MastraMessageV1['content'],
|
|
337
|
+
...test.generateSampleMessageV2({ threadId: thread.id, content: 'First' }),
|
|
282
338
|
},
|
|
283
339
|
{
|
|
284
|
-
...test.
|
|
285
|
-
content: [{ type: 'text', text: 'Second' }] as MastraMessageV1['content'],
|
|
340
|
+
...test.generateSampleMessageV2({ threadId: thread.id, content: 'Second' }),
|
|
286
341
|
},
|
|
287
342
|
{
|
|
288
|
-
...test.
|
|
289
|
-
content: [{ type: 'text', text: 'Third' }] as MastraMessageV1['content'],
|
|
343
|
+
...test.generateSampleMessageV2({ threadId: thread.id, content: 'Third' }),
|
|
290
344
|
},
|
|
291
345
|
];
|
|
292
346
|
|
|
293
|
-
await store.saveMessages({ messages });
|
|
347
|
+
await store.saveMessages({ messages, format: 'v2' });
|
|
294
348
|
|
|
295
|
-
const retrievedMessages = await store.getMessages({ threadId: thread.id });
|
|
349
|
+
const retrievedMessages = await store.getMessages({ threadId: thread.id, format: 'v2' });
|
|
296
350
|
expect(retrievedMessages).toHaveLength(3);
|
|
297
351
|
|
|
298
352
|
// Verify order is maintained
|
|
299
353
|
retrievedMessages.forEach((msg, idx) => {
|
|
300
|
-
expect((
|
|
354
|
+
expect((msg as any).content.parts).toEqual(messages[idx]!.content.parts);
|
|
301
355
|
});
|
|
302
356
|
});
|
|
357
|
+
|
|
358
|
+
// it('should retrieve messages w/ next/prev messages by message id + resource id', async () => {
|
|
359
|
+
// const test = new Test(store).build();
|
|
360
|
+
// const messages: MastraMessageV2[] = [
|
|
361
|
+
// test.generateSampleMessageV2({ threadId: 'thread-one', content: 'First', resourceId: 'cross-thread-resource' }),
|
|
362
|
+
// test.generateSampleMessageV2({
|
|
363
|
+
// threadId: 'thread-one',
|
|
364
|
+
// content: 'Second',
|
|
365
|
+
// resourceId: 'cross-thread-resource',
|
|
366
|
+
// }),
|
|
367
|
+
// test.generateSampleMessageV2({ threadId: 'thread-one', content: 'Third', resourceId: 'cross-thread-resource' }),
|
|
368
|
+
|
|
369
|
+
// test.generateSampleMessageV2({
|
|
370
|
+
// threadId: 'thread-two',
|
|
371
|
+
// content: 'Fourth',
|
|
372
|
+
// resourceId: 'cross-thread-resource',
|
|
373
|
+
// }),
|
|
374
|
+
// test.generateSampleMessageV2({ threadId: 'thread-two', content: 'Fifth', resourceId: 'cross-thread-resource' }),
|
|
375
|
+
// test.generateSampleMessageV2({ threadId: 'thread-two', content: 'Sixth', resourceId: 'cross-thread-resource' }),
|
|
376
|
+
|
|
377
|
+
// test.generateSampleMessageV2({ threadId: 'thread-three', content: 'Seventh', resourceId: 'other-resource' }),
|
|
378
|
+
// test.generateSampleMessageV2({ threadId: 'thread-three', content: 'Eighth', resourceId: 'other-resource' }),
|
|
379
|
+
// ];
|
|
380
|
+
|
|
381
|
+
// await store.saveMessages({ messages: messages, format: 'v2' });
|
|
382
|
+
|
|
383
|
+
// const retrievedMessages: MastraMessageV2[] = await store.getMessages({ threadId: 'thread-one', format: 'v2' });
|
|
384
|
+
// expect(retrievedMessages).toHaveLength(3);
|
|
385
|
+
// expect(retrievedMessages.map(m => (m.content.parts[0] as any).text)).toEqual(['First', 'Second', 'Third']);
|
|
386
|
+
|
|
387
|
+
// const retrievedMessages2: MastraMessageV2[] = await store.getMessages({ threadId: 'thread-two', format: 'v2' });
|
|
388
|
+
// expect(retrievedMessages2).toHaveLength(3);
|
|
389
|
+
// expect(retrievedMessages2.map(m => (m.content.parts[0] as any).text)).toEqual(['Fourth', 'Fifth', 'Sixth']);
|
|
390
|
+
|
|
391
|
+
// const retrievedMessages3: MastraMessageV2[] = await store.getMessages({ threadId: 'thread-three', format: 'v2' });
|
|
392
|
+
// expect(retrievedMessages3).toHaveLength(2);
|
|
393
|
+
// expect(retrievedMessages3.map(m => (m.content.parts[0] as any).text)).toEqual(['Seventh', 'Eighth']);
|
|
394
|
+
|
|
395
|
+
// const crossThreadMessages: MastraMessageV2[] = await store.getMessages({
|
|
396
|
+
// threadId: 'thread-doesnt-exist',
|
|
397
|
+
// resourceId: 'cross-thread-resource',
|
|
398
|
+
// format: 'v2',
|
|
399
|
+
// selectBy: {
|
|
400
|
+
// last: 0,
|
|
401
|
+
// include: [
|
|
402
|
+
// {
|
|
403
|
+
// id: messages[1].id,
|
|
404
|
+
// withNextMessages: 2,
|
|
405
|
+
// withPreviousMessages: 2,
|
|
406
|
+
// },
|
|
407
|
+
// {
|
|
408
|
+
// id: messages[4].id,
|
|
409
|
+
// withPreviousMessages: 2,
|
|
410
|
+
// withNextMessages: 2,
|
|
411
|
+
// },
|
|
412
|
+
// ],
|
|
413
|
+
// },
|
|
414
|
+
// });
|
|
415
|
+
|
|
416
|
+
// expect(crossThreadMessages).toHaveLength(6);
|
|
417
|
+
// expect(crossThreadMessages.filter(m => m.threadId === `thread-one`)).toHaveLength(3);
|
|
418
|
+
// expect(crossThreadMessages.filter(m => m.threadId === `thread-two`)).toHaveLength(3);
|
|
419
|
+
|
|
420
|
+
// const crossThreadMessages2: MastraMessageV2[] = await store.getMessages({
|
|
421
|
+
// threadId: 'thread-one',
|
|
422
|
+
// resourceId: 'cross-thread-resource',
|
|
423
|
+
// format: 'v2',
|
|
424
|
+
// selectBy: {
|
|
425
|
+
// last: 0,
|
|
426
|
+
// include: [
|
|
427
|
+
// {
|
|
428
|
+
// id: messages[4].id,
|
|
429
|
+
// withPreviousMessages: 1,
|
|
430
|
+
// withNextMessages: 30,
|
|
431
|
+
// },
|
|
432
|
+
// ],
|
|
433
|
+
// },
|
|
434
|
+
// });
|
|
435
|
+
|
|
436
|
+
// expect(crossThreadMessages2).toHaveLength(3);
|
|
437
|
+
// expect(crossThreadMessages2.filter(m => m.threadId === `thread-one`)).toHaveLength(0);
|
|
438
|
+
// expect(crossThreadMessages2.filter(m => m.threadId === `thread-two`)).toHaveLength(3);
|
|
439
|
+
|
|
440
|
+
// const crossThreadMessages3: MastraMessageV2[] = await store.getMessages({
|
|
441
|
+
// threadId: 'thread-two',
|
|
442
|
+
// resourceId: 'cross-thread-resource',
|
|
443
|
+
// format: 'v2',
|
|
444
|
+
// selectBy: {
|
|
445
|
+
// last: 0,
|
|
446
|
+
// include: [
|
|
447
|
+
// {
|
|
448
|
+
// id: messages[1].id,
|
|
449
|
+
// withNextMessages: 1,
|
|
450
|
+
// withPreviousMessages: 1,
|
|
451
|
+
// },
|
|
452
|
+
// ],
|
|
453
|
+
// },
|
|
454
|
+
// });
|
|
455
|
+
|
|
456
|
+
// expect(crossThreadMessages3).toHaveLength(3);
|
|
457
|
+
// expect(crossThreadMessages3.filter(m => m.threadId === `thread-one`)).toHaveLength(3);
|
|
458
|
+
// expect(crossThreadMessages3.filter(m => m.threadId === `thread-two`)).toHaveLength(0);
|
|
459
|
+
// });
|
|
303
460
|
});
|
|
304
461
|
|
|
305
462
|
describe('Edge Cases and Error Handling', () => {
|
|
@@ -485,6 +642,7 @@ describe('MongoDBStore', () => {
|
|
|
485
642
|
],
|
|
486
643
|
serializedStepGraph: [],
|
|
487
644
|
runId: runId,
|
|
645
|
+
status: 'running',
|
|
488
646
|
timestamp: Date.now(),
|
|
489
647
|
};
|
|
490
648
|
|
|
@@ -773,6 +931,89 @@ describe('MongoDBStore', () => {
|
|
|
773
931
|
});
|
|
774
932
|
});
|
|
775
933
|
|
|
934
|
+
describe('alterTable (no-op/schemaless)', () => {
|
|
935
|
+
const TEST_TABLE = 'test_alter_table'; // Use "table" or "collection" as appropriate
|
|
936
|
+
beforeEach(async () => {
|
|
937
|
+
await store.clearTable({ tableName: TEST_TABLE as TABLE_NAMES });
|
|
938
|
+
});
|
|
939
|
+
|
|
940
|
+
afterEach(async () => {
|
|
941
|
+
await store.clearTable({ tableName: TEST_TABLE as TABLE_NAMES });
|
|
942
|
+
});
|
|
943
|
+
|
|
944
|
+
it('allows inserting records with new fields without alterTable', async () => {
|
|
945
|
+
await store.insert({
|
|
946
|
+
tableName: TEST_TABLE as TABLE_NAMES,
|
|
947
|
+
record: { id: '1', name: 'Alice' },
|
|
948
|
+
});
|
|
949
|
+
await store.insert({
|
|
950
|
+
tableName: TEST_TABLE as TABLE_NAMES,
|
|
951
|
+
record: { id: '2', name: 'Bob', newField: 123 },
|
|
952
|
+
});
|
|
953
|
+
|
|
954
|
+
const row = await store.load<{ id: string; name: string; newField?: number }[]>({
|
|
955
|
+
tableName: TEST_TABLE as TABLE_NAMES,
|
|
956
|
+
keys: { id: '2' },
|
|
957
|
+
});
|
|
958
|
+
expect(row?.[0]?.newField).toBe(123);
|
|
959
|
+
});
|
|
960
|
+
|
|
961
|
+
it('does not throw when calling alterTable (no-op)', async () => {
|
|
962
|
+
await expect(
|
|
963
|
+
store.alterTable({
|
|
964
|
+
tableName: TEST_TABLE as TABLE_NAMES,
|
|
965
|
+
schema: {
|
|
966
|
+
id: { type: 'text', primaryKey: true, nullable: false },
|
|
967
|
+
name: { type: 'text', nullable: true },
|
|
968
|
+
extra: { type: 'integer', nullable: true },
|
|
969
|
+
},
|
|
970
|
+
ifNotExists: ['extra'],
|
|
971
|
+
}),
|
|
972
|
+
).resolves.not.toThrow();
|
|
973
|
+
});
|
|
974
|
+
|
|
975
|
+
it('can add multiple new fields at write time', async () => {
|
|
976
|
+
await store.insert({
|
|
977
|
+
tableName: TEST_TABLE as TABLE_NAMES,
|
|
978
|
+
record: { id: '3', name: 'Charlie', age: 30, city: 'Paris' },
|
|
979
|
+
});
|
|
980
|
+
const row = await store.load<{ id: string; name: string; age?: number; city?: string }[]>({
|
|
981
|
+
tableName: TEST_TABLE as TABLE_NAMES,
|
|
982
|
+
keys: { id: '3' },
|
|
983
|
+
});
|
|
984
|
+
expect(row?.[0]?.age).toBe(30);
|
|
985
|
+
expect(row?.[0]?.city).toBe('Paris');
|
|
986
|
+
});
|
|
987
|
+
|
|
988
|
+
it('can retrieve all fields, including dynamically added ones', async () => {
|
|
989
|
+
await store.insert({
|
|
990
|
+
tableName: TEST_TABLE as TABLE_NAMES,
|
|
991
|
+
record: { id: '4', name: 'Dana', hobby: 'skiing' },
|
|
992
|
+
});
|
|
993
|
+
const row = await store.load<{ id: string; name: string; hobby?: string }[]>({
|
|
994
|
+
tableName: TEST_TABLE as TABLE_NAMES,
|
|
995
|
+
keys: { id: '4' },
|
|
996
|
+
});
|
|
997
|
+
expect(row?.[0]?.hobby).toBe('skiing');
|
|
998
|
+
});
|
|
999
|
+
|
|
1000
|
+
it('does not restrict or error on arbitrary new fields', async () => {
|
|
1001
|
+
await expect(
|
|
1002
|
+
store.insert({
|
|
1003
|
+
tableName: TEST_TABLE as TABLE_NAMES,
|
|
1004
|
+
record: { id: '5', weirdField: { nested: true }, another: [1, 2, 3] },
|
|
1005
|
+
}),
|
|
1006
|
+
).resolves.not.toThrow();
|
|
1007
|
+
|
|
1008
|
+
const row = await store.load<{ id: string; weirdField?: any; another?: any }[]>({
|
|
1009
|
+
tableName: TEST_TABLE as TABLE_NAMES,
|
|
1010
|
+
keys: { id: '5' },
|
|
1011
|
+
});
|
|
1012
|
+
expect(row?.[0]?.weirdField).toEqual({ nested: true });
|
|
1013
|
+
expect(row?.[0]?.another).toEqual([1, 2, 3]);
|
|
1014
|
+
});
|
|
1015
|
+
});
|
|
1016
|
+
|
|
776
1017
|
afterAll(async () => {
|
|
777
1018
|
try {
|
|
778
1019
|
await store.close();
|
package/src/storage/index.ts
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
import { MessageList } from '@mastra/core/agent';
|
|
2
2
|
import type { MetricResult, TestInfo } from '@mastra/core/eval';
|
|
3
3
|
import type { MastraMessageV1, MastraMessageV2, StorageThreadType } from '@mastra/core/memory';
|
|
4
|
-
import type {
|
|
4
|
+
import type {
|
|
5
|
+
EvalRow,
|
|
6
|
+
PaginationInfo,
|
|
7
|
+
StorageColumn,
|
|
8
|
+
StorageGetMessagesArg,
|
|
9
|
+
StorageGetTracesArg,
|
|
10
|
+
TABLE_NAMES,
|
|
11
|
+
WorkflowRun,
|
|
12
|
+
} from '@mastra/core/storage';
|
|
5
13
|
import {
|
|
6
14
|
MastraStorage,
|
|
7
15
|
TABLE_EVALS,
|
|
@@ -10,6 +18,7 @@ import {
|
|
|
10
18
|
TABLE_TRACES,
|
|
11
19
|
TABLE_WORKFLOW_SNAPSHOT,
|
|
12
20
|
} from '@mastra/core/storage';
|
|
21
|
+
import type { Trace } from '@mastra/core/telemetry';
|
|
13
22
|
import type { WorkflowRunState } from '@mastra/core/workflows';
|
|
14
23
|
import type { Db, MongoClientOptions } from 'mongodb';
|
|
15
24
|
import { MongoClient } from 'mongodb';
|
|
@@ -74,6 +83,20 @@ export class MongoDBStore extends MastraStorage {
|
|
|
74
83
|
// Nothing to do here, MongoDB is schemaless
|
|
75
84
|
}
|
|
76
85
|
|
|
86
|
+
/**
|
|
87
|
+
* No-op: This backend is schemaless and does not require schema changes.
|
|
88
|
+
* @param tableName Name of the table
|
|
89
|
+
* @param schema Schema of the table
|
|
90
|
+
* @param ifNotExists Array of column names to add if they don't exist
|
|
91
|
+
*/
|
|
92
|
+
async alterTable(_args: {
|
|
93
|
+
tableName: TABLE_NAMES;
|
|
94
|
+
schema: Record<string, StorageColumn>;
|
|
95
|
+
ifNotExists: string[];
|
|
96
|
+
}): Promise<void> {
|
|
97
|
+
// Nothing to do here, MongoDB is schemaless
|
|
98
|
+
}
|
|
99
|
+
|
|
77
100
|
async clearTable({ tableName }: { tableName: TABLE_NAMES }): Promise<void> {
|
|
78
101
|
try {
|
|
79
102
|
const collection = await this.getCollection(tableName);
|
|
@@ -232,7 +255,15 @@ export class MongoDBStore extends MastraStorage {
|
|
|
232
255
|
}
|
|
233
256
|
}
|
|
234
257
|
|
|
235
|
-
async getMessages
|
|
258
|
+
public async getMessages(args: StorageGetMessagesArg & { format?: 'v1' }): Promise<MastraMessageV1[]>;
|
|
259
|
+
public async getMessages(args: StorageGetMessagesArg & { format: 'v2' }): Promise<MastraMessageV2[]>;
|
|
260
|
+
public async getMessages({
|
|
261
|
+
threadId,
|
|
262
|
+
selectBy,
|
|
263
|
+
format,
|
|
264
|
+
}: StorageGetMessagesArg & {
|
|
265
|
+
format?: 'v1' | 'v2';
|
|
266
|
+
}): Promise<MastraMessageV1[] | MastraMessageV2[]> {
|
|
236
267
|
try {
|
|
237
268
|
const limit = typeof selectBy?.last === 'number' ? selectBy.last : 40;
|
|
238
269
|
const include = selectBy?.include || [];
|
|
@@ -287,7 +318,9 @@ export class MongoDBStore extends MastraStorage {
|
|
|
287
318
|
// Sort all messages by creation date ascending
|
|
288
319
|
messages.sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime());
|
|
289
320
|
|
|
290
|
-
|
|
321
|
+
const list = new MessageList().add(messages.slice(0, limit), 'memory');
|
|
322
|
+
if (format === `v2`) return list.get.all.v2();
|
|
323
|
+
return list.get.all.v1();
|
|
291
324
|
} catch (error) {
|
|
292
325
|
this.logger.error('Error getting messages:', error as Error);
|
|
293
326
|
throw error;
|
|
@@ -311,6 +344,7 @@ export class MongoDBStore extends MastraStorage {
|
|
|
311
344
|
this.logger.error('Thread ID is required to save messages');
|
|
312
345
|
throw new Error('Thread ID is required');
|
|
313
346
|
}
|
|
347
|
+
|
|
314
348
|
try {
|
|
315
349
|
// Prepare batch statements for all messages
|
|
316
350
|
const messagesToInsert = messages.map(message => {
|
|
@@ -326,9 +360,15 @@ export class MongoDBStore extends MastraStorage {
|
|
|
326
360
|
};
|
|
327
361
|
});
|
|
328
362
|
|
|
329
|
-
// Execute
|
|
363
|
+
// Execute message inserts and thread update in parallel for better performance
|
|
330
364
|
const collection = await this.getCollection(TABLE_MESSAGES);
|
|
331
|
-
await
|
|
365
|
+
const threadsCollection = await this.getCollection(TABLE_THREADS);
|
|
366
|
+
|
|
367
|
+
await Promise.all([
|
|
368
|
+
collection.insertMany(messagesToInsert),
|
|
369
|
+
threadsCollection.updateOne({ id: threadId }, { $set: { updatedAt: new Date() } }),
|
|
370
|
+
]);
|
|
371
|
+
|
|
332
372
|
const list = new MessageList().add(messages, 'memory');
|
|
333
373
|
if (format === `v2`) return list.get.all.v2();
|
|
334
374
|
return list.get.all.v1();
|
|
@@ -652,6 +692,7 @@ export class MongoDBStore extends MastraStorage {
|
|
|
652
692
|
type: row.type,
|
|
653
693
|
createdAt: new Date(row.createdAt as string),
|
|
654
694
|
threadId: row.thread_id,
|
|
695
|
+
resourceId: row.resourceId,
|
|
655
696
|
} as MastraMessageV2;
|
|
656
697
|
}
|
|
657
698
|
|
|
@@ -679,6 +720,24 @@ export class MongoDBStore extends MastraStorage {
|
|
|
679
720
|
};
|
|
680
721
|
}
|
|
681
722
|
|
|
723
|
+
async getTracesPaginated(_args: StorageGetTracesArg): Promise<PaginationInfo & { traces: Trace[] }> {
|
|
724
|
+
throw new Error('Method not implemented.');
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
async getThreadsByResourceIdPaginated(_args: {
|
|
728
|
+
resourceId: string;
|
|
729
|
+
page?: number;
|
|
730
|
+
perPage?: number;
|
|
731
|
+
}): Promise<PaginationInfo & { threads: StorageThreadType[] }> {
|
|
732
|
+
throw new Error('Method not implemented.');
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
async getMessagesPaginated(
|
|
736
|
+
_args: StorageGetMessagesArg,
|
|
737
|
+
): Promise<PaginationInfo & { messages: MastraMessageV1[] | MastraMessageV2[] }> {
|
|
738
|
+
throw new Error('Method not implemented.');
|
|
739
|
+
}
|
|
740
|
+
|
|
682
741
|
async close(): Promise<void> {
|
|
683
742
|
await this.#client.close();
|
|
684
743
|
}
|