@mastra/pg 0.15.3-alpha.0 → 0.15.3-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/CHANGELOG.md +20 -0
- package/README.md +123 -0
- package/dist/index.cjs +305 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +306 -2
- package/dist/index.js.map +1 -1
- package/dist/storage/domains/operations/index.d.ts +23 -1
- package/dist/storage/domains/operations/index.d.ts.map +1 -1
- package/dist/storage/index.d.ts +3 -0
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/storage/performance-indexes/performance-test.d.ts +46 -0
- package/dist/storage/performance-indexes/performance-test.d.ts.map +1 -0
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# @mastra/pg
|
|
2
2
|
|
|
3
|
+
## 0.15.3-alpha.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Add Cloud SQL + IAM authentication support to PostgresStore ([#7855](https://github.com/mastra-ai/mastra/pull/7855))
|
|
8
|
+
|
|
9
|
+
- Update peerdep of @mastra/core ([#7619](https://github.com/mastra-ai/mastra/pull/7619))
|
|
10
|
+
|
|
11
|
+
- Updated dependencies [[`a1bb887`](https://github.com/mastra-ai/mastra/commit/a1bb887e8bfae44230f487648da72e96ef824561), [`a0f5f1c`](https://github.com/mastra-ai/mastra/commit/a0f5f1ca39c3c5c6d26202e9fcab986b4fe14568), [`b356f5f`](https://github.com/mastra-ai/mastra/commit/b356f5f7566cb3edb755d91f00b72fc1420b2a37), [`f5ce05f`](https://github.com/mastra-ai/mastra/commit/f5ce05f831d42c69559bf4c0fdb46ccb920fc3a3), [`9f6f30f`](https://github.com/mastra-ai/mastra/commit/9f6f30f04ec6648bbca798ea8aad59317c40d8db), [`d706fad`](https://github.com/mastra-ai/mastra/commit/d706fad6e6e4b72357b18d229ba38e6c913c0e70), [`5c3768f`](https://github.com/mastra-ai/mastra/commit/5c3768fa959454232ad76715c381f4aac00c6881), [`8a3f5e4`](https://github.com/mastra-ai/mastra/commit/8a3f5e4212ec36b302957deb4bd47005ab598382)]:
|
|
12
|
+
- @mastra/core@0.17.0-alpha.3
|
|
13
|
+
|
|
14
|
+
## 0.15.3-alpha.1
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- Postgresql Storage Query Index Performance: Adds index operations and automatic indexing for Postgresql ([#7757](https://github.com/mastra-ai/mastra/pull/7757))
|
|
19
|
+
|
|
20
|
+
- Updated dependencies [[`60c9cec`](https://github.com/mastra-ai/mastra/commit/60c9cec7048a79a87440f7840c383875bd710d93), [`897995e`](https://github.com/mastra-ai/mastra/commit/897995e630d572fe2891e7ede817938cabb43251)]:
|
|
21
|
+
- @mastra/core@0.16.4-alpha.2
|
|
22
|
+
|
|
3
23
|
## 0.15.3-alpha.0
|
|
4
24
|
|
|
5
25
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -160,6 +160,129 @@ Example filter:
|
|
|
160
160
|
- `getMessages(threadId)`: Get all messages for a thread
|
|
161
161
|
- `deleteMessages(messageIds)`: Delete specific messages
|
|
162
162
|
|
|
163
|
+
## Index Management
|
|
164
|
+
|
|
165
|
+
The PostgreSQL store provides comprehensive index management capabilities to optimize query performance.
|
|
166
|
+
|
|
167
|
+
### Automatic Performance Indexes
|
|
168
|
+
|
|
169
|
+
PostgreSQL storage automatically creates composite indexes during initialization for common query patterns:
|
|
170
|
+
|
|
171
|
+
- `mastra_threads_resourceid_createdat_idx`: (resourceId, createdAt DESC)
|
|
172
|
+
- `mastra_messages_thread_id_createdat_idx`: (thread_id, createdAt DESC)
|
|
173
|
+
- `mastra_traces_name_starttime_idx`: (name, startTime DESC)
|
|
174
|
+
- `mastra_evals_agent_name_created_at_idx`: (agent_name, created_at DESC)
|
|
175
|
+
|
|
176
|
+
These indexes significantly improve performance for filtered queries with sorting.
|
|
177
|
+
|
|
178
|
+
### Creating Custom Indexes
|
|
179
|
+
|
|
180
|
+
Create additional indexes to optimize specific query patterns:
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
// Basic index for common queries
|
|
184
|
+
await store.createIndex({
|
|
185
|
+
name: 'idx_threads_resource',
|
|
186
|
+
table: 'mastra_threads',
|
|
187
|
+
columns: ['resourceId'],
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
// Composite index with sort order for filtering + sorting
|
|
191
|
+
await store.createIndex({
|
|
192
|
+
name: 'idx_messages_composite',
|
|
193
|
+
table: 'mastra_messages',
|
|
194
|
+
columns: ['thread_id', 'createdAt DESC'],
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
// GIN index for JSONB columns (fast JSON queries)
|
|
198
|
+
await store.createIndex({
|
|
199
|
+
name: 'idx_traces_attributes',
|
|
200
|
+
table: 'mastra_traces',
|
|
201
|
+
columns: ['attributes'],
|
|
202
|
+
method: 'gin',
|
|
203
|
+
});
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
For more advanced use cases, you can also use:
|
|
207
|
+
|
|
208
|
+
- `unique: true` for unique constraints
|
|
209
|
+
- `where: 'condition'` for partial indexes
|
|
210
|
+
- `method: 'brin'` for time-series data
|
|
211
|
+
- `storage: { fillfactor: 90 }` for update-heavy tables
|
|
212
|
+
- `concurrent: true` for non-blocking creation (default)
|
|
213
|
+
|
|
214
|
+
### Managing Indexes
|
|
215
|
+
|
|
216
|
+
```typescript
|
|
217
|
+
// List all indexes
|
|
218
|
+
const allIndexes = await store.listIndexes();
|
|
219
|
+
|
|
220
|
+
// List indexes for specific table
|
|
221
|
+
const threadIndexes = await store.listIndexes('mastra_threads');
|
|
222
|
+
|
|
223
|
+
// Get detailed statistics for an index
|
|
224
|
+
const stats = await store.describeIndex('idx_threads_resource');
|
|
225
|
+
console.log(stats);
|
|
226
|
+
// {
|
|
227
|
+
// name: 'idx_threads_resource',
|
|
228
|
+
// table: 'mastra_threads',
|
|
229
|
+
// columns: ['resourceId', 'createdAt'],
|
|
230
|
+
// unique: false,
|
|
231
|
+
// size: '128 KB',
|
|
232
|
+
// definition: 'CREATE INDEX idx_threads_resource...',
|
|
233
|
+
// method: 'btree',
|
|
234
|
+
// scans: 1542, // Number of index scans
|
|
235
|
+
// tuples_read: 45230, // Tuples read via index
|
|
236
|
+
// tuples_fetched: 12050 // Tuples fetched via index
|
|
237
|
+
// }
|
|
238
|
+
|
|
239
|
+
// Drop an index
|
|
240
|
+
await store.dropIndex('idx_threads_status');
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### Index Types and Use Cases
|
|
244
|
+
|
|
245
|
+
| Index Type | Best For | Storage | Speed |
|
|
246
|
+
| ------------------- | --------------------------------------- | ---------- | -------------------------- |
|
|
247
|
+
| **btree** (default) | Range queries, sorting, general purpose | Moderate | Fast |
|
|
248
|
+
| **hash** | Equality comparisons only | Small | Very fast for `=` |
|
|
249
|
+
| **gin** | JSONB, arrays, full-text search | Large | Fast for contains |
|
|
250
|
+
| **gist** | Geometric data, full-text search | Moderate | Fast for nearest-neighbor |
|
|
251
|
+
| **spgist** | Non-balanced data, text patterns | Small | Fast for specific patterns |
|
|
252
|
+
| **brin** | Large tables with natural ordering | Very small | Fast for ranges |
|
|
253
|
+
|
|
254
|
+
### Index Options
|
|
255
|
+
|
|
256
|
+
- `name` (required): Index name
|
|
257
|
+
- `table` (required): Table name
|
|
258
|
+
- `columns` (required): Array of column names (can include DESC/ASC)
|
|
259
|
+
- `unique`: Create unique index (default: false)
|
|
260
|
+
- `concurrent`: Non-blocking index creation (default: true)
|
|
261
|
+
- `where`: Partial index condition
|
|
262
|
+
- `method`: Index type ('btree' | 'hash' | 'gin' | 'gist' | 'spgist' | 'brin')
|
|
263
|
+
- `opclass`: Operator class for GIN/GIST indexes
|
|
264
|
+
- `storage`: Storage parameters (e.g., { fillfactor: 90 })
|
|
265
|
+
- `tablespace`: Tablespace name for index placement
|
|
266
|
+
|
|
267
|
+
### Monitoring Index Performance
|
|
268
|
+
|
|
269
|
+
```typescript
|
|
270
|
+
// Check index usage statistics
|
|
271
|
+
const stats = await store.describeIndex('idx_threads_resource');
|
|
272
|
+
|
|
273
|
+
// Identify unused indexes
|
|
274
|
+
if (stats.scans === 0) {
|
|
275
|
+
console.log(`Index ${stats.name} is unused - consider removing`);
|
|
276
|
+
await store.dropIndex(stats.name);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Monitor index efficiency
|
|
280
|
+
const efficiency = stats.tuples_fetched / stats.tuples_read;
|
|
281
|
+
if (efficiency < 0.5) {
|
|
282
|
+
console.log(`Index ${stats.name} has low efficiency: ${efficiency}`);
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
163
286
|
## Related Links
|
|
164
287
|
|
|
165
288
|
- [pgvector Documentation](https://github.com/pgvector/pgvector)
|
package/dist/index.cjs
CHANGED
|
@@ -2374,6 +2374,303 @@ var StoreOperationsPG = class extends storage.StoreOperations {
|
|
|
2374
2374
|
);
|
|
2375
2375
|
}
|
|
2376
2376
|
}
|
|
2377
|
+
/**
|
|
2378
|
+
* Create a new index on a table
|
|
2379
|
+
*/
|
|
2380
|
+
async createIndex(options) {
|
|
2381
|
+
try {
|
|
2382
|
+
const {
|
|
2383
|
+
name,
|
|
2384
|
+
table,
|
|
2385
|
+
columns,
|
|
2386
|
+
unique = false,
|
|
2387
|
+
concurrent = true,
|
|
2388
|
+
where,
|
|
2389
|
+
method = "btree",
|
|
2390
|
+
opclass,
|
|
2391
|
+
storage,
|
|
2392
|
+
tablespace
|
|
2393
|
+
} = options;
|
|
2394
|
+
const schemaName = this.schemaName || "public";
|
|
2395
|
+
const fullTableName = getTableName({
|
|
2396
|
+
indexName: table,
|
|
2397
|
+
schemaName: getSchemaName(this.schemaName)
|
|
2398
|
+
});
|
|
2399
|
+
const indexExists = await this.client.oneOrNone(
|
|
2400
|
+
`SELECT 1 FROM pg_indexes
|
|
2401
|
+
WHERE indexname = $1
|
|
2402
|
+
AND schemaname = $2`,
|
|
2403
|
+
[name, schemaName]
|
|
2404
|
+
);
|
|
2405
|
+
if (indexExists) {
|
|
2406
|
+
return;
|
|
2407
|
+
}
|
|
2408
|
+
const uniqueStr = unique ? "UNIQUE " : "";
|
|
2409
|
+
const concurrentStr = concurrent ? "CONCURRENTLY " : "";
|
|
2410
|
+
const methodStr = method !== "btree" ? `USING ${method} ` : "";
|
|
2411
|
+
const columnsStr = columns.map((col) => {
|
|
2412
|
+
if (col.includes(" DESC") || col.includes(" ASC")) {
|
|
2413
|
+
const [colName, ...modifiers] = col.split(" ");
|
|
2414
|
+
if (!colName) {
|
|
2415
|
+
throw new Error(`Invalid column specification: ${col}`);
|
|
2416
|
+
}
|
|
2417
|
+
const quotedCol2 = `"${utils.parseSqlIdentifier(colName, "column name")}" ${modifiers.join(" ")}`;
|
|
2418
|
+
return opclass ? `${quotedCol2} ${opclass}` : quotedCol2;
|
|
2419
|
+
}
|
|
2420
|
+
const quotedCol = `"${utils.parseSqlIdentifier(col, "column name")}"`;
|
|
2421
|
+
return opclass ? `${quotedCol} ${opclass}` : quotedCol;
|
|
2422
|
+
}).join(", ");
|
|
2423
|
+
const whereStr = where ? ` WHERE ${where}` : "";
|
|
2424
|
+
const tablespaceStr = tablespace ? ` TABLESPACE ${tablespace}` : "";
|
|
2425
|
+
let withStr = "";
|
|
2426
|
+
if (storage && Object.keys(storage).length > 0) {
|
|
2427
|
+
const storageParams = Object.entries(storage).map(([key, value]) => `${key} = ${value}`).join(", ");
|
|
2428
|
+
withStr = ` WITH (${storageParams})`;
|
|
2429
|
+
}
|
|
2430
|
+
const sql = `CREATE ${uniqueStr}INDEX ${concurrentStr}${name} ON ${fullTableName} ${methodStr}(${columnsStr})${withStr}${tablespaceStr}${whereStr}`;
|
|
2431
|
+
await this.client.none(sql);
|
|
2432
|
+
} catch (error$1) {
|
|
2433
|
+
if (error$1 instanceof Error && error$1.message.includes("CONCURRENTLY")) {
|
|
2434
|
+
const retryOptions = { ...options, concurrent: false };
|
|
2435
|
+
return this.createIndex(retryOptions);
|
|
2436
|
+
}
|
|
2437
|
+
throw new error.MastraError(
|
|
2438
|
+
{
|
|
2439
|
+
id: "MASTRA_STORAGE_PG_INDEX_CREATE_FAILED",
|
|
2440
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2441
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
2442
|
+
details: {
|
|
2443
|
+
indexName: options.name,
|
|
2444
|
+
tableName: options.table
|
|
2445
|
+
}
|
|
2446
|
+
},
|
|
2447
|
+
error$1
|
|
2448
|
+
);
|
|
2449
|
+
}
|
|
2450
|
+
}
|
|
2451
|
+
/**
|
|
2452
|
+
* Drop an existing index
|
|
2453
|
+
*/
|
|
2454
|
+
async dropIndex(indexName) {
|
|
2455
|
+
try {
|
|
2456
|
+
const schemaName = this.schemaName || "public";
|
|
2457
|
+
const indexExists = await this.client.oneOrNone(
|
|
2458
|
+
`SELECT 1 FROM pg_indexes
|
|
2459
|
+
WHERE indexname = $1
|
|
2460
|
+
AND schemaname = $2`,
|
|
2461
|
+
[indexName, schemaName]
|
|
2462
|
+
);
|
|
2463
|
+
if (!indexExists) {
|
|
2464
|
+
return;
|
|
2465
|
+
}
|
|
2466
|
+
const sql = `DROP INDEX IF EXISTS ${getSchemaName(this.schemaName)}.${indexName}`;
|
|
2467
|
+
await this.client.none(sql);
|
|
2468
|
+
} catch (error$1) {
|
|
2469
|
+
throw new error.MastraError(
|
|
2470
|
+
{
|
|
2471
|
+
id: "MASTRA_STORAGE_PG_INDEX_DROP_FAILED",
|
|
2472
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2473
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
2474
|
+
details: {
|
|
2475
|
+
indexName
|
|
2476
|
+
}
|
|
2477
|
+
},
|
|
2478
|
+
error$1
|
|
2479
|
+
);
|
|
2480
|
+
}
|
|
2481
|
+
}
|
|
2482
|
+
/**
|
|
2483
|
+
* List indexes for a specific table or all tables
|
|
2484
|
+
*/
|
|
2485
|
+
async listIndexes(tableName) {
|
|
2486
|
+
try {
|
|
2487
|
+
const schemaName = this.schemaName || "public";
|
|
2488
|
+
let query;
|
|
2489
|
+
let params;
|
|
2490
|
+
if (tableName) {
|
|
2491
|
+
query = `
|
|
2492
|
+
SELECT
|
|
2493
|
+
i.indexname as name,
|
|
2494
|
+
i.tablename as table,
|
|
2495
|
+
i.indexdef as definition,
|
|
2496
|
+
ix.indisunique as is_unique,
|
|
2497
|
+
pg_size_pretty(pg_relation_size(c.oid)) as size,
|
|
2498
|
+
array_agg(a.attname ORDER BY array_position(ix.indkey, a.attnum)) as columns
|
|
2499
|
+
FROM pg_indexes i
|
|
2500
|
+
JOIN pg_class c ON c.relname = i.indexname AND c.relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = i.schemaname)
|
|
2501
|
+
JOIN pg_index ix ON ix.indexrelid = c.oid
|
|
2502
|
+
JOIN pg_attribute a ON a.attrelid = ix.indrelid AND a.attnum = ANY(ix.indkey)
|
|
2503
|
+
WHERE i.schemaname = $1
|
|
2504
|
+
AND i.tablename = $2
|
|
2505
|
+
GROUP BY i.indexname, i.tablename, i.indexdef, ix.indisunique, c.oid
|
|
2506
|
+
`;
|
|
2507
|
+
params = [schemaName, tableName];
|
|
2508
|
+
} else {
|
|
2509
|
+
query = `
|
|
2510
|
+
SELECT
|
|
2511
|
+
i.indexname as name,
|
|
2512
|
+
i.tablename as table,
|
|
2513
|
+
i.indexdef as definition,
|
|
2514
|
+
ix.indisunique as is_unique,
|
|
2515
|
+
pg_size_pretty(pg_relation_size(c.oid)) as size,
|
|
2516
|
+
array_agg(a.attname ORDER BY array_position(ix.indkey, a.attnum)) as columns
|
|
2517
|
+
FROM pg_indexes i
|
|
2518
|
+
JOIN pg_class c ON c.relname = i.indexname AND c.relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = i.schemaname)
|
|
2519
|
+
JOIN pg_index ix ON ix.indexrelid = c.oid
|
|
2520
|
+
JOIN pg_attribute a ON a.attrelid = ix.indrelid AND a.attnum = ANY(ix.indkey)
|
|
2521
|
+
WHERE i.schemaname = $1
|
|
2522
|
+
GROUP BY i.indexname, i.tablename, i.indexdef, ix.indisunique, c.oid
|
|
2523
|
+
`;
|
|
2524
|
+
params = [schemaName];
|
|
2525
|
+
}
|
|
2526
|
+
const results = await this.client.manyOrNone(query, params);
|
|
2527
|
+
return results.map((row) => {
|
|
2528
|
+
let columns = [];
|
|
2529
|
+
if (typeof row.columns === "string" && row.columns.startsWith("{") && row.columns.endsWith("}")) {
|
|
2530
|
+
const arrayContent = row.columns.slice(1, -1);
|
|
2531
|
+
columns = arrayContent ? arrayContent.split(",") : [];
|
|
2532
|
+
} else if (Array.isArray(row.columns)) {
|
|
2533
|
+
columns = row.columns;
|
|
2534
|
+
}
|
|
2535
|
+
return {
|
|
2536
|
+
name: row.name,
|
|
2537
|
+
table: row.table,
|
|
2538
|
+
columns,
|
|
2539
|
+
unique: row.is_unique || false,
|
|
2540
|
+
size: row.size || "0",
|
|
2541
|
+
definition: row.definition || ""
|
|
2542
|
+
};
|
|
2543
|
+
});
|
|
2544
|
+
} catch (error$1) {
|
|
2545
|
+
throw new error.MastraError(
|
|
2546
|
+
{
|
|
2547
|
+
id: "MASTRA_STORAGE_PG_INDEX_LIST_FAILED",
|
|
2548
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2549
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
2550
|
+
details: tableName ? {
|
|
2551
|
+
tableName
|
|
2552
|
+
} : {}
|
|
2553
|
+
},
|
|
2554
|
+
error$1
|
|
2555
|
+
);
|
|
2556
|
+
}
|
|
2557
|
+
}
|
|
2558
|
+
/**
|
|
2559
|
+
* Creates automatic indexes for optimal query performance
|
|
2560
|
+
* These composite indexes cover both filtering and sorting in single index
|
|
2561
|
+
*/
|
|
2562
|
+
async createAutomaticIndexes() {
|
|
2563
|
+
try {
|
|
2564
|
+
const schemaPrefix = this.schemaName ? `${this.schemaName}_` : "";
|
|
2565
|
+
const indexes = [
|
|
2566
|
+
// Composite index for threads (filter + sort)
|
|
2567
|
+
{
|
|
2568
|
+
name: `${schemaPrefix}mastra_threads_resourceid_createdat_idx`,
|
|
2569
|
+
table: storage.TABLE_THREADS,
|
|
2570
|
+
columns: ["resourceId", "createdAt DESC"]
|
|
2571
|
+
},
|
|
2572
|
+
// Composite index for messages (filter + sort)
|
|
2573
|
+
{
|
|
2574
|
+
name: `${schemaPrefix}mastra_messages_thread_id_createdat_idx`,
|
|
2575
|
+
table: storage.TABLE_MESSAGES,
|
|
2576
|
+
columns: ["thread_id", "createdAt DESC"]
|
|
2577
|
+
},
|
|
2578
|
+
// Composite index for traces (filter + sort)
|
|
2579
|
+
{
|
|
2580
|
+
name: `${schemaPrefix}mastra_traces_name_starttime_idx`,
|
|
2581
|
+
table: storage.TABLE_TRACES,
|
|
2582
|
+
columns: ["name", "startTime DESC"]
|
|
2583
|
+
},
|
|
2584
|
+
// Composite index for evals (filter + sort)
|
|
2585
|
+
{
|
|
2586
|
+
name: `${schemaPrefix}mastra_evals_agent_name_created_at_idx`,
|
|
2587
|
+
table: storage.TABLE_EVALS,
|
|
2588
|
+
columns: ["agent_name", "created_at DESC"]
|
|
2589
|
+
}
|
|
2590
|
+
];
|
|
2591
|
+
for (const indexOptions of indexes) {
|
|
2592
|
+
try {
|
|
2593
|
+
await this.createIndex(indexOptions);
|
|
2594
|
+
} catch (error) {
|
|
2595
|
+
this.logger?.warn?.(`Failed to create index ${indexOptions.name}:`, error);
|
|
2596
|
+
}
|
|
2597
|
+
}
|
|
2598
|
+
} catch (error$1) {
|
|
2599
|
+
throw new error.MastraError(
|
|
2600
|
+
{
|
|
2601
|
+
id: "MASTRA_STORAGE_PG_STORE_CREATE_PERFORMANCE_INDEXES_FAILED",
|
|
2602
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2603
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
2604
|
+
},
|
|
2605
|
+
error$1
|
|
2606
|
+
);
|
|
2607
|
+
}
|
|
2608
|
+
}
|
|
2609
|
+
/**
|
|
2610
|
+
* Get detailed statistics for a specific index
|
|
2611
|
+
*/
|
|
2612
|
+
async describeIndex(indexName) {
|
|
2613
|
+
try {
|
|
2614
|
+
const schemaName = this.schemaName || "public";
|
|
2615
|
+
const query = `
|
|
2616
|
+
SELECT
|
|
2617
|
+
i.indexname as name,
|
|
2618
|
+
i.tablename as table,
|
|
2619
|
+
i.indexdef as definition,
|
|
2620
|
+
ix.indisunique as is_unique,
|
|
2621
|
+
pg_size_pretty(pg_relation_size(c.oid)) as size,
|
|
2622
|
+
array_agg(a.attname ORDER BY array_position(ix.indkey, a.attnum)) as columns,
|
|
2623
|
+
am.amname as method,
|
|
2624
|
+
s.idx_scan as scans,
|
|
2625
|
+
s.idx_tup_read as tuples_read,
|
|
2626
|
+
s.idx_tup_fetch as tuples_fetched
|
|
2627
|
+
FROM pg_indexes i
|
|
2628
|
+
JOIN pg_class c ON c.relname = i.indexname AND c.relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = i.schemaname)
|
|
2629
|
+
JOIN pg_index ix ON ix.indexrelid = c.oid
|
|
2630
|
+
JOIN pg_attribute a ON a.attrelid = ix.indrelid AND a.attnum = ANY(ix.indkey)
|
|
2631
|
+
JOIN pg_am am ON c.relam = am.oid
|
|
2632
|
+
LEFT JOIN pg_stat_user_indexes s ON s.indexrelname = i.indexname AND s.schemaname = i.schemaname
|
|
2633
|
+
WHERE i.schemaname = $1
|
|
2634
|
+
AND i.indexname = $2
|
|
2635
|
+
GROUP BY i.indexname, i.tablename, i.indexdef, ix.indisunique, c.oid, am.amname, s.idx_scan, s.idx_tup_read, s.idx_tup_fetch
|
|
2636
|
+
`;
|
|
2637
|
+
const result = await this.client.oneOrNone(query, [schemaName, indexName]);
|
|
2638
|
+
if (!result) {
|
|
2639
|
+
throw new Error(`Index "${indexName}" not found in schema "${schemaName}"`);
|
|
2640
|
+
}
|
|
2641
|
+
let columns = [];
|
|
2642
|
+
if (typeof result.columns === "string" && result.columns.startsWith("{") && result.columns.endsWith("}")) {
|
|
2643
|
+
const arrayContent = result.columns.slice(1, -1);
|
|
2644
|
+
columns = arrayContent ? arrayContent.split(",") : [];
|
|
2645
|
+
} else if (Array.isArray(result.columns)) {
|
|
2646
|
+
columns = result.columns;
|
|
2647
|
+
}
|
|
2648
|
+
return {
|
|
2649
|
+
name: result.name,
|
|
2650
|
+
table: result.table,
|
|
2651
|
+
columns,
|
|
2652
|
+
unique: result.is_unique || false,
|
|
2653
|
+
size: result.size || "0",
|
|
2654
|
+
definition: result.definition || "",
|
|
2655
|
+
method: result.method || "btree",
|
|
2656
|
+
scans: parseInt(result.scans) || 0,
|
|
2657
|
+
tuples_read: parseInt(result.tuples_read) || 0,
|
|
2658
|
+
tuples_fetched: parseInt(result.tuples_fetched) || 0
|
|
2659
|
+
};
|
|
2660
|
+
} catch (error$1) {
|
|
2661
|
+
throw new error.MastraError(
|
|
2662
|
+
{
|
|
2663
|
+
id: "MASTRA_STORAGE_PG_INDEX_DESCRIBE_FAILED",
|
|
2664
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2665
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
2666
|
+
details: {
|
|
2667
|
+
indexName
|
|
2668
|
+
}
|
|
2669
|
+
},
|
|
2670
|
+
error$1
|
|
2671
|
+
);
|
|
2672
|
+
}
|
|
2673
|
+
}
|
|
2377
2674
|
};
|
|
2378
2675
|
function transformScoreRow(row) {
|
|
2379
2676
|
return {
|
|
@@ -3077,6 +3374,11 @@ var PostgresStore = class extends storage.MastraStorage {
|
|
|
3077
3374
|
memory
|
|
3078
3375
|
};
|
|
3079
3376
|
await super.init();
|
|
3377
|
+
try {
|
|
3378
|
+
await operations.createAutomaticIndexes();
|
|
3379
|
+
} catch (indexError) {
|
|
3380
|
+
console.warn("Failed to create indexes:", indexError);
|
|
3381
|
+
}
|
|
3080
3382
|
} catch (error$1) {
|
|
3081
3383
|
this.isConnected = false;
|
|
3082
3384
|
throw new error.MastraError(
|
|
@@ -3107,7 +3409,9 @@ var PostgresStore = class extends storage.MastraStorage {
|
|
|
3107
3409
|
resourceWorkingMemory: true,
|
|
3108
3410
|
hasColumn: true,
|
|
3109
3411
|
createTable: true,
|
|
3110
|
-
deleteMessages: true
|
|
3412
|
+
deleteMessages: true,
|
|
3413
|
+
aiTracing: false,
|
|
3414
|
+
indexManagement: true
|
|
3111
3415
|
};
|
|
3112
3416
|
}
|
|
3113
3417
|
/** @deprecated use getEvals instead */
|