@mastra/pg 1.20.0 → 1.20.1-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/CHANGELOG.md +18 -0
- package/dist/docs/SKILL.md +2 -2
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/docs/references/docs-deployment-workers.md +253 -7
- package/dist/docs/references/docs-memory-semantic-recall.md +1 -1
- package/dist/docs/references/docs-memory-working-memory.md +3 -3
- package/dist/docs/references/{docs-storage-overview.md → docs-storage.md} +8 -7
- package/dist/docs/references/integrations-databases-postgresql.md +11 -9
- package/dist/docs/references/reference-rag-chunking-and-embedding.md +1 -1
- package/dist/docs/references/reference-rag-metadata-filters.md +1 -1
- package/dist/docs/references/reference-storage-retention.md +1 -1
- package/dist/docs/references/reference-tools-vector-query-tool.md +1 -1
- package/dist/docs/references/reference-vectors-pg.md +1 -1
- package/dist/index.cjs +113 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +113 -5
- package/dist/index.js.map +1 -1
- package/dist/storage/db/index.d.ts +12 -0
- package/dist/storage/db/index.d.ts.map +1 -1
- package/dist/storage/db/schema-snapshot.d.ts +2 -0
- package/dist/storage/db/schema-snapshot.d.ts.map +1 -1
- package/dist/storage/domains/workflows/index.d.ts +1 -2
- package/dist/storage/domains/workflows/index.d.ts.map +1 -1
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -2152,7 +2152,7 @@ async function loadSchemaSnapshot(client, schemaName) {
|
|
|
2152
2152
|
const schema = schemaName || "public";
|
|
2153
2153
|
const [tableRows, columnRows, indexRows] = await Promise.all([
|
|
2154
2154
|
client.manyOrNone(`SELECT tablename FROM pg_catalog.pg_tables WHERE schemaname = $1`, [schema]),
|
|
2155
|
-
client.manyOrNone(`SELECT c.relname AS table_name, a.attname AS column_name
|
|
2155
|
+
client.manyOrNone(`SELECT c.relname AS table_name, a.attname AS column_name, format_type(a.atttypid, a.atttypmod) AS data_type
|
|
2156
2156
|
FROM pg_catalog.pg_class c
|
|
2157
2157
|
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
|
2158
2158
|
JOIN pg_catalog.pg_attribute a ON a.attrelid = c.oid
|
|
@@ -2167,6 +2167,7 @@ async function loadSchemaSnapshot(client, schemaName) {
|
|
|
2167
2167
|
WHERE n.nspname = $1`, [schema])
|
|
2168
2168
|
]);
|
|
2169
2169
|
const columns = /* @__PURE__ */ new Map();
|
|
2170
|
+
const columnTypes = /* @__PURE__ */ new Map();
|
|
2170
2171
|
for (const row of columnRows) {
|
|
2171
2172
|
let set = columns.get(row.table_name);
|
|
2172
2173
|
if (!set) {
|
|
@@ -2174,6 +2175,12 @@ async function loadSchemaSnapshot(client, schemaName) {
|
|
|
2174
2175
|
columns.set(row.table_name, set);
|
|
2175
2176
|
}
|
|
2176
2177
|
set.add(row.column_name);
|
|
2178
|
+
let types = columnTypes.get(row.table_name);
|
|
2179
|
+
if (!types) {
|
|
2180
|
+
types = /* @__PURE__ */ new Map();
|
|
2181
|
+
columnTypes.set(row.table_name, types);
|
|
2182
|
+
}
|
|
2183
|
+
types.set(row.column_name, row.data_type);
|
|
2177
2184
|
}
|
|
2178
2185
|
const indexes = /* @__PURE__ */ new Set();
|
|
2179
2186
|
const replicaIdentityIndexes = /* @__PURE__ */ new Set();
|
|
@@ -2187,6 +2194,7 @@ async function loadSchemaSnapshot(client, schemaName) {
|
|
|
2187
2194
|
schemaName: schema,
|
|
2188
2195
|
tables: new Set(tableRows.map((r) => r.tablename)),
|
|
2189
2196
|
columns,
|
|
2197
|
+
columnTypes,
|
|
2190
2198
|
indexes,
|
|
2191
2199
|
replicaIdentityIndexes,
|
|
2192
2200
|
primaryKeyIndexes
|
|
@@ -2440,6 +2448,8 @@ var PgDB = class extends MastraBase {
|
|
|
2440
2448
|
skipDefaultIndexes;
|
|
2441
2449
|
/** Cache of actual table columns: tableName -> Set<columnName> */
|
|
2442
2450
|
tableColumnsCache = /* @__PURE__ */ new Map();
|
|
2451
|
+
/** Cache of column Postgres data types: tableName -> columnName -> data_type */
|
|
2452
|
+
columnTypeCache = /* @__PURE__ */ new Map();
|
|
2443
2453
|
constructor(config) {
|
|
2444
2454
|
super({
|
|
2445
2455
|
component: "STORAGE",
|
|
@@ -2514,7 +2524,9 @@ var PgDB = class extends MastraBase {
|
|
|
2514
2524
|
}
|
|
2515
2525
|
}
|
|
2516
2526
|
this.tableColumnsCache.delete(oldName);
|
|
2527
|
+
this.columnTypeCache.delete(oldName);
|
|
2517
2528
|
this.tableColumnsCache.delete(newName);
|
|
2529
|
+
this.columnTypeCache.delete(newName);
|
|
2518
2530
|
}
|
|
2519
2531
|
/**
|
|
2520
2532
|
* Records an out-of-band `DROP TABLE` in the init snapshot. See
|
|
@@ -2530,8 +2542,10 @@ var PgDB = class extends MastraBase {
|
|
|
2530
2542
|
if (snapshot) {
|
|
2531
2543
|
snapshot.tables.delete(tableName);
|
|
2532
2544
|
snapshot.columns.delete(tableName);
|
|
2545
|
+
snapshot.columnTypes.delete(tableName);
|
|
2533
2546
|
}
|
|
2534
2547
|
this.tableColumnsCache.delete(tableName);
|
|
2548
|
+
this.columnTypeCache.delete(tableName);
|
|
2535
2549
|
}
|
|
2536
2550
|
/**
|
|
2537
2551
|
* Records an out-of-band `ALTER TABLE … ADD COLUMN` in the init snapshot.
|
|
@@ -2541,6 +2555,7 @@ var PgDB = class extends MastraBase {
|
|
|
2541
2555
|
const snapshot = this.schemaSnapshot;
|
|
2542
2556
|
if (snapshot) this.snapshotColumns(snapshot, tableName).add(column);
|
|
2543
2557
|
this.tableColumnsCache.delete(tableName);
|
|
2558
|
+
this.columnTypeCache.delete(tableName);
|
|
2544
2559
|
}
|
|
2545
2560
|
/**
|
|
2546
2561
|
* Gets the set of column names that actually exist in the database table.
|
|
@@ -2583,6 +2598,50 @@ var PgDB = class extends MastraBase {
|
|
|
2583
2598
|
]);
|
|
2584
2599
|
}
|
|
2585
2600
|
/**
|
|
2601
|
+
* Returns the Postgres data type of a column (e.g. `jsonb`, `json`, `text`),
|
|
2602
|
+
* or null when the table or column does not exist.
|
|
2603
|
+
*
|
|
2604
|
+
* Answered from the init snapshot when one is installed, so a warm `init()`
|
|
2605
|
+
* issues no catalog probe. Outside init, results are cached per instance and
|
|
2606
|
+
* the cache is invalidated alongside {@link tableColumnsCache} whenever DDL
|
|
2607
|
+
* changes a table.
|
|
2608
|
+
*/
|
|
2609
|
+
async getColumnType(table, column) {
|
|
2610
|
+
const snapshot = this.schemaSnapshot;
|
|
2611
|
+
if (snapshot) {
|
|
2612
|
+
const types = snapshot.columnTypes.get(table);
|
|
2613
|
+
const known = types?.get(column) ?? types?.get(column.toLowerCase());
|
|
2614
|
+
if (known) return known;
|
|
2615
|
+
if (types) return null;
|
|
2616
|
+
}
|
|
2617
|
+
const cached = this.columnTypeCache.get(table)?.get(column);
|
|
2618
|
+
if (cached !== void 0) return cached;
|
|
2619
|
+
const schema = this.schemaName || "public";
|
|
2620
|
+
const dataType = (await this.client.oneOrNone(`SELECT data_type FROM information_schema.columns WHERE table_schema = $1 AND table_name = $2 AND (column_name = $3 OR column_name = $4)`, [
|
|
2621
|
+
schema,
|
|
2622
|
+
table,
|
|
2623
|
+
column,
|
|
2624
|
+
column.toLowerCase()
|
|
2625
|
+
]))?.data_type ?? null;
|
|
2626
|
+
if (dataType) {
|
|
2627
|
+
if (snapshot) {
|
|
2628
|
+
let snapshotTypes = snapshot.columnTypes.get(table);
|
|
2629
|
+
if (!snapshotTypes) {
|
|
2630
|
+
snapshotTypes = /* @__PURE__ */ new Map();
|
|
2631
|
+
snapshot.columnTypes.set(table, snapshotTypes);
|
|
2632
|
+
}
|
|
2633
|
+
snapshotTypes.set(column, dataType);
|
|
2634
|
+
}
|
|
2635
|
+
let types = this.columnTypeCache.get(table);
|
|
2636
|
+
if (!types) {
|
|
2637
|
+
types = /* @__PURE__ */ new Map();
|
|
2638
|
+
this.columnTypeCache.set(table, types);
|
|
2639
|
+
}
|
|
2640
|
+
types.set(column, dataType);
|
|
2641
|
+
}
|
|
2642
|
+
return dataType;
|
|
2643
|
+
}
|
|
2644
|
+
/**
|
|
2586
2645
|
* Prepares values for insertion, handling JSONB columns by stringifying them
|
|
2587
2646
|
*/
|
|
2588
2647
|
prepareValuesForInsert(record, tableName) {
|
|
@@ -2781,6 +2840,7 @@ MIGRATION REQUIRED: Duplicate spans detected in ${duplicateInfo.tableName}\n====
|
|
|
2781
2840
|
}, error);
|
|
2782
2841
|
} finally {
|
|
2783
2842
|
this.tableColumnsCache.delete(tableName);
|
|
2843
|
+
this.columnTypeCache.delete(tableName);
|
|
2784
2844
|
}
|
|
2785
2845
|
}
|
|
2786
2846
|
async setupTimestampTriggers(tableName) {
|
|
@@ -3103,6 +3163,7 @@ MIGRATION REQUIRED: Duplicate spans detected in ${duplicateInfo.tableName}\n====
|
|
|
3103
3163
|
}, error);
|
|
3104
3164
|
} finally {
|
|
3105
3165
|
this.tableColumnsCache.delete(tableName);
|
|
3166
|
+
this.columnTypeCache.delete(tableName);
|
|
3106
3167
|
}
|
|
3107
3168
|
}
|
|
3108
3169
|
async load({ tableName, keys }) {
|
|
@@ -3166,6 +3227,7 @@ MIGRATION REQUIRED: Duplicate spans detected in ${duplicateInfo.tableName}\n====
|
|
|
3166
3227
|
}, error);
|
|
3167
3228
|
} finally {
|
|
3168
3229
|
this.tableColumnsCache.delete(tableName);
|
|
3230
|
+
this.columnTypeCache.delete(tableName);
|
|
3169
3231
|
}
|
|
3170
3232
|
}
|
|
3171
3233
|
async createIndex(options) {
|
|
@@ -19298,6 +19360,29 @@ function getTableName({ indexName, schemaName }) {
|
|
|
19298
19360
|
const quotedIndexName = `"${indexName}"`;
|
|
19299
19361
|
return schemaName ? `${schemaName}.${quotedIndexName}` : quotedIndexName;
|
|
19300
19362
|
}
|
|
19363
|
+
/** Base name (before any schema prefix) of the expression index backing the status filter. */
|
|
19364
|
+
const WORKFLOW_SNAPSHOT_STATUS_INDEX = "mastra_workflow_snapshot_name_status_createdat_idx";
|
|
19365
|
+
/**
|
|
19366
|
+
* Schema-prefixed name of the status index, lowercased and truncated the same way Postgres
|
|
19367
|
+
* stores it, so the init snapshot's index set answers "does it exist?" without a probe or a
|
|
19368
|
+
* no-op `CREATE INDEX` (schema-prefixed names routinely exceed the 63-byte limit).
|
|
19369
|
+
*/
|
|
19370
|
+
function workflowSnapshotStatusIndexName(schemaName) {
|
|
19371
|
+
return buildConstraintName({
|
|
19372
|
+
baseName: WORKFLOW_SNAPSHOT_STATUS_INDEX,
|
|
19373
|
+
schemaName: schemaName && schemaName !== "public" ? schemaName : void 0
|
|
19374
|
+
});
|
|
19375
|
+
}
|
|
19376
|
+
/**
|
|
19377
|
+
* Expression index on `(workflow_name, snapshot->>'status', "createdAt" DESC)` so
|
|
19378
|
+
* listWorkflowRuns() status filters can use an index instead of scanning every snapshot.
|
|
19379
|
+
*/
|
|
19380
|
+
function workflowSnapshotStatusIndexSQL(indexName, schemaName) {
|
|
19381
|
+
return `CREATE INDEX IF NOT EXISTS "${indexName}" ON ${getTableName({
|
|
19382
|
+
indexName: TABLE_WORKFLOW_SNAPSHOT,
|
|
19383
|
+
schemaName: getSchemaName(schemaName)
|
|
19384
|
+
})} (workflow_name, (snapshot ->> 'status'), "createdAt" DESC)`;
|
|
19385
|
+
}
|
|
19301
19386
|
/**
|
|
19302
19387
|
* Sanitizes JSON string for PostgreSQL jsonb:
|
|
19303
19388
|
* - Removes problematic Unicode sequences:
|
|
@@ -19358,33 +19443,55 @@ var WorkflowsPG = class WorkflowsPG extends WorkflowsStorage {
|
|
|
19358
19443
|
updatedAt: new Date(row.updatedAtZ || row.updatedAt)
|
|
19359
19444
|
};
|
|
19360
19445
|
}
|
|
19446
|
+
static getDefaultIndexDefs(schemaPrefix) {
|
|
19447
|
+
return [{
|
|
19448
|
+
name: `${schemaPrefix}mastra_workflow_snapshot_name_createdat_idx`,
|
|
19449
|
+
table: TABLE_WORKFLOW_SNAPSHOT,
|
|
19450
|
+
columns: ["workflow_name", "createdAt DESC"]
|
|
19451
|
+
}];
|
|
19452
|
+
}
|
|
19361
19453
|
/**
|
|
19362
19454
|
* Returns all DDL statements for this domain: table with unique constraint.
|
|
19363
19455
|
* Used by exportSchemas to produce a complete, reproducible schema export.
|
|
19364
19456
|
*/
|
|
19365
19457
|
static getExportDDL(schemaName) {
|
|
19366
19458
|
const statements = [];
|
|
19459
|
+
const parsedSchema = schemaName ? parseSqlIdentifier(schemaName, "schema name") : "";
|
|
19460
|
+
const schemaPrefix = parsedSchema && parsedSchema !== "public" ? `${parsedSchema}_` : "";
|
|
19367
19461
|
statements.push(generateTableSQL({
|
|
19368
19462
|
tableName: TABLE_WORKFLOW_SNAPSHOT,
|
|
19369
19463
|
schema: TABLE_SCHEMAS[TABLE_WORKFLOW_SNAPSHOT],
|
|
19370
19464
|
schemaName,
|
|
19371
19465
|
includeAllConstraints: true
|
|
19372
19466
|
}));
|
|
19467
|
+
for (const idx of WorkflowsPG.getDefaultIndexDefs(schemaPrefix)) statements.push(generateIndexSQL(idx, schemaName));
|
|
19468
|
+
statements.push(`${workflowSnapshotStatusIndexSQL(workflowSnapshotStatusIndexName(parsedSchema), schemaName)};`);
|
|
19373
19469
|
return statements;
|
|
19374
19470
|
}
|
|
19375
19471
|
/**
|
|
19376
19472
|
* Returns default index definitions for the workflows domain tables.
|
|
19377
|
-
* Currently no default indexes are defined for workflows.
|
|
19378
19473
|
*/
|
|
19379
19474
|
getDefaultIndexDefinitions() {
|
|
19380
|
-
|
|
19475
|
+
const schemaPrefix = this.#schema !== "public" ? `${this.#schema}_` : "";
|
|
19476
|
+
return WorkflowsPG.getDefaultIndexDefs(schemaPrefix);
|
|
19381
19477
|
}
|
|
19382
19478
|
/**
|
|
19383
19479
|
* Creates default indexes for optimal query performance.
|
|
19384
|
-
* Currently no default indexes are defined for workflows.
|
|
19385
19480
|
*/
|
|
19386
19481
|
async createDefaultIndexes() {
|
|
19387
19482
|
if (this.#skipDefaultIndexes) return;
|
|
19483
|
+
for (const indexDef of this.getDefaultIndexDefinitions()) try {
|
|
19484
|
+
await this.#db.createIndex(indexDef);
|
|
19485
|
+
} catch (error) {
|
|
19486
|
+
this.logger?.warn?.(`Failed to create index ${indexDef.name}:`, error);
|
|
19487
|
+
}
|
|
19488
|
+
if (await this.#db.getColumnType(TABLE_WORKFLOW_SNAPSHOT, "snapshot") !== "jsonb") return;
|
|
19489
|
+
const indexName = workflowSnapshotStatusIndexName(this.#schema);
|
|
19490
|
+
try {
|
|
19491
|
+
await this.#db.createIndexFromStatement(indexName, workflowSnapshotStatusIndexSQL(indexName, this.#schema));
|
|
19492
|
+
} catch (error) {
|
|
19493
|
+
this.logger?.warn?.(`Failed to create index ${indexName}:`, error);
|
|
19494
|
+
}
|
|
19388
19495
|
}
|
|
19389
19496
|
async init() {
|
|
19390
19497
|
await this.#db.createTable({
|
|
@@ -19674,7 +19781,8 @@ var WorkflowsPG = class WorkflowsPG extends WorkflowsStorage {
|
|
|
19674
19781
|
paramIndex++;
|
|
19675
19782
|
}
|
|
19676
19783
|
if (status) {
|
|
19677
|
-
|
|
19784
|
+
const statusExpr = await this.#db.getColumnType(TABLE_WORKFLOW_SNAPSHOT, "snapshot") === "jsonb" ? `snapshot ->> 'status'` : `regexp_replace(snapshot::text, '\\\\u(0000|[Dd][89A-Fa-f][0-9A-Fa-f]{2})', '', 'g')::jsonb ->> 'status'`;
|
|
19785
|
+
conditions.push(`${statusExpr} = $${paramIndex}`);
|
|
19678
19786
|
values.push(status);
|
|
19679
19787
|
paramIndex++;
|
|
19680
19788
|
}
|