@mastra/mongodb 0.13.3 → 0.13.6-alpha.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.
@@ -1,155 +0,0 @@
1
- import { ErrorCategory, ErrorDomain, MastraError } from '@mastra/core/error';
2
- import { safelyParseJSON, StoreOperations, TABLE_SCHEMAS } from '@mastra/core/storage';
3
- import type { StorageColumn, TABLE_NAMES } from '@mastra/core/storage';
4
- import type { ConnectorHandler } from '../../connectors/base';
5
-
6
- export interface MongoDBOperationsConfig {
7
- connector: ConnectorHandler;
8
- }
9
- export class StoreOperationsMongoDB extends StoreOperations {
10
- readonly #connector: ConnectorHandler;
11
-
12
- constructor(config: MongoDBOperationsConfig) {
13
- super();
14
- this.#connector = config.connector;
15
- }
16
-
17
- async getCollection(collectionName: string) {
18
- return this.#connector.getCollection(collectionName);
19
- }
20
-
21
- async hasColumn(_table: string, _column: string): Promise<boolean> {
22
- // MongoDB is schemaless, so we can assume any column exists
23
- // We could check a sample document, but for now return true
24
- return true;
25
- }
26
-
27
- async createTable(): Promise<void> {
28
- // Nothing to do here, MongoDB is schemaless
29
- }
30
-
31
- async alterTable(_args: {
32
- tableName: TABLE_NAMES;
33
- schema: Record<string, StorageColumn>;
34
- ifNotExists: string[];
35
- }): Promise<void> {
36
- // Nothing to do here, MongoDB is schemaless
37
- }
38
-
39
- async clearTable({ tableName }: { tableName: TABLE_NAMES }): Promise<void> {
40
- try {
41
- const collection = await this.getCollection(tableName);
42
- await collection.deleteMany({});
43
- } catch (error) {
44
- if (error instanceof Error) {
45
- const matstraError = new MastraError(
46
- {
47
- id: 'STORAGE_MONGODB_STORE_CLEAR_TABLE_FAILED',
48
- domain: ErrorDomain.STORAGE,
49
- category: ErrorCategory.THIRD_PARTY,
50
- details: { tableName },
51
- },
52
- error,
53
- );
54
- this.logger.error(matstraError.message);
55
- this.logger?.trackException(matstraError);
56
- }
57
- }
58
- }
59
-
60
- async dropTable({ tableName }: { tableName: TABLE_NAMES }): Promise<void> {
61
- try {
62
- const collection = await this.getCollection(tableName);
63
- await collection.drop();
64
- } catch (error) {
65
- // Collection might not exist, which is fine
66
- if (error instanceof Error && error.message.includes('ns not found')) {
67
- return;
68
- }
69
- throw new MastraError(
70
- {
71
- id: 'MONGODB_STORE_DROP_TABLE_FAILED',
72
- domain: ErrorDomain.STORAGE,
73
- category: ErrorCategory.THIRD_PARTY,
74
- details: { tableName },
75
- },
76
- error,
77
- );
78
- }
79
- }
80
-
81
- private processJsonbFields(tableName: TABLE_NAMES, record: Record<string, any>): Record<string, any> {
82
- const schema = TABLE_SCHEMAS[tableName];
83
-
84
- return Object.fromEntries(
85
- Object.entries(schema).map(([key, value]) => {
86
- if (value.type === 'jsonb' && record[key] && typeof record[key] === 'string') {
87
- return [key, safelyParseJSON(record[key])];
88
- }
89
- return [key, record[key]];
90
- }),
91
- );
92
- }
93
-
94
- async insert({ tableName, record }: { tableName: TABLE_NAMES; record: Record<string, any> }): Promise<void> {
95
- try {
96
- const collection = await this.getCollection(tableName);
97
- const recordToInsert = this.processJsonbFields(tableName, record);
98
- await collection.insertOne(recordToInsert);
99
- } catch (error) {
100
- if (error instanceof Error) {
101
- const matstraError = new MastraError(
102
- {
103
- id: 'STORAGE_MONGODB_STORE_INSERT_FAILED',
104
- domain: ErrorDomain.STORAGE,
105
- category: ErrorCategory.THIRD_PARTY,
106
- details: { tableName },
107
- },
108
- error,
109
- );
110
- this.logger.error(matstraError.message);
111
- this.logger?.trackException(matstraError);
112
- }
113
- }
114
- }
115
-
116
- async batchInsert({ tableName, records }: { tableName: TABLE_NAMES; records: Record<string, any>[] }): Promise<void> {
117
- if (!records.length) {
118
- return;
119
- }
120
-
121
- try {
122
- const collection = await this.getCollection(tableName);
123
- const processedRecords = records.map(record => this.processJsonbFields(tableName, record));
124
- await collection.insertMany(processedRecords);
125
- } catch (error) {
126
- throw new MastraError(
127
- {
128
- id: 'STORAGE_MONGODB_STORE_BATCH_INSERT_FAILED',
129
- domain: ErrorDomain.STORAGE,
130
- category: ErrorCategory.THIRD_PARTY,
131
- details: { tableName },
132
- },
133
- error,
134
- );
135
- }
136
- }
137
-
138
- async load<R>({ tableName, keys }: { tableName: TABLE_NAMES; keys: Record<string, string> }): Promise<R | null> {
139
- this.logger.info(`Loading ${tableName} with keys ${JSON.stringify(keys)}`);
140
- try {
141
- const collection = await this.getCollection(tableName);
142
- return (await collection.find(keys).toArray()) as R;
143
- } catch (error) {
144
- throw new MastraError(
145
- {
146
- id: 'STORAGE_MONGODB_STORE_LOAD_FAILED',
147
- domain: ErrorDomain.STORAGE,
148
- category: ErrorCategory.THIRD_PARTY,
149
- details: { tableName },
150
- },
151
- error,
152
- );
153
- }
154
- }
155
- }
@@ -1,389 +0,0 @@
1
- import { ErrorCategory, ErrorDomain, MastraError } from '@mastra/core/error';
2
- import type { ScoreRowData, ScoringEntityType, ScoringSource } from '@mastra/core/scores';
3
- import { ScoresStorage, TABLE_SCORERS, safelyParseJSON } from '@mastra/core/storage';
4
- import type { PaginationInfo, StoragePagination } from '@mastra/core/storage';
5
- import type { StoreOperationsMongoDB } from '../operations';
6
-
7
- function transformScoreRow(row: Record<string, any>): ScoreRowData {
8
- let scorerValue: any = null;
9
- if (row.scorer) {
10
- try {
11
- scorerValue = typeof row.scorer === 'string' ? safelyParseJSON(row.scorer) : row.scorer;
12
- } catch (e) {
13
- console.warn('Failed to parse scorer:', e);
14
- }
15
- }
16
-
17
- let preprocessStepResultValue: any = null;
18
- if (row.preprocessStepResult) {
19
- try {
20
- preprocessStepResultValue =
21
- typeof row.preprocessStepResult === 'string'
22
- ? safelyParseJSON(row.preprocessStepResult)
23
- : row.preprocessStepResult;
24
- } catch (e) {
25
- console.warn('Failed to parse preprocessStepResult:', e);
26
- }
27
- }
28
-
29
- let analyzeStepResultValue: any = null;
30
- if (row.analyzeStepResult) {
31
- try {
32
- analyzeStepResultValue =
33
- typeof row.analyzeStepResult === 'string' ? safelyParseJSON(row.analyzeStepResult) : row.analyzeStepResult;
34
- } catch (e) {
35
- console.warn('Failed to parse analyzeStepResult:', e);
36
- }
37
- }
38
-
39
- let inputValue: any = null;
40
- if (row.input) {
41
- try {
42
- inputValue = typeof row.input === 'string' ? safelyParseJSON(row.input) : row.input;
43
- } catch (e) {
44
- console.warn('Failed to parse input:', e);
45
- }
46
- }
47
-
48
- let outputValue: any = null;
49
- if (row.output) {
50
- try {
51
- outputValue = typeof row.output === 'string' ? safelyParseJSON(row.output) : row.output;
52
- } catch (e) {
53
- console.warn('Failed to parse output:', e);
54
- }
55
- }
56
-
57
- let entityValue: any = null;
58
- if (row.entity) {
59
- try {
60
- entityValue = typeof row.entity === 'string' ? safelyParseJSON(row.entity) : row.entity;
61
- } catch (e) {
62
- console.warn('Failed to parse entity:', e);
63
- }
64
- }
65
-
66
- let runtimeContextValue: any = null;
67
- if (row.runtimeContext) {
68
- try {
69
- runtimeContextValue =
70
- typeof row.runtimeContext === 'string' ? safelyParseJSON(row.runtimeContext) : row.runtimeContext;
71
- } catch (e) {
72
- console.warn('Failed to parse runtimeContext:', e);
73
- }
74
- }
75
-
76
- return {
77
- id: row.id as string,
78
- entityId: row.entityId as string,
79
- entityType: row.entityType as ScoringEntityType,
80
- scorerId: row.scorerId as string,
81
- traceId: row.traceId as string,
82
- runId: row.runId as string,
83
- scorer: scorerValue,
84
- preprocessStepResult: preprocessStepResultValue,
85
- analyzeStepResult: analyzeStepResultValue,
86
- score: row.score as number,
87
- reason: row.reason as string,
88
- extractPrompt: row.extractPrompt as string,
89
- analyzePrompt: row.analyzePrompt as string,
90
- reasonPrompt: row.reasonPrompt as string,
91
- input: inputValue,
92
- output: outputValue,
93
- additionalContext: row.additionalContext,
94
- runtimeContext: runtimeContextValue,
95
- entity: entityValue,
96
- source: row.source as ScoringSource,
97
- resourceId: row.resourceId as string,
98
- threadId: row.threadId as string,
99
- createdAt: new Date(row.createdAt),
100
- updatedAt: new Date(row.updatedAt),
101
- };
102
- }
103
-
104
- export class ScoresStorageMongoDB extends ScoresStorage {
105
- private operations: StoreOperationsMongoDB;
106
-
107
- constructor({ operations }: { operations: StoreOperationsMongoDB }) {
108
- super();
109
- this.operations = operations;
110
- }
111
-
112
- async getScoreById({ id }: { id: string }): Promise<ScoreRowData | null> {
113
- try {
114
- const collection = await this.operations.getCollection(TABLE_SCORERS);
115
- const document = await collection.findOne({ id });
116
-
117
- if (!document) {
118
- return null;
119
- }
120
-
121
- return transformScoreRow(document);
122
- } catch (error) {
123
- throw new MastraError(
124
- {
125
- id: 'STORAGE_MONGODB_STORE_GET_SCORE_BY_ID_FAILED',
126
- domain: ErrorDomain.STORAGE,
127
- category: ErrorCategory.THIRD_PARTY,
128
- details: { id },
129
- },
130
- error,
131
- );
132
- }
133
- }
134
-
135
- async saveScore(score: Omit<ScoreRowData, 'id' | 'createdAt' | 'updatedAt'>): Promise<{ score: ScoreRowData }> {
136
- try {
137
- const now = new Date();
138
- const scoreId = `score-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
139
-
140
- const scoreData = {
141
- id: scoreId,
142
- entityId: score.entityId,
143
- entityType: score.entityType,
144
- scorerId: score.scorerId,
145
- traceId: score.traceId || '',
146
- runId: score.runId,
147
- scorer: typeof score.scorer === 'string' ? safelyParseJSON(score.scorer) : score.scorer,
148
- preprocessStepResult:
149
- typeof score.preprocessStepResult === 'string'
150
- ? safelyParseJSON(score.preprocessStepResult)
151
- : score.preprocessStepResult,
152
- analyzeStepResult:
153
- typeof score.analyzeStepResult === 'string'
154
- ? safelyParseJSON(score.analyzeStepResult)
155
- : score.analyzeStepResult,
156
- score: score.score,
157
- reason: score.reason,
158
- preprocessPrompt: score.preprocessPrompt,
159
- generateScorePrompt: score.generateScorePrompt,
160
- generateReasonPrompt: score.generateReasonPrompt,
161
- analyzePrompt: score.analyzePrompt,
162
- reasonPrompt: score.reasonPrompt,
163
- input: typeof score.input === 'string' ? safelyParseJSON(score.input) : score.input,
164
- output: typeof score.output === 'string' ? safelyParseJSON(score.output) : score.output,
165
- additionalContext: score.additionalContext,
166
- runtimeContext:
167
- typeof score.runtimeContext === 'string' ? safelyParseJSON(score.runtimeContext) : score.runtimeContext,
168
- entity: typeof score.entity === 'string' ? safelyParseJSON(score.entity) : score.entity,
169
- source: score.source,
170
- resourceId: score.resourceId || '',
171
- threadId: score.threadId || '',
172
- createdAt: now,
173
- updatedAt: now,
174
- };
175
-
176
- const collection = await this.operations.getCollection(TABLE_SCORERS);
177
- await collection.insertOne(scoreData);
178
-
179
- const savedScore: ScoreRowData = {
180
- ...score,
181
- id: scoreId,
182
- createdAt: now,
183
- updatedAt: now,
184
- };
185
-
186
- return { score: savedScore };
187
- } catch (error) {
188
- throw new MastraError(
189
- {
190
- id: 'STORAGE_MONGODB_STORE_SAVE_SCORE_FAILED',
191
- domain: ErrorDomain.STORAGE,
192
- category: ErrorCategory.THIRD_PARTY,
193
- details: { scorerId: score.scorerId, runId: score.runId },
194
- },
195
- error,
196
- );
197
- }
198
- }
199
-
200
- async getScoresByScorerId({
201
- scorerId,
202
- pagination,
203
- entityId,
204
- entityType,
205
- source,
206
- }: {
207
- scorerId: string;
208
- pagination: StoragePagination;
209
- entityId?: string;
210
- entityType?: string;
211
- source?: ScoringSource;
212
- }): Promise<{ pagination: PaginationInfo; scores: ScoreRowData[] }> {
213
- try {
214
- const query: any = { scorerId };
215
-
216
- if (entityId) {
217
- query.entityId = entityId;
218
- }
219
-
220
- if (entityType) {
221
- query.entityType = entityType;
222
- }
223
-
224
- if (source) {
225
- query.source = source;
226
- }
227
-
228
- const collection = await this.operations.getCollection(TABLE_SCORERS);
229
- const total = await collection.countDocuments(query);
230
- const currentOffset = pagination.page * pagination.perPage;
231
-
232
- if (total === 0) {
233
- return {
234
- scores: [],
235
- pagination: {
236
- total: 0,
237
- page: pagination.page,
238
- perPage: pagination.perPage,
239
- hasMore: false,
240
- },
241
- };
242
- }
243
-
244
- const documents = await collection
245
- .find(query)
246
- .sort({ createdAt: 'desc' })
247
- .skip(currentOffset)
248
- .limit(pagination.perPage)
249
- .toArray();
250
-
251
- const scores = documents.map(row => transformScoreRow(row));
252
- const hasMore = currentOffset + scores.length < total;
253
-
254
- return {
255
- scores,
256
- pagination: {
257
- total,
258
- page: pagination.page,
259
- perPage: pagination.perPage,
260
- hasMore,
261
- },
262
- };
263
- } catch (error) {
264
- throw new MastraError(
265
- {
266
- id: 'STORAGE_MONGODB_STORE_GET_SCORES_BY_SCORER_ID_FAILED',
267
- domain: ErrorDomain.STORAGE,
268
- category: ErrorCategory.THIRD_PARTY,
269
- details: { scorerId, page: pagination.page, perPage: pagination.perPage },
270
- },
271
- error,
272
- );
273
- }
274
- }
275
-
276
- async getScoresByRunId({
277
- runId,
278
- pagination,
279
- }: {
280
- runId: string;
281
- pagination: StoragePagination;
282
- }): Promise<{ pagination: PaginationInfo; scores: ScoreRowData[] }> {
283
- try {
284
- const collection = await this.operations.getCollection(TABLE_SCORERS);
285
- const total = await collection.countDocuments({ runId });
286
- const currentOffset = pagination.page * pagination.perPage;
287
-
288
- if (total === 0) {
289
- return {
290
- scores: [],
291
- pagination: {
292
- total: 0,
293
- page: pagination.page,
294
- perPage: pagination.perPage,
295
- hasMore: false,
296
- },
297
- };
298
- }
299
-
300
- const documents = await collection
301
- .find({ runId })
302
- .sort({ createdAt: 'desc' })
303
- .skip(currentOffset)
304
- .limit(pagination.perPage)
305
- .toArray();
306
-
307
- const scores = documents.map(row => transformScoreRow(row));
308
- const hasMore = currentOffset + scores.length < total;
309
-
310
- return {
311
- scores,
312
- pagination: {
313
- total,
314
- page: pagination.page,
315
- perPage: pagination.perPage,
316
- hasMore,
317
- },
318
- };
319
- } catch (error) {
320
- throw new MastraError(
321
- {
322
- id: 'STORAGE_MONGODB_STORE_GET_SCORES_BY_RUN_ID_FAILED',
323
- domain: ErrorDomain.STORAGE,
324
- category: ErrorCategory.THIRD_PARTY,
325
- details: { runId, page: pagination.page, perPage: pagination.perPage },
326
- },
327
- error,
328
- );
329
- }
330
- }
331
-
332
- async getScoresByEntityId({
333
- entityId,
334
- entityType,
335
- pagination,
336
- }: {
337
- pagination: StoragePagination;
338
- entityId: string;
339
- entityType: string;
340
- }): Promise<{ pagination: PaginationInfo; scores: ScoreRowData[] }> {
341
- try {
342
- const collection = await this.operations.getCollection(TABLE_SCORERS);
343
- const total = await collection.countDocuments({ entityId, entityType });
344
- const currentOffset = pagination.page * pagination.perPage;
345
-
346
- if (total === 0) {
347
- return {
348
- scores: [],
349
- pagination: {
350
- total: 0,
351
- page: pagination.page,
352
- perPage: pagination.perPage,
353
- hasMore: false,
354
- },
355
- };
356
- }
357
-
358
- const documents = await collection
359
- .find({ entityId, entityType })
360
- .sort({ createdAt: 'desc' })
361
- .skip(currentOffset)
362
- .limit(pagination.perPage)
363
- .toArray();
364
-
365
- const scores = documents.map(row => transformScoreRow(row));
366
- const hasMore = currentOffset + scores.length < total;
367
-
368
- return {
369
- scores,
370
- pagination: {
371
- total,
372
- page: pagination.page,
373
- perPage: pagination.perPage,
374
- hasMore,
375
- },
376
- };
377
- } catch (error) {
378
- throw new MastraError(
379
- {
380
- id: 'STORAGE_MONGODB_STORE_GET_SCORES_BY_ENTITY_ID_FAILED',
381
- domain: ErrorDomain.STORAGE,
382
- category: ErrorCategory.THIRD_PARTY,
383
- details: { entityId, entityType, page: pagination.page, perPage: pagination.perPage },
384
- },
385
- error,
386
- );
387
- }
388
- }
389
- }
@@ -1,142 +0,0 @@
1
- import { ErrorCategory, ErrorDomain, MastraError } from '@mastra/core/error';
2
- import type { PaginationInfo, StorageGetTracesArg, StorageGetTracesPaginatedArg } from '@mastra/core/storage';
3
- import { TABLE_TRACES, TracesStorage, safelyParseJSON } from '@mastra/core/storage';
4
- import type { Trace } from '@mastra/core/telemetry';
5
- import type { StoreOperationsMongoDB } from '../operations';
6
-
7
- export class TracesStorageMongoDB extends TracesStorage {
8
- private operations: StoreOperationsMongoDB;
9
-
10
- constructor({ operations }: { operations: StoreOperationsMongoDB }) {
11
- super();
12
- this.operations = operations;
13
- }
14
-
15
- async getTraces(args: StorageGetTracesArg): Promise<Trace[]> {
16
- if (args.fromDate || args.toDate) {
17
- (args as any).dateRange = {
18
- start: args.fromDate,
19
- end: args.toDate,
20
- };
21
- }
22
- try {
23
- const result = await this.getTracesPaginated(args);
24
- return result.traces;
25
- } catch (error) {
26
- throw new MastraError(
27
- {
28
- id: 'STORAGE_MONGODB_STORE_GET_TRACES_FAILED',
29
- domain: ErrorDomain.STORAGE,
30
- category: ErrorCategory.THIRD_PARTY,
31
- },
32
- error,
33
- );
34
- }
35
- }
36
-
37
- async getTracesPaginated(args: StorageGetTracesPaginatedArg): Promise<PaginationInfo & { traces: Trace[] }> {
38
- const { name, scope, page = 0, perPage = 100, attributes, filters, dateRange } = args;
39
- const fromDate = dateRange?.start;
40
- const toDate = dateRange?.end;
41
- const currentOffset = page * perPage;
42
-
43
- const query: any = {};
44
- if (name) {
45
- query['name'] = new RegExp(name);
46
- }
47
-
48
- if (scope) {
49
- query['scope'] = scope;
50
- }
51
-
52
- if (attributes) {
53
- query['$and'] = Object.entries(attributes).map(([key, value]) => ({
54
- [`attributes.${key}`]: value,
55
- }));
56
- }
57
-
58
- if (filters) {
59
- Object.entries(filters).forEach(([key, value]) => {
60
- query[key] = value;
61
- });
62
- }
63
-
64
- if (fromDate || toDate) {
65
- query['createdAt'] = {};
66
- if (fromDate) {
67
- query['createdAt']['$gte'] = fromDate;
68
- }
69
- if (toDate) {
70
- query['createdAt']['$lte'] = toDate;
71
- }
72
- }
73
-
74
- try {
75
- const collection = await this.operations.getCollection(TABLE_TRACES);
76
-
77
- // Get total count
78
- const total = await collection.countDocuments(query);
79
-
80
- if (total === 0) {
81
- return {
82
- traces: [],
83
- total: 0,
84
- page,
85
- perPage,
86
- hasMore: false,
87
- };
88
- }
89
-
90
- // Get results with pagination
91
- const result = await collection
92
- .find(query, {
93
- sort: { startTime: -1 },
94
- })
95
- .limit(perPage)
96
- .skip(currentOffset)
97
- .toArray();
98
-
99
- const traces = result.map(row => ({
100
- id: row.id,
101
- parentSpanId: row.parentSpanId,
102
- traceId: row.traceId,
103
- name: row.name,
104
- scope: row.scope,
105
- kind: row.kind,
106
- status: safelyParseJSON(row.status),
107
- events: safelyParseJSON(row.events),
108
- links: safelyParseJSON(row.links),
109
- attributes: safelyParseJSON(row.attributes),
110
- startTime: row.startTime,
111
- endTime: row.endTime,
112
- other: safelyParseJSON(row.other),
113
- createdAt: row.createdAt,
114
- })) as Trace[];
115
-
116
- return {
117
- traces,
118
- total,
119
- page,
120
- perPage,
121
- hasMore: currentOffset + traces.length < total,
122
- };
123
- } catch (error) {
124
- throw new MastraError(
125
- {
126
- id: 'STORAGE_MONGODB_STORE_GET_TRACES_PAGINATED_FAILED',
127
- domain: ErrorDomain.STORAGE,
128
- category: ErrorCategory.THIRD_PARTY,
129
- },
130
- error,
131
- );
132
- }
133
- }
134
-
135
- async batchTraceInsert({ records }: { records: Record<string, any>[] }): Promise<void> {
136
- this.logger.debug('Batch inserting traces', { count: records.length });
137
- await this.operations.batchInsert({
138
- tableName: TABLE_TRACES,
139
- records,
140
- });
141
- }
142
- }