@mastra/pg 1.36.0-alpha.1 → 1.36.0-alpha.3

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.cjs CHANGED
@@ -2719,7 +2719,8 @@ async function loadSchemaSnapshot(client, schemaName) {
2719
2719
  notNullColumns,
2720
2720
  indexes,
2721
2721
  replicaIdentityIndexes,
2722
- primaryKeyIndexes
2722
+ primaryKeyIndexes,
2723
+ createdTables: /* @__PURE__ */ new Set()
2723
2724
  };
2724
2725
  }
2725
2726
  // src/storage/db/index.ts
@@ -2879,26 +2880,30 @@ function generateTableSQL({ tableName, schema, schemaName, compositePrimaryKey,
2879
2880
  ` : ""}
2880
2881
  `;
2881
2882
  }
2883
+ function indexColumnsSQL(columns, opclass) {
2884
+ return columns.map((col) => {
2885
+ const [colName, ...modifiers] = col.includes(" DESC") || col.includes(" ASC") ? col.split(" ") : [col];
2886
+ if (!colName) throw new Error(`Invalid column specification: ${col}`);
2887
+ return [
2888
+ `"${(0, _mastra_core_utils.parseSqlIdentifier)(colName, "column name")}"`,
2889
+ opclass,
2890
+ ...modifiers
2891
+ ].filter(Boolean).join(" ");
2892
+ }).join(", ");
2893
+ }
2882
2894
  /**
2883
2895
  * Generates a CREATE INDEX SQL statement from index options.
2884
2896
  * Used by exportSchemas to produce index DDL without a database connection.
2885
2897
  */
2886
2898
  function generateIndexSQL(options, schemaName) {
2887
- const { name, table, columns, unique = false, where, method = "btree" } = options;
2899
+ const { name, table, columns, unique = false, where, method = "btree", opclass } = options;
2888
2900
  const fullTableName = getTableName$6({
2889
2901
  indexName: table,
2890
2902
  schemaName: getSchemaName$6(schemaName)
2891
2903
  });
2892
2904
  const uniqueStr = unique ? "UNIQUE " : "";
2893
2905
  const methodStr = method !== "btree" ? `USING ${method} ` : "";
2894
- const columnsStr = columns.map((col) => {
2895
- if (col.includes(" DESC") || col.includes(" ASC")) {
2896
- const [colName, ...modifiers] = col.split(" ");
2897
- if (!colName) throw new Error(`Invalid column specification: ${col}`);
2898
- return `"${(0, _mastra_core_utils.parseSqlIdentifier)(colName, "column name")}" ${modifiers.join(" ")}`;
2899
- }
2900
- return `"${(0, _mastra_core_utils.parseSqlIdentifier)(col, "column name")}"`;
2901
- }).join(", ");
2906
+ const columnsStr = indexColumnsSQL(columns, opclass);
2902
2907
  const whereStr = where ? ` WHERE ${where}` : "";
2903
2908
  return `CREATE ${uniqueStr}INDEX IF NOT EXISTS ${`"${(0, _mastra_core_utils.parseSqlIdentifier)(name, "index name")}"`} ON ${fullTableName} ${methodStr}(${columnsStr})${whereStr};`;
2904
2909
  }
@@ -3409,6 +3414,7 @@ var PgDB = class extends _mastra_core_base.MastraBase {
3409
3414
  if (this.schemaName) await this.setupSchema();
3410
3415
  const snapshot = this.schemaSnapshot;
3411
3416
  if (!snapshot || !this.snapshotShowsTableConverged(snapshot, tableName)) {
3417
+ const isNewTable = snapshot ? !snapshot.tables.has(tableName) : false;
3412
3418
  const sql = generateTableSQL({
3413
3419
  tableName,
3414
3420
  schema,
@@ -3422,6 +3428,7 @@ var PgDB = class extends _mastra_core_base.MastraBase {
3422
3428
  }
3423
3429
  if (snapshot) {
3424
3430
  snapshot.tables.add(tableName);
3431
+ if (isNewTable) snapshot.createdTables.add(tableName);
3425
3432
  const created = this.snapshotColumns(snapshot, tableName);
3426
3433
  for (const [name, def] of Object.entries(schema)) {
3427
3434
  const parsedName = (0, _mastra_core_utils.parseSqlIdentifier)(name, "column name");
@@ -3890,18 +3897,9 @@ MIGRATION REQUIRED: Duplicate spans detected in ${duplicateInfo.tableName}\n====
3890
3897
  const snapshot = this.schemaSnapshot;
3891
3898
  if (snapshot?.indexes.has(name)) return;
3892
3899
  const uniqueStr = unique ? "UNIQUE " : "";
3893
- const concurrentStr = concurrent ? "CONCURRENTLY " : "";
3900
+ const concurrentStr = concurrent && !this.isTableCreatedInThisInit(table) ? "CONCURRENTLY " : "";
3894
3901
  const methodStr = method !== "btree" ? `USING ${method} ` : "";
3895
- const columnsStr = columns.map((col) => {
3896
- if (col.includes(" DESC") || col.includes(" ASC")) {
3897
- const [colName, ...modifiers] = col.split(" ");
3898
- if (!colName) throw new Error(`Invalid column specification: ${col}`);
3899
- const quotedCol = `"${(0, _mastra_core_utils.parseSqlIdentifier)(colName, "column name")}" ${modifiers.join(" ")}`;
3900
- return opclass ? `${quotedCol} ${opclass}` : quotedCol;
3901
- }
3902
- const quotedCol = `"${(0, _mastra_core_utils.parseSqlIdentifier)(col, "column name")}"`;
3903
- return opclass ? `${quotedCol} ${opclass}` : quotedCol;
3904
- }).join(", ");
3902
+ const columnsStr = indexColumnsSQL(columns, opclass);
3905
3903
  const whereStr = where ? ` WHERE ${where}` : "";
3906
3904
  const tablespaceStr = tablespace ? ` TABLESPACE ${tablespace}` : "";
3907
3905
  let withStr = "";
@@ -3934,6 +3932,13 @@ MIGRATION REQUIRED: Duplicate spans detected in ${duplicateInfo.tableName}\n====
3934
3932
  if (snapshot?.indexes.has(indexName)) return;
3935
3933
  if (await buildIndex(this.client, this.schemaName || "public", indexName, () => this.timedIndexBuild(indexName, sql), this.logger)) snapshot?.indexes.add(indexName);
3936
3934
  }
3935
+ /**
3936
+ * Whether `tableName` was absent when this init's snapshot was read and this
3937
+ * init created it, so its indexes can be built without CONCURRENTLY.
3938
+ */
3939
+ isTableCreatedInThisInit(tableName) {
3940
+ return this.schemaSnapshot?.createdTables.has(tableName) ?? false;
3941
+ }
3937
3942
  async timedIndexBuild(indexName, sql) {
3938
3943
  const startedAt = Date.now();
3939
3944
  this.logger.info(`Creating index ${indexName}`);
@@ -11673,6 +11678,13 @@ function dedupeMessagesForSave(messages) {
11673
11678
  }
11674
11679
  return Array.from(deduped.values());
11675
11680
  }
11681
+ /** Shallow merge; keys patched to `undefined` are dropped when serialized. Non-object metadata is replaced. */
11682
+ function mergeMetadata(existing, patch) {
11683
+ return {
11684
+ ...existing && typeof existing === "object" && !Array.isArray(existing) ? existing : {},
11685
+ ...patch
11686
+ };
11687
+ }
11676
11688
  var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
11677
11689
  supportsPartialThreadUpdate = true;
11678
11690
  supportsObservationalMemory = true;
@@ -12239,7 +12251,7 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
12239
12251
  const createdAt = toUtcISOString(thread.createdAt);
12240
12252
  const updatedAt = toUtcISOString(thread.updatedAt);
12241
12253
  const metadataJson = thread.metadata ? toPgJson(thread.metadata) : null;
12242
- await this.#fenced(fence, "saveThread", (q) => q.none(`INSERT INTO ${tableName} (
12254
+ const saved = await this.#fenced(fence, "saveThread", (q) => q.oneOrNone(`INSERT INTO ${tableName} AS t (
12243
12255
  id,
12244
12256
  "resourceId",
12245
12257
  title,
@@ -12250,13 +12262,12 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
12250
12262
  "updatedAtZ"
12251
12263
  ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
12252
12264
  ON CONFLICT (id) DO UPDATE SET
12253
- "resourceId" = EXCLUDED."resourceId",
12254
12265
  title = EXCLUDED.title,
12255
12266
  metadata = EXCLUDED.metadata,
12256
- "createdAt" = EXCLUDED."createdAt",
12257
- "createdAtZ" = EXCLUDED."createdAtZ",
12258
12267
  "updatedAt" = EXCLUDED."updatedAt",
12259
- "updatedAtZ" = EXCLUDED."updatedAtZ"`, [
12268
+ "updatedAtZ" = EXCLUDED."updatedAtZ"
12269
+ WHERE t."resourceId" = EXCLUDED."resourceId"
12270
+ RETURNING *`, [
12260
12271
  thread.id,
12261
12272
  thread.resourceId,
12262
12273
  thread.title,
@@ -12266,12 +12277,26 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
12266
12277
  updatedAt,
12267
12278
  updatedAt
12268
12279
  ]));
12280
+ if (!saved) throw new _mastra_core_error.MastraError({
12281
+ id: (0, _mastra_core_storage.createStorageErrorId)("PG", "SAVE_THREAD", "RESOURCE_ID_MISMATCH"),
12282
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
12283
+ category: _mastra_core_error.ErrorCategory.USER,
12284
+ text: `Thread ${thread.id} already exists and belongs to a different resource. Use updateThreadResourceId to move a thread and its messages to another resource.`,
12285
+ details: {
12286
+ threadId: thread.id,
12287
+ resourceId: thread.resourceId
12288
+ }
12289
+ });
12269
12290
  return {
12270
- ...thread,
12271
- metadata: metadataJson ? JSON.parse(metadataJson) : thread.metadata
12291
+ id: saved.id,
12292
+ resourceId: saved.resourceId,
12293
+ title: saved.title,
12294
+ metadata: saved.metadata == null ? void 0 : typeof saved.metadata === "string" ? JSON.parse(saved.metadata) : saved.metadata,
12295
+ createdAt: saved.createdAtZ || saved.createdAt,
12296
+ updatedAt: saved.updatedAtZ || saved.updatedAt
12272
12297
  };
12273
12298
  } catch (error) {
12274
- if ((0, _mastra_core_storage.isRunFenceConflictError)(error)) throw error;
12299
+ if (error instanceof _mastra_core_error.MastraError || (0, _mastra_core_storage.isRunFenceConflictError)(error)) throw error;
12275
12300
  throw new _mastra_core_error.MastraError({
12276
12301
  id: (0, _mastra_core_storage.createStorageErrorId)("PG", "SAVE_THREAD", "FAILED"),
12277
12302
  domain: _mastra_core_error.ErrorDomain.STORAGE,
@@ -12280,52 +12305,125 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
12280
12305
  }, error);
12281
12306
  }
12282
12307
  }
12283
- async updateThread({ id, title, metadata, fence }) {
12308
+ #toThread(row) {
12309
+ return {
12310
+ id: row.id,
12311
+ resourceId: row.resourceId,
12312
+ title: row.title,
12313
+ metadata: typeof row.metadata === "string" ? JSON.parse(row.metadata) : row.metadata,
12314
+ createdAt: row.createdAtZ || row.createdAt,
12315
+ updatedAt: row.updatedAtZ || row.updatedAt
12316
+ };
12317
+ }
12318
+ async #lockThread(t, tableName, { id, resourceId }) {
12319
+ const params = [id];
12320
+ let query = `SELECT * FROM ${tableName} WHERE id = $1`;
12321
+ if (resourceId !== void 0) {
12322
+ query += ` AND "resourceId" = $2`;
12323
+ params.push(resourceId);
12324
+ }
12325
+ const row = await t.oneOrNone(`${query} FOR UPDATE`, params);
12326
+ return row ? this.#toThread(row) : null;
12327
+ }
12328
+ /**
12329
+ * Writes `title` (when given) and the full `metadata` value (when given).
12330
+ * Callers that merge metadata must hold the row lock from `#lockThread`.
12331
+ */
12332
+ async #writeThread(q, tableName, { id, title, metadata }) {
12333
+ const nowStr = toUtcISOString(/* @__PURE__ */ new Date());
12334
+ const params = [
12335
+ title ?? null,
12336
+ nowStr,
12337
+ nowStr,
12338
+ id
12339
+ ];
12340
+ let metadataSet = "";
12341
+ if (metadata !== void 0) {
12342
+ params.push(toPgJson(metadata));
12343
+ metadataSet = "metadata = $5,";
12344
+ }
12345
+ const row = await q.oneOrNone(`UPDATE ${tableName}
12346
+ SET
12347
+ title = COALESCE($1, title),
12348
+ ${metadataSet}
12349
+ "updatedAt" = $2,
12350
+ "updatedAtZ" = $3
12351
+ WHERE id = $4
12352
+ RETURNING *`, params);
12353
+ return row ? this.#toThread(row) : null;
12354
+ }
12355
+ /**
12356
+ * Cross-process atomic metadata read-modify-write: the thread row stays locked
12357
+ * (`SELECT ... FOR UPDATE`) from the read through the write, so concurrent
12358
+ * writers from any process serialize instead of overwriting each other.
12359
+ */
12360
+ async updateThreadMetadata({ id, resourceId, update, fence: explicitFence }) {
12361
+ const fence = (0, _mastra_core_storage.resolveRunFence)(this, explicitFence);
12362
+ const threadsTable = getTableName$3({
12363
+ indexName: _mastra_core_storage.TABLE_THREADS,
12364
+ schemaName: getSchemaName$3(this.#schema)
12365
+ });
12366
+ try {
12367
+ return await this.#db.client.tx(async (t) => {
12368
+ if (fence) await assertRunFence(t, this.#runFencesTable(), fence, "updateThreadMetadata");
12369
+ const thread = await this.#lockThread(t, threadsTable, {
12370
+ id,
12371
+ resourceId
12372
+ });
12373
+ if (!thread) return null;
12374
+ const metadata = update(thread);
12375
+ if (!metadata) return thread;
12376
+ return this.#writeThread(t, threadsTable, {
12377
+ id,
12378
+ metadata: mergeMetadata(thread.metadata, metadata)
12379
+ });
12380
+ });
12381
+ } catch (error) {
12382
+ if (error instanceof _mastra_core_error.MastraError || (0, _mastra_core_storage.isRunFenceConflictError)(error)) throw error;
12383
+ throw new _mastra_core_error.MastraError({
12384
+ id: (0, _mastra_core_storage.createStorageErrorId)("PG", "UPDATE_THREAD_METADATA", "FAILED"),
12385
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
12386
+ category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
12387
+ details: { threadId: id }
12388
+ }, error);
12389
+ }
12390
+ }
12391
+ async updateThread({ id, title, metadata, fence: explicitFence }) {
12284
12392
  const threadTableName = getTableName$3({
12285
12393
  indexName: _mastra_core_storage.TABLE_THREADS,
12286
12394
  schemaName: getSchemaName$3(this.#schema)
12287
12395
  });
12396
+ const notFound = () => new _mastra_core_error.MastraError({
12397
+ id: (0, _mastra_core_storage.createStorageErrorId)("PG", "UPDATE_THREAD", "FAILED"),
12398
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
12399
+ category: _mastra_core_error.ErrorCategory.USER,
12400
+ text: `Thread ${id} not found`,
12401
+ details: {
12402
+ threadId: id,
12403
+ title: title ?? null
12404
+ }
12405
+ });
12288
12406
  try {
12289
- return await this.#fenced(fence, "updateThread", async (q) => {
12290
- const existingThread = await this.#getThreadById(q, { threadId: id });
12291
- if (!existingThread) throw new _mastra_core_error.MastraError({
12292
- id: (0, _mastra_core_storage.createStorageErrorId)("PG", "UPDATE_THREAD", "FAILED"),
12293
- domain: _mastra_core_error.ErrorDomain.STORAGE,
12294
- category: _mastra_core_error.ErrorCategory.USER,
12295
- text: `Thread ${id} not found`,
12296
- details: {
12297
- threadId: id,
12298
- title: title ?? null
12299
- }
12407
+ if (metadata === void 0) return await this.#fenced(explicitFence, "updateThread", async (q) => {
12408
+ const thread = await this.#writeThread(q, threadTableName, {
12409
+ id,
12410
+ title
12300
12411
  });
12301
- const mergedMetadata = {
12302
- ...existingThread.metadata,
12303
- ...metadata
12304
- };
12305
- const nowStr = toUtcISOString(/* @__PURE__ */ new Date());
12306
- const thread = await q.one(`UPDATE ${threadTableName}
12307
- SET
12308
- title = COALESCE($1, title),
12309
- metadata = $2,
12310
- "updatedAt" = $3,
12311
- "updatedAtZ" = $4
12312
- WHERE id = $5
12313
- RETURNING *
12314
- `, [
12315
- title ?? null,
12316
- mergedMetadata,
12317
- nowStr,
12318
- nowStr,
12319
- id
12320
- ]);
12321
- return {
12322
- id: thread.id,
12323
- resourceId: thread.resourceId,
12324
- title: thread.title,
12325
- metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
12326
- createdAt: thread.createdAtZ || thread.createdAt,
12327
- updatedAt: thread.updatedAtZ || thread.updatedAt
12328
- };
12412
+ if (!thread) throw notFound();
12413
+ return thread;
12414
+ });
12415
+ const fence = (0, _mastra_core_storage.resolveRunFence)(this, explicitFence);
12416
+ return await this.#db.client.tx(async (t) => {
12417
+ if (fence) await assertRunFence(t, this.#runFencesTable(), fence, "updateThread");
12418
+ const existing = await this.#lockThread(t, threadTableName, { id });
12419
+ if (!existing) throw notFound();
12420
+ const thread = await this.#writeThread(t, threadTableName, {
12421
+ id,
12422
+ title,
12423
+ metadata: mergeMetadata(existing.metadata, metadata)
12424
+ });
12425
+ if (!thread) throw notFound();
12426
+ return thread;
12329
12427
  });
12330
12428
  } catch (error) {
12331
12429
  if (error instanceof _mastra_core_error.MastraError || (0, _mastra_core_storage.isRunFenceConflictError)(error)) throw error;
@@ -17381,8 +17479,12 @@ ${onConflict}`,
17381
17479
  async function insertRows(client, schema, table, records, partitioning, onConflict) {
17382
17480
  const insert = buildInsert(schema, table, records, onConflict);
17383
17481
  if (!insert) return;
17482
+ await withPartitionRetry(client, schema, table, records, partitioning, () => client.query(insert.text, insert.values));
17483
+ }
17484
+ /** Retry a complete write after creating a missing native partition, outside any failed transaction. */
17485
+ async function withPartitionRetry(client, schema, table, records, partitioning, write) {
17384
17486
  try {
17385
- await client.query(insert.text, insert.values);
17487
+ return await write();
17386
17488
  } catch (error) {
17387
17489
  if (!isMissingPartitionError(error) || await resolveMode(client, partitioning) !== "native") throw error;
17388
17490
  const days = withinPartitionWindow(recordDays(records, SIGNAL_TIME_COLUMN[table]), partitioning);
@@ -17395,7 +17497,7 @@ async function insertRows(client, schema, table, records, partitioning, onConfli
17395
17497
  cause
17396
17498
  }), { cause });
17397
17499
  });
17398
- await client.query(insert.text, insert.values);
17500
+ return await write();
17399
17501
  }
17400
17502
  }
17401
17503
  /** `42501`: the role may not create the child, or does not own the parent it must attach to. */
@@ -18329,13 +18431,47 @@ function pushFeedbackIdentity(acc, feedbackType, feedbackSource) {
18329
18431
  acc.conditions.push(`"valueNumber" IS NOT NULL`);
18330
18432
  }
18331
18433
  async function createFeedback(client, schema, args, partitioning) {
18332
- const row = feedbackRecordToRow(args.feedback);
18333
- await insertRows(client, schema, TABLE_FEEDBACK_EVENTS, [row], partitioning, FEEDBACK_UPSERT_CLAUSE);
18434
+ await writeFeedback(client, schema, [args.feedback], args.onConflict, partitioning);
18435
+ }
18436
+ async function replaceFeedback(client, schema, args, partitioning) {
18437
+ await writeFeedback(client, schema, [args.feedback], "replace", partitioning, true);
18334
18438
  }
18335
18439
  async function batchCreateFeedback(client, schema, args, partitioning) {
18336
- if (args.feedbacks.length === 0) return;
18337
- const rows = [...new Map(args.feedbacks.map((feedback) => [feedback.feedbackId, feedback])).values()].map(feedbackRecordToRow);
18338
- await insertRows(client, schema, TABLE_FEEDBACK_EVENTS, rows, partitioning, FEEDBACK_UPSERT_CLAUSE);
18440
+ await writeFeedback(client, schema, args.feedbacks, args.onConflict, partitioning);
18441
+ }
18442
+ /** Serialize feedback writes by ID, including absent IDs and retries with a different timestamp. */
18443
+ async function writeFeedback(client, schema, feedbacks, onConflict, partitioning, preserveIdentity = false) {
18444
+ if (!feedbacks.length) return;
18445
+ const currentFeedback = new Map((onConflict === "ignore" ? [...feedbacks].reverse() : feedbacks).map((feedback) => [feedback.feedbackId, feedback]));
18446
+ const rows = [...currentFeedback.values()].map(feedbackRecordToRow);
18447
+ const ids = [...currentFeedback.keys()].sort();
18448
+ await withPartitionRetry(client, schema, TABLE_FEEDBACK_EVENTS, rows, partitioning, () => client.tx(async (tx) => {
18449
+ await tx.query(`SELECT pg_advisory_xact_lock(hashtextextended(lock_key, 0))
18450
+ FROM unnest($1::text[]) WITH ORDINALITY AS locks(lock_key, position)
18451
+ ORDER BY position`, [ids.map((id) => JSON.stringify([
18452
+ schema,
18453
+ TABLE_FEEDBACK_EVENTS,
18454
+ id
18455
+ ]))]);
18456
+ const existing = await tx.any(`SELECT DISTINCT ON ("feedbackId") "feedbackId", "traceId", "timestamp", "organizationId", "resourceId"
18457
+ FROM ${qualifiedTable(schema, TABLE_FEEDBACK_EVENTS)}
18458
+ WHERE "feedbackId" = ANY($1::text[]) ORDER BY "feedbackId", "cursorId" DESC`, [ids]);
18459
+ const byId = new Map(existing.map((row) => [row.feedbackId, row]));
18460
+ const accepted = rows.filter((row) => {
18461
+ const previous = byId.get(row.feedbackId);
18462
+ if (!previous) return true;
18463
+ if (onConflict === "ignore") return false;
18464
+ if (preserveIdentity && (previous.traceId !== row.traceId || new Date(previous.timestamp).getTime() !== new Date(row.timestamp).getTime() || (previous.organizationId ?? null) !== (row.organizationId ?? null) || (previous.resourceId ?? null) !== (row.resourceId ?? null))) throw new _mastra_core_error.MastraError({
18465
+ id: "OBSERVABILITY_FEEDBACK_IDENTITY_CONFLICT",
18466
+ domain: _mastra_core_error.ErrorDomain.MASTRA_OBSERVABILITY,
18467
+ category: _mastra_core_error.ErrorCategory.USER,
18468
+ text: "Feedback replacement must preserve its trace, timestamp, and tenant"
18469
+ });
18470
+ return true;
18471
+ });
18472
+ const insert = buildInsert(schema, TABLE_FEEDBACK_EVENTS, accepted, FEEDBACK_UPSERT_CLAUSE);
18473
+ if (insert) await tx.query(insert.text, insert.values);
18474
+ }));
18339
18475
  }
18340
18476
  async function getFeedbackById(client, schema, feedbackId) {
18341
18477
  const row = await client.oneOrNone(`SELECT ${FEEDBACK_SELECT_COLUMNS} FROM ${qualifiedTable(schema, TABLE_FEEDBACK_EVENTS)}
@@ -22026,6 +22162,7 @@ var ObservabilityStoragePostgresVNext = class ObservabilityStoragePostgresVNext
22026
22162
  "thread-query",
22027
22163
  "trace-query-tenant-scope",
22028
22164
  "feedback",
22165
+ "feedback-replacement",
22029
22166
  "trace-query-context-ids",
22030
22167
  ...contextFieldFeatures,
22031
22168
  ...timingFeatures,
@@ -22054,6 +22191,7 @@ var ObservabilityStoragePostgresVNext = class ObservabilityStoragePostgresVNext
22054
22191
  "thread-query",
22055
22192
  "trace-query-tenant-scope",
22056
22193
  "feedback",
22194
+ "feedback-replacement",
22057
22195
  "trace-query-context-ids",
22058
22196
  ...contextFieldFeatures,
22059
22197
  ...timingFeatures,
@@ -22153,6 +22291,9 @@ var ObservabilityStoragePostgresVNext = class ObservabilityStoragePostgresVNext
22153
22291
  async batchCreateScores(args) {
22154
22292
  await this.#run("BATCH_CREATE_SCORES", () => batchCreateScores(this.#client, this.#schema, args, this.#writePartitioning()), { count: args.scores.length });
22155
22293
  }
22294
+ async writeFeedbackReplacement(args) {
22295
+ await this.#run("REPLACE_FEEDBACK", () => replaceFeedback(this.#client, this.#schema, args, this.#writePartitioning()));
22296
+ }
22156
22297
  async createFeedback(args) {
22157
22298
  await this.#run("CREATE_FEEDBACK", () => createFeedback(this.#client, this.#schema, args, this.#writePartitioning()));
22158
22299
  }
@@ -22178,7 +22319,7 @@ var ObservabilityStoragePostgresVNext = class ObservabilityStoragePostgresVNext
22178
22319
  return this.#run("GET_SCORE_BY_ID", () => getScoreById(this.#readClient, this.#schema, scoreId), { scoreId });
22179
22320
  }
22180
22321
  async getFeedbackById(feedbackId) {
22181
- return this.#run("GET_FEEDBACK_BY_ID", () => getFeedbackById(this.#readClient, this.#schema, feedbackId), { feedbackId });
22322
+ return this.#run("GET_FEEDBACK_BY_ID", () => getFeedbackById(this.#client, this.#schema, feedbackId), { feedbackId });
22182
22323
  }
22183
22324
  async listFeedback(args) {
22184
22325
  return this.#run("LIST_FEEDBACK", () => listFeedback(this.#readClient, this.#schema, args));
@@ -25964,15 +26105,16 @@ var WorkflowsPG = class WorkflowsPG extends _mastra_core_storage.WorkflowsStorag
25964
26105
  this.logger?.warn?.(`Failed to create index ${stateBaseIndexName}:`, error);
25965
26106
  }
25966
26107
  if (await this.#db.getColumnType(_mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT, "snapshot") !== "jsonb") return;
26108
+ const concurrently = !this.#db.isTableCreatedInThisInit(_mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT);
25967
26109
  const indexName = workflowSnapshotStatusIndexName(this.#schema);
25968
26110
  try {
25969
- await this.#db.createIndexFromStatement(indexName, workflowSnapshotStatusIndexSQL(indexName, this.#schema, true));
26111
+ await this.#db.createIndexFromStatement(indexName, workflowSnapshotStatusIndexSQL(indexName, this.#schema, concurrently));
25970
26112
  } catch (error) {
25971
26113
  this.logger?.warn?.(`Failed to create index ${indexName}:`, error);
25972
26114
  }
25973
26115
  const threadIdIndexName = workflowSnapshotThreadIdIndexName(this.#schema);
25974
26116
  try {
25975
- await this.#db.createIndexFromStatement(threadIdIndexName, workflowSnapshotThreadIdIndexSQL(threadIdIndexName, this.#schema, true));
26117
+ await this.#db.createIndexFromStatement(threadIdIndexName, workflowSnapshotThreadIdIndexSQL(threadIdIndexName, this.#schema, concurrently));
25976
26118
  } catch (error) {
25977
26119
  this.logger?.warn?.(`Failed to create index ${threadIdIndexName}:`, error);
25978
26120
  }