@mastra/pg 0.11.1-alpha.0 → 0.11.1-alpha.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/.turbo/turbo-build.log +7 -7
- package/CHANGELOG.md +28 -0
- package/dist/_tsup-dts-rollup.d.cts +40 -6
- package/dist/_tsup-dts-rollup.d.ts +40 -6
- package/dist/index.cjs +808 -255
- package/dist/index.js +785 -232
- package/package.json +4 -4
- package/src/storage/index.test.ts +428 -35
- package/src/storage/index.ts +596 -197
- package/src/vector/filter.test.ts +12 -12
- package/src/vector/filter.ts +36 -7
- package/src/vector/index.test.ts +2 -2
- package/src/vector/index.ts +283 -90
- package/src/vector/sql-builder.ts +2 -1
package/src/storage/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { MessageList } from '@mastra/core/agent';
|
|
2
2
|
import type { MastraMessageContentV2, MastraMessageV2 } from '@mastra/core/agent';
|
|
3
|
+
import { ErrorCategory, ErrorDomain, MastraError } from '@mastra/core/error';
|
|
3
4
|
import type { MetricResult } from '@mastra/core/eval';
|
|
4
5
|
import type { MastraMessageV1, StorageThreadType } from '@mastra/core/memory';
|
|
5
6
|
import {
|
|
@@ -7,6 +8,7 @@ import {
|
|
|
7
8
|
TABLE_MESSAGES,
|
|
8
9
|
TABLE_THREADS,
|
|
9
10
|
TABLE_TRACES,
|
|
11
|
+
TABLE_RESOURCES,
|
|
10
12
|
TABLE_WORKFLOW_SNAPSHOT,
|
|
11
13
|
TABLE_EVALS,
|
|
12
14
|
} from '@mastra/core/storage';
|
|
@@ -15,6 +17,7 @@ import type {
|
|
|
15
17
|
PaginationInfo,
|
|
16
18
|
StorageColumn,
|
|
17
19
|
StorageGetMessagesArg,
|
|
20
|
+
StorageResourceType,
|
|
18
21
|
TABLE_NAMES,
|
|
19
22
|
WorkflowRun,
|
|
20
23
|
WorkflowRuns,
|
|
@@ -50,48 +53,61 @@ export class PostgresStore extends MastraStorage {
|
|
|
50
53
|
|
|
51
54
|
constructor(config: PostgresConfig) {
|
|
52
55
|
// Validation: connectionString or host/database/user/password must not be empty
|
|
53
|
-
|
|
54
|
-
if (
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
'PostgresStore: connectionString must be provided and cannot be empty. Passing an empty string may cause fallback to local Postgres defaults.',
|
|
61
|
-
);
|
|
62
|
-
}
|
|
63
|
-
} else {
|
|
64
|
-
const required = ['host', 'database', 'user', 'password'];
|
|
65
|
-
for (const key of required) {
|
|
66
|
-
if (!(key in config) || typeof (config as any)[key] !== 'string' || (config as any)[key].trim() === '') {
|
|
56
|
+
try {
|
|
57
|
+
if ('connectionString' in config) {
|
|
58
|
+
if (
|
|
59
|
+
!config.connectionString ||
|
|
60
|
+
typeof config.connectionString !== 'string' ||
|
|
61
|
+
config.connectionString.trim() === ''
|
|
62
|
+
) {
|
|
67
63
|
throw new Error(
|
|
68
|
-
|
|
64
|
+
'PostgresStore: connectionString must be provided and cannot be empty. Passing an empty string may cause fallback to local Postgres defaults.',
|
|
69
65
|
);
|
|
70
66
|
}
|
|
67
|
+
} else {
|
|
68
|
+
const required = ['host', 'database', 'user', 'password'];
|
|
69
|
+
for (const key of required) {
|
|
70
|
+
if (!(key in config) || typeof (config as any)[key] !== 'string' || (config as any)[key].trim() === '') {
|
|
71
|
+
throw new Error(
|
|
72
|
+
`PostgresStore: ${key} must be provided and cannot be empty. Passing an empty string may cause fallback to local Postgres defaults.`,
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
71
76
|
}
|
|
77
|
+
super({ name: 'PostgresStore' });
|
|
78
|
+
this.pgp = pgPromise();
|
|
79
|
+
this.schema = config.schemaName;
|
|
80
|
+
this.db = this.pgp(
|
|
81
|
+
`connectionString` in config
|
|
82
|
+
? { connectionString: config.connectionString }
|
|
83
|
+
: {
|
|
84
|
+
host: config.host,
|
|
85
|
+
port: config.port,
|
|
86
|
+
database: config.database,
|
|
87
|
+
user: config.user,
|
|
88
|
+
password: config.password,
|
|
89
|
+
ssl: config.ssl,
|
|
90
|
+
},
|
|
91
|
+
);
|
|
92
|
+
} catch (e) {
|
|
93
|
+
throw new MastraError(
|
|
94
|
+
{
|
|
95
|
+
id: 'MASTRA_STORAGE_PG_STORE_INITIALIZATION_FAILED',
|
|
96
|
+
domain: ErrorDomain.STORAGE,
|
|
97
|
+
category: ErrorCategory.USER,
|
|
98
|
+
},
|
|
99
|
+
e,
|
|
100
|
+
);
|
|
72
101
|
}
|
|
73
|
-
super({ name: 'PostgresStore' });
|
|
74
|
-
this.pgp = pgPromise();
|
|
75
|
-
this.schema = config.schemaName;
|
|
76
|
-
this.db = this.pgp(
|
|
77
|
-
`connectionString` in config
|
|
78
|
-
? { connectionString: config.connectionString }
|
|
79
|
-
: {
|
|
80
|
-
host: config.host,
|
|
81
|
-
port: config.port,
|
|
82
|
-
database: config.database,
|
|
83
|
-
user: config.user,
|
|
84
|
-
password: config.password,
|
|
85
|
-
ssl: config.ssl,
|
|
86
|
-
},
|
|
87
|
-
);
|
|
88
102
|
}
|
|
89
103
|
|
|
90
104
|
public get supports(): {
|
|
91
105
|
selectByIncludeResourceScope: boolean;
|
|
106
|
+
resourceWorkingMemory: boolean;
|
|
92
107
|
} {
|
|
93
108
|
return {
|
|
94
109
|
selectByIncludeResourceScope: true,
|
|
110
|
+
resourceWorkingMemory: true,
|
|
95
111
|
};
|
|
96
112
|
}
|
|
97
113
|
|
|
@@ -163,9 +179,19 @@ export class PostgresStore extends MastraStorage {
|
|
|
163
179
|
}
|
|
164
180
|
await this.db.query('COMMIT');
|
|
165
181
|
} catch (error) {
|
|
166
|
-
console.error(`Error inserting into ${tableName}:`, error);
|
|
167
182
|
await this.db.query('ROLLBACK');
|
|
168
|
-
throw
|
|
183
|
+
throw new MastraError(
|
|
184
|
+
{
|
|
185
|
+
id: 'MASTRA_STORAGE_PG_STORE_BATCH_INSERT_FAILED',
|
|
186
|
+
domain: ErrorDomain.STORAGE,
|
|
187
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
188
|
+
details: {
|
|
189
|
+
tableName,
|
|
190
|
+
numberOfRecords: records.length,
|
|
191
|
+
},
|
|
192
|
+
},
|
|
193
|
+
error,
|
|
194
|
+
);
|
|
169
195
|
}
|
|
170
196
|
}
|
|
171
197
|
|
|
@@ -250,8 +276,24 @@ export class PostgresStore extends MastraStorage {
|
|
|
250
276
|
|
|
251
277
|
// Get total count
|
|
252
278
|
const countQuery = `SELECT COUNT(*) FROM ${this.getTableName(TABLE_TRACES)} ${whereClause}`;
|
|
253
|
-
|
|
254
|
-
|
|
279
|
+
let total = 0;
|
|
280
|
+
try {
|
|
281
|
+
const countResult = await this.db.one(countQuery, queryParams);
|
|
282
|
+
total = parseInt(countResult.count, 10);
|
|
283
|
+
} catch (error) {
|
|
284
|
+
throw new MastraError(
|
|
285
|
+
{
|
|
286
|
+
id: 'MASTRA_STORAGE_PG_STORE_GET_TRACES_PAGINATED_FAILED_TO_RETRIEVE_TOTAL_COUNT',
|
|
287
|
+
domain: ErrorDomain.STORAGE,
|
|
288
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
289
|
+
details: {
|
|
290
|
+
name: args.name ?? '',
|
|
291
|
+
scope: args.scope ?? '',
|
|
292
|
+
},
|
|
293
|
+
},
|
|
294
|
+
error,
|
|
295
|
+
);
|
|
296
|
+
}
|
|
255
297
|
|
|
256
298
|
if (total === 0) {
|
|
257
299
|
return {
|
|
@@ -268,31 +310,46 @@ export class PostgresStore extends MastraStorage {
|
|
|
268
310
|
)} ${whereClause} ORDER BY "createdAt" DESC LIMIT $${paramIndex++} OFFSET $${paramIndex++}`;
|
|
269
311
|
const finalQueryParams = [...queryParams, perPage, currentOffset];
|
|
270
312
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
313
|
+
try {
|
|
314
|
+
const rows = await this.db.manyOrNone<any>(dataQuery, finalQueryParams);
|
|
315
|
+
const traces = rows.map(row => ({
|
|
316
|
+
id: row.id,
|
|
317
|
+
parentSpanId: row.parentSpanId,
|
|
318
|
+
traceId: row.traceId,
|
|
319
|
+
name: row.name,
|
|
320
|
+
scope: row.scope,
|
|
321
|
+
kind: row.kind,
|
|
322
|
+
status: row.status,
|
|
323
|
+
events: row.events,
|
|
324
|
+
links: row.links,
|
|
325
|
+
attributes: row.attributes,
|
|
326
|
+
startTime: row.startTime,
|
|
327
|
+
endTime: row.endTime,
|
|
328
|
+
other: row.other,
|
|
329
|
+
createdAt: row.createdAt,
|
|
330
|
+
}));
|
|
288
331
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
332
|
+
return {
|
|
333
|
+
traces,
|
|
334
|
+
total,
|
|
335
|
+
page,
|
|
336
|
+
perPage,
|
|
337
|
+
hasMore: currentOffset + traces.length < total,
|
|
338
|
+
};
|
|
339
|
+
} catch (error) {
|
|
340
|
+
throw new MastraError(
|
|
341
|
+
{
|
|
342
|
+
id: 'MASTRA_STORAGE_PG_STORE_GET_TRACES_PAGINATED_FAILED_TO_RETRIEVE_TRACES',
|
|
343
|
+
domain: ErrorDomain.STORAGE,
|
|
344
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
345
|
+
details: {
|
|
346
|
+
name: args.name ?? '',
|
|
347
|
+
scope: args.scope ?? '',
|
|
348
|
+
},
|
|
349
|
+
},
|
|
350
|
+
error,
|
|
351
|
+
);
|
|
352
|
+
}
|
|
296
353
|
}
|
|
297
354
|
|
|
298
355
|
private async setupSchema() {
|
|
@@ -390,8 +447,17 @@ export class PostgresStore extends MastraStorage {
|
|
|
390
447
|
|
|
391
448
|
await this.db.none(sql);
|
|
392
449
|
} catch (error) {
|
|
393
|
-
|
|
394
|
-
|
|
450
|
+
throw new MastraError(
|
|
451
|
+
{
|
|
452
|
+
id: 'MASTRA_STORAGE_PG_STORE_CREATE_TABLE_FAILED',
|
|
453
|
+
domain: ErrorDomain.STORAGE,
|
|
454
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
455
|
+
details: {
|
|
456
|
+
tableName,
|
|
457
|
+
},
|
|
458
|
+
},
|
|
459
|
+
error,
|
|
460
|
+
);
|
|
395
461
|
}
|
|
396
462
|
}
|
|
397
463
|
|
|
@@ -439,10 +505,17 @@ export class PostgresStore extends MastraStorage {
|
|
|
439
505
|
}
|
|
440
506
|
}
|
|
441
507
|
} catch (error) {
|
|
442
|
-
|
|
443
|
-
|
|
508
|
+
throw new MastraError(
|
|
509
|
+
{
|
|
510
|
+
id: 'MASTRA_STORAGE_PG_STORE_ALTER_TABLE_FAILED',
|
|
511
|
+
domain: ErrorDomain.STORAGE,
|
|
512
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
513
|
+
details: {
|
|
514
|
+
tableName,
|
|
515
|
+
},
|
|
516
|
+
},
|
|
517
|
+
error,
|
|
444
518
|
);
|
|
445
|
-
throw new Error(`Failed to alter table ${tableName}: ${error}`);
|
|
446
519
|
}
|
|
447
520
|
}
|
|
448
521
|
|
|
@@ -450,8 +523,17 @@ export class PostgresStore extends MastraStorage {
|
|
|
450
523
|
try {
|
|
451
524
|
await this.db.none(`TRUNCATE TABLE ${this.getTableName(tableName)} CASCADE`);
|
|
452
525
|
} catch (error) {
|
|
453
|
-
|
|
454
|
-
|
|
526
|
+
throw new MastraError(
|
|
527
|
+
{
|
|
528
|
+
id: 'MASTRA_STORAGE_PG_STORE_CLEAR_TABLE_FAILED',
|
|
529
|
+
domain: ErrorDomain.STORAGE,
|
|
530
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
531
|
+
details: {
|
|
532
|
+
tableName,
|
|
533
|
+
},
|
|
534
|
+
},
|
|
535
|
+
error,
|
|
536
|
+
);
|
|
455
537
|
}
|
|
456
538
|
}
|
|
457
539
|
|
|
@@ -466,8 +548,17 @@ export class PostgresStore extends MastraStorage {
|
|
|
466
548
|
values,
|
|
467
549
|
);
|
|
468
550
|
} catch (error) {
|
|
469
|
-
|
|
470
|
-
|
|
551
|
+
throw new MastraError(
|
|
552
|
+
{
|
|
553
|
+
id: 'MASTRA_STORAGE_PG_STORE_INSERT_FAILED',
|
|
554
|
+
domain: ErrorDomain.STORAGE,
|
|
555
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
556
|
+
details: {
|
|
557
|
+
tableName,
|
|
558
|
+
},
|
|
559
|
+
},
|
|
560
|
+
error,
|
|
561
|
+
);
|
|
471
562
|
}
|
|
472
563
|
}
|
|
473
564
|
|
|
@@ -497,8 +588,17 @@ export class PostgresStore extends MastraStorage {
|
|
|
497
588
|
|
|
498
589
|
return result;
|
|
499
590
|
} catch (error) {
|
|
500
|
-
|
|
501
|
-
|
|
591
|
+
throw new MastraError(
|
|
592
|
+
{
|
|
593
|
+
id: 'MASTRA_STORAGE_PG_STORE_LOAD_FAILED',
|
|
594
|
+
domain: ErrorDomain.STORAGE,
|
|
595
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
596
|
+
details: {
|
|
597
|
+
tableName,
|
|
598
|
+
},
|
|
599
|
+
},
|
|
600
|
+
error,
|
|
601
|
+
);
|
|
502
602
|
}
|
|
503
603
|
}
|
|
504
604
|
|
|
@@ -528,8 +628,17 @@ export class PostgresStore extends MastraStorage {
|
|
|
528
628
|
updatedAt: thread.updatedAt,
|
|
529
629
|
};
|
|
530
630
|
} catch (error) {
|
|
531
|
-
|
|
532
|
-
|
|
631
|
+
throw new MastraError(
|
|
632
|
+
{
|
|
633
|
+
id: 'MASTRA_STORAGE_PG_STORE_GET_THREAD_BY_ID_FAILED',
|
|
634
|
+
domain: ErrorDomain.STORAGE,
|
|
635
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
636
|
+
details: {
|
|
637
|
+
threadId,
|
|
638
|
+
},
|
|
639
|
+
},
|
|
640
|
+
error,
|
|
641
|
+
);
|
|
533
642
|
}
|
|
534
643
|
}
|
|
535
644
|
|
|
@@ -601,7 +710,20 @@ export class PostgresStore extends MastraStorage {
|
|
|
601
710
|
hasMore: currentOffset + threads.length < total,
|
|
602
711
|
};
|
|
603
712
|
} catch (error) {
|
|
604
|
-
|
|
713
|
+
const mastraError = new MastraError(
|
|
714
|
+
{
|
|
715
|
+
id: 'MASTRA_STORAGE_PG_STORE_GET_THREADS_BY_RESOURCE_ID_PAGINATED_FAILED',
|
|
716
|
+
domain: ErrorDomain.STORAGE,
|
|
717
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
718
|
+
details: {
|
|
719
|
+
resourceId,
|
|
720
|
+
page,
|
|
721
|
+
},
|
|
722
|
+
},
|
|
723
|
+
error,
|
|
724
|
+
);
|
|
725
|
+
this.logger?.error?.(mastraError.toString());
|
|
726
|
+
this.logger?.trackException(mastraError);
|
|
605
727
|
return { threads: [], total: 0, page, perPage: perPageInput || 100, hasMore: false };
|
|
606
728
|
}
|
|
607
729
|
}
|
|
@@ -635,8 +757,17 @@ export class PostgresStore extends MastraStorage {
|
|
|
635
757
|
|
|
636
758
|
return thread;
|
|
637
759
|
} catch (error) {
|
|
638
|
-
|
|
639
|
-
|
|
760
|
+
throw new MastraError(
|
|
761
|
+
{
|
|
762
|
+
id: 'MASTRA_STORAGE_PG_STORE_SAVE_THREAD_FAILED',
|
|
763
|
+
domain: ErrorDomain.STORAGE,
|
|
764
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
765
|
+
details: {
|
|
766
|
+
threadId: thread.id,
|
|
767
|
+
},
|
|
768
|
+
},
|
|
769
|
+
error,
|
|
770
|
+
);
|
|
640
771
|
}
|
|
641
772
|
}
|
|
642
773
|
|
|
@@ -649,24 +780,33 @@ export class PostgresStore extends MastraStorage {
|
|
|
649
780
|
title: string;
|
|
650
781
|
metadata: Record<string, unknown>;
|
|
651
782
|
}): Promise<StorageThreadType> {
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
783
|
+
// First get the existing thread to merge metadata
|
|
784
|
+
const existingThread = await this.getThreadById({ threadId: id });
|
|
785
|
+
if (!existingThread) {
|
|
786
|
+
throw new MastraError({
|
|
787
|
+
id: 'MASTRA_STORAGE_PG_STORE_UPDATE_THREAD_FAILED',
|
|
788
|
+
domain: ErrorDomain.STORAGE,
|
|
789
|
+
category: ErrorCategory.USER,
|
|
790
|
+
text: `Thread ${id} not found`,
|
|
791
|
+
details: {
|
|
792
|
+
threadId: id,
|
|
793
|
+
title,
|
|
794
|
+
},
|
|
795
|
+
});
|
|
796
|
+
}
|
|
658
797
|
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
798
|
+
// Merge the existing metadata with the new metadata
|
|
799
|
+
const mergedMetadata = {
|
|
800
|
+
...existingThread.metadata,
|
|
801
|
+
...metadata,
|
|
802
|
+
};
|
|
664
803
|
|
|
804
|
+
try {
|
|
665
805
|
const thread = await this.db.one<StorageThreadType>(
|
|
666
806
|
`UPDATE ${this.getTableName(TABLE_THREADS)}
|
|
667
807
|
SET title = $1,
|
|
668
|
-
|
|
669
|
-
|
|
808
|
+
metadata = $2,
|
|
809
|
+
"updatedAt" = $3
|
|
670
810
|
WHERE id = $4
|
|
671
811
|
RETURNING *`,
|
|
672
812
|
[title, mergedMetadata, new Date().toISOString(), id],
|
|
@@ -679,8 +819,18 @@ export class PostgresStore extends MastraStorage {
|
|
|
679
819
|
updatedAt: thread.updatedAt,
|
|
680
820
|
};
|
|
681
821
|
} catch (error) {
|
|
682
|
-
|
|
683
|
-
|
|
822
|
+
throw new MastraError(
|
|
823
|
+
{
|
|
824
|
+
id: 'MASTRA_STORAGE_PG_STORE_UPDATE_THREAD_FAILED',
|
|
825
|
+
domain: ErrorDomain.STORAGE,
|
|
826
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
827
|
+
details: {
|
|
828
|
+
threadId: id,
|
|
829
|
+
title,
|
|
830
|
+
},
|
|
831
|
+
},
|
|
832
|
+
error,
|
|
833
|
+
);
|
|
684
834
|
}
|
|
685
835
|
}
|
|
686
836
|
|
|
@@ -694,41 +844,42 @@ export class PostgresStore extends MastraStorage {
|
|
|
694
844
|
await t.none(`DELETE FROM ${this.getTableName(TABLE_THREADS)} WHERE id = $1`, [threadId]);
|
|
695
845
|
});
|
|
696
846
|
} catch (error) {
|
|
697
|
-
|
|
698
|
-
|
|
847
|
+
throw new MastraError(
|
|
848
|
+
{
|
|
849
|
+
id: 'MASTRA_STORAGE_PG_STORE_DELETE_THREAD_FAILED',
|
|
850
|
+
domain: ErrorDomain.STORAGE,
|
|
851
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
852
|
+
details: {
|
|
853
|
+
threadId,
|
|
854
|
+
},
|
|
855
|
+
},
|
|
856
|
+
error,
|
|
857
|
+
);
|
|
699
858
|
}
|
|
700
859
|
}
|
|
701
860
|
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
const
|
|
715
|
-
const
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
const
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
let paramIdx = 1;
|
|
725
|
-
|
|
726
|
-
for (const inc of include) {
|
|
727
|
-
const { id, withPreviousMessages = 0, withNextMessages = 0 } = inc;
|
|
728
|
-
// if threadId is provided, use it, otherwise use threadId from args
|
|
729
|
-
const searchId = inc.threadId || threadId;
|
|
730
|
-
unionQueries.push(
|
|
731
|
-
`
|
|
861
|
+
private async _getIncludedMessages({
|
|
862
|
+
threadId,
|
|
863
|
+
selectBy,
|
|
864
|
+
orderByStatement,
|
|
865
|
+
}: {
|
|
866
|
+
threadId: string;
|
|
867
|
+
selectBy: StorageGetMessagesArg['selectBy'];
|
|
868
|
+
orderByStatement: string;
|
|
869
|
+
}) {
|
|
870
|
+
const include = selectBy?.include;
|
|
871
|
+
if (!include) return null;
|
|
872
|
+
|
|
873
|
+
const unionQueries: string[] = [];
|
|
874
|
+
const params: any[] = [];
|
|
875
|
+
let paramIdx = 1;
|
|
876
|
+
|
|
877
|
+
for (const inc of include) {
|
|
878
|
+
const { id, withPreviousMessages = 0, withNextMessages = 0 } = inc;
|
|
879
|
+
// if threadId is provided, use it, otherwise use threadId from args
|
|
880
|
+
const searchId = inc.threadId || threadId;
|
|
881
|
+
unionQueries.push(
|
|
882
|
+
`
|
|
732
883
|
SELECT * FROM (
|
|
733
884
|
WITH ordered_messages AS (
|
|
734
885
|
SELECT
|
|
@@ -760,37 +911,59 @@ export class PostgresStore extends MastraStorage {
|
|
|
760
911
|
)
|
|
761
912
|
) AS query_${paramIdx}
|
|
762
913
|
`, // Keep ASC for final sorting after fetching context
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
914
|
+
);
|
|
915
|
+
params.push(searchId, id, withPreviousMessages, withNextMessages);
|
|
916
|
+
paramIdx += 4;
|
|
917
|
+
}
|
|
918
|
+
const finalQuery = unionQueries.join(' UNION ALL ') + ' ORDER BY "createdAt" ASC';
|
|
919
|
+
const includedRows = await this.db.manyOrNone(finalQuery, params);
|
|
920
|
+
const seen = new Set<string>();
|
|
921
|
+
const dedupedRows = includedRows.filter(row => {
|
|
922
|
+
if (seen.has(row.id)) return false;
|
|
923
|
+
seen.add(row.id);
|
|
924
|
+
return true;
|
|
925
|
+
});
|
|
926
|
+
return dedupedRows;
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
/**
|
|
930
|
+
* @deprecated use getMessagesPaginated instead
|
|
931
|
+
*/
|
|
932
|
+
public async getMessages(args: StorageGetMessagesArg & { format?: 'v1' }): Promise<MastraMessageV1[]>;
|
|
933
|
+
public async getMessages(args: StorageGetMessagesArg & { format: 'v2' }): Promise<MastraMessageV2[]>;
|
|
934
|
+
public async getMessages(
|
|
935
|
+
args: StorageGetMessagesArg & {
|
|
936
|
+
format?: 'v1' | 'v2';
|
|
937
|
+
},
|
|
938
|
+
): Promise<MastraMessageV1[] | MastraMessageV2[]> {
|
|
939
|
+
const { threadId, format, selectBy } = args;
|
|
940
|
+
|
|
941
|
+
const selectStatement = `SELECT id, content, role, type, "createdAt", thread_id AS "threadId"`;
|
|
942
|
+
const orderByStatement = `ORDER BY "createdAt" DESC`;
|
|
943
|
+
const limit = this.resolveMessageLimit({ last: selectBy?.last, defaultLimit: 40 });
|
|
944
|
+
|
|
945
|
+
try {
|
|
946
|
+
let rows: any[] = [];
|
|
947
|
+
const include = selectBy?.include || [];
|
|
948
|
+
|
|
949
|
+
if (include?.length) {
|
|
950
|
+
const includeMessages = await this._getIncludedMessages({ threadId, selectBy, orderByStatement });
|
|
951
|
+
if (includeMessages) {
|
|
952
|
+
rows.push(...includeMessages);
|
|
791
953
|
}
|
|
792
954
|
}
|
|
793
955
|
|
|
956
|
+
const excludeIds = rows.map(m => m.id);
|
|
957
|
+
const excludeIdsParam = excludeIds.map((_, idx) => `$${idx + 2}`).join(', ');
|
|
958
|
+
let query = `${selectStatement} FROM ${this.getTableName(TABLE_MESSAGES)} WHERE thread_id = $1
|
|
959
|
+
${excludeIds.length ? `AND id NOT IN (${excludeIdsParam})` : ''}
|
|
960
|
+
${orderByStatement}
|
|
961
|
+
LIMIT $${excludeIds.length + 2}
|
|
962
|
+
`;
|
|
963
|
+
const queryParams: any[] = [threadId, ...excludeIds, limit];
|
|
964
|
+
const remainingRows = await this.db.manyOrNone(query, queryParams);
|
|
965
|
+
rows.push(...remainingRows);
|
|
966
|
+
|
|
794
967
|
const fetchedMessages = (rows || []).map(message => {
|
|
795
968
|
if (typeof message.content === 'string') {
|
|
796
969
|
try {
|
|
@@ -815,7 +988,19 @@ export class PostgresStore extends MastraStorage {
|
|
|
815
988
|
)
|
|
816
989
|
: sortedMessages;
|
|
817
990
|
} catch (error) {
|
|
818
|
-
|
|
991
|
+
const mastraError = new MastraError(
|
|
992
|
+
{
|
|
993
|
+
id: 'MASTRA_STORAGE_PG_STORE_GET_MESSAGES_FAILED',
|
|
994
|
+
domain: ErrorDomain.STORAGE,
|
|
995
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
996
|
+
details: {
|
|
997
|
+
threadId,
|
|
998
|
+
},
|
|
999
|
+
},
|
|
1000
|
+
error,
|
|
1001
|
+
);
|
|
1002
|
+
this.logger?.error?.(mastraError.toString());
|
|
1003
|
+
this.logger?.trackException(mastraError);
|
|
819
1004
|
return [];
|
|
820
1005
|
}
|
|
821
1006
|
}
|
|
@@ -833,8 +1018,20 @@ export class PostgresStore extends MastraStorage {
|
|
|
833
1018
|
const selectStatement = `SELECT id, content, role, type, "createdAt", thread_id AS "threadId"`;
|
|
834
1019
|
const orderByStatement = `ORDER BY "createdAt" DESC`;
|
|
835
1020
|
|
|
1021
|
+
const messages: MastraMessageV2[] = [];
|
|
1022
|
+
|
|
1023
|
+
if (selectBy?.include?.length) {
|
|
1024
|
+
const includeMessages = await this._getIncludedMessages({ threadId, selectBy, orderByStatement });
|
|
1025
|
+
if (includeMessages) {
|
|
1026
|
+
messages.push(...includeMessages);
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
|
|
836
1030
|
try {
|
|
837
|
-
const perPage =
|
|
1031
|
+
const perPage =
|
|
1032
|
+
perPageInput !== undefined
|
|
1033
|
+
? perPageInput
|
|
1034
|
+
: this.resolveMessageLimit({ last: selectBy?.last, defaultLimit: 40 });
|
|
838
1035
|
const currentOffset = page * perPage;
|
|
839
1036
|
|
|
840
1037
|
const conditions: string[] = [`thread_id = $1`];
|
|
@@ -855,7 +1052,7 @@ export class PostgresStore extends MastraStorage {
|
|
|
855
1052
|
const countResult = await this.db.one(countQuery, queryParams);
|
|
856
1053
|
const total = parseInt(countResult.count, 10);
|
|
857
1054
|
|
|
858
|
-
if (total === 0) {
|
|
1055
|
+
if (total === 0 && messages.length === 0) {
|
|
859
1056
|
return {
|
|
860
1057
|
messages: [],
|
|
861
1058
|
total: 0,
|
|
@@ -865,12 +1062,17 @@ export class PostgresStore extends MastraStorage {
|
|
|
865
1062
|
};
|
|
866
1063
|
}
|
|
867
1064
|
|
|
1065
|
+
const excludeIds = messages.map(m => m.id);
|
|
1066
|
+
const excludeIdsParam = excludeIds.map((_, idx) => `$${idx + paramIndex}`).join(', ');
|
|
1067
|
+
paramIndex += excludeIds.length;
|
|
1068
|
+
|
|
868
1069
|
const dataQuery = `${selectStatement} FROM ${this.getTableName(
|
|
869
1070
|
TABLE_MESSAGES,
|
|
870
|
-
)} ${whereClause} ${orderByStatement} LIMIT $${paramIndex++} OFFSET $${paramIndex++}`;
|
|
871
|
-
const rows = await this.db.manyOrNone(dataQuery, [...queryParams, perPage, currentOffset]);
|
|
1071
|
+
)} ${whereClause} ${excludeIds.length ? `AND id NOT IN (${excludeIdsParam})` : ''}${orderByStatement} LIMIT $${paramIndex++} OFFSET $${paramIndex++}`;
|
|
1072
|
+
const rows = await this.db.manyOrNone(dataQuery, [...queryParams, ...excludeIds, perPage, currentOffset]);
|
|
1073
|
+
messages.push(...(rows || []));
|
|
872
1074
|
|
|
873
|
-
const list = new MessageList().add(
|
|
1075
|
+
const list = new MessageList().add(messages, 'memory');
|
|
874
1076
|
const messagesToReturn = format === `v2` ? list.get.all.v2() : list.get.all.v1();
|
|
875
1077
|
|
|
876
1078
|
return {
|
|
@@ -881,7 +1083,20 @@ export class PostgresStore extends MastraStorage {
|
|
|
881
1083
|
hasMore: currentOffset + rows.length < total,
|
|
882
1084
|
};
|
|
883
1085
|
} catch (error) {
|
|
884
|
-
|
|
1086
|
+
const mastraError = new MastraError(
|
|
1087
|
+
{
|
|
1088
|
+
id: 'MASTRA_STORAGE_PG_STORE_GET_MESSAGES_PAGINATED_FAILED',
|
|
1089
|
+
domain: ErrorDomain.STORAGE,
|
|
1090
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1091
|
+
details: {
|
|
1092
|
+
threadId,
|
|
1093
|
+
page,
|
|
1094
|
+
},
|
|
1095
|
+
},
|
|
1096
|
+
error,
|
|
1097
|
+
);
|
|
1098
|
+
this.logger?.error?.(mastraError.toString());
|
|
1099
|
+
this.logger?.trackException(mastraError);
|
|
885
1100
|
return { messages: [], total: 0, page, perPage: perPageInput || 40, hasMore: false };
|
|
886
1101
|
}
|
|
887
1102
|
}
|
|
@@ -896,18 +1111,31 @@ export class PostgresStore extends MastraStorage {
|
|
|
896
1111
|
| { messages: MastraMessageV2[]; format: 'v2' }): Promise<MastraMessageV2[] | MastraMessageV1[]> {
|
|
897
1112
|
if (messages.length === 0) return messages;
|
|
898
1113
|
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
1114
|
+
const threadId = messages[0]?.threadId;
|
|
1115
|
+
if (!threadId) {
|
|
1116
|
+
throw new MastraError({
|
|
1117
|
+
id: 'MASTRA_STORAGE_PG_STORE_SAVE_MESSAGES_FAILED',
|
|
1118
|
+
domain: ErrorDomain.STORAGE,
|
|
1119
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1120
|
+
text: `Thread ID is required`,
|
|
1121
|
+
});
|
|
1122
|
+
}
|
|
904
1123
|
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
1124
|
+
// Check if thread exists
|
|
1125
|
+
const thread = await this.getThreadById({ threadId });
|
|
1126
|
+
if (!thread) {
|
|
1127
|
+
throw new MastraError({
|
|
1128
|
+
id: 'MASTRA_STORAGE_PG_STORE_SAVE_MESSAGES_FAILED',
|
|
1129
|
+
domain: ErrorDomain.STORAGE,
|
|
1130
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1131
|
+
text: `Thread ${threadId} not found`,
|
|
1132
|
+
details: {
|
|
1133
|
+
threadId,
|
|
1134
|
+
},
|
|
1135
|
+
});
|
|
1136
|
+
}
|
|
910
1137
|
|
|
1138
|
+
try {
|
|
911
1139
|
await this.db.tx(async t => {
|
|
912
1140
|
// Execute message inserts and thread update in parallel for better performance
|
|
913
1141
|
const messageInserts = messages.map(message => {
|
|
@@ -923,7 +1151,13 @@ export class PostgresStore extends MastraStorage {
|
|
|
923
1151
|
}
|
|
924
1152
|
return t.none(
|
|
925
1153
|
`INSERT INTO ${this.getTableName(TABLE_MESSAGES)} (id, thread_id, content, "createdAt", role, type, "resourceId")
|
|
926
|
-
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
|
1154
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
|
1155
|
+
ON CONFLICT (id) DO UPDATE SET
|
|
1156
|
+
thread_id = EXCLUDED.thread_id,
|
|
1157
|
+
content = EXCLUDED.content,
|
|
1158
|
+
role = EXCLUDED.role,
|
|
1159
|
+
type = EXCLUDED.type,
|
|
1160
|
+
"resourceId" = EXCLUDED."resourceId"`,
|
|
927
1161
|
[
|
|
928
1162
|
message.id,
|
|
929
1163
|
message.threadId,
|
|
@@ -950,8 +1184,17 @@ export class PostgresStore extends MastraStorage {
|
|
|
950
1184
|
if (format === `v2`) return list.get.all.v2();
|
|
951
1185
|
return list.get.all.v1();
|
|
952
1186
|
} catch (error) {
|
|
953
|
-
|
|
954
|
-
|
|
1187
|
+
throw new MastraError(
|
|
1188
|
+
{
|
|
1189
|
+
id: 'MASTRA_STORAGE_PG_STORE_SAVE_MESSAGES_FAILED',
|
|
1190
|
+
domain: ErrorDomain.STORAGE,
|
|
1191
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1192
|
+
details: {
|
|
1193
|
+
threadId,
|
|
1194
|
+
},
|
|
1195
|
+
},
|
|
1196
|
+
error,
|
|
1197
|
+
);
|
|
955
1198
|
}
|
|
956
1199
|
}
|
|
957
1200
|
|
|
@@ -980,8 +1223,18 @@ export class PostgresStore extends MastraStorage {
|
|
|
980
1223
|
[workflowName, runId, JSON.stringify(snapshot), now, now],
|
|
981
1224
|
);
|
|
982
1225
|
} catch (error) {
|
|
983
|
-
|
|
984
|
-
|
|
1226
|
+
throw new MastraError(
|
|
1227
|
+
{
|
|
1228
|
+
id: 'MASTRA_STORAGE_PG_STORE_PERSIST_WORKFLOW_SNAPSHOT_FAILED',
|
|
1229
|
+
domain: ErrorDomain.STORAGE,
|
|
1230
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1231
|
+
details: {
|
|
1232
|
+
workflowName,
|
|
1233
|
+
runId,
|
|
1234
|
+
},
|
|
1235
|
+
},
|
|
1236
|
+
error,
|
|
1237
|
+
);
|
|
985
1238
|
}
|
|
986
1239
|
}
|
|
987
1240
|
|
|
@@ -1007,8 +1260,18 @@ export class PostgresStore extends MastraStorage {
|
|
|
1007
1260
|
|
|
1008
1261
|
return (result as any).snapshot;
|
|
1009
1262
|
} catch (error) {
|
|
1010
|
-
|
|
1011
|
-
|
|
1263
|
+
throw new MastraError(
|
|
1264
|
+
{
|
|
1265
|
+
id: 'MASTRA_STORAGE_PG_STORE_LOAD_WORKFLOW_SNAPSHOT_FAILED',
|
|
1266
|
+
domain: ErrorDomain.STORAGE,
|
|
1267
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1268
|
+
details: {
|
|
1269
|
+
workflowName,
|
|
1270
|
+
runId,
|
|
1271
|
+
},
|
|
1272
|
+
},
|
|
1273
|
+
error,
|
|
1274
|
+
);
|
|
1012
1275
|
}
|
|
1013
1276
|
}
|
|
1014
1277
|
|
|
@@ -1122,8 +1385,17 @@ export class PostgresStore extends MastraStorage {
|
|
|
1122
1385
|
// Use runs.length as total when not paginating
|
|
1123
1386
|
return { runs, total: total || runs.length };
|
|
1124
1387
|
} catch (error) {
|
|
1125
|
-
|
|
1126
|
-
|
|
1388
|
+
throw new MastraError(
|
|
1389
|
+
{
|
|
1390
|
+
id: 'MASTRA_STORAGE_PG_STORE_GET_WORKFLOW_RUNS_FAILED',
|
|
1391
|
+
domain: ErrorDomain.STORAGE,
|
|
1392
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1393
|
+
details: {
|
|
1394
|
+
workflowName: workflowName || 'all',
|
|
1395
|
+
},
|
|
1396
|
+
},
|
|
1397
|
+
error,
|
|
1398
|
+
);
|
|
1127
1399
|
}
|
|
1128
1400
|
}
|
|
1129
1401
|
|
|
@@ -1169,8 +1441,18 @@ export class PostgresStore extends MastraStorage {
|
|
|
1169
1441
|
|
|
1170
1442
|
return this.parseWorkflowRun(result);
|
|
1171
1443
|
} catch (error) {
|
|
1172
|
-
|
|
1173
|
-
|
|
1444
|
+
throw new MastraError(
|
|
1445
|
+
{
|
|
1446
|
+
id: 'MASTRA_STORAGE_PG_STORE_GET_WORKFLOW_RUN_BY_ID_FAILED',
|
|
1447
|
+
domain: ErrorDomain.STORAGE,
|
|
1448
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1449
|
+
details: {
|
|
1450
|
+
runId,
|
|
1451
|
+
workflowName: workflowName || '',
|
|
1452
|
+
},
|
|
1453
|
+
},
|
|
1454
|
+
error,
|
|
1455
|
+
);
|
|
1174
1456
|
}
|
|
1175
1457
|
}
|
|
1176
1458
|
|
|
@@ -1216,32 +1498,52 @@ export class PostgresStore extends MastraStorage {
|
|
|
1216
1498
|
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
|
|
1217
1499
|
|
|
1218
1500
|
const countQuery = `SELECT COUNT(*) FROM ${this.getTableName(TABLE_EVALS)} ${whereClause}`;
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1501
|
+
try {
|
|
1502
|
+
const countResult = await this.db.one(countQuery, queryParams);
|
|
1503
|
+
const total = parseInt(countResult.count, 10);
|
|
1504
|
+
const currentOffset = page * perPage;
|
|
1505
|
+
|
|
1506
|
+
if (total === 0) {
|
|
1507
|
+
return {
|
|
1508
|
+
evals: [],
|
|
1509
|
+
total: 0,
|
|
1510
|
+
page,
|
|
1511
|
+
perPage,
|
|
1512
|
+
hasMore: false,
|
|
1513
|
+
};
|
|
1514
|
+
}
|
|
1515
|
+
|
|
1516
|
+
const dataQuery = `SELECT * FROM ${this.getTableName(
|
|
1517
|
+
TABLE_EVALS,
|
|
1518
|
+
)} ${whereClause} ORDER BY created_at DESC LIMIT $${paramIndex++} OFFSET $${paramIndex++}`;
|
|
1519
|
+
const rows = await this.db.manyOrNone(dataQuery, [...queryParams, perPage, currentOffset]);
|
|
1222
1520
|
|
|
1223
|
-
if (total === 0) {
|
|
1224
1521
|
return {
|
|
1225
|
-
evals: [],
|
|
1226
|
-
total
|
|
1522
|
+
evals: rows?.map(row => this.transformEvalRow(row)) ?? [],
|
|
1523
|
+
total,
|
|
1227
1524
|
page,
|
|
1228
1525
|
perPage,
|
|
1229
|
-
hasMore:
|
|
1526
|
+
hasMore: currentOffset + (rows?.length ?? 0) < total,
|
|
1230
1527
|
};
|
|
1528
|
+
} catch (error) {
|
|
1529
|
+
const mastraError = new MastraError(
|
|
1530
|
+
{
|
|
1531
|
+
id: 'MASTRA_STORAGE_PG_STORE_GET_EVALS_FAILED',
|
|
1532
|
+
domain: ErrorDomain.STORAGE,
|
|
1533
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1534
|
+
details: {
|
|
1535
|
+
agentName: agentName || 'all',
|
|
1536
|
+
type: type || 'all',
|
|
1537
|
+
page,
|
|
1538
|
+
perPage,
|
|
1539
|
+
},
|
|
1540
|
+
},
|
|
1541
|
+
error,
|
|
1542
|
+
);
|
|
1543
|
+
this.logger?.error?.(mastraError.toString());
|
|
1544
|
+
this.logger?.trackException(mastraError);
|
|
1545
|
+
throw mastraError;
|
|
1231
1546
|
}
|
|
1232
|
-
|
|
1233
|
-
const dataQuery = `SELECT * FROM ${this.getTableName(
|
|
1234
|
-
TABLE_EVALS,
|
|
1235
|
-
)} ${whereClause} ORDER BY created_at DESC LIMIT $${paramIndex++} OFFSET $${paramIndex++}`;
|
|
1236
|
-
const rows = await this.db.manyOrNone(dataQuery, [...queryParams, perPage, currentOffset]);
|
|
1237
|
-
|
|
1238
|
-
return {
|
|
1239
|
-
evals: rows?.map(row => this.transformEvalRow(row)) ?? [],
|
|
1240
|
-
total,
|
|
1241
|
-
page,
|
|
1242
|
-
perPage,
|
|
1243
|
-
hasMore: currentOffset + (rows?.length ?? 0) < total,
|
|
1244
|
-
};
|
|
1245
1547
|
}
|
|
1246
1548
|
|
|
1247
1549
|
async updateMessages({
|
|
@@ -1373,4 +1675,101 @@ export class PostgresStore extends MastraStorage {
|
|
|
1373
1675
|
return message;
|
|
1374
1676
|
});
|
|
1375
1677
|
}
|
|
1678
|
+
|
|
1679
|
+
async getResourceById({ resourceId }: { resourceId: string }): Promise<StorageResourceType | null> {
|
|
1680
|
+
const tableName = this.getTableName(TABLE_RESOURCES);
|
|
1681
|
+
const result = await this.db.oneOrNone<StorageResourceType>(`SELECT * FROM ${tableName} WHERE id = $1`, [
|
|
1682
|
+
resourceId,
|
|
1683
|
+
]);
|
|
1684
|
+
|
|
1685
|
+
if (!result) {
|
|
1686
|
+
return null;
|
|
1687
|
+
}
|
|
1688
|
+
|
|
1689
|
+
return {
|
|
1690
|
+
...result,
|
|
1691
|
+
// Ensure workingMemory is always returned as a string, regardless of automatic parsing
|
|
1692
|
+
workingMemory:
|
|
1693
|
+
typeof result.workingMemory === 'object' ? JSON.stringify(result.workingMemory) : result.workingMemory,
|
|
1694
|
+
metadata: typeof result.metadata === 'string' ? JSON.parse(result.metadata) : result.metadata,
|
|
1695
|
+
};
|
|
1696
|
+
}
|
|
1697
|
+
|
|
1698
|
+
async saveResource({ resource }: { resource: StorageResourceType }): Promise<StorageResourceType> {
|
|
1699
|
+
const tableName = this.getTableName(TABLE_RESOURCES);
|
|
1700
|
+
await this.db.none(
|
|
1701
|
+
`INSERT INTO ${tableName} (id, "workingMemory", metadata, "createdAt", "updatedAt")
|
|
1702
|
+
VALUES ($1, $2, $3, $4, $5)`,
|
|
1703
|
+
[
|
|
1704
|
+
resource.id,
|
|
1705
|
+
resource.workingMemory,
|
|
1706
|
+
JSON.stringify(resource.metadata),
|
|
1707
|
+
resource.createdAt.toISOString(),
|
|
1708
|
+
resource.updatedAt.toISOString(),
|
|
1709
|
+
],
|
|
1710
|
+
);
|
|
1711
|
+
|
|
1712
|
+
return resource;
|
|
1713
|
+
}
|
|
1714
|
+
|
|
1715
|
+
async updateResource({
|
|
1716
|
+
resourceId,
|
|
1717
|
+
workingMemory,
|
|
1718
|
+
metadata,
|
|
1719
|
+
}: {
|
|
1720
|
+
resourceId: string;
|
|
1721
|
+
workingMemory?: string;
|
|
1722
|
+
metadata?: Record<string, unknown>;
|
|
1723
|
+
}): Promise<StorageResourceType> {
|
|
1724
|
+
const existingResource = await this.getResourceById({ resourceId });
|
|
1725
|
+
|
|
1726
|
+
if (!existingResource) {
|
|
1727
|
+
// Create new resource if it doesn't exist
|
|
1728
|
+
const newResource: StorageResourceType = {
|
|
1729
|
+
id: resourceId,
|
|
1730
|
+
workingMemory,
|
|
1731
|
+
metadata: metadata || {},
|
|
1732
|
+
createdAt: new Date(),
|
|
1733
|
+
updatedAt: new Date(),
|
|
1734
|
+
};
|
|
1735
|
+
return this.saveResource({ resource: newResource });
|
|
1736
|
+
}
|
|
1737
|
+
|
|
1738
|
+
const updatedResource = {
|
|
1739
|
+
...existingResource,
|
|
1740
|
+
workingMemory: workingMemory !== undefined ? workingMemory : existingResource.workingMemory,
|
|
1741
|
+
metadata: {
|
|
1742
|
+
...existingResource.metadata,
|
|
1743
|
+
...metadata,
|
|
1744
|
+
},
|
|
1745
|
+
updatedAt: new Date(),
|
|
1746
|
+
};
|
|
1747
|
+
|
|
1748
|
+
const tableName = this.getTableName(TABLE_RESOURCES);
|
|
1749
|
+
const updates: string[] = [];
|
|
1750
|
+
const values: any[] = [];
|
|
1751
|
+
let paramIndex = 1;
|
|
1752
|
+
|
|
1753
|
+
if (workingMemory !== undefined) {
|
|
1754
|
+
updates.push(`"workingMemory" = $${paramIndex}`);
|
|
1755
|
+
values.push(workingMemory);
|
|
1756
|
+
paramIndex++;
|
|
1757
|
+
}
|
|
1758
|
+
|
|
1759
|
+
if (metadata) {
|
|
1760
|
+
updates.push(`metadata = $${paramIndex}`);
|
|
1761
|
+
values.push(JSON.stringify(updatedResource.metadata));
|
|
1762
|
+
paramIndex++;
|
|
1763
|
+
}
|
|
1764
|
+
|
|
1765
|
+
updates.push(`"updatedAt" = $${paramIndex}`);
|
|
1766
|
+
values.push(updatedResource.updatedAt.toISOString());
|
|
1767
|
+
paramIndex++;
|
|
1768
|
+
|
|
1769
|
+
values.push(resourceId);
|
|
1770
|
+
|
|
1771
|
+
await this.db.none(`UPDATE ${tableName} SET ${updates.join(', ')} WHERE id = $${paramIndex}`, values);
|
|
1772
|
+
|
|
1773
|
+
return updatedResource;
|
|
1774
|
+
}
|
|
1376
1775
|
}
|