@mastra/duckdb 1.2.0 → 1.3.0-alpha.0

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.
@@ -1188,7 +1188,16 @@ async function listLogs(db, args) {
1188
1188
  logs
1189
1189
  };
1190
1190
  }
1191
- function getAggregationSql2(aggregation, measure = "value") {
1191
+ function resolveDistinctColumnSql(distinctColumn) {
1192
+ if (!distinctColumn) {
1193
+ throw new Error(`count_distinct aggregation requires a 'distinctColumn' argument`);
1194
+ }
1195
+ if (!storage.METRIC_DISTINCT_COLUMNS.includes(distinctColumn)) {
1196
+ throw new Error(`Invalid distinctColumn: ${distinctColumn}`);
1197
+ }
1198
+ return utils.parseFieldKey(distinctColumn);
1199
+ }
1200
+ function getAggregationSql2(aggregation, measure = "value", distinctColumn) {
1192
1201
  switch (aggregation) {
1193
1202
  case "sum":
1194
1203
  return `SUM(${measure})`;
@@ -1200,6 +1209,9 @@ function getAggregationSql2(aggregation, measure = "value") {
1200
1209
  return `MAX(${measure})`;
1201
1210
  case "count":
1202
1211
  return `CAST(COUNT(${measure}) AS DOUBLE)`;
1212
+ case "count_distinct": {
1213
+ return `CAST(approx_count_distinct(${resolveDistinctColumnSql(distinctColumn)}) AS DOUBLE)`;
1214
+ }
1203
1215
  case "last":
1204
1216
  return `arg_max(${measure}, timestamp)`;
1205
1217
  default:
@@ -1445,7 +1457,7 @@ async function listMetrics(db, args) {
1445
1457
  };
1446
1458
  }
1447
1459
  async function getMetricAggregate(db, args) {
1448
- const aggSql = getAggregationSql2(args.aggregation);
1460
+ const aggSql = getAggregationSql2(args.aggregation, "value", args.distinctColumn);
1449
1461
  const { clause: nameClause, params: nameParams } = buildMetricNameFilter(args.name);
1450
1462
  const { clause: filterClause, params: filterParams } = buildWhereClause(
1451
1463
  args.filters
@@ -1529,7 +1541,7 @@ async function getMetricAggregate(db, args) {
1529
1541
  return { value, estimatedCost: costSummary.estimatedCost, costUnit: costSummary.costUnit };
1530
1542
  }
1531
1543
  async function getMetricBreakdown(db, args) {
1532
- const aggSql = getAggregationSql2(args.aggregation);
1544
+ const aggSql = getAggregationSql2(args.aggregation, "value", args.distinctColumn);
1533
1545
  const { clause: nameClause, params: nameParams } = buildMetricNameFilter(args.name);
1534
1546
  const { clause: filterClause, params: filterParams } = buildWhereClause(
1535
1547
  args.filters
@@ -1543,8 +1555,11 @@ async function getMetricBreakdown(db, args) {
1543
1555
  const resolvedGroupBy = resolveGroupBy(args.groupBy);
1544
1556
  const selectGroupBy = resolvedGroupBy.map((entry) => entry.selectSql).join(", ");
1545
1557
  const groupByCols = resolvedGroupBy.map((entry) => entry.groupSql).join(", ");
1546
- const sql = `SELECT ${selectGroupBy}, ${aggSql} AS value, ${getCostSummarySelect()} FROM metric_events ${whereClause} GROUP BY ${groupByCols} ORDER BY value DESC`;
1547
- const rows = await db.query(sql, allParams);
1558
+ const orderDirection = args.orderDirection === "ASC" ? "ASC" : "DESC";
1559
+ const limitClause = typeof args.limit === "number" ? `LIMIT ?` : "";
1560
+ const limitParams = typeof args.limit === "number" ? [args.limit] : [];
1561
+ const sql = `SELECT ${selectGroupBy}, ${aggSql} AS value, ${getCostSummarySelect()} FROM metric_events ${whereClause} GROUP BY ${groupByCols} ORDER BY value ${orderDirection} ${limitClause}`;
1562
+ const rows = await db.query(sql, [...allParams, ...limitParams]);
1548
1563
  const groups = rows.map((row) => {
1549
1564
  const dimensions = {};
1550
1565
  for (const entry of resolvedGroupBy) {
@@ -1562,7 +1577,7 @@ async function getMetricBreakdown(db, args) {
1562
1577
  return { groups };
1563
1578
  }
1564
1579
  async function getMetricTimeSeries(db, args) {
1565
- const aggSql = getAggregationSql2(args.aggregation);
1580
+ const aggSql = getAggregationSql2(args.aggregation, "value", args.distinctColumn);
1566
1581
  const intervalSql = getIntervalSql2(args.interval);
1567
1582
  const { clause: nameClause, params: nameParams } = buildMetricNameFilter(args.name);
1568
1583
  const { clause: filterClause, params: filterParams } = buildWhereClause(
@@ -2146,6 +2161,12 @@ async function listScores(db, args) {
2146
2161
  scores: rows.map((row) => rowToScoreRecord(row))
2147
2162
  };
2148
2163
  }
2164
+ async function getScoreById(db, scoreId) {
2165
+ const rows = await db.query(`SELECT * FROM score_events WHERE scoreId = ? LIMIT 1`, [
2166
+ scoreId
2167
+ ]);
2168
+ return rows[0] ? rowToScoreRecord(rows[0]) : null;
2169
+ }
2149
2170
  async function getScoreAggregate(db, args) {
2150
2171
  const aggSql = getAggregationSql3(args.aggregation);
2151
2172
  const { clause, params } = buildScoreWhereClause(args);
@@ -2639,6 +2660,82 @@ async function listTraces(db, args) {
2639
2660
  spans: storage.toTraceSpans(spans)
2640
2661
  };
2641
2662
  }
2663
+ var BRANCH_SPAN_TYPE_PLACEHOLDERS = storage.BRANCH_SPAN_TYPES.map(() => "?").join(", ");
2664
+ async function getSpans(db, args) {
2665
+ if (args.spanIds.length === 0) {
2666
+ return { traceId: args.traceId, spans: [] };
2667
+ }
2668
+ const placeholders = args.spanIds.map(() => "?").join(", ");
2669
+ const rows = await db.query(
2670
+ `${SPAN_RECONSTRUCT_SELECT}
2671
+ WHERE traceId = ? AND spanId IN (${placeholders})
2672
+ GROUP BY traceId, spanId`,
2673
+ [args.traceId, ...args.spanIds]
2674
+ );
2675
+ return {
2676
+ traceId: args.traceId,
2677
+ spans: rows.map((row) => rowToSpanRecord(row))
2678
+ };
2679
+ }
2680
+ async function listBranches(db, args) {
2681
+ const filters = args.filters ?? {};
2682
+ const page = Number(args.pagination?.page ?? 0);
2683
+ const perPage = Number(args.pagination?.perPage ?? 10);
2684
+ const orderBy = { field: args.orderBy?.field ?? "startedAt", direction: args.orderBy?.direction ?? "DESC" };
2685
+ const { spanType, ...passthroughFilters } = filters;
2686
+ const { clause: filterClause, params: filterParams } = buildWhereClause(passthroughFilters);
2687
+ const orderByClause = buildOrderByClause(orderBy);
2688
+ const { clause: paginationClause, params: paginationParams } = buildPaginationClause({ page, perPage });
2689
+ let prefilterClause;
2690
+ let prefilterParams;
2691
+ if (typeof spanType === "string") {
2692
+ if (!storage.BRANCH_SPAN_TYPES.includes(spanType)) {
2693
+ return {
2694
+ pagination: { total: 0, page, perPage, hasMore: false },
2695
+ branches: []
2696
+ };
2697
+ }
2698
+ prefilterClause = `WHERE spanType = ?`;
2699
+ prefilterParams = [spanType];
2700
+ } else {
2701
+ prefilterClause = `WHERE spanType IN (${BRANCH_SPAN_TYPE_PLACEHOLDERS})`;
2702
+ prefilterParams = [...storage.BRANCH_SPAN_TYPES];
2703
+ }
2704
+ const cteSql = `
2705
+ WITH branch_anchors AS (
2706
+ ${SPAN_RECONSTRUCT_SELECT}
2707
+ ${prefilterClause}
2708
+ GROUP BY traceId, spanId
2709
+ )
2710
+ `;
2711
+ const countSql = `
2712
+ ${cteSql}
2713
+ SELECT COUNT(*) as total FROM branch_anchors ${filterClause}
2714
+ `;
2715
+ const countResult = await db.query(countSql, [...prefilterParams, ...filterParams]);
2716
+ const total = Number(countResult[0]?.total ?? 0);
2717
+ if (total === 0) {
2718
+ return {
2719
+ pagination: { total: 0, page, perPage, hasMore: false },
2720
+ branches: []
2721
+ };
2722
+ }
2723
+ const dataSql = `
2724
+ ${cteSql}
2725
+ SELECT * FROM branch_anchors ${filterClause} ${orderByClause} ${paginationClause}
2726
+ `;
2727
+ const rows = await db.query(dataSql, [...prefilterParams, ...filterParams, ...paginationParams]);
2728
+ const spans = rows.map((row) => rowToSpanRecord(row));
2729
+ return {
2730
+ pagination: {
2731
+ total,
2732
+ page,
2733
+ perPage,
2734
+ hasMore: (page + 1) * perPage < total
2735
+ },
2736
+ branches: storage.toTraceSpans(spans)
2737
+ };
2738
+ }
2642
2739
 
2643
2740
  // src/storage/domains/observability/index.ts
2644
2741
  function buildSignalMigrationRequiredMessage(args) {
@@ -2741,6 +2838,9 @@ var ObservabilityStorageDuckDB = class extends storage.ObservabilityStorage {
2741
2838
  async getSpan(args) {
2742
2839
  return getSpan(this.db, args);
2743
2840
  }
2841
+ async getSpans(args) {
2842
+ return getSpans(this.db, args);
2843
+ }
2744
2844
  async getRootSpan(args) {
2745
2845
  return getRootSpan(this.db, args);
2746
2846
  }
@@ -2753,6 +2853,9 @@ var ObservabilityStorageDuckDB = class extends storage.ObservabilityStorage {
2753
2853
  async listTraces(args) {
2754
2854
  return listTraces(this.db, args);
2755
2855
  }
2856
+ async listBranches(args) {
2857
+ return listBranches(this.db, args);
2858
+ }
2756
2859
  // Logs
2757
2860
  async batchCreateLogs(args) {
2758
2861
  return batchCreateLogs(this.db, args);
@@ -2815,6 +2918,9 @@ var ObservabilityStorageDuckDB = class extends storage.ObservabilityStorage {
2815
2918
  async listScores(args) {
2816
2919
  return listScores(this.db, args);
2817
2920
  }
2921
+ async getScoreById(scoreId) {
2922
+ return getScoreById(this.db, scoreId);
2923
+ }
2818
2924
  async getScoreAggregate(args) {
2819
2925
  return getScoreAggregate(this.db, args);
2820
2926
  }
@@ -2852,5 +2958,5 @@ var ObservabilityStorageDuckDB = class extends storage.ObservabilityStorage {
2852
2958
  };
2853
2959
 
2854
2960
  exports.ObservabilityStorageDuckDB = ObservabilityStorageDuckDB;
2855
- //# sourceMappingURL=observability-AILZGFQT.cjs.map
2856
- //# sourceMappingURL=observability-AILZGFQT.cjs.map
2961
+ //# sourceMappingURL=observability-YJW7WSXX.cjs.map
2962
+ //# sourceMappingURL=observability-YJW7WSXX.cjs.map