@mastra/duckdb 1.2.0 → 1.3.0-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/CHANGELOG.md +56 -0
- package/dist/docs/SKILL.md +2 -1
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/docs/references/reference-storage-duckdb.md +150 -0
- package/dist/index.cjs +13 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +13 -1
- package/dist/index.js.map +1 -1
- package/dist/{observability-AILZGFQT.cjs → observability-2PJ44OVC.cjs} +307 -33
- package/dist/observability-2PJ44OVC.cjs.map +1 -0
- package/dist/{observability-YJBOVLPV.js → observability-7LL4LLXY.js} +308 -34
- package/dist/observability-7LL4LLXY.js.map +1 -0
- package/dist/storage/domains/observability/index.d.ts +4 -1
- package/dist/storage/domains/observability/index.d.ts.map +1 -1
- package/dist/storage/domains/observability/metrics.d.ts.map +1 -1
- package/dist/storage/domains/observability/scores.d.ts +2 -1
- package/dist/storage/domains/observability/scores.d.ts.map +1 -1
- package/dist/storage/domains/observability/tracing.d.ts +41 -2
- package/dist/storage/domains/observability/tracing.d.ts.map +1 -1
- package/dist/storage/index.d.ts +3 -0
- package/dist/storage/index.d.ts.map +1 -1
- package/package.json +9 -9
- package/dist/observability-AILZGFQT.cjs.map +0 -1
- package/dist/observability-YJBOVLPV.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DuckDBConnection } from './chunk-37GBWD4M.js';
|
|
2
2
|
import { MastraError, ErrorCategory, ErrorDomain } from '@mastra/core/error';
|
|
3
|
-
import { ObservabilityStorage, createStorageErrorId, toTraceSpans } from '@mastra/core/storage';
|
|
3
|
+
import { BRANCH_SPAN_TYPES, ObservabilityStorage, createStorageErrorId, toTraceSpans, METRIC_DISTINCT_COLUMNS } from '@mastra/core/storage';
|
|
4
4
|
import { EntityType } from '@mastra/core/observability';
|
|
5
5
|
import { parseFieldKey } from '@mastra/core/utils';
|
|
6
6
|
|
|
@@ -1186,7 +1186,16 @@ async function listLogs(db, args) {
|
|
|
1186
1186
|
logs
|
|
1187
1187
|
};
|
|
1188
1188
|
}
|
|
1189
|
-
function
|
|
1189
|
+
function resolveDistinctColumnSql(distinctColumn) {
|
|
1190
|
+
if (!distinctColumn) {
|
|
1191
|
+
throw new Error(`count_distinct aggregation requires a 'distinctColumn' argument`);
|
|
1192
|
+
}
|
|
1193
|
+
if (!METRIC_DISTINCT_COLUMNS.includes(distinctColumn)) {
|
|
1194
|
+
throw new Error(`Invalid distinctColumn: ${distinctColumn}`);
|
|
1195
|
+
}
|
|
1196
|
+
return parseFieldKey(distinctColumn);
|
|
1197
|
+
}
|
|
1198
|
+
function getAggregationSql2(aggregation, measure = "value", distinctColumn) {
|
|
1190
1199
|
switch (aggregation) {
|
|
1191
1200
|
case "sum":
|
|
1192
1201
|
return `SUM(${measure})`;
|
|
@@ -1198,6 +1207,9 @@ function getAggregationSql2(aggregation, measure = "value") {
|
|
|
1198
1207
|
return `MAX(${measure})`;
|
|
1199
1208
|
case "count":
|
|
1200
1209
|
return `CAST(COUNT(${measure}) AS DOUBLE)`;
|
|
1210
|
+
case "count_distinct": {
|
|
1211
|
+
return `CAST(approx_count_distinct(${resolveDistinctColumnSql(distinctColumn)}) AS DOUBLE)`;
|
|
1212
|
+
}
|
|
1201
1213
|
case "last":
|
|
1202
1214
|
return `arg_max(${measure}, timestamp)`;
|
|
1203
1215
|
default:
|
|
@@ -1443,7 +1455,7 @@ async function listMetrics(db, args) {
|
|
|
1443
1455
|
};
|
|
1444
1456
|
}
|
|
1445
1457
|
async function getMetricAggregate(db, args) {
|
|
1446
|
-
const aggSql = getAggregationSql2(args.aggregation);
|
|
1458
|
+
const aggSql = getAggregationSql2(args.aggregation, "value", args.distinctColumn);
|
|
1447
1459
|
const { clause: nameClause, params: nameParams } = buildMetricNameFilter(args.name);
|
|
1448
1460
|
const { clause: filterClause, params: filterParams } = buildWhereClause(
|
|
1449
1461
|
args.filters
|
|
@@ -1527,7 +1539,7 @@ async function getMetricAggregate(db, args) {
|
|
|
1527
1539
|
return { value, estimatedCost: costSummary.estimatedCost, costUnit: costSummary.costUnit };
|
|
1528
1540
|
}
|
|
1529
1541
|
async function getMetricBreakdown(db, args) {
|
|
1530
|
-
const aggSql = getAggregationSql2(args.aggregation);
|
|
1542
|
+
const aggSql = getAggregationSql2(args.aggregation, "value", args.distinctColumn);
|
|
1531
1543
|
const { clause: nameClause, params: nameParams } = buildMetricNameFilter(args.name);
|
|
1532
1544
|
const { clause: filterClause, params: filterParams } = buildWhereClause(
|
|
1533
1545
|
args.filters
|
|
@@ -1541,8 +1553,11 @@ async function getMetricBreakdown(db, args) {
|
|
|
1541
1553
|
const resolvedGroupBy = resolveGroupBy(args.groupBy);
|
|
1542
1554
|
const selectGroupBy = resolvedGroupBy.map((entry) => entry.selectSql).join(", ");
|
|
1543
1555
|
const groupByCols = resolvedGroupBy.map((entry) => entry.groupSql).join(", ");
|
|
1544
|
-
const
|
|
1545
|
-
const
|
|
1556
|
+
const orderDirection = args.orderDirection === "ASC" ? "ASC" : "DESC";
|
|
1557
|
+
const limitClause = typeof args.limit === "number" ? `LIMIT ?` : "";
|
|
1558
|
+
const limitParams = typeof args.limit === "number" ? [args.limit] : [];
|
|
1559
|
+
const sql = `SELECT ${selectGroupBy}, ${aggSql} AS value, ${getCostSummarySelect()} FROM metric_events ${whereClause} GROUP BY ${groupByCols} ORDER BY value ${orderDirection} ${limitClause}`;
|
|
1560
|
+
const rows = await db.query(sql, [...allParams, ...limitParams]);
|
|
1546
1561
|
const groups = rows.map((row) => {
|
|
1547
1562
|
const dimensions = {};
|
|
1548
1563
|
for (const entry of resolvedGroupBy) {
|
|
@@ -1560,7 +1575,7 @@ async function getMetricBreakdown(db, args) {
|
|
|
1560
1575
|
return { groups };
|
|
1561
1576
|
}
|
|
1562
1577
|
async function getMetricTimeSeries(db, args) {
|
|
1563
|
-
const aggSql = getAggregationSql2(args.aggregation);
|
|
1578
|
+
const aggSql = getAggregationSql2(args.aggregation, "value", args.distinctColumn);
|
|
1564
1579
|
const intervalSql = getIntervalSql2(args.interval);
|
|
1565
1580
|
const { clause: nameClause, params: nameParams } = buildMetricNameFilter(args.name);
|
|
1566
1581
|
const { clause: filterClause, params: filterParams } = buildWhereClause(
|
|
@@ -2144,6 +2159,12 @@ async function listScores(db, args) {
|
|
|
2144
2159
|
scores: rows.map((row) => rowToScoreRecord(row))
|
|
2145
2160
|
};
|
|
2146
2161
|
}
|
|
2162
|
+
async function getScoreById(db, scoreId) {
|
|
2163
|
+
const rows = await db.query(`SELECT * FROM score_events WHERE scoreId = ? LIMIT 1`, [
|
|
2164
|
+
scoreId
|
|
2165
|
+
]);
|
|
2166
|
+
return rows[0] ? rowToScoreRecord(rows[0]) : null;
|
|
2167
|
+
}
|
|
2147
2168
|
async function getScoreAggregate(db, args) {
|
|
2148
2169
|
const aggSql = getAggregationSql3(args.aggregation);
|
|
2149
2170
|
const { clause, params } = buildScoreWhereClause(args);
|
|
@@ -2413,11 +2434,91 @@ function rowToSpanRecord(row) {
|
|
|
2413
2434
|
updatedAt: null
|
|
2414
2435
|
};
|
|
2415
2436
|
}
|
|
2416
|
-
function buildHasChildErrorClause(hasChildError) {
|
|
2437
|
+
function buildHasChildErrorClause(hasChildError, rootAlias) {
|
|
2417
2438
|
if (hasChildError === void 0) return "";
|
|
2418
|
-
const base = `SELECT 1 FROM
|
|
2439
|
+
const base = `SELECT 1 FROM span_events c WHERE c.traceId = ${rootAlias}.traceId AND c.spanId != ${rootAlias}.spanId AND c.error IS NOT NULL`;
|
|
2419
2440
|
return hasChildError ? `EXISTS (${base})` : `NOT EXISTS (${base})`;
|
|
2420
2441
|
}
|
|
2442
|
+
var PREFILTER_KEYS = /* @__PURE__ */ new Set([
|
|
2443
|
+
"traceId",
|
|
2444
|
+
"spanId",
|
|
2445
|
+
"parentSpanId",
|
|
2446
|
+
"name",
|
|
2447
|
+
"spanType",
|
|
2448
|
+
"source",
|
|
2449
|
+
"entityType",
|
|
2450
|
+
"entityId",
|
|
2451
|
+
"entityName",
|
|
2452
|
+
"entityVersionId",
|
|
2453
|
+
"experimentId",
|
|
2454
|
+
"userId",
|
|
2455
|
+
"organizationId",
|
|
2456
|
+
"resourceId",
|
|
2457
|
+
"runId",
|
|
2458
|
+
"sessionId",
|
|
2459
|
+
"threadId",
|
|
2460
|
+
"requestId",
|
|
2461
|
+
"environment",
|
|
2462
|
+
"serviceName"
|
|
2463
|
+
]);
|
|
2464
|
+
var SAFE_PREFILTER_ORDER_FIELDS = /* @__PURE__ */ new Set(["startedAt"]);
|
|
2465
|
+
function intersectTimestampRange(existing, incoming) {
|
|
2466
|
+
if (!existing) return { ...incoming };
|
|
2467
|
+
const merged = { ...existing };
|
|
2468
|
+
if (incoming.start !== void 0) {
|
|
2469
|
+
if (merged.start === void 0 || incoming.start.getTime() > merged.start.getTime()) {
|
|
2470
|
+
merged.start = incoming.start;
|
|
2471
|
+
merged.startExclusive = incoming.startExclusive;
|
|
2472
|
+
} else if (incoming.start.getTime() === merged.start.getTime()) {
|
|
2473
|
+
merged.startExclusive = (merged.startExclusive ?? false) || (incoming.startExclusive ?? false);
|
|
2474
|
+
}
|
|
2475
|
+
}
|
|
2476
|
+
if (incoming.end !== void 0) {
|
|
2477
|
+
if (merged.end === void 0 || incoming.end.getTime() < merged.end.getTime()) {
|
|
2478
|
+
merged.end = incoming.end;
|
|
2479
|
+
merged.endExclusive = incoming.endExclusive;
|
|
2480
|
+
} else if (incoming.end.getTime() === merged.end.getTime()) {
|
|
2481
|
+
merged.endExclusive = (merged.endExclusive ?? false) || (incoming.endExclusive ?? false);
|
|
2482
|
+
}
|
|
2483
|
+
}
|
|
2484
|
+
return merged;
|
|
2485
|
+
}
|
|
2486
|
+
function partitionAnchorFilters(filters) {
|
|
2487
|
+
const prefilter = {};
|
|
2488
|
+
const postAgg = {};
|
|
2489
|
+
let hasChildError;
|
|
2490
|
+
for (const [key, value] of Object.entries(filters)) {
|
|
2491
|
+
if (value === void 0 || value === null) continue;
|
|
2492
|
+
if (key === "hasChildError") {
|
|
2493
|
+
if (typeof value === "boolean") hasChildError = value;
|
|
2494
|
+
continue;
|
|
2495
|
+
}
|
|
2496
|
+
if (key === "startedAt") {
|
|
2497
|
+
prefilter.timestamp = intersectTimestampRange(
|
|
2498
|
+
prefilter.timestamp,
|
|
2499
|
+
value
|
|
2500
|
+
);
|
|
2501
|
+
continue;
|
|
2502
|
+
}
|
|
2503
|
+
if (key === "endedAt") {
|
|
2504
|
+
postAgg.endedAt = value;
|
|
2505
|
+
const dateRange = value;
|
|
2506
|
+
if (dateRange?.end) {
|
|
2507
|
+
prefilter.timestamp = intersectTimestampRange(prefilter.timestamp, {
|
|
2508
|
+
end: dateRange.end,
|
|
2509
|
+
endExclusive: dateRange.endExclusive
|
|
2510
|
+
});
|
|
2511
|
+
}
|
|
2512
|
+
continue;
|
|
2513
|
+
}
|
|
2514
|
+
if (PREFILTER_KEYS.has(key)) {
|
|
2515
|
+
prefilter[key] = value;
|
|
2516
|
+
continue;
|
|
2517
|
+
}
|
|
2518
|
+
postAgg[key] = value;
|
|
2519
|
+
}
|
|
2520
|
+
return { prefilter, postAgg, hasChildError };
|
|
2521
|
+
}
|
|
2421
2522
|
function toValuesTuple(row) {
|
|
2422
2523
|
return [
|
|
2423
2524
|
v(row.eventType),
|
|
@@ -2596,47 +2697,211 @@ async function listTraces(db, args) {
|
|
|
2596
2697
|
const page = Number(args.pagination?.page ?? 0);
|
|
2597
2698
|
const perPage = Number(args.pagination?.perPage ?? 10);
|
|
2598
2699
|
const orderBy = { field: args.orderBy?.field ?? "startedAt", direction: args.orderBy?.direction ?? "DESC" };
|
|
2599
|
-
const {
|
|
2600
|
-
const
|
|
2601
|
-
const
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
const
|
|
2605
|
-
const
|
|
2606
|
-
if (
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2700
|
+
const { prefilter, postAgg, hasChildError } = partitionAnchorFilters(filters);
|
|
2701
|
+
const { clause: prefilterClause, params: prefilterParams } = buildWhereClause(prefilter);
|
|
2702
|
+
const prefilterParts = [`eventType = 'start'`, `parentSpanId IS NULL`];
|
|
2703
|
+
if (prefilterClause) prefilterParts.push(prefilterClause.replace(/^WHERE\s+/i, ""));
|
|
2704
|
+
const prefilterWhere = `WHERE ${prefilterParts.join(" AND ")}`;
|
|
2705
|
+
const outerAlias = "outer_root";
|
|
2706
|
+
const orderDir = orderBy.direction.toUpperCase();
|
|
2707
|
+
if (orderDir !== "ASC" && orderDir !== "DESC") {
|
|
2708
|
+
throw new Error(`Invalid sort direction: ${orderBy.direction}`);
|
|
2709
|
+
}
|
|
2710
|
+
const canOrderInPrefilter = SAFE_PREFILTER_ORDER_FIELDS.has(orderBy.field);
|
|
2711
|
+
const hasPostAggFilters = Object.keys(postAgg).length > 0 || hasChildError !== void 0 || !canOrderInPrefilter;
|
|
2712
|
+
if (!hasPostAggFilters) {
|
|
2713
|
+
const prefilterOrderBy = `ORDER BY timestamp ${orderDir}`;
|
|
2714
|
+
const offset = page * perPage;
|
|
2715
|
+
const countSql2 = `
|
|
2716
|
+
SELECT COUNT(*) as total
|
|
2717
|
+
FROM span_events AS ${outerAlias}
|
|
2718
|
+
${prefilterWhere}
|
|
2719
|
+
`;
|
|
2720
|
+
const countResult2 = await db.query(countSql2, prefilterParams);
|
|
2721
|
+
const total2 = Number(countResult2[0]?.total ?? 0);
|
|
2722
|
+
const pageSql = `
|
|
2723
|
+
WITH page_roots AS (
|
|
2724
|
+
SELECT traceId, spanId
|
|
2725
|
+
FROM span_events AS ${outerAlias}
|
|
2726
|
+
${prefilterWhere}
|
|
2727
|
+
${prefilterOrderBy}
|
|
2728
|
+
LIMIT ? OFFSET ?
|
|
2729
|
+
)
|
|
2610
2730
|
${SPAN_RECONSTRUCT_SELECT}
|
|
2731
|
+
WHERE (traceId, spanId) IN (SELECT traceId, spanId FROM page_roots)
|
|
2611
2732
|
GROUP BY traceId, spanId
|
|
2733
|
+
${buildOrderByClause(orderBy)}
|
|
2734
|
+
`;
|
|
2735
|
+
const rows2 = await db.query(pageSql, [...prefilterParams, perPage, offset]);
|
|
2736
|
+
const spans2 = rows2.map((row) => rowToSpanRecord(row));
|
|
2737
|
+
return {
|
|
2738
|
+
pagination: { total: total2, page, perPage, hasMore: (page + 1) * perPage < total2 },
|
|
2739
|
+
spans: toTraceSpans(spans2)
|
|
2740
|
+
};
|
|
2741
|
+
}
|
|
2742
|
+
const { clause: postAggClause, params: postAggParams } = buildWhereClause(postAgg);
|
|
2743
|
+
const postAggParts = [];
|
|
2744
|
+
if (postAggClause) postAggParts.push(postAggClause.replace(/^WHERE\s+/i, ""));
|
|
2745
|
+
const childErrorClause = buildHasChildErrorClause(hasChildError, "root_spans");
|
|
2746
|
+
if (childErrorClause) postAggParts.push(childErrorClause);
|
|
2747
|
+
const postAggWhere = postAggParts.length > 0 ? `WHERE ${postAggParts.join(" AND ")}` : "";
|
|
2748
|
+
const cteSql = `
|
|
2749
|
+
WITH candidate_roots AS (
|
|
2750
|
+
SELECT traceId, spanId
|
|
2751
|
+
FROM span_events AS ${outerAlias}
|
|
2752
|
+
${prefilterWhere}
|
|
2612
2753
|
),
|
|
2613
2754
|
root_spans AS (
|
|
2614
|
-
|
|
2615
|
-
WHERE
|
|
2755
|
+
${SPAN_RECONSTRUCT_SELECT}
|
|
2756
|
+
WHERE (traceId, spanId) IN (SELECT traceId, spanId FROM candidate_roots)
|
|
2757
|
+
GROUP BY traceId, spanId
|
|
2616
2758
|
)
|
|
2617
2759
|
`;
|
|
2760
|
+
const orderByClause = buildOrderByClause(orderBy);
|
|
2761
|
+
const { clause: paginationClause, params: paginationParams } = buildPaginationClause({ page, perPage });
|
|
2618
2762
|
const countSql = `
|
|
2619
2763
|
${cteSql}
|
|
2620
|
-
SELECT COUNT(*) as total FROM root_spans ${
|
|
2764
|
+
SELECT COUNT(*) as total FROM root_spans ${postAggWhere}
|
|
2621
2765
|
`;
|
|
2622
|
-
const countResult = await db.query(countSql,
|
|
2766
|
+
const countResult = await db.query(countSql, [...prefilterParams, ...postAggParams]);
|
|
2623
2767
|
const total = Number(countResult[0]?.total ?? 0);
|
|
2624
2768
|
const dataSql = `
|
|
2625
2769
|
${cteSql}
|
|
2626
|
-
SELECT * FROM root_spans ${
|
|
2770
|
+
SELECT * FROM root_spans ${postAggWhere} ${orderByClause} ${paginationClause}
|
|
2627
2771
|
`;
|
|
2628
|
-
const rows = await db.query(dataSql, [...
|
|
2772
|
+
const rows = await db.query(dataSql, [...prefilterParams, ...postAggParams, ...paginationParams]);
|
|
2629
2773
|
const spans = rows.map((row) => rowToSpanRecord(row));
|
|
2630
2774
|
return {
|
|
2631
|
-
pagination: {
|
|
2632
|
-
total,
|
|
2633
|
-
page,
|
|
2634
|
-
perPage,
|
|
2635
|
-
hasMore: (page + 1) * perPage < total
|
|
2636
|
-
},
|
|
2775
|
+
pagination: { total, page, perPage, hasMore: (page + 1) * perPage < total },
|
|
2637
2776
|
spans: toTraceSpans(spans)
|
|
2638
2777
|
};
|
|
2639
2778
|
}
|
|
2779
|
+
var BRANCH_SPAN_TYPE_PLACEHOLDERS = BRANCH_SPAN_TYPES.map(() => "?").join(", ");
|
|
2780
|
+
async function getSpans(db, args) {
|
|
2781
|
+
if (args.spanIds.length === 0) {
|
|
2782
|
+
return { traceId: args.traceId, spans: [] };
|
|
2783
|
+
}
|
|
2784
|
+
const placeholders = args.spanIds.map(() => "?").join(", ");
|
|
2785
|
+
const rows = await db.query(
|
|
2786
|
+
`${SPAN_RECONSTRUCT_SELECT}
|
|
2787
|
+
WHERE traceId = ? AND spanId IN (${placeholders})
|
|
2788
|
+
GROUP BY traceId, spanId`,
|
|
2789
|
+
[args.traceId, ...args.spanIds]
|
|
2790
|
+
);
|
|
2791
|
+
return {
|
|
2792
|
+
traceId: args.traceId,
|
|
2793
|
+
spans: rows.map((row) => rowToSpanRecord(row))
|
|
2794
|
+
};
|
|
2795
|
+
}
|
|
2796
|
+
async function listBranches(db, args) {
|
|
2797
|
+
const filters = args.filters ?? {};
|
|
2798
|
+
const page = Number(args.pagination?.page ?? 0);
|
|
2799
|
+
const perPage = Number(args.pagination?.perPage ?? 10);
|
|
2800
|
+
const orderBy = { field: args.orderBy?.field ?? "startedAt", direction: args.orderBy?.direction ?? "DESC" };
|
|
2801
|
+
const userSpanType = filters.spanType;
|
|
2802
|
+
if (typeof userSpanType === "string" && !BRANCH_SPAN_TYPES.includes(userSpanType)) {
|
|
2803
|
+
return {
|
|
2804
|
+
pagination: { total: 0, page, perPage, hasMore: false },
|
|
2805
|
+
branches: []
|
|
2806
|
+
};
|
|
2807
|
+
}
|
|
2808
|
+
const { spanType: _spanType, ...rest } = filters;
|
|
2809
|
+
const { prefilter, postAgg} = partitionAnchorFilters(rest);
|
|
2810
|
+
const { clause: prefilterClause, params: prefilterFilterParams } = buildWhereClause(prefilter);
|
|
2811
|
+
const prefilterParts = [`eventType = 'start'`];
|
|
2812
|
+
let spanTypeParams;
|
|
2813
|
+
if (typeof userSpanType === "string") {
|
|
2814
|
+
prefilterParts.push(`spanType = ?`);
|
|
2815
|
+
spanTypeParams = [userSpanType];
|
|
2816
|
+
} else {
|
|
2817
|
+
prefilterParts.push(`spanType IN (${BRANCH_SPAN_TYPE_PLACEHOLDERS})`);
|
|
2818
|
+
spanTypeParams = [...BRANCH_SPAN_TYPES];
|
|
2819
|
+
}
|
|
2820
|
+
if (prefilterClause) prefilterParts.push(prefilterClause.replace(/^WHERE\s+/i, ""));
|
|
2821
|
+
const prefilterWhere = `WHERE ${prefilterParts.join(" AND ")}`;
|
|
2822
|
+
const prefilterParams = [...spanTypeParams, ...prefilterFilterParams];
|
|
2823
|
+
const outerAlias = "outer_anchor";
|
|
2824
|
+
const orderDir = orderBy.direction.toUpperCase();
|
|
2825
|
+
if (orderDir !== "ASC" && orderDir !== "DESC") {
|
|
2826
|
+
throw new Error(`Invalid sort direction: ${orderBy.direction}`);
|
|
2827
|
+
}
|
|
2828
|
+
const canOrderInPrefilter = SAFE_PREFILTER_ORDER_FIELDS.has(orderBy.field);
|
|
2829
|
+
const hasPostAggFilters = Object.keys(postAgg).length > 0 || !canOrderInPrefilter;
|
|
2830
|
+
if (!hasPostAggFilters) {
|
|
2831
|
+
const prefilterOrderBy = `ORDER BY timestamp ${orderDir}`;
|
|
2832
|
+
const offset = page * perPage;
|
|
2833
|
+
const countSql2 = `
|
|
2834
|
+
SELECT COUNT(*) as total
|
|
2835
|
+
FROM span_events AS ${outerAlias}
|
|
2836
|
+
${prefilterWhere}
|
|
2837
|
+
`;
|
|
2838
|
+
const countResult2 = await db.query(countSql2, prefilterParams);
|
|
2839
|
+
const total2 = Number(countResult2[0]?.total ?? 0);
|
|
2840
|
+
if (total2 === 0) {
|
|
2841
|
+
return {
|
|
2842
|
+
pagination: { total: 0, page, perPage, hasMore: false },
|
|
2843
|
+
branches: []
|
|
2844
|
+
};
|
|
2845
|
+
}
|
|
2846
|
+
const pageSql = `
|
|
2847
|
+
WITH page_anchors AS (
|
|
2848
|
+
SELECT traceId, spanId
|
|
2849
|
+
FROM span_events AS ${outerAlias}
|
|
2850
|
+
${prefilterWhere}
|
|
2851
|
+
${prefilterOrderBy}
|
|
2852
|
+
LIMIT ? OFFSET ?
|
|
2853
|
+
)
|
|
2854
|
+
${SPAN_RECONSTRUCT_SELECT}
|
|
2855
|
+
WHERE (traceId, spanId) IN (SELECT traceId, spanId FROM page_anchors)
|
|
2856
|
+
GROUP BY traceId, spanId
|
|
2857
|
+
${buildOrderByClause(orderBy)}
|
|
2858
|
+
`;
|
|
2859
|
+
const rows2 = await db.query(pageSql, [...prefilterParams, perPage, offset]);
|
|
2860
|
+
const spans2 = rows2.map((row) => rowToSpanRecord(row));
|
|
2861
|
+
return {
|
|
2862
|
+
pagination: { total: total2, page, perPage, hasMore: (page + 1) * perPage < total2 },
|
|
2863
|
+
branches: toTraceSpans(spans2)
|
|
2864
|
+
};
|
|
2865
|
+
}
|
|
2866
|
+
const { clause: postAggClause, params: postAggParams } = buildWhereClause(postAgg);
|
|
2867
|
+
const postAggWhere = postAggClause ? postAggClause : "";
|
|
2868
|
+
const orderByClause = buildOrderByClause(orderBy);
|
|
2869
|
+
const { clause: paginationClause, params: paginationParams } = buildPaginationClause({ page, perPage });
|
|
2870
|
+
const cteSql = `
|
|
2871
|
+
WITH candidate_anchors AS (
|
|
2872
|
+
SELECT traceId, spanId
|
|
2873
|
+
FROM span_events AS ${outerAlias}
|
|
2874
|
+
${prefilterWhere}
|
|
2875
|
+
),
|
|
2876
|
+
branch_anchors AS (
|
|
2877
|
+
${SPAN_RECONSTRUCT_SELECT}
|
|
2878
|
+
WHERE (traceId, spanId) IN (SELECT traceId, spanId FROM candidate_anchors)
|
|
2879
|
+
GROUP BY traceId, spanId
|
|
2880
|
+
)
|
|
2881
|
+
`;
|
|
2882
|
+
const countSql = `
|
|
2883
|
+
${cteSql}
|
|
2884
|
+
SELECT COUNT(*) as total FROM branch_anchors ${postAggWhere}
|
|
2885
|
+
`;
|
|
2886
|
+
const countResult = await db.query(countSql, [...prefilterParams, ...postAggParams]);
|
|
2887
|
+
const total = Number(countResult[0]?.total ?? 0);
|
|
2888
|
+
if (total === 0) {
|
|
2889
|
+
return {
|
|
2890
|
+
pagination: { total: 0, page, perPage, hasMore: false },
|
|
2891
|
+
branches: []
|
|
2892
|
+
};
|
|
2893
|
+
}
|
|
2894
|
+
const dataSql = `
|
|
2895
|
+
${cteSql}
|
|
2896
|
+
SELECT * FROM branch_anchors ${postAggWhere} ${orderByClause} ${paginationClause}
|
|
2897
|
+
`;
|
|
2898
|
+
const rows = await db.query(dataSql, [...prefilterParams, ...postAggParams, ...paginationParams]);
|
|
2899
|
+
const spans = rows.map((row) => rowToSpanRecord(row));
|
|
2900
|
+
return {
|
|
2901
|
+
pagination: { total, page, perPage, hasMore: (page + 1) * perPage < total },
|
|
2902
|
+
branches: toTraceSpans(spans)
|
|
2903
|
+
};
|
|
2904
|
+
}
|
|
2640
2905
|
|
|
2641
2906
|
// src/storage/domains/observability/index.ts
|
|
2642
2907
|
function buildSignalMigrationRequiredMessage(args) {
|
|
@@ -2739,6 +3004,9 @@ var ObservabilityStorageDuckDB = class extends ObservabilityStorage {
|
|
|
2739
3004
|
async getSpan(args) {
|
|
2740
3005
|
return getSpan(this.db, args);
|
|
2741
3006
|
}
|
|
3007
|
+
async getSpans(args) {
|
|
3008
|
+
return getSpans(this.db, args);
|
|
3009
|
+
}
|
|
2742
3010
|
async getRootSpan(args) {
|
|
2743
3011
|
return getRootSpan(this.db, args);
|
|
2744
3012
|
}
|
|
@@ -2751,6 +3019,9 @@ var ObservabilityStorageDuckDB = class extends ObservabilityStorage {
|
|
|
2751
3019
|
async listTraces(args) {
|
|
2752
3020
|
return listTraces(this.db, args);
|
|
2753
3021
|
}
|
|
3022
|
+
async listBranches(args) {
|
|
3023
|
+
return listBranches(this.db, args);
|
|
3024
|
+
}
|
|
2754
3025
|
// Logs
|
|
2755
3026
|
async batchCreateLogs(args) {
|
|
2756
3027
|
return batchCreateLogs(this.db, args);
|
|
@@ -2813,6 +3084,9 @@ var ObservabilityStorageDuckDB = class extends ObservabilityStorage {
|
|
|
2813
3084
|
async listScores(args) {
|
|
2814
3085
|
return listScores(this.db, args);
|
|
2815
3086
|
}
|
|
3087
|
+
async getScoreById(scoreId) {
|
|
3088
|
+
return getScoreById(this.db, scoreId);
|
|
3089
|
+
}
|
|
2816
3090
|
async getScoreAggregate(args) {
|
|
2817
3091
|
return getScoreAggregate(this.db, args);
|
|
2818
3092
|
}
|
|
@@ -2850,5 +3124,5 @@ var ObservabilityStorageDuckDB = class extends ObservabilityStorage {
|
|
|
2850
3124
|
};
|
|
2851
3125
|
|
|
2852
3126
|
export { ObservabilityStorageDuckDB };
|
|
2853
|
-
//# sourceMappingURL=observability-
|
|
2854
|
-
//# sourceMappingURL=observability-
|
|
3127
|
+
//# sourceMappingURL=observability-7LL4LLXY.js.map
|
|
3128
|
+
//# sourceMappingURL=observability-7LL4LLXY.js.map
|