@mastra/pg 0.15.3-alpha.0 → 0.15.3-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/dist/index.js CHANGED
@@ -5,7 +5,7 @@ import { Mutex } from 'async-mutex';
5
5
  import pg from 'pg';
6
6
  import xxhash from 'xxhash-wasm';
7
7
  import { BaseFilterTranslator } from '@mastra/core/vector/filter';
8
- import { MastraStorage, StoreOperations, TABLE_WORKFLOW_SNAPSHOT, ScoresStorage, TABLE_SCORERS, TracesStorage, safelyParseJSON, TABLE_TRACES, WorkflowsStorage, LegacyEvalsStorage, MemoryStorage, resolveMessageLimit, TABLE_RESOURCES, TABLE_EVALS, TABLE_THREADS, TABLE_MESSAGES } from '@mastra/core/storage';
8
+ import { MastraStorage, StoreOperations, TABLE_WORKFLOW_SNAPSHOT, TABLE_THREADS, TABLE_MESSAGES, TABLE_TRACES, TABLE_EVALS, ScoresStorage, TABLE_SCORERS, TracesStorage, safelyParseJSON, WorkflowsStorage, LegacyEvalsStorage, MemoryStorage, resolveMessageLimit, TABLE_RESOURCES } from '@mastra/core/storage';
9
9
  import pgPromise from 'pg-promise';
10
10
  import { MessageList } from '@mastra/core/agent';
11
11
 
@@ -2366,6 +2366,303 @@ var StoreOperationsPG = class extends StoreOperations {
2366
2366
  );
2367
2367
  }
2368
2368
  }
2369
+ /**
2370
+ * Create a new index on a table
2371
+ */
2372
+ async createIndex(options) {
2373
+ try {
2374
+ const {
2375
+ name,
2376
+ table,
2377
+ columns,
2378
+ unique = false,
2379
+ concurrent = true,
2380
+ where,
2381
+ method = "btree",
2382
+ opclass,
2383
+ storage,
2384
+ tablespace
2385
+ } = options;
2386
+ const schemaName = this.schemaName || "public";
2387
+ const fullTableName = getTableName({
2388
+ indexName: table,
2389
+ schemaName: getSchemaName(this.schemaName)
2390
+ });
2391
+ const indexExists = await this.client.oneOrNone(
2392
+ `SELECT 1 FROM pg_indexes
2393
+ WHERE indexname = $1
2394
+ AND schemaname = $2`,
2395
+ [name, schemaName]
2396
+ );
2397
+ if (indexExists) {
2398
+ return;
2399
+ }
2400
+ const uniqueStr = unique ? "UNIQUE " : "";
2401
+ const concurrentStr = concurrent ? "CONCURRENTLY " : "";
2402
+ const methodStr = method !== "btree" ? `USING ${method} ` : "";
2403
+ const columnsStr = columns.map((col) => {
2404
+ if (col.includes(" DESC") || col.includes(" ASC")) {
2405
+ const [colName, ...modifiers] = col.split(" ");
2406
+ if (!colName) {
2407
+ throw new Error(`Invalid column specification: ${col}`);
2408
+ }
2409
+ const quotedCol2 = `"${parseSqlIdentifier(colName, "column name")}" ${modifiers.join(" ")}`;
2410
+ return opclass ? `${quotedCol2} ${opclass}` : quotedCol2;
2411
+ }
2412
+ const quotedCol = `"${parseSqlIdentifier(col, "column name")}"`;
2413
+ return opclass ? `${quotedCol} ${opclass}` : quotedCol;
2414
+ }).join(", ");
2415
+ const whereStr = where ? ` WHERE ${where}` : "";
2416
+ const tablespaceStr = tablespace ? ` TABLESPACE ${tablespace}` : "";
2417
+ let withStr = "";
2418
+ if (storage && Object.keys(storage).length > 0) {
2419
+ const storageParams = Object.entries(storage).map(([key, value]) => `${key} = ${value}`).join(", ");
2420
+ withStr = ` WITH (${storageParams})`;
2421
+ }
2422
+ const sql = `CREATE ${uniqueStr}INDEX ${concurrentStr}${name} ON ${fullTableName} ${methodStr}(${columnsStr})${withStr}${tablespaceStr}${whereStr}`;
2423
+ await this.client.none(sql);
2424
+ } catch (error) {
2425
+ if (error instanceof Error && error.message.includes("CONCURRENTLY")) {
2426
+ const retryOptions = { ...options, concurrent: false };
2427
+ return this.createIndex(retryOptions);
2428
+ }
2429
+ throw new MastraError(
2430
+ {
2431
+ id: "MASTRA_STORAGE_PG_INDEX_CREATE_FAILED",
2432
+ domain: ErrorDomain.STORAGE,
2433
+ category: ErrorCategory.THIRD_PARTY,
2434
+ details: {
2435
+ indexName: options.name,
2436
+ tableName: options.table
2437
+ }
2438
+ },
2439
+ error
2440
+ );
2441
+ }
2442
+ }
2443
+ /**
2444
+ * Drop an existing index
2445
+ */
2446
+ async dropIndex(indexName) {
2447
+ try {
2448
+ const schemaName = this.schemaName || "public";
2449
+ const indexExists = await this.client.oneOrNone(
2450
+ `SELECT 1 FROM pg_indexes
2451
+ WHERE indexname = $1
2452
+ AND schemaname = $2`,
2453
+ [indexName, schemaName]
2454
+ );
2455
+ if (!indexExists) {
2456
+ return;
2457
+ }
2458
+ const sql = `DROP INDEX IF EXISTS ${getSchemaName(this.schemaName)}.${indexName}`;
2459
+ await this.client.none(sql);
2460
+ } catch (error) {
2461
+ throw new MastraError(
2462
+ {
2463
+ id: "MASTRA_STORAGE_PG_INDEX_DROP_FAILED",
2464
+ domain: ErrorDomain.STORAGE,
2465
+ category: ErrorCategory.THIRD_PARTY,
2466
+ details: {
2467
+ indexName
2468
+ }
2469
+ },
2470
+ error
2471
+ );
2472
+ }
2473
+ }
2474
+ /**
2475
+ * List indexes for a specific table or all tables
2476
+ */
2477
+ async listIndexes(tableName) {
2478
+ try {
2479
+ const schemaName = this.schemaName || "public";
2480
+ let query;
2481
+ let params;
2482
+ if (tableName) {
2483
+ query = `
2484
+ SELECT
2485
+ i.indexname as name,
2486
+ i.tablename as table,
2487
+ i.indexdef as definition,
2488
+ ix.indisunique as is_unique,
2489
+ pg_size_pretty(pg_relation_size(c.oid)) as size,
2490
+ array_agg(a.attname ORDER BY array_position(ix.indkey, a.attnum)) as columns
2491
+ FROM pg_indexes i
2492
+ JOIN pg_class c ON c.relname = i.indexname AND c.relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = i.schemaname)
2493
+ JOIN pg_index ix ON ix.indexrelid = c.oid
2494
+ JOIN pg_attribute a ON a.attrelid = ix.indrelid AND a.attnum = ANY(ix.indkey)
2495
+ WHERE i.schemaname = $1
2496
+ AND i.tablename = $2
2497
+ GROUP BY i.indexname, i.tablename, i.indexdef, ix.indisunique, c.oid
2498
+ `;
2499
+ params = [schemaName, tableName];
2500
+ } else {
2501
+ query = `
2502
+ SELECT
2503
+ i.indexname as name,
2504
+ i.tablename as table,
2505
+ i.indexdef as definition,
2506
+ ix.indisunique as is_unique,
2507
+ pg_size_pretty(pg_relation_size(c.oid)) as size,
2508
+ array_agg(a.attname ORDER BY array_position(ix.indkey, a.attnum)) as columns
2509
+ FROM pg_indexes i
2510
+ JOIN pg_class c ON c.relname = i.indexname AND c.relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = i.schemaname)
2511
+ JOIN pg_index ix ON ix.indexrelid = c.oid
2512
+ JOIN pg_attribute a ON a.attrelid = ix.indrelid AND a.attnum = ANY(ix.indkey)
2513
+ WHERE i.schemaname = $1
2514
+ GROUP BY i.indexname, i.tablename, i.indexdef, ix.indisunique, c.oid
2515
+ `;
2516
+ params = [schemaName];
2517
+ }
2518
+ const results = await this.client.manyOrNone(query, params);
2519
+ return results.map((row) => {
2520
+ let columns = [];
2521
+ if (typeof row.columns === "string" && row.columns.startsWith("{") && row.columns.endsWith("}")) {
2522
+ const arrayContent = row.columns.slice(1, -1);
2523
+ columns = arrayContent ? arrayContent.split(",") : [];
2524
+ } else if (Array.isArray(row.columns)) {
2525
+ columns = row.columns;
2526
+ }
2527
+ return {
2528
+ name: row.name,
2529
+ table: row.table,
2530
+ columns,
2531
+ unique: row.is_unique || false,
2532
+ size: row.size || "0",
2533
+ definition: row.definition || ""
2534
+ };
2535
+ });
2536
+ } catch (error) {
2537
+ throw new MastraError(
2538
+ {
2539
+ id: "MASTRA_STORAGE_PG_INDEX_LIST_FAILED",
2540
+ domain: ErrorDomain.STORAGE,
2541
+ category: ErrorCategory.THIRD_PARTY,
2542
+ details: tableName ? {
2543
+ tableName
2544
+ } : {}
2545
+ },
2546
+ error
2547
+ );
2548
+ }
2549
+ }
2550
+ /**
2551
+ * Creates automatic indexes for optimal query performance
2552
+ * These composite indexes cover both filtering and sorting in single index
2553
+ */
2554
+ async createAutomaticIndexes() {
2555
+ try {
2556
+ const schemaPrefix = this.schemaName ? `${this.schemaName}_` : "";
2557
+ const indexes = [
2558
+ // Composite index for threads (filter + sort)
2559
+ {
2560
+ name: `${schemaPrefix}mastra_threads_resourceid_createdat_idx`,
2561
+ table: TABLE_THREADS,
2562
+ columns: ["resourceId", "createdAt DESC"]
2563
+ },
2564
+ // Composite index for messages (filter + sort)
2565
+ {
2566
+ name: `${schemaPrefix}mastra_messages_thread_id_createdat_idx`,
2567
+ table: TABLE_MESSAGES,
2568
+ columns: ["thread_id", "createdAt DESC"]
2569
+ },
2570
+ // Composite index for traces (filter + sort)
2571
+ {
2572
+ name: `${schemaPrefix}mastra_traces_name_starttime_idx`,
2573
+ table: TABLE_TRACES,
2574
+ columns: ["name", "startTime DESC"]
2575
+ },
2576
+ // Composite index for evals (filter + sort)
2577
+ {
2578
+ name: `${schemaPrefix}mastra_evals_agent_name_created_at_idx`,
2579
+ table: TABLE_EVALS,
2580
+ columns: ["agent_name", "created_at DESC"]
2581
+ }
2582
+ ];
2583
+ for (const indexOptions of indexes) {
2584
+ try {
2585
+ await this.createIndex(indexOptions);
2586
+ } catch (error) {
2587
+ this.logger?.warn?.(`Failed to create index ${indexOptions.name}:`, error);
2588
+ }
2589
+ }
2590
+ } catch (error) {
2591
+ throw new MastraError(
2592
+ {
2593
+ id: "MASTRA_STORAGE_PG_STORE_CREATE_PERFORMANCE_INDEXES_FAILED",
2594
+ domain: ErrorDomain.STORAGE,
2595
+ category: ErrorCategory.THIRD_PARTY
2596
+ },
2597
+ error
2598
+ );
2599
+ }
2600
+ }
2601
+ /**
2602
+ * Get detailed statistics for a specific index
2603
+ */
2604
+ async describeIndex(indexName) {
2605
+ try {
2606
+ const schemaName = this.schemaName || "public";
2607
+ const query = `
2608
+ SELECT
2609
+ i.indexname as name,
2610
+ i.tablename as table,
2611
+ i.indexdef as definition,
2612
+ ix.indisunique as is_unique,
2613
+ pg_size_pretty(pg_relation_size(c.oid)) as size,
2614
+ array_agg(a.attname ORDER BY array_position(ix.indkey, a.attnum)) as columns,
2615
+ am.amname as method,
2616
+ s.idx_scan as scans,
2617
+ s.idx_tup_read as tuples_read,
2618
+ s.idx_tup_fetch as tuples_fetched
2619
+ FROM pg_indexes i
2620
+ JOIN pg_class c ON c.relname = i.indexname AND c.relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = i.schemaname)
2621
+ JOIN pg_index ix ON ix.indexrelid = c.oid
2622
+ JOIN pg_attribute a ON a.attrelid = ix.indrelid AND a.attnum = ANY(ix.indkey)
2623
+ JOIN pg_am am ON c.relam = am.oid
2624
+ LEFT JOIN pg_stat_user_indexes s ON s.indexrelname = i.indexname AND s.schemaname = i.schemaname
2625
+ WHERE i.schemaname = $1
2626
+ AND i.indexname = $2
2627
+ 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
2628
+ `;
2629
+ const result = await this.client.oneOrNone(query, [schemaName, indexName]);
2630
+ if (!result) {
2631
+ throw new Error(`Index "${indexName}" not found in schema "${schemaName}"`);
2632
+ }
2633
+ let columns = [];
2634
+ if (typeof result.columns === "string" && result.columns.startsWith("{") && result.columns.endsWith("}")) {
2635
+ const arrayContent = result.columns.slice(1, -1);
2636
+ columns = arrayContent ? arrayContent.split(",") : [];
2637
+ } else if (Array.isArray(result.columns)) {
2638
+ columns = result.columns;
2639
+ }
2640
+ return {
2641
+ name: result.name,
2642
+ table: result.table,
2643
+ columns,
2644
+ unique: result.is_unique || false,
2645
+ size: result.size || "0",
2646
+ definition: result.definition || "",
2647
+ method: result.method || "btree",
2648
+ scans: parseInt(result.scans) || 0,
2649
+ tuples_read: parseInt(result.tuples_read) || 0,
2650
+ tuples_fetched: parseInt(result.tuples_fetched) || 0
2651
+ };
2652
+ } catch (error) {
2653
+ throw new MastraError(
2654
+ {
2655
+ id: "MASTRA_STORAGE_PG_INDEX_DESCRIBE_FAILED",
2656
+ domain: ErrorDomain.STORAGE,
2657
+ category: ErrorCategory.THIRD_PARTY,
2658
+ details: {
2659
+ indexName
2660
+ }
2661
+ },
2662
+ error
2663
+ );
2664
+ }
2665
+ }
2369
2666
  };
2370
2667
  function transformScoreRow(row) {
2371
2668
  return {
@@ -3069,6 +3366,11 @@ var PostgresStore = class extends MastraStorage {
3069
3366
  memory
3070
3367
  };
3071
3368
  await super.init();
3369
+ try {
3370
+ await operations.createAutomaticIndexes();
3371
+ } catch (indexError) {
3372
+ console.warn("Failed to create indexes:", indexError);
3373
+ }
3072
3374
  } catch (error) {
3073
3375
  this.isConnected = false;
3074
3376
  throw new MastraError(
@@ -3099,7 +3401,9 @@ var PostgresStore = class extends MastraStorage {
3099
3401
  resourceWorkingMemory: true,
3100
3402
  hasColumn: true,
3101
3403
  createTable: true,
3102
- deleteMessages: true
3404
+ deleteMessages: true,
3405
+ aiTracing: false,
3406
+ indexManagement: true
3103
3407
  };
3104
3408
  }
3105
3409
  /** @deprecated use getEvals instead */