drizzle-cube 0.1.4 → 0.1.6
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/README.md +4 -17
- package/dist/adapters/hono/index.js +163 -94
- package/dist/client/client/CubeClient.d.ts +1 -0
- package/dist/client/components/Modal.d.ts +2 -1
- package/dist/client/components/QueryBuilder/CubeMetaExplorer.d.ts +4 -0
- package/dist/client/components/QueryBuilder/QueryPanel.d.ts +4 -0
- package/dist/client/components/QueryBuilder/ResultsPanel.d.ts +4 -0
- package/dist/client/components/QueryBuilder/SetupPanel.d.ts +11 -0
- package/dist/client/components/QueryBuilder/index.d.ts +3 -0
- package/dist/client/components/QueryBuilder/types.d.ts +132 -0
- package/dist/client/components/QueryBuilder/utils.d.ts +42 -0
- package/dist/client/index.d.ts +1 -0
- package/dist/client/index.js +11429 -9727
- package/dist/client/styles.css +1 -1
- package/dist/server/index.d.ts +10 -0
- package/dist/server/index.js +339 -313
- package/package.json +6 -1
package/README.md
CHANGED
|
@@ -4,11 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
Transform your Drizzle schema into a powerful, type-safe analytics platform with SQL injection protection and full TypeScript support.
|
|
6
6
|
|
|
7
|
-
📖 **[Documentation](https://www.drizzle-cube.dev/)**
|
|
8
|
-
|
|
9
|
-
> **⚠️ DEVELOPMENT WARNING**
|
|
10
|
-
> **This project is under active development and is not yet fully functional. I will update here when we reach an alpha/working version!**
|
|
11
|
-
> Feel free to star ⭐ the repo to stay updated on progress.
|
|
7
|
+
📖 **[Documentation](https://www.drizzle-cube.dev/)**
|
|
8
|
+
🚀 **[Try the Sandbox](https://try.drizzle-cube.dev/)**
|
|
12
9
|
|
|
13
10
|
[](https://www.npmjs.com/package/drizzle-cube)
|
|
14
11
|
[](https://www.typescriptlang.org/)
|
|
@@ -320,15 +317,8 @@ Supports all Cube.js filter operators with Drizzle safety:
|
|
|
320
317
|
|
|
321
318
|
## Documentation
|
|
322
319
|
|
|
323
|
-
📚 **[Full Documentation](https://drizzle-cube.dev/
|
|
324
|
-
|
|
325
|
-
### Quick Links
|
|
326
|
-
- [Getting Started](https://drizzle-cube.dev/help/getting-started) - Installation and first steps
|
|
327
|
-
- [Core Concepts](https://drizzle-cube.dev/help/getting-started/concepts) - Cubes, dimensions, and measures
|
|
328
|
-
- [Semantic Layer](https://drizzle-cube.dev/help/semantic-layer) - Advanced semantic layer features
|
|
329
|
-
- [React Client](https://drizzle-cube.dev/help/client) - Dashboard and chart components
|
|
330
|
-
- [Hono Adapter](https://drizzle-cube.dev/help/adapters/hono) - Web framework integration
|
|
331
|
-
- [Security](https://drizzle-cube.dev/help/semantic-layer/security) - Multi-tenant security patterns
|
|
320
|
+
📚 **[Full Documentation](https://www.drizzle-cube.dev/)** - Complete guides and API reference
|
|
321
|
+
🚀 **[Try the Sandbox](https://try.drizzle-cube.dev/)** - Working example version to experiment with
|
|
332
322
|
|
|
333
323
|
### Local Development
|
|
334
324
|
```bash
|
|
@@ -341,9 +331,6 @@ npm run build:help
|
|
|
341
331
|
|
|
342
332
|
## Examples
|
|
343
333
|
|
|
344
|
-
🚀 **[Live Examples](https://github.com/cliftonc/drizzle-cube/tree/main/examples)**
|
|
345
|
-
|
|
346
|
-
- **[Basic Example](https://github.com/cliftonc/drizzle-cube/tree/main/examples/basic)** - Simple semantic layer setup
|
|
347
334
|
- **[Hono Example](https://github.com/cliftonc/drizzle-cube/tree/main/examples/hono)** - Full-featured dashboard with Cloudflare Workers
|
|
348
335
|
|
|
349
336
|
## Contributing
|
|
@@ -1,63 +1,79 @@
|
|
|
1
|
-
import { Hono as
|
|
2
|
-
var
|
|
3
|
-
const
|
|
1
|
+
import { Hono as D } from "hono";
|
|
2
|
+
var S = (q) => {
|
|
3
|
+
const d = {
|
|
4
4
|
...{
|
|
5
5
|
origin: "*",
|
|
6
6
|
allowMethods: ["GET", "HEAD", "PUT", "POST", "DELETE", "PATCH"],
|
|
7
7
|
allowHeaders: [],
|
|
8
8
|
exposeHeaders: []
|
|
9
9
|
},
|
|
10
|
-
...
|
|
11
|
-
},
|
|
12
|
-
return async function(n,
|
|
13
|
-
var
|
|
14
|
-
function
|
|
15
|
-
n.res.headers.set(
|
|
10
|
+
...q
|
|
11
|
+
}, A = /* @__PURE__ */ ((u) => typeof u == "string" ? u === "*" ? () => u : (n) => u === n ? n : null : typeof u == "function" ? u : (n) => u.includes(n) ? n : null)(d.origin), j = ((u) => typeof u == "function" ? u : Array.isArray(u) ? () => u : () => [])(d.allowMethods);
|
|
12
|
+
return async function(n, m) {
|
|
13
|
+
var x;
|
|
14
|
+
function p(h, f) {
|
|
15
|
+
n.res.headers.set(h, f);
|
|
16
16
|
}
|
|
17
|
-
const
|
|
18
|
-
if (
|
|
19
|
-
const
|
|
20
|
-
|
|
17
|
+
const b = A(n.req.header("origin") || "", n);
|
|
18
|
+
if (b && p("Access-Control-Allow-Origin", b), d.origin !== "*") {
|
|
19
|
+
const h = n.req.header("Vary");
|
|
20
|
+
h ? p("Vary", h) : p("Vary", "Origin");
|
|
21
21
|
}
|
|
22
|
-
if (
|
|
23
|
-
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
let
|
|
27
|
-
if (!(
|
|
28
|
-
const
|
|
29
|
-
|
|
22
|
+
if (d.credentials && p("Access-Control-Allow-Credentials", "true"), (x = d.exposeHeaders) != null && x.length && p("Access-Control-Expose-Headers", d.exposeHeaders.join(",")), n.req.method === "OPTIONS") {
|
|
23
|
+
d.maxAge != null && p("Access-Control-Max-Age", d.maxAge.toString());
|
|
24
|
+
const h = j(n.req.header("origin") || "", n);
|
|
25
|
+
h.length && p("Access-Control-Allow-Methods", h.join(","));
|
|
26
|
+
let f = d.allowHeaders;
|
|
27
|
+
if (!(f != null && f.length)) {
|
|
28
|
+
const e = n.req.header("Access-Control-Request-Headers");
|
|
29
|
+
e && (f = e.split(/\s*,\s*/));
|
|
30
30
|
}
|
|
31
|
-
return
|
|
31
|
+
return f != null && f.length && (p("Access-Control-Allow-Headers", f.join(",")), n.res.headers.append("Vary", "Access-Control-Request-Headers")), n.res.headers.delete("Content-Length"), n.res.headers.delete("Content-Type"), new Response(null, {
|
|
32
32
|
headers: n.res.headers,
|
|
33
33
|
status: 204,
|
|
34
34
|
statusText: "No Content"
|
|
35
35
|
});
|
|
36
36
|
}
|
|
37
|
-
await
|
|
37
|
+
await m();
|
|
38
38
|
};
|
|
39
39
|
};
|
|
40
|
-
function E(
|
|
40
|
+
function E(q) {
|
|
41
41
|
const {
|
|
42
42
|
semanticLayer: a,
|
|
43
|
-
drizzle:
|
|
44
|
-
schema:
|
|
45
|
-
getSecurityContext:
|
|
43
|
+
drizzle: d,
|
|
44
|
+
schema: A,
|
|
45
|
+
getSecurityContext: j,
|
|
46
46
|
cors: u,
|
|
47
47
|
basePath: n = "/cubejs-api/v1"
|
|
48
|
-
} =
|
|
49
|
-
u &&
|
|
48
|
+
} = q, m = new D();
|
|
49
|
+
u && m.use("/*", S(u)), a.hasExecutor() || a.setDrizzle(d, A), m.post(`${n}/load`, async (e) => {
|
|
50
50
|
try {
|
|
51
|
-
const r = await e.req.json(), s = r.query || r, t = await
|
|
51
|
+
const r = await e.req.json(), s = r.query || r, t = await j(e), o = a.validateQuery(s);
|
|
52
52
|
if (!o.isValid)
|
|
53
53
|
return e.json({
|
|
54
54
|
error: `Query validation failed: ${o.errors.join(", ")}`
|
|
55
55
|
}, 400);
|
|
56
|
-
const i = await a.executeMultiCubeQuery(s, t);
|
|
56
|
+
const i = await a.executeMultiCubeQuery(s, t), l = h(a), y = b(), g = (/* @__PURE__ */ new Date()).toISOString(), Q = x(s);
|
|
57
57
|
return e.json({
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
queryType: "regularQuery",
|
|
59
|
+
results: [{
|
|
60
|
+
query: s,
|
|
61
|
+
lastRefreshTime: g,
|
|
62
|
+
usedPreAggregations: {},
|
|
63
|
+
transformedQuery: Q,
|
|
64
|
+
requestId: y,
|
|
65
|
+
annotation: i.annotation,
|
|
66
|
+
dataSource: "default",
|
|
67
|
+
dbType: l,
|
|
68
|
+
extDbType: l,
|
|
69
|
+
external: !1,
|
|
70
|
+
slowQuery: !1,
|
|
71
|
+
data: i.data
|
|
72
|
+
}],
|
|
73
|
+
pivotQuery: {
|
|
74
|
+
...s,
|
|
75
|
+
queryType: "regularQuery"
|
|
76
|
+
},
|
|
61
77
|
slowQuery: !1
|
|
62
78
|
});
|
|
63
79
|
} catch (r) {
|
|
@@ -65,23 +81,39 @@ function E(y) {
|
|
|
65
81
|
error: r instanceof Error ? r.message : "Query execution failed"
|
|
66
82
|
}, 500);
|
|
67
83
|
}
|
|
68
|
-
}),
|
|
84
|
+
}), m.get(`${n}/load`, async (e) => {
|
|
69
85
|
try {
|
|
70
86
|
const r = e.req.query("query");
|
|
71
87
|
if (!r)
|
|
72
88
|
return e.json({
|
|
73
89
|
error: "Query parameter is required"
|
|
74
90
|
}, 400);
|
|
75
|
-
const s = JSON.parse(r), t = await
|
|
91
|
+
const s = JSON.parse(r), t = await j(e), o = a.validateQuery(s);
|
|
76
92
|
if (!o.isValid)
|
|
77
93
|
return e.json({
|
|
78
94
|
error: `Query validation failed: ${o.errors.join(", ")}`
|
|
79
95
|
}, 400);
|
|
80
|
-
const i = await a.executeMultiCubeQuery(s, t);
|
|
96
|
+
const i = await a.executeMultiCubeQuery(s, t), l = h(a), y = b(), g = (/* @__PURE__ */ new Date()).toISOString(), Q = x(s);
|
|
81
97
|
return e.json({
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
98
|
+
queryType: "regularQuery",
|
|
99
|
+
results: [{
|
|
100
|
+
query: s,
|
|
101
|
+
lastRefreshTime: g,
|
|
102
|
+
usedPreAggregations: {},
|
|
103
|
+
transformedQuery: Q,
|
|
104
|
+
requestId: y,
|
|
105
|
+
annotation: i.annotation,
|
|
106
|
+
dataSource: "default",
|
|
107
|
+
dbType: l,
|
|
108
|
+
extDbType: l,
|
|
109
|
+
external: !1,
|
|
110
|
+
slowQuery: !1,
|
|
111
|
+
data: i.data
|
|
112
|
+
}],
|
|
113
|
+
pivotQuery: {
|
|
114
|
+
...s,
|
|
115
|
+
queryType: "regularQuery"
|
|
116
|
+
},
|
|
85
117
|
slowQuery: !1
|
|
86
118
|
});
|
|
87
119
|
} catch (r) {
|
|
@@ -89,7 +121,7 @@ function E(y) {
|
|
|
89
121
|
error: r instanceof Error ? r.message : "Query execution failed"
|
|
90
122
|
}, 500);
|
|
91
123
|
}
|
|
92
|
-
}),
|
|
124
|
+
}), m.get(`${n}/meta`, (e) => {
|
|
93
125
|
try {
|
|
94
126
|
const r = a.getMetadata();
|
|
95
127
|
return e.json({
|
|
@@ -100,23 +132,23 @@ function E(y) {
|
|
|
100
132
|
error: r instanceof Error ? r.message : "Failed to fetch metadata"
|
|
101
133
|
}, 500);
|
|
102
134
|
}
|
|
103
|
-
}),
|
|
135
|
+
}), m.post(`${n}/sql`, async (e) => {
|
|
104
136
|
var r, s;
|
|
105
137
|
try {
|
|
106
|
-
const t = await e.req.json(), o = await
|
|
138
|
+
const t = await e.req.json(), o = await j(e), i = a.validateQuery(t);
|
|
107
139
|
if (!i.isValid)
|
|
108
140
|
return e.json({
|
|
109
141
|
error: `Query validation failed: ${i.errors.join(", ")}`
|
|
110
142
|
}, 400);
|
|
111
|
-
const
|
|
112
|
-
if (!
|
|
143
|
+
const l = ((r = t.measures) == null ? void 0 : r[0]) || ((s = t.dimensions) == null ? void 0 : s[0]);
|
|
144
|
+
if (!l)
|
|
113
145
|
return e.json({
|
|
114
146
|
error: "No measures or dimensions specified"
|
|
115
147
|
}, 400);
|
|
116
|
-
const
|
|
148
|
+
const y = l.split(".")[0], g = await a.generateSQL(y, t, o);
|
|
117
149
|
return e.json({
|
|
118
|
-
sql:
|
|
119
|
-
params:
|
|
150
|
+
sql: g.sql,
|
|
151
|
+
params: g.params || [],
|
|
120
152
|
query: t
|
|
121
153
|
});
|
|
122
154
|
} catch (t) {
|
|
@@ -124,7 +156,7 @@ function E(y) {
|
|
|
124
156
|
error: t instanceof Error ? t.message : "SQL generation failed"
|
|
125
157
|
}, 500);
|
|
126
158
|
}
|
|
127
|
-
}),
|
|
159
|
+
}), m.get(`${n}/sql`, async (e) => {
|
|
128
160
|
var r, s;
|
|
129
161
|
try {
|
|
130
162
|
const t = e.req.query("query");
|
|
@@ -132,17 +164,17 @@ function E(y) {
|
|
|
132
164
|
return e.json({
|
|
133
165
|
error: "Query parameter is required"
|
|
134
166
|
}, 400);
|
|
135
|
-
const o = JSON.parse(t), i = await
|
|
136
|
-
if (!
|
|
167
|
+
const o = JSON.parse(t), i = await j(e), l = a.validateQuery(o);
|
|
168
|
+
if (!l.isValid)
|
|
137
169
|
return e.json({
|
|
138
|
-
error: `Query validation failed: ${
|
|
170
|
+
error: `Query validation failed: ${l.errors.join(", ")}`
|
|
139
171
|
}, 400);
|
|
140
|
-
const
|
|
141
|
-
if (!
|
|
172
|
+
const y = ((r = o.measures) == null ? void 0 : r[0]) || ((s = o.dimensions) == null ? void 0 : s[0]);
|
|
173
|
+
if (!y)
|
|
142
174
|
return e.json({
|
|
143
175
|
error: "No measures or dimensions specified"
|
|
144
176
|
}, 400);
|
|
145
|
-
const
|
|
177
|
+
const g = y.split(".")[0], Q = await a.generateSQL(g, o, i);
|
|
146
178
|
return e.json({
|
|
147
179
|
sql: Q.sql,
|
|
148
180
|
params: Q.params || [],
|
|
@@ -154,30 +186,67 @@ function E(y) {
|
|
|
154
186
|
}, 500);
|
|
155
187
|
}
|
|
156
188
|
});
|
|
157
|
-
function
|
|
189
|
+
function p(e) {
|
|
158
190
|
var s, t, o, i;
|
|
159
191
|
let r = 0;
|
|
160
192
|
return r += (((s = e.measures) == null ? void 0 : s.length) || 0) * 1, r += (((t = e.dimensions) == null ? void 0 : t.length) || 0) * 1, r += (((o = e.filters) == null ? void 0 : o.length) || 0) * 2, r += (((i = e.timeDimensions) == null ? void 0 : i.length) || 0) * 3, r <= 5 ? "low" : r <= 15 ? "medium" : "high";
|
|
161
193
|
}
|
|
162
|
-
|
|
163
|
-
|
|
194
|
+
function b() {
|
|
195
|
+
const e = Date.now(), r = Math.random().toString(36).substring(2, 9);
|
|
196
|
+
return `${e}-${r}`;
|
|
197
|
+
}
|
|
198
|
+
function x(e) {
|
|
199
|
+
const r = e.dimensions || [], s = e.timeDimensions || [], t = e.measures || [];
|
|
200
|
+
return {
|
|
201
|
+
sortedDimensions: r,
|
|
202
|
+
sortedTimeDimensions: s,
|
|
203
|
+
timeDimensions: s,
|
|
204
|
+
measures: t,
|
|
205
|
+
leafMeasureAdditive: !0,
|
|
206
|
+
leafMeasures: t,
|
|
207
|
+
measureToLeafMeasures: {},
|
|
208
|
+
hasNoTimeDimensionsWithoutGranularity: !0,
|
|
209
|
+
allFiltersWithinSelectedDimensions: !0,
|
|
210
|
+
isAdditive: !0,
|
|
211
|
+
granularityHierarchies: {},
|
|
212
|
+
hasMultipliedMeasures: !1,
|
|
213
|
+
hasCumulativeMeasures: !1,
|
|
214
|
+
windowGranularity: null,
|
|
215
|
+
filterDimensionsSingleValueEqual: {},
|
|
216
|
+
ownedDimensions: r,
|
|
217
|
+
ownedTimeDimensionsWithRollupGranularity: [],
|
|
218
|
+
ownedTimeDimensionsAsIs: [],
|
|
219
|
+
allBackAliasMembers: {},
|
|
220
|
+
hasMultiStage: !1
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
function h(e) {
|
|
224
|
+
if (e.hasExecutor()) {
|
|
225
|
+
const r = e.databaseExecutor;
|
|
226
|
+
if (r != null && r.engineType)
|
|
227
|
+
return r.engineType;
|
|
228
|
+
}
|
|
229
|
+
return "postgres";
|
|
230
|
+
}
|
|
231
|
+
async function f(e, r) {
|
|
232
|
+
var y, g, Q, v;
|
|
164
233
|
const s = a.validateQuery(e);
|
|
165
234
|
if (!s.isValid)
|
|
166
235
|
throw new Error(`Query validation failed: ${s.errors.join(", ")}`);
|
|
167
236
|
const t = /* @__PURE__ */ new Set();
|
|
168
|
-
(
|
|
169
|
-
const
|
|
170
|
-
t.add(
|
|
171
|
-
}), (
|
|
172
|
-
const
|
|
173
|
-
t.add(
|
|
174
|
-
}), (Q = e.timeDimensions) == null || Q.forEach((
|
|
175
|
-
const
|
|
176
|
-
t.add(
|
|
177
|
-
}), (
|
|
178
|
-
if ("member" in
|
|
179
|
-
const
|
|
180
|
-
t.add(
|
|
237
|
+
(y = e.measures) == null || y.forEach((c) => {
|
|
238
|
+
const w = c.split(".")[0];
|
|
239
|
+
t.add(w);
|
|
240
|
+
}), (g = e.dimensions) == null || g.forEach((c) => {
|
|
241
|
+
const w = c.split(".")[0];
|
|
242
|
+
t.add(w);
|
|
243
|
+
}), (Q = e.timeDimensions) == null || Q.forEach((c) => {
|
|
244
|
+
const w = c.dimension.split(".")[0];
|
|
245
|
+
t.add(w);
|
|
246
|
+
}), (v = e.filters) == null || v.forEach((c) => {
|
|
247
|
+
if ("member" in c) {
|
|
248
|
+
const w = c.member.split(".")[0];
|
|
249
|
+
t.add(w);
|
|
181
250
|
}
|
|
182
251
|
});
|
|
183
252
|
const o = t.size > 1;
|
|
@@ -185,16 +254,16 @@ function E(y) {
|
|
|
185
254
|
if (o)
|
|
186
255
|
i = await a.generateMultiCubeSQL(e, r);
|
|
187
256
|
else {
|
|
188
|
-
const
|
|
189
|
-
i = await a.generateSQL(
|
|
257
|
+
const c = Array.from(t)[0];
|
|
258
|
+
i = await a.generateSQL(c, e, r);
|
|
190
259
|
}
|
|
191
|
-
const
|
|
192
|
-
var
|
|
260
|
+
const l = Array.from(t).map((c) => {
|
|
261
|
+
var w, T;
|
|
193
262
|
return {
|
|
194
|
-
cube:
|
|
263
|
+
cube: c,
|
|
195
264
|
query: {
|
|
196
|
-
measures: ((
|
|
197
|
-
dimensions: ((
|
|
265
|
+
measures: ((w = e.measures) == null ? void 0 : w.filter((C) => C.startsWith(c + "."))) || [],
|
|
266
|
+
dimensions: ((T = e.dimensions) == null ? void 0 : T.filter((C) => C.startsWith(c + "."))) || [],
|
|
198
267
|
filters: e.filters || [],
|
|
199
268
|
timeDimensions: e.timeDimensions || [],
|
|
200
269
|
order: e.order || {},
|
|
@@ -205,9 +274,9 @@ function E(y) {
|
|
|
205
274
|
});
|
|
206
275
|
return {
|
|
207
276
|
queryType: "regularQuery",
|
|
208
|
-
normalizedQueries:
|
|
277
|
+
normalizedQueries: l,
|
|
209
278
|
queryOrder: Array.from(t),
|
|
210
|
-
transformedQueries:
|
|
279
|
+
transformedQueries: l,
|
|
211
280
|
pivotQuery: {
|
|
212
281
|
query: e,
|
|
213
282
|
cubes: Array.from(t)
|
|
@@ -216,16 +285,16 @@ function E(y) {
|
|
|
216
285
|
sql: [i.sql],
|
|
217
286
|
params: i.params || []
|
|
218
287
|
},
|
|
219
|
-
complexity:
|
|
288
|
+
complexity: p(e),
|
|
220
289
|
valid: !0,
|
|
221
290
|
cubesUsed: Array.from(t),
|
|
222
291
|
joinType: o ? "multi_cube_join" : "single_cube",
|
|
223
292
|
query: e
|
|
224
293
|
};
|
|
225
294
|
}
|
|
226
|
-
return
|
|
295
|
+
return m.post(`${n}/dry-run`, async (e) => {
|
|
227
296
|
try {
|
|
228
|
-
const r = await e.req.json(), s = r.query || r, t = await
|
|
297
|
+
const r = await e.req.json(), s = r.query || r, t = await j(e), o = await f(s, t);
|
|
229
298
|
return e.json(o);
|
|
230
299
|
} catch (r) {
|
|
231
300
|
return console.error("Dry-run error:", r), e.json({
|
|
@@ -233,7 +302,7 @@ function E(y) {
|
|
|
233
302
|
valid: !1
|
|
234
303
|
}, 400);
|
|
235
304
|
}
|
|
236
|
-
}),
|
|
305
|
+
}), m.get(`${n}/dry-run`, async (e) => {
|
|
237
306
|
try {
|
|
238
307
|
const r = e.req.query("query");
|
|
239
308
|
if (!r)
|
|
@@ -241,7 +310,7 @@ function E(y) {
|
|
|
241
310
|
error: "Query parameter is required",
|
|
242
311
|
valid: !1
|
|
243
312
|
}, 400);
|
|
244
|
-
const s = JSON.parse(r), t = await
|
|
313
|
+
const s = JSON.parse(r), t = await j(e), o = await f(s, t);
|
|
245
314
|
return e.json(o);
|
|
246
315
|
} catch (r) {
|
|
247
316
|
return console.error("Dry-run error:", r), e.json({
|
|
@@ -249,18 +318,18 @@ function E(y) {
|
|
|
249
318
|
valid: !1
|
|
250
319
|
}, 400);
|
|
251
320
|
}
|
|
252
|
-
}),
|
|
321
|
+
}), m;
|
|
253
322
|
}
|
|
254
|
-
function
|
|
255
|
-
const
|
|
256
|
-
return
|
|
323
|
+
function M(q, a) {
|
|
324
|
+
const d = E(a);
|
|
325
|
+
return q.route("/", d), q;
|
|
257
326
|
}
|
|
258
|
-
function
|
|
259
|
-
const a = new
|
|
260
|
-
return
|
|
327
|
+
function R(q) {
|
|
328
|
+
const a = new D();
|
|
329
|
+
return M(a, q);
|
|
261
330
|
}
|
|
262
331
|
export {
|
|
263
|
-
|
|
332
|
+
R as createCubeApp,
|
|
264
333
|
E as createCubeRoutes,
|
|
265
|
-
|
|
334
|
+
M as mountCubeRoutes
|
|
266
335
|
};
|
|
@@ -3,13 +3,14 @@ export interface ModalProps {
|
|
|
3
3
|
isOpen: boolean;
|
|
4
4
|
onClose: () => void;
|
|
5
5
|
title?: string;
|
|
6
|
-
size?: 'sm' | 'md' | 'lg' | 'xl' | 'full';
|
|
6
|
+
size?: 'sm' | 'md' | 'lg' | 'xl' | 'full' | 'fullscreen';
|
|
7
7
|
closeOnBackdropClick?: boolean;
|
|
8
8
|
closeOnEscape?: boolean;
|
|
9
9
|
showCloseButton?: boolean;
|
|
10
10
|
className?: string;
|
|
11
11
|
children: React.ReactNode;
|
|
12
12
|
footer?: React.ReactNode;
|
|
13
|
+
noPadding?: boolean;
|
|
13
14
|
}
|
|
14
15
|
declare const Modal: React.FC<ModalProps>;
|
|
15
16
|
export default Modal;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
import { ApiConfig } from './types';
|
|
3
|
+
interface SetupPanelProps {
|
|
4
|
+
isOpen: boolean;
|
|
5
|
+
onToggle: () => void;
|
|
6
|
+
config: ApiConfig;
|
|
7
|
+
onConfigChange: (config: ApiConfig) => void;
|
|
8
|
+
onReset: () => void;
|
|
9
|
+
}
|
|
10
|
+
declare const SetupPanel: React.FC<SetupPanelProps>;
|
|
11
|
+
export default SetupPanel;
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { CubeQuery } from '../../types';
|
|
2
|
+
export interface MetaField {
|
|
3
|
+
name: string;
|
|
4
|
+
title: string;
|
|
5
|
+
shortTitle: string;
|
|
6
|
+
type: string;
|
|
7
|
+
description?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface MetaCube {
|
|
10
|
+
name: string;
|
|
11
|
+
title: string;
|
|
12
|
+
description: string;
|
|
13
|
+
measures: MetaField[];
|
|
14
|
+
dimensions: MetaField[];
|
|
15
|
+
segments: MetaField[];
|
|
16
|
+
}
|
|
17
|
+
export interface MetaResponse {
|
|
18
|
+
cubes: MetaCube[];
|
|
19
|
+
}
|
|
20
|
+
export type ValidationStatus = 'idle' | 'validating' | 'valid' | 'invalid';
|
|
21
|
+
export type ExecutionStatus = 'idle' | 'loading' | 'success' | 'error';
|
|
22
|
+
export type SchemaStatus = 'idle' | 'loading' | 'success' | 'error';
|
|
23
|
+
export interface QueryBuilderState {
|
|
24
|
+
query: CubeQuery;
|
|
25
|
+
schema: MetaResponse | null;
|
|
26
|
+
schemaStatus: SchemaStatus;
|
|
27
|
+
schemaError: string | null;
|
|
28
|
+
validationStatus: ValidationStatus;
|
|
29
|
+
validationError: string | null;
|
|
30
|
+
validationSql: {
|
|
31
|
+
sql: string[];
|
|
32
|
+
params: any[];
|
|
33
|
+
} | null;
|
|
34
|
+
executionStatus: ExecutionStatus;
|
|
35
|
+
executionResults: any[] | null;
|
|
36
|
+
executionError: string | null;
|
|
37
|
+
totalRowCount: number | null;
|
|
38
|
+
totalRowCountStatus: 'idle' | 'loading' | 'success' | 'error';
|
|
39
|
+
}
|
|
40
|
+
export interface ValidationResult {
|
|
41
|
+
valid?: boolean;
|
|
42
|
+
error?: string;
|
|
43
|
+
query?: CubeQuery;
|
|
44
|
+
sql?: {
|
|
45
|
+
sql: string[];
|
|
46
|
+
params: any[];
|
|
47
|
+
};
|
|
48
|
+
queryType?: string;
|
|
49
|
+
normalizedQueries?: any[];
|
|
50
|
+
queryOrder?: string[];
|
|
51
|
+
transformedQueries?: any[];
|
|
52
|
+
pivotQuery?: any;
|
|
53
|
+
complexity?: string;
|
|
54
|
+
cubesUsed?: string[];
|
|
55
|
+
joinType?: string;
|
|
56
|
+
}
|
|
57
|
+
export interface ApiConfig {
|
|
58
|
+
baseApiUrl: string;
|
|
59
|
+
apiToken: string;
|
|
60
|
+
}
|
|
61
|
+
export interface QueryBuilderProps {
|
|
62
|
+
baseUrl: string;
|
|
63
|
+
className?: string;
|
|
64
|
+
initialQuery?: CubeQuery;
|
|
65
|
+
disableLocalStorage?: boolean;
|
|
66
|
+
hideSettings?: boolean;
|
|
67
|
+
}
|
|
68
|
+
export interface QueryBuilderRef {
|
|
69
|
+
getCurrentQuery: () => CubeQuery;
|
|
70
|
+
getValidationState: () => {
|
|
71
|
+
status: ValidationStatus;
|
|
72
|
+
result?: ValidationResult;
|
|
73
|
+
};
|
|
74
|
+
getValidationResult: () => ValidationResult | null;
|
|
75
|
+
}
|
|
76
|
+
export interface CubeMetaExplorerProps {
|
|
77
|
+
schema: MetaResponse | null;
|
|
78
|
+
schemaStatus: SchemaStatus;
|
|
79
|
+
schemaError: string | null;
|
|
80
|
+
selectedFields: {
|
|
81
|
+
measures: string[];
|
|
82
|
+
dimensions: string[];
|
|
83
|
+
timeDimensions: string[];
|
|
84
|
+
};
|
|
85
|
+
onFieldSelect: (fieldName: string, fieldType: 'measures' | 'dimensions' | 'timeDimensions') => void;
|
|
86
|
+
onFieldDeselect: (fieldName: string, fieldType: 'measures' | 'dimensions' | 'timeDimensions') => void;
|
|
87
|
+
onRetrySchema?: () => void;
|
|
88
|
+
onOpenSettings?: () => void;
|
|
89
|
+
}
|
|
90
|
+
export interface QueryPanelProps {
|
|
91
|
+
query: CubeQuery;
|
|
92
|
+
validationStatus: ValidationStatus;
|
|
93
|
+
validationError: string | null;
|
|
94
|
+
validationSql: {
|
|
95
|
+
sql: string[];
|
|
96
|
+
params: any[];
|
|
97
|
+
} | null;
|
|
98
|
+
onValidate: () => void;
|
|
99
|
+
onExecute: () => void;
|
|
100
|
+
onRemoveField: (fieldName: string, fieldType: 'measures' | 'dimensions' | 'timeDimensions') => void;
|
|
101
|
+
onTimeDimensionGranularityChange: (dimensionName: string, granularity: string) => void;
|
|
102
|
+
onClearQuery?: () => void;
|
|
103
|
+
showSettings?: boolean;
|
|
104
|
+
onSettingsClick?: () => void;
|
|
105
|
+
}
|
|
106
|
+
export interface ResultsPanelProps {
|
|
107
|
+
executionStatus: ExecutionStatus;
|
|
108
|
+
executionResults: any[] | null;
|
|
109
|
+
executionError: string | null;
|
|
110
|
+
query: CubeQuery;
|
|
111
|
+
displayLimit?: number;
|
|
112
|
+
onDisplayLimitChange?: (limit: number) => void;
|
|
113
|
+
totalRowCount?: number | null;
|
|
114
|
+
totalRowCountStatus?: 'idle' | 'loading' | 'success' | 'error';
|
|
115
|
+
}
|
|
116
|
+
export declare const TIME_GRANULARITIES: readonly [{
|
|
117
|
+
readonly value: "day";
|
|
118
|
+
readonly label: "Day";
|
|
119
|
+
}, {
|
|
120
|
+
readonly value: "week";
|
|
121
|
+
readonly label: "Week";
|
|
122
|
+
}, {
|
|
123
|
+
readonly value: "month";
|
|
124
|
+
readonly label: "Month";
|
|
125
|
+
}, {
|
|
126
|
+
readonly value: "quarter";
|
|
127
|
+
readonly label: "Quarter";
|
|
128
|
+
}, {
|
|
129
|
+
readonly value: "year";
|
|
130
|
+
readonly label: "Year";
|
|
131
|
+
}];
|
|
132
|
+
export type TimeGranularity = typeof TIME_GRANULARITIES[number]['value'];
|