@mastra/pg 1.30.0-alpha.0 → 1.30.0-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.
@@ -3,7 +3,7 @@ name: mastra-pg
3
3
  description: Documentation for @mastra/pg. Use when working with @mastra/pg APIs, configuration, or implementation.
4
4
  metadata:
5
5
  package: "@mastra/pg"
6
- version: "1.30.0-alpha.0"
6
+ version: "1.30.0-alpha.2"
7
7
  ---
8
8
 
9
9
  ## When to use
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.30.0-alpha.0",
2
+ "version": "1.30.0-alpha.2",
3
3
  "package": "@mastra/pg",
4
4
  "exports": {},
5
5
  "modules": {}
package/dist/index.cjs CHANGED
@@ -18280,6 +18280,166 @@ async function queryThreads(client, schema, plan, timeoutMs) {
18280
18280
  }) : null }
18281
18281
  });
18282
18282
  }
18283
+ /** Compile a span-row filter with exactly the same rules as trace span predicates. */
18284
+ function compileSpanQueryPredicate(predicate, offset) {
18285
+ return compileScalarPredicate(predicate, SPAN_FIELDS, offset);
18286
+ }
18287
+ //#endregion
18288
+ //#region src/storage/domains/observability/v-next/span-query.ts
18289
+ const identityFields = [
18290
+ "organizationId",
18291
+ "resourceId",
18292
+ "traceId",
18293
+ "spanId"
18294
+ ];
18295
+ const fields = [
18296
+ ...identityFields,
18297
+ "parentSpanId",
18298
+ "name",
18299
+ "spanType",
18300
+ "entityType",
18301
+ "entityId",
18302
+ "entityName",
18303
+ "entityVersionId",
18304
+ "parentEntityVersionId",
18305
+ "rootEntityVersionId",
18306
+ "runId",
18307
+ "sessionId",
18308
+ "userId"
18309
+ ];
18310
+ const identities = identityFields.map((field) => `"${field}"`).join(", ");
18311
+ const identityOrder = identityFields.map((field) => `"${field}" COLLATE "C" ASC NULLS LAST`).join(", ");
18312
+ function selectedKeys(rows, values) {
18313
+ return rows.map((row) => `(${identityFields.map((field) => {
18314
+ values.push(row[field]);
18315
+ return `"${field}" ${field === "traceId" || field === "spanId" ? "=" : "IS NOT DISTINCT FROM"} $${values.length}::text`;
18316
+ }).join(" AND ")})`).join(" OR ");
18317
+ }
18318
+ function afterCursor(plan, values) {
18319
+ if (!plan.cursor) return "TRUE";
18320
+ const cursor = plan.cursor;
18321
+ values.push(cursor.sortValue);
18322
+ const timestamp = `$${values.length}::timestamptz`;
18323
+ const field = `s."${plan.orderBy.field}"`;
18324
+ const terms = [`${field} ${plan.orderBy.direction === "asc" ? ">" : "<"} ${timestamp}`];
18325
+ const equal = [`${field} = ${timestamp}`];
18326
+ for (const key of identityFields) {
18327
+ const ref = `s."${key}" COLLATE "C"`;
18328
+ const value = cursor[key];
18329
+ if (value === null) equal.push(`${ref} IS NULL`);
18330
+ else {
18331
+ values.push(value);
18332
+ const parameter = `$${values.length}::text COLLATE "C"`;
18333
+ terms.push(`(${equal.join(" AND ")} AND (${ref} > ${parameter} OR ${ref} IS NULL))`);
18334
+ equal.push(`${ref} = ${parameter}`);
18335
+ }
18336
+ }
18337
+ return `(${terms.join(" OR ")})`;
18338
+ }
18339
+ function compilePostgresSpanQuery(schema, plan) {
18340
+ const values = [plan.timeRange.from, plan.timeRange.to];
18341
+ const scope = [];
18342
+ if (plan.scope) {
18343
+ values.push(plan.scope.organizationId);
18344
+ scope.push(`"organizationId" = $${values.length}`);
18345
+ if (plan.scope.resourceId !== void 0) {
18346
+ values.push(plan.scope.resourceId);
18347
+ scope.push(`"resourceId" = $${values.length}`);
18348
+ }
18349
+ }
18350
+ const predicate = plan.where ? compileSpanQueryPredicate(plan.where, values.length + 1) : {
18351
+ sql: "TRUE",
18352
+ values: []
18353
+ };
18354
+ values.push(...predicate.values);
18355
+ const after = afterCursor(plan, values);
18356
+ values.push(plan.limit + 1);
18357
+ const table = qualifiedTable(schema, TABLE_SPAN_EVENTS);
18358
+ return {
18359
+ text: `WITH candidate_ids AS MATERIALIZED (
18360
+ SELECT DISTINCT ${identities} FROM ${table}
18361
+ WHERE "startedAt" >= $1 AND "startedAt" < $2 AND "endedAt" >= $1 AND NOT "isPending"
18362
+ ${scope.length ? `AND ${scope.join(" AND ")}` : ""}
18363
+ ), current_spans AS MATERIALIZED (
18364
+ SELECT DISTINCT ON (${identities})
18365
+ ${fields.map((field) => `"${field}"`).join(", ")}, "startedAt", "endedAt", "cursorId"::text AS version,
18366
+ CASE WHEN jsonb_typeof(attributes -> 'model') = 'string' THEN attributes ->> 'model' END AS model,
18367
+ CASE WHEN jsonb_typeof(attributes -> 'provider') = 'string' THEN attributes ->> 'provider' END AS provider,
18368
+ (EXTRACT(EPOCH FROM ("endedAt" - "startedAt")) * 1000)::float8 AS "durationMs",
18369
+ CASE WHEN error IS NULL THEN 'success' ELSE 'error' END AS status,
18370
+ error IS NOT NULL AS "hasError"
18371
+ FROM ${table} e
18372
+ WHERE NOT "isPending" AND "endedAt" >= $1 AND (
18373
+ "organizationId" IS NULL, COALESCE("organizationId", ''), "resourceId" IS NULL, COALESCE("resourceId", ''), "traceId", "spanId"
18374
+ ) IN (
18375
+ SELECT "organizationId" IS NULL, COALESCE("organizationId", ''), "resourceId" IS NULL, COALESCE("resourceId", ''), "traceId", "spanId" FROM candidate_ids
18376
+ ) ${scope.length ? `AND ${scope.join(" AND ")}` : ""}
18377
+ ORDER BY ${identities}, "endedAt" DESC, "cursorId" DESC
18378
+ ), candidates AS (
18379
+ SELECT *, CASE WHEN "hasError" THEN 'error' ELSE NULL END AS error FROM current_spans
18380
+ )
18381
+ SELECT ${[
18382
+ ...identityFields,
18383
+ "parentSpanId",
18384
+ "name",
18385
+ "spanType",
18386
+ "entityType",
18387
+ "entityId",
18388
+ "entityName",
18389
+ "model",
18390
+ "provider",
18391
+ "startedAt",
18392
+ "endedAt",
18393
+ "durationMs",
18394
+ "status",
18395
+ "version"
18396
+ ].map((field) => `s."${field}"`).join(", ")}
18397
+ FROM candidates s WHERE s."startedAt" >= $1 AND s."startedAt" < $2 AND (${predicate.sql}) AND ${after}
18398
+ ORDER BY s."${plan.orderBy.field}" ${plan.orderBy.direction === "asc" ? "ASC" : "DESC"}, ${identityOrder}
18399
+ LIMIT $${values.length}`,
18400
+ values
18401
+ };
18402
+ }
18403
+ async function querySpans(client, schema, plan, timeoutMs) {
18404
+ const deadline = performance.now() + _mastra_core_storage.resolveTraceQueryTimeoutMs(timeoutMs);
18405
+ return runWithPostgresTraceQueryTimeout(client, timeoutMs, async (tx) => {
18406
+ const query = compilePostgresSpanQuery(schema, plan);
18407
+ const rows = await tx.any(query.text, query.values);
18408
+ const selected = rows.map(({ version: _version, startedAt, endedAt, ...row }) => ({
18409
+ ...row,
18410
+ startedAt: startedAt.toISOString(),
18411
+ endedAt: endedAt.toISOString()
18412
+ }));
18413
+ const page = rows.slice(0, plan.limit);
18414
+ if (!page.length) return _mastra_core_storage.buildSpanQueryResponse(plan, selected, [], []);
18415
+ const remaining = async () => {
18416
+ const ms = Math.floor(deadline - performance.now());
18417
+ if (ms <= 0) throw new _mastra_core_storage.TraceQueryExecutionError();
18418
+ await tx.query(`SELECT set_config('statement_timeout', $1, true)`, [`${ms}ms`]);
18419
+ };
18420
+ await remaining();
18421
+ const payloadValues = [];
18422
+ const payloadWhere = page.map((row) => {
18423
+ const key = selectedKeys([row], payloadValues);
18424
+ payloadValues.push(row.version);
18425
+ return `(${key} AND "cursorId" = $${payloadValues.length}::bigint)`;
18426
+ }).join(" OR ");
18427
+ const payloads = await tx.any(`SELECT ${identities},
18428
+ left(input::text, ${_mastra_core_storage.SPAN_QUERY_MAX_PREVIEW_CHARACTERS + 1}) AS "inputPreview", left(output::text, ${_mastra_core_storage.SPAN_QUERY_MAX_PREVIEW_CHARACTERS + 1}) AS "outputPreview"
18429
+ FROM ${qualifiedTable(schema, TABLE_SPAN_EVENTS)} WHERE ${payloadWhere}`, payloadValues);
18430
+ await remaining();
18431
+ const metricValues = [];
18432
+ const metricWhere = selectedKeys(page, metricValues);
18433
+ const metrics = await tx.any(`SELECT ${identities}, name, "estimatedCost", "costUnit",
18434
+ "costMetadata" ->> 'allocation' AS allocation, COALESCE("costMetadata" ? 'error', false) AS "costError"
18435
+ FROM (SELECT DISTINCT ON (${identities}, "metricId") ${identities}, name, "estimatedCost", "costUnit", "costMetadata" FROM ${qualifiedTable(schema, TABLE_METRIC_EVENTS)}
18436
+ WHERE (${metricWhere}) AND name LIKE 'mastra_model_%'
18437
+ ORDER BY ${identities}, "metricId", "cursorId" DESC) m
18438
+ LIMIT ${_mastra_core_storage.SPAN_QUERY_MAX_COST_METRICS + 1}`, metricValues);
18439
+ if (metrics.length > _mastra_core_storage.SPAN_QUERY_MAX_COST_METRICS) throw new _mastra_core_storage.TraceQueryResourceLimitError();
18440
+ return _mastra_core_storage.buildSpanQueryResponse(plan, selected, payloads, metrics);
18441
+ }, { repeatableRead: true });
18442
+ }
18283
18443
  //#endregion
18284
18444
  //#region src/storage/domains/observability/v-next/trace-aggregate.ts
18285
18445
  /** Trace-root column expressions (alias `r`) for each groupable dimension; same values `where` sees. */
@@ -19175,6 +19335,7 @@ async function dangerouslyClearTracing(client, schema) {
19175
19335
  * application database — observability writes will degrade app performance.
19176
19336
  * Use it through `MastraCompositeStore` with a dedicated Postgres connection.
19177
19337
  */
19338
+ const spanQueryFeatures = typeof _mastra_core_storage.planSpanQuery === "function" ? ["span-query"] : [];
19178
19339
  function wrapError(op, error, details) {
19179
19340
  if (error instanceof _mastra_core_error.MastraError || error instanceof _mastra_core_storage.TraceQueryCursorError || error instanceof _mastra_core_storage.TraceQueryExecutionError || error instanceof _mastra_core_storage.TraceQueryResourceLimitError) throw error;
19180
19341
  throw new _mastra_core_error.MastraError({
@@ -19364,6 +19525,7 @@ var ObservabilityStoragePostgresVNext = class ObservabilityStoragePostgresVNext
19364
19525
  "metric-discovery",
19365
19526
  "trace-query",
19366
19527
  "trace-aggregate",
19528
+ ...spanQueryFeatures,
19367
19529
  "trace-query-root-duration",
19368
19530
  "trace-query-discovery",
19369
19531
  "thread-query",
@@ -19383,6 +19545,7 @@ var ObservabilityStoragePostgresVNext = class ObservabilityStoragePostgresVNext
19383
19545
  "delta-polling",
19384
19546
  "trace-query",
19385
19547
  "trace-aggregate",
19548
+ ...spanQueryFeatures,
19386
19549
  "trace-query-root-duration",
19387
19550
  "trace-query-discovery",
19388
19551
  "thread-query",
@@ -19431,6 +19594,9 @@ var ObservabilityStoragePostgresVNext = class ObservabilityStoragePostgresVNext
19431
19594
  async listTraces(args) {
19432
19595
  return this.#run("LIST_TRACES", () => listTraces(this.#readClient, this.#schema, args));
19433
19596
  }
19597
+ async querySpans(plan) {
19598
+ return this.#run("QUERY_SPANS", () => querySpans(this.#readClient, this.#schema, plan, this.#traceQueryTimeoutMs));
19599
+ }
19434
19600
  async queryTraces(plan) {
19435
19601
  return this.#run("QUERY_TRACES", () => queryTraces(this.#readClient, this.#schema, plan, this.#traceQueryTimeoutMs));
19436
19602
  }
@@ -20448,9 +20614,9 @@ var SchedulesPG = class SchedulesPG extends _mastra_core_storage.SchedulesStorag
20448
20614
  if (!updated) throw new Error(`Schedule ${id} not found`);
20449
20615
  return updated;
20450
20616
  }
20451
- async updateScheduleNextFire(id, expectedNextFireAt, newNextFireAt, lastFireAt, lastRunId) {
20617
+ async updateScheduleNextFire(id, expectedNextFireAt, newNextFireAt, lastFireAt, lastRunId, newStatus) {
20452
20618
  return ((await this.#client.query(`UPDATE ${this.#table(_mastra_core_storage.TABLE_SCHEDULES)}
20453
- SET next_fire_at = $1, last_fire_at = $2, last_run_id = $3, updated_at = $4
20619
+ SET next_fire_at = $1, last_fire_at = $2, last_run_id = $3, updated_at = $4, status = COALESCE($8, status)
20454
20620
  WHERE id = $5 AND next_fire_at = $6 AND status = $7`, [
20455
20621
  newNextFireAt,
20456
20622
  lastFireAt,
@@ -20458,7 +20624,8 @@ var SchedulesPG = class SchedulesPG extends _mastra_core_storage.SchedulesStorag
20458
20624
  Date.now(),
20459
20625
  id,
20460
20626
  expectedNextFireAt,
20461
- "active"
20627
+ "active",
20628
+ newStatus ?? null
20462
20629
  ])).rowCount ?? 0) > 0;
20463
20630
  }
20464
20631
  async deleteSchedule(id) {