@mastra/pg 0.3.4 → 0.4.0-alpha.1
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 +37 -0
- package/dist/_tsup-dts-rollup.d.cts +21 -83
- package/dist/_tsup-dts-rollup.d.ts +21 -83
- package/dist/index.cjs +169 -185
- package/dist/index.js +169 -185
- package/docker-compose.perf.yaml +9 -9
- package/package.json +7 -4
- package/src/storage/index.test.ts +32 -51
- package/src/storage/index.ts +13 -17
- package/src/vector/index.test.ts +52 -179
- package/src/vector/index.ts +64 -152
- package/src/vector/sql-builder.ts +110 -77
- package/src/vector/vector.performance.test.ts +2 -2
|
@@ -41,10 +41,7 @@ const createSampleMessage = (threadId: string): MessageType => ({
|
|
|
41
41
|
createdAt: new Date(),
|
|
42
42
|
});
|
|
43
43
|
|
|
44
|
-
const createSampleWorkflowSnapshot = (
|
|
45
|
-
status: WorkflowRunState['context']['steps'][string]['status'],
|
|
46
|
-
createdAt?: Date,
|
|
47
|
-
) => {
|
|
44
|
+
const createSampleWorkflowSnapshot = (status: WorkflowRunState['context'][string]['status'], createdAt?: Date) => {
|
|
48
45
|
const runId = `run-${randomUUID()}`;
|
|
49
46
|
const stepId = `step-${randomUUID()}`;
|
|
50
47
|
const timestamp = createdAt || new Date();
|
|
@@ -52,21 +49,18 @@ const createSampleWorkflowSnapshot = (
|
|
|
52
49
|
result: { success: true },
|
|
53
50
|
value: {},
|
|
54
51
|
context: {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
error: undefined,
|
|
60
|
-
},
|
|
52
|
+
[stepId]: {
|
|
53
|
+
status,
|
|
54
|
+
payload: {},
|
|
55
|
+
error: undefined,
|
|
61
56
|
},
|
|
62
|
-
|
|
63
|
-
attempts: {},
|
|
57
|
+
input: {},
|
|
64
58
|
},
|
|
65
59
|
activePaths: [],
|
|
66
60
|
suspendedPaths: {},
|
|
67
61
|
runId,
|
|
68
62
|
timestamp: timestamp.getTime(),
|
|
69
|
-
};
|
|
63
|
+
} as unknown as WorkflowRunState;
|
|
70
64
|
return { snapshot, runId, stepId };
|
|
71
65
|
};
|
|
72
66
|
|
|
@@ -92,7 +86,7 @@ const checkWorkflowSnapshot = (snapshot: WorkflowRunState | string, stepId: stri
|
|
|
92
86
|
if (typeof snapshot === 'string') {
|
|
93
87
|
throw new Error('Expected WorkflowRunState, got string');
|
|
94
88
|
}
|
|
95
|
-
expect(snapshot.context?.
|
|
89
|
+
expect(snapshot.context?.[stepId]?.status).toBe(status);
|
|
96
90
|
};
|
|
97
91
|
|
|
98
92
|
describe('PostgresStore', () => {
|
|
@@ -356,17 +350,15 @@ describe('PostgresStore', () => {
|
|
|
356
350
|
const snapshot = {
|
|
357
351
|
status: 'running',
|
|
358
352
|
context: {
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
attempts: {},
|
|
362
|
-
triggerData: { type: 'manual' },
|
|
353
|
+
input: { type: 'manual' },
|
|
354
|
+
step1: { status: 'success', output: { data: 'test' } },
|
|
363
355
|
},
|
|
364
356
|
value: {},
|
|
365
357
|
activePaths: [],
|
|
366
358
|
suspendedPaths: {},
|
|
367
359
|
runId,
|
|
368
360
|
timestamp: new Date().getTime(),
|
|
369
|
-
};
|
|
361
|
+
} as unknown as WorkflowRunState;
|
|
370
362
|
|
|
371
363
|
await store.persistWorkflowSnapshot({
|
|
372
364
|
workflowName,
|
|
@@ -397,10 +389,7 @@ describe('PostgresStore', () => {
|
|
|
397
389
|
const initialSnapshot = {
|
|
398
390
|
status: 'running',
|
|
399
391
|
context: {
|
|
400
|
-
|
|
401
|
-
stepResults: {},
|
|
402
|
-
attempts: {},
|
|
403
|
-
triggerData: { type: 'manual' },
|
|
392
|
+
input: { type: 'manual' },
|
|
404
393
|
},
|
|
405
394
|
value: {},
|
|
406
395
|
activePaths: [],
|
|
@@ -412,18 +401,14 @@ describe('PostgresStore', () => {
|
|
|
412
401
|
await store.persistWorkflowSnapshot({
|
|
413
402
|
workflowName,
|
|
414
403
|
runId,
|
|
415
|
-
snapshot: initialSnapshot,
|
|
404
|
+
snapshot: initialSnapshot as unknown as WorkflowRunState,
|
|
416
405
|
});
|
|
417
406
|
|
|
418
407
|
const updatedSnapshot = {
|
|
419
|
-
status: '
|
|
408
|
+
status: 'success',
|
|
420
409
|
context: {
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
'step-1': { status: 'success', result: { data: 'test' } },
|
|
424
|
-
},
|
|
425
|
-
attempts: { 'step-1': 1 },
|
|
426
|
-
triggerData: { type: 'manual' },
|
|
410
|
+
input: { type: 'manual' },
|
|
411
|
+
'step-1': { status: 'success', result: { data: 'test' } },
|
|
427
412
|
},
|
|
428
413
|
value: {},
|
|
429
414
|
activePaths: [],
|
|
@@ -435,7 +420,7 @@ describe('PostgresStore', () => {
|
|
|
435
420
|
await store.persistWorkflowSnapshot({
|
|
436
421
|
workflowName,
|
|
437
422
|
runId,
|
|
438
|
-
snapshot: updatedSnapshot,
|
|
423
|
+
snapshot: updatedSnapshot as unknown as WorkflowRunState,
|
|
439
424
|
});
|
|
440
425
|
|
|
441
426
|
const loadedSnapshot = await store.loadWorkflowSnapshot({
|
|
@@ -452,25 +437,21 @@ describe('PostgresStore', () => {
|
|
|
452
437
|
const complexSnapshot = {
|
|
453
438
|
value: { currentState: 'running' },
|
|
454
439
|
context: {
|
|
455
|
-
|
|
456
|
-
'
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
date: new Date().toISOString(),
|
|
463
|
-
},
|
|
440
|
+
'step-1': {
|
|
441
|
+
status: 'success',
|
|
442
|
+
output: {
|
|
443
|
+
nestedData: {
|
|
444
|
+
array: [1, 2, 3],
|
|
445
|
+
object: { key: 'value' },
|
|
446
|
+
date: new Date().toISOString(),
|
|
464
447
|
},
|
|
465
448
|
},
|
|
466
|
-
'step-2': {
|
|
467
|
-
status: 'waiting',
|
|
468
|
-
dependencies: ['step-3', 'step-4'],
|
|
469
|
-
},
|
|
470
449
|
},
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
450
|
+
'step-2': {
|
|
451
|
+
status: 'waiting',
|
|
452
|
+
dependencies: ['step-3', 'step-4'],
|
|
453
|
+
},
|
|
454
|
+
input: {
|
|
474
455
|
type: 'scheduled',
|
|
475
456
|
metadata: {
|
|
476
457
|
schedule: '0 0 * * *',
|
|
@@ -498,7 +479,7 @@ describe('PostgresStore', () => {
|
|
|
498
479
|
await store.persistWorkflowSnapshot({
|
|
499
480
|
workflowName,
|
|
500
481
|
runId,
|
|
501
|
-
snapshot: complexSnapshot,
|
|
482
|
+
snapshot: complexSnapshot as unknown as WorkflowRunState,
|
|
502
483
|
});
|
|
503
484
|
|
|
504
485
|
const loadedSnapshot = await store.loadWorkflowSnapshot({
|
|
@@ -704,7 +685,7 @@ describe('PostgresStore', () => {
|
|
|
704
685
|
// Insert multiple workflow runs for the same resourceId
|
|
705
686
|
resourceId = 'resource-shared';
|
|
706
687
|
for (const status of ['success', 'failed']) {
|
|
707
|
-
const sample = createSampleWorkflowSnapshot(status as WorkflowRunState['context'][
|
|
688
|
+
const sample = createSampleWorkflowSnapshot(status as WorkflowRunState['context'][string]['status']);
|
|
708
689
|
runIds.push(sample.runId);
|
|
709
690
|
await store.insert({
|
|
710
691
|
tableName: TABLE_WORKFLOW_SNAPSHOT,
|
|
@@ -719,7 +700,7 @@ describe('PostgresStore', () => {
|
|
|
719
700
|
});
|
|
720
701
|
}
|
|
721
702
|
// Insert a run with a different resourceId
|
|
722
|
-
const other = createSampleWorkflowSnapshot('
|
|
703
|
+
const other = createSampleWorkflowSnapshot('suspended');
|
|
723
704
|
await store.insert({
|
|
724
705
|
tableName: TABLE_WORKFLOW_SNAPSHOT,
|
|
725
706
|
record: {
|
package/src/storage/index.ts
CHANGED
|
@@ -16,16 +16,13 @@ import type {
|
|
|
16
16
|
WorkflowRun,
|
|
17
17
|
WorkflowRuns,
|
|
18
18
|
} from '@mastra/core/storage';
|
|
19
|
+
import { parseSqlIdentifier } from '@mastra/core/utils';
|
|
19
20
|
import type { WorkflowRunState } from '@mastra/core/workflows';
|
|
20
21
|
import pgPromise from 'pg-promise';
|
|
21
22
|
import type { ISSLConfig } from 'pg-promise/typescript/pg-subset';
|
|
22
23
|
|
|
23
24
|
export type PostgresConfig = {
|
|
24
25
|
schemaName?: string;
|
|
25
|
-
/**
|
|
26
|
-
* @deprecated Use `schemaName` instead. Support for `schema` will be removed on May 20th, 2025.
|
|
27
|
-
*/
|
|
28
|
-
schema?: string;
|
|
29
26
|
} & (
|
|
30
27
|
| {
|
|
31
28
|
host: string;
|
|
@@ -71,13 +68,7 @@ export class PostgresStore extends MastraStorage {
|
|
|
71
68
|
}
|
|
72
69
|
super({ name: 'PostgresStore' });
|
|
73
70
|
this.pgp = pgPromise();
|
|
74
|
-
|
|
75
|
-
if ('schema' in config && config.schema) {
|
|
76
|
-
console.warn(
|
|
77
|
-
'[DEPRECATION NOTICE] The "schema" option in PostgresStore is deprecated. Please use "schemaName" instead. Support for "schema" will be removed on May 20th, 2025.',
|
|
78
|
-
);
|
|
79
|
-
}
|
|
80
|
-
this.schema = config.schemaName ?? config.schema;
|
|
71
|
+
this.schema = config.schemaName;
|
|
81
72
|
this.db = this.pgp(
|
|
82
73
|
`connectionString` in config
|
|
83
74
|
? { connectionString: config.connectionString }
|
|
@@ -93,7 +84,9 @@ export class PostgresStore extends MastraStorage {
|
|
|
93
84
|
}
|
|
94
85
|
|
|
95
86
|
private getTableName(indexName: string) {
|
|
96
|
-
|
|
87
|
+
const parsedIndexName = parseSqlIdentifier(indexName, 'table name');
|
|
88
|
+
const parsedSchemaName = this.schema ? parseSqlIdentifier(this.schema, 'schema name') : undefined;
|
|
89
|
+
return parsedSchemaName ? `${parsedSchemaName}."${parsedIndexName}"` : `"${parsedIndexName}"`;
|
|
97
90
|
}
|
|
98
91
|
|
|
99
92
|
async getEvalsByAgentName(agentName: string, type?: 'test' | 'live'): Promise<EvalRow[]> {
|
|
@@ -192,13 +185,15 @@ export class PostgresStore extends MastraStorage {
|
|
|
192
185
|
}
|
|
193
186
|
if (attributes) {
|
|
194
187
|
Object.keys(attributes).forEach(key => {
|
|
195
|
-
|
|
188
|
+
const parsedKey = parseSqlIdentifier(key, 'attribute key');
|
|
189
|
+
conditions.push(`attributes->>'${parsedKey}' = \$${idx++}`);
|
|
196
190
|
});
|
|
197
191
|
}
|
|
198
192
|
|
|
199
193
|
if (filters) {
|
|
200
194
|
Object.entries(filters).forEach(([key]) => {
|
|
201
|
-
|
|
195
|
+
const parsedKey = parseSqlIdentifier(key, 'filter key');
|
|
196
|
+
conditions.push(`${parsedKey} = \$${idx++}`);
|
|
202
197
|
});
|
|
203
198
|
}
|
|
204
199
|
|
|
@@ -341,10 +336,11 @@ export class PostgresStore extends MastraStorage {
|
|
|
341
336
|
try {
|
|
342
337
|
const columns = Object.entries(schema)
|
|
343
338
|
.map(([name, def]) => {
|
|
339
|
+
const parsedName = parseSqlIdentifier(name, 'column name');
|
|
344
340
|
const constraints = [];
|
|
345
341
|
if (def.primaryKey) constraints.push('PRIMARY KEY');
|
|
346
342
|
if (!def.nullable) constraints.push('NOT NULL');
|
|
347
|
-
return `"${
|
|
343
|
+
return `"${parsedName}" ${def.type.toUpperCase()} ${constraints.join(' ')}`;
|
|
348
344
|
})
|
|
349
345
|
.join(',\n');
|
|
350
346
|
|
|
@@ -392,7 +388,7 @@ export class PostgresStore extends MastraStorage {
|
|
|
392
388
|
|
|
393
389
|
async insert({ tableName, record }: { tableName: TABLE_NAMES; record: Record<string, any> }): Promise<void> {
|
|
394
390
|
try {
|
|
395
|
-
const columns = Object.keys(record);
|
|
391
|
+
const columns = Object.keys(record).map(col => parseSqlIdentifier(col, 'column name'));
|
|
396
392
|
const values = Object.values(record);
|
|
397
393
|
const placeholders = values.map((_, i) => `$${i + 1}`).join(', ');
|
|
398
394
|
|
|
@@ -408,7 +404,7 @@ export class PostgresStore extends MastraStorage {
|
|
|
408
404
|
|
|
409
405
|
async load<R>({ tableName, keys }: { tableName: TABLE_NAMES; keys: Record<string, string> }): Promise<R | null> {
|
|
410
406
|
try {
|
|
411
|
-
const keyEntries = Object.entries(keys);
|
|
407
|
+
const keyEntries = Object.entries(keys).map(([key, value]) => [parseSqlIdentifier(key, 'column name'), value]);
|
|
412
408
|
const conditions = keyEntries.map(([key], index) => `"${key}" = $${index + 1}`).join(' AND ');
|
|
413
409
|
const values = keyEntries.map(([_, value]) => value);
|
|
414
410
|
|