drizzle-cube 0.3.32 → 0.4.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.
- package/dist/adapters/express/index.cjs +1 -1
- package/dist/adapters/express/index.js +1 -1
- package/dist/adapters/fastify/index.cjs +1 -1
- package/dist/adapters/fastify/index.js +1 -1
- package/dist/adapters/hono/index.cjs +1 -1
- package/dist/adapters/hono/index.js +1 -1
- package/dist/adapters/{mcp-transport-B2rGcu1X.js → mcp-transport-Bbz3qrIy.js} +4324 -3230
- package/dist/adapters/mcp-transport-CXF4E5QJ.cjs +257 -0
- package/dist/adapters/nextjs/index.cjs +1 -1
- package/dist/adapters/nextjs/index.js +1 -1
- package/dist/adapters/utils.cjs +8 -8
- package/dist/adapters/utils.d.ts +2 -137
- package/dist/adapters/utils.js +1347 -1356
- package/dist/client/chunks/{DashboardEditModal-rLcmZpe_.js → DashboardEditModal-Bv7e3Q7O.js} +2 -2
- package/dist/client/chunks/{DashboardEditModal-rLcmZpe_.js.map → DashboardEditModal-Bv7e3Q7O.js.map} +1 -1
- package/dist/client/chunks/{analysis-builder-DCt5C58c.js → analysis-builder-BfH-w92z.js} +2962 -3019
- package/dist/client/chunks/analysis-builder-BfH-w92z.js.map +1 -0
- package/dist/client/chunks/{analysis-builder-shared-ysrRYGiU.js → analysis-builder-shared-DsbdRCzz.js} +361 -361
- package/dist/client/chunks/{analysis-builder-shared-ysrRYGiU.js.map → analysis-builder-shared-DsbdRCzz.js.map} +1 -1
- package/dist/client/chunks/useDirtyStateTracking-CTS_m9mg.js.map +1 -1
- package/dist/client/components/AnalysisBuilder/AnalysisResultsPanel.d.ts +2 -1
- package/dist/client/components/AnalysisBuilder/types.d.ts +18 -6
- package/dist/client/components.js +1 -1
- package/dist/client/hooks/queries/useDryRunQuery.d.ts +14 -48
- package/dist/client/hooks/useAnalysisBuilderHook.d.ts +6 -33
- package/dist/client/hooks/useAnalysisQueryExecution.d.ts +7 -7
- package/dist/client/hooks.js +194 -22
- package/dist/client/hooks.js.map +1 -1
- package/dist/client/index.js +3 -3
- package/dist/client/shared/types.d.ts +27 -0
- package/dist/client/styles.css +1 -1
- package/dist/client-bundle-stats.html +1 -1
- package/dist/server/index.cjs +49 -49
- package/dist/server/index.d.ts +1727 -547
- package/dist/server/index.js +4836 -3715
- package/package.json +1 -1
- package/dist/adapters/mcp-transport-DeD7YevT.cjs +0 -257
- package/dist/client/chunks/analysis-builder-DCt5C58c.js.map +0 -1
- package/dist/client/chunks/hooks-CdyIO1-j.js +0 -236
- package/dist/client/chunks/hooks-CdyIO1-j.js.map +0 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
1
2
|
import { AnalysisResultsPanelProps } from './types';
|
|
2
3
|
/**
|
|
3
4
|
* AnalysisResultsPanel displays query results with chart/table toggle.
|
|
@@ -9,5 +10,5 @@ import { AnalysisResultsPanelProps } from './types';
|
|
|
9
10
|
* - Stale results indicator
|
|
10
11
|
* - Display limit control for tables
|
|
11
12
|
*/
|
|
12
|
-
declare const AnalysisResultsPanel:
|
|
13
|
+
declare const AnalysisResultsPanel: React.NamedExoticComponent<AnalysisResultsPanelProps>;
|
|
13
14
|
export default AnalysisResultsPanel;
|
|
@@ -446,7 +446,7 @@ export interface AnalysisResultsPanelProps {
|
|
|
446
446
|
funnelServerQuery?: unknown;
|
|
447
447
|
/**
|
|
448
448
|
* Unified debug data for funnel queries (SQL, analysis, loading/error state).
|
|
449
|
-
*
|
|
449
|
+
* Uses common dry-run fields across all analysis modes.
|
|
450
450
|
*/
|
|
451
451
|
funnelDebugData?: {
|
|
452
452
|
sql: {
|
|
@@ -454,9 +454,13 @@ export interface AnalysisResultsPanelProps {
|
|
|
454
454
|
params: unknown[];
|
|
455
455
|
} | null;
|
|
456
456
|
analysis: unknown;
|
|
457
|
+
mode?: 'regular' | 'comparison' | 'funnel' | 'flow' | 'retention' | null;
|
|
458
|
+
queryType?: string | null;
|
|
459
|
+
joinType?: string | null;
|
|
460
|
+
cubesUsed?: string[];
|
|
461
|
+
modeMetadata?: unknown;
|
|
457
462
|
loading: boolean;
|
|
458
463
|
error: Error | null;
|
|
459
|
-
funnelMetadata?: unknown;
|
|
460
464
|
} | null;
|
|
461
465
|
/**
|
|
462
466
|
* The actual server flow query { flow: {...} } sent to the server.
|
|
@@ -465,7 +469,7 @@ export interface AnalysisResultsPanelProps {
|
|
|
465
469
|
flowServerQuery?: unknown;
|
|
466
470
|
/**
|
|
467
471
|
* Unified debug data for flow queries (SQL, analysis, loading/error state).
|
|
468
|
-
*
|
|
472
|
+
* Uses common dry-run fields across all analysis modes.
|
|
469
473
|
*/
|
|
470
474
|
flowDebugData?: {
|
|
471
475
|
sql: {
|
|
@@ -473,9 +477,13 @@ export interface AnalysisResultsPanelProps {
|
|
|
473
477
|
params: unknown[];
|
|
474
478
|
} | null;
|
|
475
479
|
analysis: unknown;
|
|
480
|
+
mode?: 'regular' | 'comparison' | 'funnel' | 'flow' | 'retention' | null;
|
|
481
|
+
queryType?: string | null;
|
|
482
|
+
joinType?: string | null;
|
|
483
|
+
cubesUsed?: string[];
|
|
484
|
+
modeMetadata?: unknown;
|
|
476
485
|
loading: boolean;
|
|
477
486
|
error: Error | null;
|
|
478
|
-
flowMetadata?: unknown;
|
|
479
487
|
} | null;
|
|
480
488
|
/**
|
|
481
489
|
* In retention mode, the actual server query { retention: {...} } sent to the API.
|
|
@@ -484,7 +492,7 @@ export interface AnalysisResultsPanelProps {
|
|
|
484
492
|
retentionServerQuery?: unknown;
|
|
485
493
|
/**
|
|
486
494
|
* Unified debug data for retention queries (SQL, analysis, loading/error state).
|
|
487
|
-
*
|
|
495
|
+
* Uses common dry-run fields across all analysis modes.
|
|
488
496
|
*/
|
|
489
497
|
retentionDebugData?: {
|
|
490
498
|
sql: {
|
|
@@ -492,9 +500,13 @@ export interface AnalysisResultsPanelProps {
|
|
|
492
500
|
params: unknown[];
|
|
493
501
|
} | null;
|
|
494
502
|
analysis: unknown;
|
|
503
|
+
mode?: 'regular' | 'comparison' | 'funnel' | 'flow' | 'retention' | null;
|
|
504
|
+
queryType?: string | null;
|
|
505
|
+
joinType?: string | null;
|
|
506
|
+
cubesUsed?: string[];
|
|
507
|
+
modeMetadata?: unknown;
|
|
495
508
|
loading: boolean;
|
|
496
509
|
error: Error | null;
|
|
497
|
-
retentionMetadata?: unknown;
|
|
498
510
|
} | null;
|
|
499
511
|
/**
|
|
500
512
|
* Retention chart data (cohort × period matrix) for rendering.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as V, A, e as T, D as P, M as G, P as H } from "./chunks/DashboardEditModal-
|
|
1
|
+
import { a as V, A, e as T, D as P, M as G, P as H } from "./chunks/DashboardEditModal-Bv7e3Q7O.js";
|
|
2
2
|
import { jsx as c, jsxs as a } from "react/jsx-runtime";
|
|
3
3
|
import { useState as b, useEffect as o, useCallback as i } from "react";
|
|
4
4
|
import { S as y, A as N } from "./chunks/charts-core-DAF1iT_h.js";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { CubeQuery } from '../../types';
|
|
2
2
|
import { QueryAnalysis } from '../../components/AnalysisBuilder/types';
|
|
3
|
+
export type DryRunMode = 'regular' | 'comparison' | 'funnel' | 'flow' | 'retention';
|
|
3
4
|
/**
|
|
4
5
|
* Debug data entry for a single query
|
|
5
6
|
*/
|
|
@@ -11,6 +12,16 @@ export interface DebugDataEntry {
|
|
|
11
12
|
} | null;
|
|
12
13
|
/** Query analysis (dimensions, measures, complexity, etc.) */
|
|
13
14
|
analysis: QueryAnalysis | null;
|
|
15
|
+
/** Server-reported dry-run mode */
|
|
16
|
+
mode?: DryRunMode | null;
|
|
17
|
+
/** Query type label from server */
|
|
18
|
+
queryType?: string | null;
|
|
19
|
+
/** Join strategy label from server */
|
|
20
|
+
joinType?: string | null;
|
|
21
|
+
/** Referenced cubes from server */
|
|
22
|
+
cubesUsed?: string[];
|
|
23
|
+
/** Mode-specific metadata (replaces funnel/flow/retention split) */
|
|
24
|
+
modeMetadata?: unknown;
|
|
14
25
|
/** Whether this entry is loading */
|
|
15
26
|
loading: boolean;
|
|
16
27
|
/** Error if fetch failed */
|
|
@@ -101,23 +112,7 @@ export declare function useDryRunQueries(options: {
|
|
|
101
112
|
skip?: boolean;
|
|
102
113
|
staleTime?: number;
|
|
103
114
|
}): UseMultiDryRunQueriesResult;
|
|
104
|
-
|
|
105
|
-
* Debug data entry for funnel queries
|
|
106
|
-
*/
|
|
107
|
-
export interface FunnelDebugDataEntry extends DebugDataEntry {
|
|
108
|
-
/** Funnel-specific metadata from server */
|
|
109
|
-
funnelMetadata?: {
|
|
110
|
-
stepCount: number;
|
|
111
|
-
steps: Array<{
|
|
112
|
-
index: number;
|
|
113
|
-
name: string;
|
|
114
|
-
timeToConvert?: string;
|
|
115
|
-
cube?: string;
|
|
116
|
-
}>;
|
|
117
|
-
bindingKey: unknown;
|
|
118
|
-
timeDimension: unknown;
|
|
119
|
-
};
|
|
120
|
-
}
|
|
115
|
+
export type FunnelDebugDataEntry = DebugDataEntry;
|
|
121
116
|
/**
|
|
122
117
|
* TanStack Query hook for funnel query dry-run (debug) data
|
|
123
118
|
*
|
|
@@ -130,23 +125,7 @@ export declare function useFunnelDryRunQuery(serverQuery: unknown | null, option
|
|
|
130
125
|
debugData: FunnelDebugDataEntry;
|
|
131
126
|
refetch: () => void;
|
|
132
127
|
};
|
|
133
|
-
|
|
134
|
-
* Debug data entry for flow queries
|
|
135
|
-
*/
|
|
136
|
-
export interface FlowDebugDataEntry extends DebugDataEntry {
|
|
137
|
-
/** Flow-specific metadata from server */
|
|
138
|
-
flowMetadata?: {
|
|
139
|
-
stepsBefore: number;
|
|
140
|
-
stepsAfter: number;
|
|
141
|
-
bindingKey: unknown;
|
|
142
|
-
timeDimension: unknown;
|
|
143
|
-
eventDimension: string;
|
|
144
|
-
startingStep: {
|
|
145
|
-
name: string;
|
|
146
|
-
filter: unknown;
|
|
147
|
-
};
|
|
148
|
-
};
|
|
149
|
-
}
|
|
128
|
+
export type FlowDebugDataEntry = DebugDataEntry;
|
|
150
129
|
/**
|
|
151
130
|
* TanStack Query hook for flow query dry-run (debug) data
|
|
152
131
|
*
|
|
@@ -159,20 +138,7 @@ export declare function useFlowDryRunQuery(serverQuery: unknown | null, options?
|
|
|
159
138
|
debugData: FlowDebugDataEntry;
|
|
160
139
|
refetch: () => void;
|
|
161
140
|
};
|
|
162
|
-
|
|
163
|
-
* Debug data entry for retention queries
|
|
164
|
-
*/
|
|
165
|
-
export interface RetentionDebugDataEntry extends DebugDataEntry {
|
|
166
|
-
/** Retention-specific metadata from server */
|
|
167
|
-
retentionMetadata?: {
|
|
168
|
-
totalCohorts: number;
|
|
169
|
-
totalUsers: number;
|
|
170
|
-
periods: number;
|
|
171
|
-
cohortGranularity: string;
|
|
172
|
-
periodGranularity: string;
|
|
173
|
-
retentionType: string;
|
|
174
|
-
};
|
|
175
|
-
}
|
|
141
|
+
export type RetentionDebugDataEntry = DebugDataEntry;
|
|
176
142
|
/**
|
|
177
143
|
* TanStack Query hook for retention query dry-run (debug) data
|
|
178
144
|
*
|
|
@@ -112,43 +112,16 @@ export interface UseAnalysisBuilderResult {
|
|
|
112
112
|
funnelExecutedQueries: CubeQuery[] | null;
|
|
113
113
|
/** In funnel mode, the actual server query { funnel: {...} } sent to the API */
|
|
114
114
|
funnelServerQuery: unknown | null;
|
|
115
|
-
/** In funnel mode, unified debug data (SQL, analysis,
|
|
116
|
-
funnelDebugData:
|
|
117
|
-
sql: {
|
|
118
|
-
sql: string;
|
|
119
|
-
params: unknown[];
|
|
120
|
-
} | null;
|
|
121
|
-
analysis: unknown | null;
|
|
122
|
-
loading: boolean;
|
|
123
|
-
error: Error | null;
|
|
124
|
-
funnelMetadata?: unknown;
|
|
125
|
-
} | null;
|
|
115
|
+
/** In funnel mode, unified debug data (SQL, analysis, mode metadata) */
|
|
116
|
+
funnelDebugData: DebugDataEntry | null;
|
|
126
117
|
/** In flow mode, the actual server query { flow: {...} } sent to the API */
|
|
127
118
|
flowServerQuery: unknown | null;
|
|
128
|
-
/** In flow mode, unified debug data (SQL, analysis,
|
|
129
|
-
flowDebugData:
|
|
130
|
-
sql: {
|
|
131
|
-
sql: string;
|
|
132
|
-
params: unknown[];
|
|
133
|
-
} | null;
|
|
134
|
-
analysis: unknown | null;
|
|
135
|
-
loading: boolean;
|
|
136
|
-
error: Error | null;
|
|
137
|
-
flowMetadata?: unknown;
|
|
138
|
-
} | null;
|
|
119
|
+
/** In flow mode, unified debug data (SQL, analysis, mode metadata) */
|
|
120
|
+
flowDebugData: DebugDataEntry | null;
|
|
139
121
|
/** In retention mode, the actual server query { retention: {...} } sent to the API */
|
|
140
122
|
retentionServerQuery: unknown | null;
|
|
141
|
-
/** In retention mode, unified debug data (SQL, analysis,
|
|
142
|
-
retentionDebugData:
|
|
143
|
-
sql: {
|
|
144
|
-
sql: string;
|
|
145
|
-
params: unknown[];
|
|
146
|
-
} | null;
|
|
147
|
-
analysis: unknown | null;
|
|
148
|
-
loading: boolean;
|
|
149
|
-
error: Error | null;
|
|
150
|
-
retentionMetadata?: unknown;
|
|
151
|
-
} | null;
|
|
123
|
+
/** In retention mode, unified debug data (SQL, analysis, mode metadata) */
|
|
124
|
+
retentionDebugData: DebugDataEntry | null;
|
|
152
125
|
/** In retention mode, the chart data (cohort × period matrix) */
|
|
153
126
|
retentionChartData: import('../types/retention').RetentionChartData | null;
|
|
154
127
|
/** In retention mode, validation result (errors explaining why query cannot be built) */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DebugDataEntry
|
|
1
|
+
import { DebugDataEntry } from './queries';
|
|
2
2
|
import { CubeQuery, MultiQueryConfig, FunnelBindingKey, QueryMergeStrategy, AnalysisType } from '../types';
|
|
3
3
|
import { ExecutionStatus } from '../components/AnalysisBuilder/types';
|
|
4
4
|
import { ServerFunnelQuery } from '../types/funnel';
|
|
@@ -93,9 +93,9 @@ export interface UseAnalysisQueryExecutionResult {
|
|
|
93
93
|
funnelServerQuery: ServerFunnelQuery | null;
|
|
94
94
|
/**
|
|
95
95
|
* Debug data specifically for funnel mode
|
|
96
|
-
* Contains
|
|
96
|
+
* Contains unified dry-run SQL and mode metadata.
|
|
97
97
|
*/
|
|
98
|
-
funnelDebugData:
|
|
98
|
+
funnelDebugData: DebugDataEntry | null;
|
|
99
99
|
/**
|
|
100
100
|
* The server flow query being executed (when analysisType === 'flow')
|
|
101
101
|
*/
|
|
@@ -106,9 +106,9 @@ export interface UseAnalysisQueryExecutionResult {
|
|
|
106
106
|
flowChartData: FlowChartData | null;
|
|
107
107
|
/**
|
|
108
108
|
* Debug data specifically for flow mode
|
|
109
|
-
* Contains
|
|
109
|
+
* Contains unified dry-run SQL and mode metadata.
|
|
110
110
|
*/
|
|
111
|
-
flowDebugData:
|
|
111
|
+
flowDebugData: DebugDataEntry | null;
|
|
112
112
|
/**
|
|
113
113
|
* The server retention query being executed (when analysisType === 'retention')
|
|
114
114
|
*/
|
|
@@ -119,9 +119,9 @@ export interface UseAnalysisQueryExecutionResult {
|
|
|
119
119
|
retentionChartData: RetentionChartData | null;
|
|
120
120
|
/**
|
|
121
121
|
* Debug data specifically for retention mode
|
|
122
|
-
* Contains
|
|
122
|
+
* Contains unified dry-run SQL and mode metadata.
|
|
123
123
|
*/
|
|
124
|
-
retentionDebugData:
|
|
124
|
+
retentionDebugData: DebugDataEntry | null;
|
|
125
125
|
/**
|
|
126
126
|
* Retention validation result (errors explaining why query cannot be built)
|
|
127
127
|
*/
|
package/dist/client/hooks.js
CHANGED
|
@@ -1,25 +1,197 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { t as p, B as h } from "./chunks/useDirtyStateTracking-CTS_m9mg.js";
|
|
2
|
+
import { e as Y, c as $, u as B, u as H, p as J, A as V, r as W, d as X, b as G, a as Z, z as ee, o as ne } from "./chunks/useDirtyStateTracking-CTS_m9mg.js";
|
|
3
|
+
import { f as m, g as E } from "./chunks/providers-D2xswCYu.js";
|
|
4
|
+
import { j as te } from "./chunks/providers-D2xswCYu.js";
|
|
5
|
+
import { a as w, i as F, u as A, j as q } from "./chunks/vendor-DfDLOfBe.js";
|
|
6
|
+
import { useMemo as b, useState as g, useCallback as d } from "react";
|
|
7
|
+
function R(e) {
|
|
8
|
+
return e ? ["cube", "dryRun", h(e)] : ["cube", "dryRun", null];
|
|
9
|
+
}
|
|
10
|
+
function M(e) {
|
|
11
|
+
return e.mode ? e.mode : e.queryType === "comparisonQuery" ? "comparison" : e.queryType === "funnelQuery" ? "funnel" : e.queryType === "flowQuery" ? "flow" : e.queryType === "retentionQuery" ? "retention" : e.queryType === "regularQuery" ? "regular" : null;
|
|
12
|
+
}
|
|
13
|
+
function x(e) {
|
|
14
|
+
const s = M(e);
|
|
15
|
+
return {
|
|
16
|
+
sql: e.sql ? { sql: e.sql.sql, params: e.sql.params || [] } : null,
|
|
17
|
+
analysis: e.analysis || null,
|
|
18
|
+
mode: s,
|
|
19
|
+
queryType: e.queryType || null,
|
|
20
|
+
joinType: e.joinType || null,
|
|
21
|
+
cubesUsed: e.cubesUsed || [],
|
|
22
|
+
modeMetadata: e.modeMetadata
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
function z(e, s = {}) {
|
|
26
|
+
const { skip: i = !1, staleTime: a = 300 * 1e3 } = s, { cubeApi: o } = m(), r = b(() => {
|
|
27
|
+
if (!e) return null;
|
|
28
|
+
const t = e;
|
|
29
|
+
return t.funnel || t.flow || t.retention ? e : p(e);
|
|
30
|
+
}, [e]), u = w({
|
|
31
|
+
queryKey: R(r),
|
|
32
|
+
queryFn: async () => {
|
|
33
|
+
if (!r) throw new Error("No query provided");
|
|
34
|
+
const t = await o.dryRun(r);
|
|
35
|
+
return x(t);
|
|
36
|
+
},
|
|
37
|
+
enabled: !!r && !i,
|
|
38
|
+
staleTime: a
|
|
39
|
+
});
|
|
40
|
+
return {
|
|
41
|
+
debugData: {
|
|
42
|
+
...u.data || {
|
|
43
|
+
sql: null,
|
|
44
|
+
analysis: null,
|
|
45
|
+
mode: null,
|
|
46
|
+
queryType: null,
|
|
47
|
+
joinType: null,
|
|
48
|
+
cubesUsed: [],
|
|
49
|
+
modeMetadata: void 0
|
|
50
|
+
},
|
|
51
|
+
loading: u.isLoading,
|
|
52
|
+
error: u.error ?? null
|
|
53
|
+
},
|
|
54
|
+
refetch: () => u.refetch()
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function j(e, s = {}) {
|
|
58
|
+
const { skip: i = !1, staleTime: a = 300 * 1e3 } = s, { cubeApi: o } = m(), r = b(() => e.map((n) => p(n)), [e]), u = F({
|
|
59
|
+
queries: r.map((n) => ({
|
|
60
|
+
queryKey: R(n),
|
|
61
|
+
queryFn: async () => {
|
|
62
|
+
const f = await o.dryRun(n);
|
|
63
|
+
return x(f);
|
|
64
|
+
},
|
|
65
|
+
enabled: !i,
|
|
66
|
+
staleTime: a
|
|
67
|
+
}))
|
|
68
|
+
}), l = u.map((n) => ({
|
|
69
|
+
...n.data || {
|
|
70
|
+
sql: null,
|
|
71
|
+
analysis: null,
|
|
72
|
+
mode: null,
|
|
73
|
+
queryType: null,
|
|
74
|
+
joinType: null,
|
|
75
|
+
cubesUsed: [],
|
|
76
|
+
modeMetadata: void 0
|
|
77
|
+
},
|
|
78
|
+
loading: n.isLoading,
|
|
79
|
+
error: n.error ?? null
|
|
80
|
+
})), t = u.some((n) => n.isLoading);
|
|
81
|
+
return {
|
|
82
|
+
debugDataPerQuery: l,
|
|
83
|
+
isLoading: t,
|
|
84
|
+
refetchAll: () => {
|
|
85
|
+
u.forEach((n) => n.refetch());
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
function S(e) {
|
|
90
|
+
const { queries: s, isMultiQueryMode: i, skip: a = !1, staleTime: o } = e, r = i ? s : s.slice(0, 1);
|
|
91
|
+
return j(r, { skip: a, staleTime: o });
|
|
92
|
+
}
|
|
93
|
+
function v(e, s) {
|
|
94
|
+
return e ? ["cube", "explain", h(e), s?.analyze ?? !1] : ["cube", "explain", null, null];
|
|
95
|
+
}
|
|
96
|
+
function D(e) {
|
|
97
|
+
return typeof e == "object" && e !== null && "funnel" in e;
|
|
98
|
+
}
|
|
99
|
+
function C(e) {
|
|
100
|
+
return typeof e == "object" && e !== null && "flow" in e;
|
|
101
|
+
}
|
|
102
|
+
function K(e) {
|
|
103
|
+
return typeof e == "object" && e !== null && "retention" in e;
|
|
104
|
+
}
|
|
105
|
+
function P(e, s = {}) {
|
|
106
|
+
const { skip: i = !1 } = s, { cubeApi: a } = m(), [o, r] = g(null), [u, l] = g(!1), t = b(() => e ? D(e) || C(e) || K(e) ? e : p(e) : null, [e]), c = !!t && !i && u, n = w({
|
|
107
|
+
queryKey: v(t, o ?? void 0),
|
|
108
|
+
queryFn: async () => {
|
|
109
|
+
if (!t) throw new Error("No query provided");
|
|
110
|
+
return await a.explain(t, o ?? void 0);
|
|
111
|
+
},
|
|
112
|
+
enabled: c,
|
|
113
|
+
// EXPLAIN queries should never be cached - always fetch fresh data
|
|
114
|
+
// This ensures users see the latest execution plan after schema/index changes
|
|
115
|
+
staleTime: 0,
|
|
116
|
+
gcTime: 0,
|
|
117
|
+
// Don't refetch automatically - this is manually triggered
|
|
118
|
+
refetchOnWindowFocus: !1,
|
|
119
|
+
refetchOnReconnect: !1,
|
|
120
|
+
refetchOnMount: !1
|
|
121
|
+
}), f = d((Q) => {
|
|
122
|
+
i || !t || (r(Q ?? null), l(!0), u && n.refetch());
|
|
123
|
+
}, [i, t, u, n]), y = d(() => {
|
|
124
|
+
l(!1), r(null);
|
|
125
|
+
}, []);
|
|
126
|
+
return {
|
|
127
|
+
explainResult: n.data ?? null,
|
|
128
|
+
isLoading: n.isLoading || n.isFetching,
|
|
129
|
+
hasRun: u,
|
|
130
|
+
error: n.error ?? null,
|
|
131
|
+
runExplain: f,
|
|
132
|
+
clearExplain: y
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
const T = ["cube", "explain", "ai"];
|
|
136
|
+
function U(e = {}) {
|
|
137
|
+
const { features: s } = E(), i = s.enableAI ?? !0, a = A(), o = e.aiEndpoint ?? "/api/ai/explain/analyze", r = q({
|
|
138
|
+
mutationKey: T,
|
|
139
|
+
mutationFn: async ({ explainResult: t, query: c }) => {
|
|
140
|
+
if (!i)
|
|
141
|
+
throw new Error("AI features are disabled");
|
|
142
|
+
const n = await fetch(o, {
|
|
143
|
+
method: "POST",
|
|
144
|
+
headers: {
|
|
145
|
+
"Content-Type": "application/json"
|
|
146
|
+
},
|
|
147
|
+
credentials: "include",
|
|
148
|
+
body: JSON.stringify({
|
|
149
|
+
explainResult: t,
|
|
150
|
+
query: c
|
|
151
|
+
})
|
|
152
|
+
});
|
|
153
|
+
if (!n.ok) {
|
|
154
|
+
const y = await n.json().catch(() => ({}));
|
|
155
|
+
throw new Error(
|
|
156
|
+
y.error || y.message || `AI analysis failed: ${n.status} ${n.statusText}`
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
return await n.json();
|
|
160
|
+
},
|
|
161
|
+
// No caching - each mutation is independent
|
|
162
|
+
gcTime: 0
|
|
163
|
+
}), u = d((t, c) => {
|
|
164
|
+
r.mutate({ explainResult: t, query: c });
|
|
165
|
+
}, [r]), l = d(() => {
|
|
166
|
+
r.reset(), a.removeQueries({ queryKey: T });
|
|
167
|
+
}, [r, a]);
|
|
168
|
+
return {
|
|
169
|
+
analysis: r.data ?? null,
|
|
170
|
+
isAnalyzing: r.isPending,
|
|
171
|
+
error: r.error ?? null,
|
|
172
|
+
analyze: u,
|
|
173
|
+
clearAnalysis: l
|
|
174
|
+
};
|
|
175
|
+
}
|
|
4
176
|
export {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
177
|
+
v as createExplainQueryKey,
|
|
178
|
+
Y as createFlowQueryKey,
|
|
179
|
+
$ as createFunnelQueryKey,
|
|
180
|
+
B as useCubeLoadQuery,
|
|
181
|
+
te as useCubeMetaQuery,
|
|
182
|
+
H as useCubeQuery,
|
|
183
|
+
J as useDebounce,
|
|
184
|
+
V as useDirtyStateTracking,
|
|
185
|
+
S as useDryRunQueries,
|
|
186
|
+
z as useDryRunQuery,
|
|
187
|
+
U as useExplainAI,
|
|
188
|
+
P as useExplainQuery,
|
|
189
|
+
W as useFilterValues,
|
|
190
|
+
X as useFlowQuery,
|
|
191
|
+
G as useFunnelQuery,
|
|
192
|
+
Z as useMultiCubeLoadQuery,
|
|
193
|
+
j as useMultiDryRunQueries,
|
|
194
|
+
ee as useResponsiveDashboard,
|
|
195
|
+
ne as useRetentionQuery
|
|
24
196
|
};
|
|
25
197
|
//# sourceMappingURL=hooks.js.map
|
package/dist/client/hooks.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hooks.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;"}
|
|
1
|
+
{"version":3,"file":"hooks.js","sources":["../../src/client/hooks/queries/useDryRunQuery.ts","../../src/client/hooks/queries/useExplainQuery.ts","../../src/client/hooks/queries/useExplainAI.ts"],"sourcesContent":["/**\n * useDryRunQuery - TanStack Query hook for dry-run (debug) data\n *\n * Features:\n * - Fetch SQL and analysis data for query debugging\n * - Support for single and multi-query modes\n * - Built-in caching with TanStack Query\n * - Parallel fetching for multiple queries\n *\n * This hook replaces the debug data useEffect in AnalysisBuilder.\n */\n\nimport { useQuery, useQueries } from '@tanstack/react-query'\nimport { useMemo } from 'react'\nimport { useCubeApi } from '../../providers/CubeApiProvider'\nimport type { CubeQuery } from '../../types'\nimport type { QueryAnalysis } from '../../components/AnalysisBuilder/types'\nimport { cleanQueryForServer } from '../../shared/utils'\nimport { stableStringify } from '../../shared/queryKey'\n\nexport type DryRunMode = 'regular' | 'comparison' | 'funnel' | 'flow' | 'retention'\n\ninterface DryRunResponsePayload {\n sql?: { sql: string; params?: unknown[] }\n analysis?: QueryAnalysis | null\n mode?: DryRunMode\n queryType?: string\n joinType?: string\n cubesUsed?: string[]\n modeMetadata?: unknown\n}\n\n/**\n * Debug data entry for a single query\n */\nexport interface DebugDataEntry {\n /** Generated SQL and parameters */\n sql: { sql: string; params: unknown[] } | null\n /** Query analysis (dimensions, measures, complexity, etc.) */\n analysis: QueryAnalysis | null\n /** Server-reported dry-run mode */\n mode?: DryRunMode | null\n /** Query type label from server */\n queryType?: string | null\n /** Join strategy label from server */\n joinType?: string | null\n /** Referenced cubes from server */\n cubesUsed?: string[]\n /** Mode-specific metadata (replaces funnel/flow/retention split) */\n modeMetadata?: unknown\n /** Whether this entry is loading */\n loading: boolean\n /** Error if fetch failed */\n error: Error | null\n}\n\n/**\n * Create a stable query key for dry-run\n */\nexport function createDryRunQueryKey(\n query: CubeQuery | null\n): readonly unknown[] {\n if (!query) return ['cube', 'dryRun', null] as const\n return ['cube', 'dryRun', stableStringify(query)] as const\n}\n\nexport interface UseDryRunQueryOptions {\n /**\n * Whether to skip the query\n * @default false\n */\n skip?: boolean\n /**\n * Stale time in milliseconds\n * @default 5 * 60 * 1000 (5 minutes)\n */\n staleTime?: number\n}\n\nexport interface UseDryRunQueryResult {\n /** Debug data for the query */\n debugData: DebugDataEntry\n /** Manually refetch */\n refetch: () => void\n}\n\nfunction inferModeFromPayload(payload: DryRunResponsePayload): DryRunMode | null {\n if (payload.mode) return payload.mode\n if (payload.queryType === 'comparisonQuery') return 'comparison'\n if (payload.queryType === 'funnelQuery') return 'funnel'\n if (payload.queryType === 'flowQuery') return 'flow'\n if (payload.queryType === 'retentionQuery') return 'retention'\n if (payload.queryType === 'regularQuery') return 'regular'\n return null\n}\n\nfunction normalizeDryRunResult(payload: DryRunResponsePayload): Omit<DebugDataEntry, 'loading' | 'error'> {\n const mode = inferModeFromPayload(payload)\n return {\n sql: payload.sql ? { sql: payload.sql.sql, params: payload.sql.params || [] } : null,\n analysis: (payload.analysis || null) as QueryAnalysis | null,\n mode,\n queryType: payload.queryType || null,\n joinType: payload.joinType || null,\n cubesUsed: payload.cubesUsed || [],\n modeMetadata: payload.modeMetadata\n }\n}\n\n/**\n * TanStack Query hook for single query dry-run (debug) data\n *\n * Usage:\n * ```tsx\n * const { debugData } = useDryRunQuery(query, { skip: !isValidQuery })\n * ```\n */\nexport function useDryRunQuery(\n query: CubeQuery | null,\n options: UseDryRunQueryOptions = {}\n): UseDryRunQueryResult {\n const { skip = false, staleTime = 5 * 60 * 1000 } = options\n const { cubeApi } = useCubeApi()\n\n // Transform query for server\n const serverQuery = useMemo(() => {\n if (!query) return null\n const modeQuery = query as CubeQuery & { funnel?: unknown; flow?: unknown; retention?: unknown }\n // Preserve specialized mode payloads as-is; cleanQueryForServer strips non-Cube.js keys.\n if (modeQuery.funnel || modeQuery.flow || modeQuery.retention) {\n return query\n }\n return cleanQueryForServer(query)\n }, [query])\n\n const queryResult = useQuery({\n queryKey: createDryRunQueryKey(serverQuery),\n queryFn: async () => {\n if (!serverQuery) throw new Error('No query provided')\n const result = await cubeApi.dryRun(serverQuery)\n return normalizeDryRunResult(result as DryRunResponsePayload)\n },\n enabled: !!serverQuery && !skip,\n staleTime,\n })\n\n const debugData: DebugDataEntry = {\n ...(queryResult.data || {\n sql: null,\n analysis: null,\n mode: null,\n queryType: null,\n joinType: null,\n cubesUsed: [],\n modeMetadata: undefined\n }),\n loading: queryResult.isLoading,\n error: queryResult.error ?? null,\n }\n\n return {\n debugData,\n refetch: () => queryResult.refetch(),\n }\n}\n\nexport interface UseMultiDryRunQueriesOptions {\n /**\n * Whether to skip all queries\n * @default false\n */\n skip?: boolean\n /**\n * Stale time in milliseconds\n * @default 5 * 60 * 1000 (5 minutes)\n */\n staleTime?: number\n}\n\nexport interface UseMultiDryRunQueriesResult {\n /** Debug data for each query */\n debugDataPerQuery: DebugDataEntry[]\n /** Whether any query is loading */\n isLoading: boolean\n /** Manually refetch all */\n refetchAll: () => void\n}\n\n/**\n * TanStack Query hook for multiple query dry-runs (debug) data\n *\n * Fetches debug data for multiple queries in parallel.\n *\n * Usage:\n * ```tsx\n * const { debugDataPerQuery, isLoading } = useMultiDryRunQueries(queries, {\n * skip: !isMultiQueryMode\n * })\n * ```\n */\nexport function useMultiDryRunQueries(\n queries: CubeQuery[],\n options: UseMultiDryRunQueriesOptions = {}\n): UseMultiDryRunQueriesResult {\n const { skip = false, staleTime = 5 * 60 * 1000 } = options\n const { cubeApi } = useCubeApi()\n\n // Transform queries for server\n const serverQueries = useMemo(() => {\n return queries.map((q) => cleanQueryForServer(q))\n }, [queries])\n\n // Use useQueries for parallel fetching\n const queryResults = useQueries({\n queries: serverQueries.map((query) => ({\n queryKey: createDryRunQueryKey(query),\n queryFn: async () => {\n const result = await cubeApi.dryRun(query)\n return normalizeDryRunResult(result as DryRunResponsePayload)\n },\n enabled: !skip,\n staleTime,\n })),\n })\n\n // Transform results to DebugDataEntry array\n const debugDataPerQuery: DebugDataEntry[] = queryResults.map((result) => ({\n ...(result.data || {\n sql: null,\n analysis: null,\n mode: null,\n queryType: null,\n joinType: null,\n cubesUsed: [],\n modeMetadata: undefined\n }),\n loading: result.isLoading,\n error: result.error ?? null,\n }))\n\n // Check if any query is loading\n const isLoading = queryResults.some((r) => r.isLoading)\n\n // Refetch all queries\n const refetchAll = () => {\n queryResults.forEach((r) => r.refetch())\n }\n\n return {\n debugDataPerQuery,\n isLoading,\n refetchAll,\n }\n}\n\n/**\n * Combined hook for single or multi-query dry-run based on mode\n *\n * This is a convenience wrapper that automatically chooses between\n * single and multi-query dry-run based on the number of queries.\n *\n * Usage:\n * ```tsx\n * const { debugDataPerQuery } = useDryRunQueries({\n * queries: isMultiQueryMode ? allQueries : [currentQuery],\n * isMultiQueryMode,\n * skip: !isValidQuery\n * })\n * ```\n */\nexport function useDryRunQueries(options: {\n queries: CubeQuery[]\n isMultiQueryMode: boolean\n skip?: boolean\n staleTime?: number\n}): UseMultiDryRunQueriesResult {\n const { queries, isMultiQueryMode, skip = false, staleTime } = options\n\n // For single query mode, wrap in array for consistent interface\n const queriesToFetch = isMultiQueryMode ? queries : queries.slice(0, 1)\n\n return useMultiDryRunQueries(queriesToFetch, { skip, staleTime })\n}\n\nexport type FunnelDebugDataEntry = DebugDataEntry\n\n/**\n * TanStack Query hook for funnel query dry-run (debug) data\n *\n * Usage:\n * ```tsx\n * const { debugData } = useFunnelDryRunQuery(serverQuery, { skip: !isFunnelMode })\n * ```\n */\nexport function useFunnelDryRunQuery(\n serverQuery: unknown | null,\n options: UseDryRunQueryOptions = {}\n): { debugData: FunnelDebugDataEntry; refetch: () => void } {\n return useDryRunQuery(serverQuery as CubeQuery | null, options)\n}\n\nexport type FlowDebugDataEntry = DebugDataEntry\n\n/**\n * TanStack Query hook for flow query dry-run (debug) data\n *\n * Usage:\n * ```tsx\n * const { debugData } = useFlowDryRunQuery(serverQuery, { skip: !isFlowMode })\n * ```\n */\nexport function useFlowDryRunQuery(\n serverQuery: unknown | null,\n options: UseDryRunQueryOptions = {}\n): { debugData: FlowDebugDataEntry; refetch: () => void } {\n return useDryRunQuery(serverQuery as CubeQuery | null, options)\n}\n\nexport type RetentionDebugDataEntry = DebugDataEntry\n\n/**\n * TanStack Query hook for retention query dry-run (debug) data\n *\n * Usage:\n * ```tsx\n * const { debugData } = useRetentionDryRunQuery(serverQuery, { skip: !isRetentionMode })\n * ```\n */\nexport function useRetentionDryRunQuery(\n serverQuery: unknown | null,\n options: UseDryRunQueryOptions = {}\n): { debugData: RetentionDebugDataEntry; refetch: () => void } {\n return useDryRunQuery(serverQuery as CubeQuery | null, options)\n}\n","/**\n * useExplainQuery - TanStack Query hook for EXPLAIN PLAN execution\n *\n * Features:\n * - Manually triggered (not automatic like useCubeLoadQuery)\n * - Returns normalized execution plan across PostgreSQL, MySQL, and SQLite\n * - Supports EXPLAIN ANALYZE for actual timing data\n * - No caching - always fetches fresh data to reflect schema/index changes\n *\n * Usage:\n * ```tsx\n * const { explainResult, isLoading, error, runExplain } = useExplainQuery(query)\n *\n * // Trigger explain manually\n * <button onClick={() => runExplain({ analyze: true })}>Explain with Timing</button>\n * ```\n */\n\nimport { useQuery } from '@tanstack/react-query'\nimport { useCallback, useMemo, useState } from 'react'\nimport { useCubeApi } from '../../providers/CubeApiProvider'\nimport type { CubeQuery, ExplainResult, ExplainOptions } from '../../types'\nimport { cleanQueryForServer } from '../../shared/utils'\nimport { stableStringify } from '../../shared/queryKey'\n\n/**\n * Query type that can be explained - includes standard queries, funnel queries, flow queries, and retention queries\n */\nexport type ExplainableQuery = CubeQuery | { funnel: unknown } | { flow: unknown } | { retention: unknown } | unknown\n\n/**\n * Create a stable query key for explain\n */\nexport function createExplainQueryKey(\n query: ExplainableQuery | null,\n options?: ExplainOptions\n): readonly unknown[] {\n if (!query) return ['cube', 'explain', null, null] as const\n return ['cube', 'explain', stableStringify(query), options?.analyze ?? false] as const\n}\n\nexport interface UseExplainQueryOptions {\n /**\n * Whether to skip the query (prevent execution even when triggered)\n * @default false\n */\n skip?: boolean\n}\n\nexport interface UseExplainQueryResult {\n /** The explain result from the server */\n explainResult: ExplainResult | null\n /** Whether the explain query is loading */\n isLoading: boolean\n /** Whether an explain has been triggered */\n hasRun: boolean\n /** Error if explain failed */\n error: Error | null\n /**\n * Manually trigger the explain query\n * @param options - Optional explain options (e.g., { analyze: true } for actual timing)\n */\n runExplain: (options?: ExplainOptions) => void\n /** Clear the explain result */\n clearExplain: () => void\n}\n\n/**\n * Check if query is a funnel query\n */\nfunction isFunnelQuery(query: unknown): query is { funnel: unknown } {\n return typeof query === 'object' && query !== null && 'funnel' in query\n}\n\n/**\n * Check if query is a flow query\n */\nfunction isFlowQuery(query: unknown): query is { flow: unknown } {\n return typeof query === 'object' && query !== null && 'flow' in query\n}\n\n/**\n * Check if query is a retention query\n */\nfunction isRetentionQuery(query: unknown): query is { retention: unknown } {\n return typeof query === 'object' && query !== null && 'retention' in query\n}\n\n/**\n * TanStack Query hook for EXPLAIN PLAN execution\n *\n * Unlike useDryRunQuery, this hook is manually triggered via `runExplain()`.\n * This is intentional because:\n * 1. EXPLAIN queries have performance overhead\n * 2. EXPLAIN ANALYZE actually executes the query\n * 3. Users should explicitly choose when to run explain\n *\n * Supports standard queries, funnel queries, and flow queries.\n *\n * Usage:\n * ```tsx\n * const { explainResult, isLoading, runExplain } = useExplainQuery(query, { skip: !isValidQuery })\n *\n * // Trigger explain\n * <button onClick={() => runExplain()}>Explain Plan</button>\n *\n * // Trigger explain with timing\n * <button onClick={() => runExplain({ analyze: true })}>Explain with Timing</button>\n * ```\n */\nexport function useExplainQuery(\n query: ExplainableQuery | null,\n options: UseExplainQueryOptions = {}\n): UseExplainQueryResult {\n const { skip = false } = options\n const { cubeApi } = useCubeApi()\n\n // Track whether explain has been triggered and with what options\n const [explainOptions, setExplainOptions] = useState<ExplainOptions | null>(null)\n const [hasTriggered, setHasTriggered] = useState(false)\n\n // Transform query for server\n // For funnel/flow/retention queries, pass them directly without cleaning\n const serverQuery = useMemo(() => {\n if (!query) return null\n // Funnel, flow, and retention queries have their own format, don't clean them\n if (isFunnelQuery(query) || isFlowQuery(query) || isRetentionQuery(query)) {\n return query\n }\n // Standard queries get cleaned\n return cleanQueryForServer(query as CubeQuery)\n }, [query])\n\n // Query is enabled only when:\n // 1. We have a query\n // 2. Skip is false\n // 3. User has triggered the explain\n const queryEnabled = !!serverQuery && !skip && hasTriggered\n\n const queryResult = useQuery({\n queryKey: createExplainQueryKey(serverQuery, explainOptions ?? undefined),\n queryFn: async () => {\n if (!serverQuery) throw new Error('No query provided')\n const result = await cubeApi.explain(serverQuery, explainOptions ?? undefined)\n return result\n },\n enabled: queryEnabled,\n // EXPLAIN queries should never be cached - always fetch fresh data\n // This ensures users see the latest execution plan after schema/index changes\n staleTime: 0,\n gcTime: 0,\n // Don't refetch automatically - this is manually triggered\n refetchOnWindowFocus: false,\n refetchOnReconnect: false,\n refetchOnMount: false,\n })\n\n // Manual trigger function\n const runExplain = useCallback((opts?: ExplainOptions) => {\n if (skip || !serverQuery) return\n setExplainOptions(opts ?? null)\n setHasTriggered(true)\n // If already triggered with same options, refetch\n if (hasTriggered) {\n queryResult.refetch()\n }\n }, [skip, serverQuery, hasTriggered, queryResult])\n\n // Clear function\n const clearExplain = useCallback(() => {\n setHasTriggered(false)\n setExplainOptions(null)\n }, [])\n\n return {\n explainResult: queryResult.data ?? null,\n isLoading: queryResult.isLoading || queryResult.isFetching,\n hasRun: hasTriggered,\n error: queryResult.error ?? null,\n runExplain,\n clearExplain,\n }\n}\n","/**\n * useExplainAI - TanStack Query hook for AI analysis of EXPLAIN plans\n *\n * Features:\n * - Manually triggered via useMutation (not automatic)\n * - Analyzes execution plans and provides actionable recommendations\n * - Returns structured recommendations (indexes, table changes, cube improvements)\n * - No caching - always fetches fresh analysis\n * - Uses the /api/ai/explain/analyze endpoint\n *\n * Usage:\n * ```tsx\n * const { analysis, isAnalyzing, error, analyze, clearAnalysis } = useExplainAI()\n *\n * // After getting an explain result, trigger AI analysis\n * <button onClick={() => analyze(explainResult, query)}>Analyze with AI</button>\n * ```\n */\n\nimport { useMutation, useQueryClient } from '@tanstack/react-query'\nimport { useCallback } from 'react'\nimport type { ExplainResult, AIExplainAnalysis } from '../../types'\nimport { useCubeFeatures } from '../../providers/CubeFeaturesProvider'\n\nexport interface UseExplainAIOptions {\n /**\n * Custom AI endpoint for explain analysis\n * @default '/api/ai/explain/analyze'\n */\n aiEndpoint?: string\n}\n\nexport interface UseExplainAIResult {\n /** The AI analysis result */\n analysis: AIExplainAnalysis | null\n /** Whether AI analysis is in progress */\n isAnalyzing: boolean\n /** Error if AI analysis failed */\n error: Error | null\n /**\n * Trigger AI analysis of an explain result\n * @param explainResult - The EXPLAIN result to analyze\n * @param query - The original semantic query\n */\n analyze: (explainResult: ExplainResult, query: unknown) => void\n /** Clear the analysis result */\n clearAnalysis: () => void\n}\n\n/**\n * Query key for AI explain analysis\n */\nexport const EXPLAIN_AI_QUERY_KEY = ['cube', 'explain', 'ai'] as const\n\n/**\n * TanStack Query hook for AI analysis of EXPLAIN plans\n *\n * This hook uses useMutation to call the AI endpoint and analyze execution plans,\n * providing actionable recommendations for performance improvement.\n *\n * Recommendations focus on what users CAN control:\n * - Index creation (with CREATE INDEX statements)\n * - Table structure changes\n * - Cube definition improvements (segments, pre-aggregations, joins)\n *\n * Usage:\n * ```tsx\n * const { analysis, isAnalyzing, analyze } = useExplainAI()\n *\n * // After running EXPLAIN\n * if (explainResult) {\n * <button onClick={() => analyze(explainResult, query)}>\n * {isAnalyzing ? 'Analyzing...' : 'Analyze with AI'}\n * </button>\n * }\n *\n * // Display recommendations\n * {analysis?.recommendations.map(rec => (\n * <div key={rec.title}>\n * <h4>{rec.title}</h4>\n * <p>{rec.description}</p>\n * {rec.sql && <pre>{rec.sql}</pre>}\n * {rec.cubeCode && <pre>{rec.cubeCode}</pre>}\n * </div>\n * ))}\n * ```\n */\nexport function useExplainAI(options: UseExplainAIOptions = {}): UseExplainAIResult {\n const { features } = useCubeFeatures()\n const enableAI = features.enableAI ?? true\n const queryClient = useQueryClient()\n\n // AI endpoint - defaults to /api/ai/explain/analyze\n // This is the standard path for AI routes in the dev server\n const aiEndpoint = options.aiEndpoint ?? '/api/ai/explain/analyze'\n\n const mutation = useMutation({\n mutationKey: EXPLAIN_AI_QUERY_KEY,\n mutationFn: async ({ explainResult, query }: { explainResult: ExplainResult; query: unknown }) => {\n // Check if AI is enabled\n if (!enableAI) {\n throw new Error('AI features are disabled')\n }\n\n const response = await fetch(aiEndpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n credentials: 'include',\n body: JSON.stringify({\n explainResult,\n query,\n }),\n })\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}))\n throw new Error(\n errorData.error ||\n errorData.message ||\n `AI analysis failed: ${response.status} ${response.statusText}`\n )\n }\n\n const result: AIExplainAnalysis = await response.json()\n return result\n },\n // No caching - each mutation is independent\n gcTime: 0,\n })\n\n const analyze = useCallback((explainResult: ExplainResult, query: unknown) => {\n mutation.mutate({ explainResult, query })\n }, [mutation])\n\n const clearAnalysis = useCallback(() => {\n mutation.reset()\n // Also invalidate any cached queries\n queryClient.removeQueries({ queryKey: EXPLAIN_AI_QUERY_KEY })\n }, [mutation, queryClient])\n\n return {\n analysis: mutation.data ?? null,\n isAnalyzing: mutation.isPending,\n error: mutation.error ?? null,\n analyze,\n clearAnalysis,\n }\n}\n"],"names":["createDryRunQueryKey","query","stableStringify","inferModeFromPayload","payload","normalizeDryRunResult","mode","useDryRunQuery","options","skip","staleTime","cubeApi","useCubeApi","serverQuery","useMemo","modeQuery","cleanQueryForServer","queryResult","useQuery","result","useMultiDryRunQueries","queries","serverQueries","q","queryResults","useQueries","debugDataPerQuery","isLoading","r","useDryRunQueries","isMultiQueryMode","queriesToFetch","createExplainQueryKey","isFunnelQuery","isFlowQuery","isRetentionQuery","useExplainQuery","explainOptions","setExplainOptions","useState","hasTriggered","setHasTriggered","queryEnabled","runExplain","useCallback","opts","clearExplain","EXPLAIN_AI_QUERY_KEY","useExplainAI","features","useCubeFeatures","enableAI","queryClient","useQueryClient","aiEndpoint","mutation","useMutation","explainResult","response","errorData","analyze","clearAnalysis"],"mappings":"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"}
|
package/dist/client/index.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { g as d, a as y, A as g, C as m, f as b, e as C, D as h, h as f, c as p, b as D, M as x, d as S, P as Q, l as A, R as M, O as F, N as v, L as T, Q as I, T as E, G as L, F as P, I as B, U as w, E as R, H as K, V, J as k, K as N, S as j, W as U, X as z, x as G, o as O, v as W, q, s as H, t as _, n as J, r as X, m as $, p as Y, w as Z, u as ee, i as ae, j as se, k as te, B as re, z as ie, y as le } from "./chunks/DashboardEditModal-
|
|
1
|
+
import { g as d, a as y, A as g, C as m, f as b, e as C, D as h, h as f, c as p, b as D, M as x, d as S, P as Q, l as A, R as M, O as F, N as v, L as T, Q as I, T as E, G as L, F as P, I as B, U as w, E as R, H as K, V, J as k, K as N, S as j, W as U, X as z, x as G, o as O, v as W, q, s as H, t as _, n as J, r as X, m as $, p as Y, w as Z, u as ee, i as ae, j as se, k as te, B as re, z as ie, y as le } from "./chunks/DashboardEditModal-Bv7e3Q7O.js";
|
|
2
2
|
import { jsx as e, jsxs as s } from "react/jsx-runtime";
|
|
3
3
|
import { L as ne, u as ue } from "./chunks/charts-core-DAF1iT_h.js";
|
|
4
4
|
import { L as de, g as ye, c as ge, b as me, i as be, p as Ce, a as he } from "./chunks/charts-loader-7pEaEz-f.js";
|
|
5
5
|
import { b as t } from "./chunks/icons-DRreo6m8.js";
|
|
6
6
|
import { D as pe, a as De, i as xe, c as Se, f as Qe, h as Ae, g as Me, r as Fe, e as ve, s as Te } from "./chunks/icons-DRreo6m8.js";
|
|
7
|
-
import { E as Ee, a as Le, p as Pe, q as Be, m as we, l as Re, r as Ke, C as Ve, D as ke, o as Ne, B as je, n as Ue, w as ze, t as Ge, d as Oe, f as We, s as qe, e as He, i as _e, c as Je, h as Xe, g as $e, u as Ye, b as Ze, y as ea, A as aa, x as sa, k as ta, v as ra, z as ia, j as la } from "./chunks/analysis-builder-shared-
|
|
7
|
+
import { E as Ee, a as Le, p as Pe, q as Be, m as we, l as Re, r as Ke, C as Ve, D as ke, o as Ne, B as je, n as Ue, w as ze, t as Ge, d as Oe, f as We, s as qe, e as He, i as _e, c as Je, h as Xe, g as $e, u as Ye, b as Ze, y as ea, A as aa, x as sa, k as ta, v as ra, z as ia, j as la } from "./chunks/analysis-builder-shared-DsbdRCzz.js";
|
|
8
8
|
import { h as na, a as ua, S as ca, e as da, d as ya, i as ga, f as ma, b as ba, g as Ca, u as ha, j as fa, c as pa, w as Da } from "./chunks/providers-D2xswCYu.js";
|
|
9
9
|
import { u as Sa } from "./chunks/chart-bubble-D-auWIjP.js";
|
|
10
10
|
import { c as Aa, f as Ma } from "./chunks/index-CApFCBF9.js";
|
|
11
11
|
import { e as va, c as Ta, l as Ia, h as Ea, k as La, j as Pa, i as Ba, m as wa, g as Ra, f as Ka, u as Va, u as ka, d as Na, b as ja, a as Ua, v as za } from "./chunks/useDirtyStateTracking-CTS_m9mg.js";
|
|
12
12
|
import { c as Oa, b as Wa, f as qa, g as Ha, a as _a, i as Ja, t as Xa } from "./chunks/funnel-utils-CyonoNeC.js";
|
|
13
13
|
import { T as Ya, c as Za, g as es, a as as, i as ss, r as ts, s as rs, b as is, w as ls } from "./chunks/theme-Dp3hFed1.js";
|
|
14
|
-
import {
|
|
14
|
+
import { createExplainQueryKey as ns, useDryRunQueries as us, useDryRunQuery as cs, useExplainAI as ds, useExplainQuery as ys, useMultiDryRunQueries as gs } from "./hooks.js";
|
|
15
15
|
import { i as bs, a as Cs } from "./chunks/flow-utils-CjQZG5qq.js";
|
|
16
16
|
import { h as fs } from "./chunks/syntaxHighlighting-DAT9C6Ss.js";
|
|
17
17
|
function o() {
|
|
@@ -83,6 +83,25 @@ export interface JoinPathAnalysis {
|
|
|
83
83
|
pathLength?: number;
|
|
84
84
|
error?: string;
|
|
85
85
|
visitedCubes?: string[];
|
|
86
|
+
selection?: {
|
|
87
|
+
strategy: 'shortest' | 'preferred' | 'fallbackShortest';
|
|
88
|
+
preferredCubes?: string[];
|
|
89
|
+
selectedRank?: number;
|
|
90
|
+
selectedScore?: number;
|
|
91
|
+
candidates?: Array<{
|
|
92
|
+
rank: number;
|
|
93
|
+
score: number;
|
|
94
|
+
usesPreferredJoin: boolean;
|
|
95
|
+
preferredCubesInPath: number;
|
|
96
|
+
usesProcessed: boolean;
|
|
97
|
+
scoreBreakdown: {
|
|
98
|
+
preferredJoinBonus: number;
|
|
99
|
+
preferredCubeBonus: number;
|
|
100
|
+
lengthPenalty: number;
|
|
101
|
+
};
|
|
102
|
+
path: JoinPathStep[];
|
|
103
|
+
}>;
|
|
104
|
+
};
|
|
86
105
|
}
|
|
87
106
|
/**
|
|
88
107
|
* Reason why a cube requires a CTE
|
|
@@ -103,6 +122,7 @@ export interface PreAggregationAnalysis {
|
|
|
103
122
|
}
|
|
104
123
|
export interface QuerySummary {
|
|
105
124
|
queryType: 'single_cube' | 'multi_cube_join' | 'multi_cube_cte';
|
|
125
|
+
measureStrategy?: 'simple' | 'keysDeduplication' | 'ctePreAggregateFallback' | 'multiFactMerge';
|
|
106
126
|
joinCount: number;
|
|
107
127
|
cteCount: number;
|
|
108
128
|
hasPreAggregation: boolean;
|
|
@@ -116,6 +136,13 @@ export interface QueryAnalysis {
|
|
|
116
136
|
preAggregations: PreAggregationAnalysis[];
|
|
117
137
|
querySummary: QuerySummary;
|
|
118
138
|
warnings?: string[];
|
|
139
|
+
planningTrace?: {
|
|
140
|
+
steps: Array<{
|
|
141
|
+
phase: 'cube_usage' | 'primary_cube_selection' | 'join_planning' | 'cte_planning' | 'measure_strategy' | 'warnings';
|
|
142
|
+
decision: string;
|
|
143
|
+
details?: Record<string, unknown>;
|
|
144
|
+
}>;
|
|
145
|
+
};
|
|
119
146
|
}
|
|
120
147
|
export interface ValidationResult {
|
|
121
148
|
valid?: boolean;
|