drizzle-cube 0.1.8 → 0.1.10
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/hono/index.js +39 -31
- package/dist/client/components/Modal.d.ts +1 -1
- package/dist/client/components/QueryBuilder/FilterBuilder.d.ts +4 -0
- package/dist/client/components/QueryBuilder/FilterGroup.d.ts +4 -0
- package/dist/client/components/QueryBuilder/FilterItem.d.ts +4 -0
- package/dist/client/components/QueryBuilder/FilterValueSelector.d.ts +4 -0
- package/dist/client/components/QueryBuilder/types.d.ts +43 -1
- package/dist/client/components/QueryBuilder/utils.d.ts +76 -1
- package/dist/client/hooks/useCubeQuery.d.ts +1 -0
- package/dist/client/hooks/useDebounce.d.ts +12 -0
- package/dist/client/hooks/useFilterValues.d.ts +16 -0
- package/dist/client/index.js +9382 -8379
- package/dist/client/styles.css +1 -1
- package/dist/client/types.d.ts +12 -5
- package/dist/server/index.d.ts +110 -9
- package/dist/server/index.js +1134 -745
- package/package.json +6 -3
package/dist/server/index.js
CHANGED
|
@@ -1,58 +1,311 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var C = (
|
|
4
|
-
import { sql as
|
|
5
|
-
import { parse as
|
|
6
|
-
|
|
1
|
+
var W = Object.defineProperty;
|
|
2
|
+
var B = (o, e, t) => e in o ? W(o, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : o[e] = t;
|
|
3
|
+
var C = (o, e, t) => B(o, typeof e != "symbol" ? e + "" : e, t);
|
|
4
|
+
import { sql as m, and as h, or as j, gt as N, lt as $, gte as w, lte as D, isNull as _, isNotNull as z, eq as v, count as y, max as Y, min as R, avg as K, sum as J, countDistinct as H, notInArray as V, ne as G, inArray as P } from "drizzle-orm";
|
|
5
|
+
import { parse as Z, stringify as X } from "yaml";
|
|
6
|
+
class O {
|
|
7
|
+
/**
|
|
8
|
+
* Helper method to build pattern for string matching
|
|
9
|
+
* Can be overridden by specific adapters if needed
|
|
10
|
+
*/
|
|
11
|
+
buildPattern(e, t) {
|
|
12
|
+
switch (e) {
|
|
13
|
+
case "contains":
|
|
14
|
+
case "notContains":
|
|
15
|
+
return `%${t}%`;
|
|
16
|
+
case "startsWith":
|
|
17
|
+
return `${t}%`;
|
|
18
|
+
case "endsWith":
|
|
19
|
+
return `%${t}`;
|
|
20
|
+
default:
|
|
21
|
+
return t;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
class q extends O {
|
|
26
|
+
getEngineType() {
|
|
27
|
+
return "postgres";
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Build PostgreSQL time dimension using DATE_TRUNC function
|
|
31
|
+
* Extracted from executor.ts:649-670 and multi-cube-builder.ts:306-320
|
|
32
|
+
*/
|
|
33
|
+
buildTimeDimension(e, t) {
|
|
34
|
+
switch (e) {
|
|
35
|
+
case "year":
|
|
36
|
+
return m`DATE_TRUNC('year', ${t}::timestamp)`;
|
|
37
|
+
case "quarter":
|
|
38
|
+
return m`DATE_TRUNC('quarter', ${t}::timestamp)`;
|
|
39
|
+
case "month":
|
|
40
|
+
return m`DATE_TRUNC('month', ${t}::timestamp)`;
|
|
41
|
+
case "week":
|
|
42
|
+
return m`DATE_TRUNC('week', ${t}::timestamp)`;
|
|
43
|
+
case "day":
|
|
44
|
+
return m`DATE_TRUNC('day', ${t}::timestamp)::timestamp`;
|
|
45
|
+
case "hour":
|
|
46
|
+
return m`DATE_TRUNC('hour', ${t}::timestamp)`;
|
|
47
|
+
case "minute":
|
|
48
|
+
return m`DATE_TRUNC('minute', ${t}::timestamp)`;
|
|
49
|
+
case "second":
|
|
50
|
+
return m`DATE_TRUNC('second', ${t}::timestamp)`;
|
|
51
|
+
default:
|
|
52
|
+
return t;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Build PostgreSQL string matching conditions using ILIKE (case-insensitive)
|
|
57
|
+
* Extracted from executor.ts:807-813 and multi-cube-builder.ts:468-474
|
|
58
|
+
*/
|
|
59
|
+
buildStringCondition(e, t, s) {
|
|
60
|
+
const n = this.buildPattern(t, s);
|
|
61
|
+
switch (t) {
|
|
62
|
+
case "contains":
|
|
63
|
+
return m`${e} ILIKE ${n}`;
|
|
64
|
+
case "notContains":
|
|
65
|
+
return m`${e} NOT ILIKE ${n}`;
|
|
66
|
+
case "startsWith":
|
|
67
|
+
return m`${e} ILIKE ${n}`;
|
|
68
|
+
case "endsWith":
|
|
69
|
+
return m`${e} ILIKE ${n}`;
|
|
70
|
+
default:
|
|
71
|
+
throw new Error(`Unsupported string operator: ${t}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Build PostgreSQL type casting using :: syntax
|
|
76
|
+
* Extracted from various locations where ::timestamp was used
|
|
77
|
+
*/
|
|
78
|
+
castToType(e, t) {
|
|
79
|
+
switch (t) {
|
|
80
|
+
case "timestamp":
|
|
81
|
+
return m`${e}::timestamp`;
|
|
82
|
+
case "decimal":
|
|
83
|
+
return m`${e}::decimal`;
|
|
84
|
+
case "integer":
|
|
85
|
+
return m`${e}::integer`;
|
|
86
|
+
default:
|
|
87
|
+
throw new Error(`Unsupported cast type: ${t}`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Build PostgreSQL COUNT aggregation
|
|
92
|
+
* Extracted from multi-cube-builder.ts:278
|
|
93
|
+
*/
|
|
94
|
+
buildCount(e) {
|
|
95
|
+
return m`COUNT(${e})`;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Build PostgreSQL COUNT DISTINCT aggregation
|
|
99
|
+
* Extracted from multi-cube-builder.ts:280
|
|
100
|
+
*/
|
|
101
|
+
buildCountDistinct(e) {
|
|
102
|
+
return m`COUNT(DISTINCT ${e})`;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Build PostgreSQL SUM aggregation
|
|
106
|
+
* Extracted from multi-cube-builder.ts:282
|
|
107
|
+
*/
|
|
108
|
+
buildSum(e) {
|
|
109
|
+
return m`SUM(${e})`;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Build PostgreSQL AVG aggregation with COALESCE for NULL handling
|
|
113
|
+
* PostgreSQL AVG returns NULL for empty sets, so we use COALESCE for consistent behavior
|
|
114
|
+
* Extracted from multi-cube-builder.ts:284
|
|
115
|
+
*/
|
|
116
|
+
buildAvg(e) {
|
|
117
|
+
return m`COALESCE(AVG(${e}), 0)`;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Build PostgreSQL MIN aggregation
|
|
121
|
+
* Extracted from multi-cube-builder.ts:286
|
|
122
|
+
*/
|
|
123
|
+
buildMin(e) {
|
|
124
|
+
return m`MIN(${e})`;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Build PostgreSQL MAX aggregation
|
|
128
|
+
* Extracted from multi-cube-builder.ts:288
|
|
129
|
+
*/
|
|
130
|
+
buildMax(e) {
|
|
131
|
+
return m`MAX(${e})`;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
class ee extends O {
|
|
135
|
+
getEngineType() {
|
|
136
|
+
return "mysql";
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Build MySQL time dimension using DATE_FORMAT function
|
|
140
|
+
* MySQL equivalent to PostgreSQL's DATE_TRUNC
|
|
141
|
+
*/
|
|
142
|
+
buildTimeDimension(e, t) {
|
|
143
|
+
const s = {
|
|
144
|
+
year: "%Y-01-01 00:00:00",
|
|
145
|
+
quarter: "%Y-%q-01 00:00:00",
|
|
146
|
+
// %q gives quarter (1,2,3,4), but we need to map this properly
|
|
147
|
+
month: "%Y-%m-01 00:00:00",
|
|
148
|
+
week: "%Y-%u-01 00:00:00",
|
|
149
|
+
// %u gives week of year
|
|
150
|
+
day: "%Y-%m-%d 00:00:00",
|
|
151
|
+
hour: "%Y-%m-%d %H:00:00",
|
|
152
|
+
minute: "%Y-%m-%d %H:%i:00",
|
|
153
|
+
second: "%Y-%m-%d %H:%i:%s"
|
|
154
|
+
};
|
|
155
|
+
switch (e) {
|
|
156
|
+
case "quarter":
|
|
157
|
+
return m`DATE_ADD(MAKEDATE(YEAR(${t}), 1), INTERVAL (QUARTER(${t}) - 1) * 3 MONTH)`;
|
|
158
|
+
case "week":
|
|
159
|
+
return m`DATE_SUB(${t}, INTERVAL WEEKDAY(${t}) DAY)`;
|
|
160
|
+
default:
|
|
161
|
+
const n = s[e];
|
|
162
|
+
return n ? m`STR_TO_DATE(DATE_FORMAT(${t}, ${n}), '%Y-%m-%d %H:%i:%s')` : t;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Build MySQL string matching conditions using LIKE
|
|
167
|
+
* MySQL LIKE is case-insensitive by default (depending on collation)
|
|
168
|
+
* For guaranteed case-insensitive matching, we use LOWER() functions
|
|
169
|
+
*/
|
|
170
|
+
buildStringCondition(e, t, s) {
|
|
171
|
+
const n = this.buildPattern(t, s.toLowerCase());
|
|
172
|
+
switch (t) {
|
|
173
|
+
case "contains":
|
|
174
|
+
return m`LOWER(${e}) LIKE ${n}`;
|
|
175
|
+
case "notContains":
|
|
176
|
+
return m`LOWER(${e}) NOT LIKE ${n}`;
|
|
177
|
+
case "startsWith":
|
|
178
|
+
return m`LOWER(${e}) LIKE ${n}`;
|
|
179
|
+
case "endsWith":
|
|
180
|
+
return m`LOWER(${e}) LIKE ${n}`;
|
|
181
|
+
default:
|
|
182
|
+
throw new Error(`Unsupported string operator: ${t}`);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Build MySQL type casting using CAST() function
|
|
187
|
+
* MySQL equivalent to PostgreSQL's :: casting syntax
|
|
188
|
+
*/
|
|
189
|
+
castToType(e, t) {
|
|
190
|
+
switch (t) {
|
|
191
|
+
case "timestamp":
|
|
192
|
+
return m`CAST(${e} AS DATETIME)`;
|
|
193
|
+
case "decimal":
|
|
194
|
+
return m`CAST(${e} AS DECIMAL(10,2))`;
|
|
195
|
+
case "integer":
|
|
196
|
+
return m`CAST(${e} AS SIGNED INTEGER)`;
|
|
197
|
+
default:
|
|
198
|
+
throw new Error(`Unsupported cast type: ${t}`);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Build MySQL COUNT aggregation
|
|
203
|
+
* Standard SQL COUNT function
|
|
204
|
+
*/
|
|
205
|
+
buildCount(e) {
|
|
206
|
+
return m`COUNT(${e})`;
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Build MySQL COUNT DISTINCT aggregation
|
|
210
|
+
* Standard SQL COUNT DISTINCT function
|
|
211
|
+
*/
|
|
212
|
+
buildCountDistinct(e) {
|
|
213
|
+
return m`COUNT(DISTINCT ${e})`;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Build MySQL SUM aggregation
|
|
217
|
+
* Standard SQL SUM function
|
|
218
|
+
*/
|
|
219
|
+
buildSum(e) {
|
|
220
|
+
return m`SUM(${e})`;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Build MySQL AVG aggregation with IFNULL for NULL handling
|
|
224
|
+
* MySQL AVG returns NULL for empty sets, using IFNULL for consistency
|
|
225
|
+
*/
|
|
226
|
+
buildAvg(e) {
|
|
227
|
+
return m`IFNULL(AVG(${e}), 0)`;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Build MySQL MIN aggregation
|
|
231
|
+
* Standard SQL MIN function
|
|
232
|
+
*/
|
|
233
|
+
buildMin(e) {
|
|
234
|
+
return m`MIN(${e})`;
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Build MySQL MAX aggregation
|
|
238
|
+
* Standard SQL MAX function
|
|
239
|
+
*/
|
|
240
|
+
buildMax(e) {
|
|
241
|
+
return m`MAX(${e})`;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
function te(o) {
|
|
245
|
+
switch (o) {
|
|
246
|
+
case "postgres":
|
|
247
|
+
return new q();
|
|
248
|
+
case "mysql":
|
|
249
|
+
return new ee();
|
|
250
|
+
case "sqlite":
|
|
251
|
+
throw new Error("SQLite adapter not yet implemented");
|
|
252
|
+
default:
|
|
253
|
+
throw new Error(`Unsupported database engine: ${o}`);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
function $e(o, e) {
|
|
7
257
|
return {
|
|
8
258
|
...e,
|
|
9
259
|
name: e.name
|
|
10
260
|
};
|
|
11
261
|
}
|
|
12
|
-
class
|
|
13
|
-
constructor(e, t) {
|
|
262
|
+
class S {
|
|
263
|
+
constructor(e, t, s) {
|
|
264
|
+
C(this, "databaseAdapter");
|
|
14
265
|
this.db = e, this.schema = t;
|
|
266
|
+
const n = s || this.getEngineType();
|
|
267
|
+
this.databaseAdapter = te(n);
|
|
15
268
|
}
|
|
16
269
|
}
|
|
17
|
-
class
|
|
270
|
+
class ne extends S {
|
|
18
271
|
async execute(e, t) {
|
|
19
272
|
if (e && typeof e == "object") {
|
|
20
273
|
if (typeof e.execute == "function") {
|
|
21
274
|
const n = await e.execute();
|
|
22
|
-
return Array.isArray(n) ? n.map((
|
|
275
|
+
return Array.isArray(n) ? n.map((r) => this.convertNumericFields(r, t)) : n;
|
|
23
276
|
}
|
|
24
277
|
if (this.db && typeof this.db.execute == "function")
|
|
25
278
|
try {
|
|
26
279
|
const n = await this.db.execute(e);
|
|
27
|
-
return Array.isArray(n) ? n.map((
|
|
280
|
+
return Array.isArray(n) ? n.map((r) => this.convertNumericFields(r, t)) : n;
|
|
28
281
|
} catch (n) {
|
|
29
282
|
if (typeof e.getSQL == "function") {
|
|
30
|
-
const
|
|
31
|
-
return Array.isArray(a) ? a.map((
|
|
283
|
+
const r = e.getSQL(), a = await this.db.execute(r);
|
|
284
|
+
return Array.isArray(a) ? a.map((i) => this.convertNumericFields(i, t)) : a;
|
|
32
285
|
}
|
|
33
286
|
throw n;
|
|
34
287
|
}
|
|
35
288
|
}
|
|
36
289
|
if (!this.db.execute)
|
|
37
290
|
throw new Error("PostgreSQL database instance must have an execute method");
|
|
38
|
-
const
|
|
39
|
-
return Array.isArray(
|
|
291
|
+
const s = await this.db.execute(e);
|
|
292
|
+
return Array.isArray(s) ? s.map((n) => this.convertNumericFields(n, t)) : s;
|
|
40
293
|
}
|
|
41
294
|
/**
|
|
42
295
|
* Convert numeric string fields to numbers (only for measure fields)
|
|
43
296
|
*/
|
|
44
297
|
convertNumericFields(e, t) {
|
|
45
298
|
if (!e || typeof e != "object") return e;
|
|
46
|
-
const
|
|
47
|
-
for (const [n,
|
|
48
|
-
t && t.includes(n) ?
|
|
49
|
-
return
|
|
299
|
+
const s = {};
|
|
300
|
+
for (const [n, r] of Object.entries(e))
|
|
301
|
+
t && t.includes(n) ? s[n] = this.coerceToNumber(r) : s[n] = r;
|
|
302
|
+
return s;
|
|
50
303
|
}
|
|
51
304
|
/**
|
|
52
305
|
* Coerce a value to a number if it represents a numeric type
|
|
53
306
|
*/
|
|
54
307
|
coerceToNumber(e) {
|
|
55
|
-
var t,
|
|
308
|
+
var t, s;
|
|
56
309
|
if (e == null || typeof e == "number") return e;
|
|
57
310
|
if (typeof e == "bigint") return Number(e);
|
|
58
311
|
if (e && typeof e == "object") {
|
|
@@ -61,7 +314,7 @@ class X extends x {
|
|
|
61
314
|
if (/^-?\d+(\.\d+)?$/.test(n))
|
|
62
315
|
return n.includes(".") ? parseFloat(n) : parseInt(n, 10);
|
|
63
316
|
}
|
|
64
|
-
if (((t = e.constructor) == null ? void 0 : t.name) === "Numeric" || ((
|
|
317
|
+
if (((t = e.constructor) == null ? void 0 : t.name) === "Numeric" || ((s = e.constructor) == null ? void 0 : s.name) === "Decimal" || "digits" in e || "sign" in e) {
|
|
65
318
|
const n = e.toString();
|
|
66
319
|
return parseFloat(n);
|
|
67
320
|
}
|
|
@@ -79,23 +332,23 @@ class X extends x {
|
|
|
79
332
|
return "postgres";
|
|
80
333
|
}
|
|
81
334
|
}
|
|
82
|
-
class
|
|
335
|
+
class se extends S {
|
|
83
336
|
async execute(e, t) {
|
|
84
337
|
if (e && typeof e == "object" && typeof e.execute == "function") {
|
|
85
|
-
const
|
|
86
|
-
return Array.isArray(
|
|
338
|
+
const s = await e.execute();
|
|
339
|
+
return Array.isArray(s) ? s.map((n) => this.convertNumericFields(n, t)) : s;
|
|
87
340
|
}
|
|
88
341
|
try {
|
|
89
342
|
if (this.db.all) {
|
|
90
|
-
const
|
|
91
|
-
return Array.isArray(
|
|
343
|
+
const s = this.db.all(e);
|
|
344
|
+
return Array.isArray(s) ? s.map((n) => this.convertNumericFields(n, t)) : s;
|
|
92
345
|
} else {
|
|
93
346
|
if (this.db.run)
|
|
94
347
|
return this.db.run(e);
|
|
95
348
|
throw new Error("SQLite database instance must have an all() or run() method");
|
|
96
349
|
}
|
|
97
|
-
} catch (
|
|
98
|
-
throw new Error(`SQLite execution failed: ${
|
|
350
|
+
} catch (s) {
|
|
351
|
+
throw new Error(`SQLite execution failed: ${s instanceof Error ? s.message : "Unknown error"}`);
|
|
99
352
|
}
|
|
100
353
|
}
|
|
101
354
|
/**
|
|
@@ -103,10 +356,10 @@ class q extends x {
|
|
|
103
356
|
*/
|
|
104
357
|
convertNumericFields(e, t) {
|
|
105
358
|
if (!e || typeof e != "object") return e;
|
|
106
|
-
const
|
|
107
|
-
for (const [n,
|
|
108
|
-
t && t.includes(n) ?
|
|
109
|
-
return
|
|
359
|
+
const s = {};
|
|
360
|
+
for (const [n, r] of Object.entries(e))
|
|
361
|
+
t && t.includes(n) ? s[n] = this.coerceToNumber(r) : s[n] = r;
|
|
362
|
+
return s;
|
|
110
363
|
}
|
|
111
364
|
/**
|
|
112
365
|
* Coerce a value to a number if it represents a numeric type
|
|
@@ -125,26 +378,26 @@ class q extends x {
|
|
|
125
378
|
return "sqlite";
|
|
126
379
|
}
|
|
127
380
|
}
|
|
128
|
-
class
|
|
381
|
+
class ie extends S {
|
|
129
382
|
async execute(e, t) {
|
|
130
383
|
if (e && typeof e == "object" && typeof e.execute == "function") {
|
|
131
384
|
const n = await e.execute();
|
|
132
|
-
return Array.isArray(n) ? n.map((
|
|
385
|
+
return Array.isArray(n) ? n.map((r) => this.convertNumericFields(r, t)) : n;
|
|
133
386
|
}
|
|
134
387
|
if (!this.db.execute)
|
|
135
388
|
throw new Error("MySQL database instance must have an execute method");
|
|
136
|
-
const
|
|
137
|
-
return Array.isArray(
|
|
389
|
+
const s = await this.db.execute(e);
|
|
390
|
+
return Array.isArray(s) ? s.map((n) => this.convertNumericFields(n, t)) : s;
|
|
138
391
|
}
|
|
139
392
|
/**
|
|
140
|
-
* Convert numeric string fields to numbers (
|
|
393
|
+
* Convert numeric string fields to numbers (measure fields + numeric dimensions)
|
|
141
394
|
*/
|
|
142
395
|
convertNumericFields(e, t) {
|
|
143
396
|
if (!e || typeof e != "object") return e;
|
|
144
|
-
const
|
|
145
|
-
for (const [n,
|
|
146
|
-
t && t.includes(n) ?
|
|
147
|
-
return
|
|
397
|
+
const s = {};
|
|
398
|
+
for (const [n, r] of Object.entries(e))
|
|
399
|
+
t && t.includes(n) ? s[n] = this.coerceToNumber(r) : s[n] = r;
|
|
400
|
+
return s;
|
|
148
401
|
}
|
|
149
402
|
/**
|
|
150
403
|
* Coerce a value to a number if it represents a numeric type
|
|
@@ -163,66 +416,75 @@ class ee extends x {
|
|
|
163
416
|
return "mysql";
|
|
164
417
|
}
|
|
165
418
|
}
|
|
166
|
-
function
|
|
167
|
-
return new
|
|
419
|
+
function F(o, e) {
|
|
420
|
+
return new ne(o, e, "postgres");
|
|
168
421
|
}
|
|
169
|
-
function M(
|
|
170
|
-
return new
|
|
422
|
+
function M(o, e) {
|
|
423
|
+
return new se(o, e, "sqlite");
|
|
171
424
|
}
|
|
172
|
-
function
|
|
173
|
-
return new
|
|
425
|
+
function re(o, e) {
|
|
426
|
+
return new ie(o, e, "mysql");
|
|
174
427
|
}
|
|
175
|
-
function
|
|
428
|
+
function L(o, e, t) {
|
|
176
429
|
if (t)
|
|
177
430
|
switch (t) {
|
|
178
431
|
case "postgres":
|
|
179
|
-
return
|
|
432
|
+
return F(o, e);
|
|
180
433
|
case "mysql":
|
|
181
|
-
return
|
|
434
|
+
return re(o, e);
|
|
182
435
|
case "sqlite":
|
|
183
|
-
return M(
|
|
436
|
+
return M(o, e);
|
|
184
437
|
}
|
|
185
|
-
if (
|
|
186
|
-
return M(
|
|
187
|
-
if (
|
|
188
|
-
return
|
|
438
|
+
if (o.all && o.run)
|
|
439
|
+
return M(o, e);
|
|
440
|
+
if (o.execute)
|
|
441
|
+
return F(o, e);
|
|
189
442
|
throw new Error("Unable to determine database engine type. Please specify engineType parameter.");
|
|
190
443
|
}
|
|
191
|
-
function
|
|
444
|
+
function Ee(o, e) {
|
|
192
445
|
return {
|
|
193
|
-
name:
|
|
446
|
+
name: o,
|
|
194
447
|
...e
|
|
195
448
|
};
|
|
196
449
|
}
|
|
197
|
-
function b(
|
|
198
|
-
return typeof
|
|
450
|
+
function b(o, e) {
|
|
451
|
+
return typeof o == "function" ? o(e) : o;
|
|
199
452
|
}
|
|
200
|
-
function
|
|
453
|
+
function oe(o, e, t) {
|
|
201
454
|
return {
|
|
202
|
-
...
|
|
455
|
+
...o,
|
|
203
456
|
cubes: e,
|
|
204
457
|
currentCube: t
|
|
205
458
|
};
|
|
206
459
|
}
|
|
207
|
-
class
|
|
460
|
+
class ae {
|
|
461
|
+
constructor(e) {
|
|
462
|
+
this.databaseAdapter = e;
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* Set the database adapter (for use when not provided in constructor)
|
|
466
|
+
*/
|
|
467
|
+
setDatabaseAdapter(e) {
|
|
468
|
+
this.databaseAdapter = e;
|
|
469
|
+
}
|
|
208
470
|
/**
|
|
209
471
|
* Analyze a semantic query to determine which cubes are involved
|
|
210
472
|
*/
|
|
211
473
|
analyzeCubeUsage(e) {
|
|
212
474
|
const t = /* @__PURE__ */ new Set();
|
|
213
475
|
if (e.measures)
|
|
214
|
-
for (const
|
|
215
|
-
const [n] =
|
|
476
|
+
for (const s of e.measures) {
|
|
477
|
+
const [n] = s.split(".");
|
|
216
478
|
t.add(n);
|
|
217
479
|
}
|
|
218
480
|
if (e.dimensions)
|
|
219
|
-
for (const
|
|
220
|
-
const [n] =
|
|
481
|
+
for (const s of e.dimensions) {
|
|
482
|
+
const [n] = s.split(".");
|
|
221
483
|
t.add(n);
|
|
222
484
|
}
|
|
223
485
|
if (e.timeDimensions)
|
|
224
|
-
for (const
|
|
225
|
-
const [n] =
|
|
486
|
+
for (const s of e.timeDimensions) {
|
|
487
|
+
const [n] = s.dimension.split(".");
|
|
226
488
|
t.add(n);
|
|
227
489
|
}
|
|
228
490
|
return t;
|
|
@@ -230,20 +492,20 @@ class ie {
|
|
|
230
492
|
/**
|
|
231
493
|
* Build a multi-cube query plan
|
|
232
494
|
*/
|
|
233
|
-
buildMultiCubeQueryPlan(e, t,
|
|
234
|
-
const n = this.analyzeCubeUsage(t),
|
|
235
|
-
if (
|
|
495
|
+
buildMultiCubeQueryPlan(e, t, s) {
|
|
496
|
+
const n = this.analyzeCubeUsage(t), r = Array.from(n);
|
|
497
|
+
if (r.length === 1)
|
|
236
498
|
throw new Error("Single cube query should use QueryExecutor directly");
|
|
237
|
-
const a = this.choosePrimaryCube(
|
|
238
|
-
if (!
|
|
499
|
+
const a = this.choosePrimaryCube(r, t), i = e.get(a);
|
|
500
|
+
if (!i)
|
|
239
501
|
throw new Error(`Primary cube '${a}' not found`);
|
|
240
|
-
const c = this.buildJoinPlan(e,
|
|
502
|
+
const c = this.buildJoinPlan(e, i, r, s), u = this.buildMultiCubeSelections(e, t, s.securityContext), l = this.buildMultiCubeWhereConditions(e, t, s), d = this.buildMultiCubeGroupByFields(e, t, s.securityContext);
|
|
241
503
|
return {
|
|
242
|
-
primaryCube:
|
|
504
|
+
primaryCube: i,
|
|
243
505
|
joinCubes: c,
|
|
244
|
-
selections:
|
|
245
|
-
whereConditions:
|
|
246
|
-
groupByFields:
|
|
506
|
+
selections: u,
|
|
507
|
+
whereConditions: l,
|
|
508
|
+
groupByFields: d
|
|
247
509
|
};
|
|
248
510
|
}
|
|
249
511
|
/**
|
|
@@ -251,85 +513,79 @@ class ie {
|
|
|
251
513
|
*/
|
|
252
514
|
choosePrimaryCube(e, t) {
|
|
253
515
|
if (t.measures && t.measures.length > 0) {
|
|
254
|
-
const [
|
|
255
|
-
return
|
|
516
|
+
const [s] = t.measures[0].split(".");
|
|
517
|
+
return s;
|
|
256
518
|
}
|
|
257
519
|
if (t.dimensions && t.dimensions.length > 0) {
|
|
258
|
-
const [
|
|
259
|
-
return
|
|
520
|
+
const [s] = t.dimensions[0].split(".");
|
|
521
|
+
return s;
|
|
260
522
|
}
|
|
261
523
|
return e[0];
|
|
262
524
|
}
|
|
263
525
|
/**
|
|
264
526
|
* Build join plan for multi-cube query
|
|
265
527
|
*/
|
|
266
|
-
buildJoinPlan(e, t,
|
|
267
|
-
var
|
|
268
|
-
const
|
|
528
|
+
buildJoinPlan(e, t, s, n) {
|
|
529
|
+
var i;
|
|
530
|
+
const r = [], a = s.filter((c) => c !== t.name);
|
|
269
531
|
for (const c of a) {
|
|
270
|
-
const
|
|
271
|
-
if (!l)
|
|
272
|
-
throw new Error(`Cube '${c}' not found`);
|
|
273
|
-
const u = (r = t.joins) == null ? void 0 : r[c];
|
|
532
|
+
const u = e.get(c);
|
|
274
533
|
if (!u)
|
|
534
|
+
throw new Error(`Cube '${c}' not found`);
|
|
535
|
+
const l = (i = t.joins) == null ? void 0 : i[c];
|
|
536
|
+
if (!l)
|
|
275
537
|
throw new Error(`No join definition found from '${t.name}' to '${c}'`);
|
|
276
|
-
const
|
|
277
|
-
|
|
278
|
-
db: {},
|
|
279
|
-
// Will be filled in during execution
|
|
280
|
-
schema: {},
|
|
281
|
-
// Will be filled in during execution
|
|
282
|
-
securityContext: n
|
|
283
|
-
},
|
|
538
|
+
const d = oe(
|
|
539
|
+
n,
|
|
284
540
|
e,
|
|
285
|
-
|
|
286
|
-
),
|
|
287
|
-
|
|
288
|
-
cube:
|
|
541
|
+
u
|
|
542
|
+
), f = l.condition(d);
|
|
543
|
+
r.push({
|
|
544
|
+
cube: u,
|
|
289
545
|
alias: `${c.toLowerCase()}_cube`,
|
|
290
|
-
joinType:
|
|
291
|
-
joinCondition:
|
|
546
|
+
joinType: l.type || "left",
|
|
547
|
+
joinCondition: f
|
|
292
548
|
});
|
|
293
549
|
}
|
|
294
|
-
return
|
|
550
|
+
return r;
|
|
295
551
|
}
|
|
296
552
|
/**
|
|
297
553
|
* Build selections across multiple cubes
|
|
298
554
|
*/
|
|
299
|
-
buildMultiCubeSelections(e, t,
|
|
300
|
-
const n = {},
|
|
555
|
+
buildMultiCubeSelections(e, t, s) {
|
|
556
|
+
const n = {}, r = {
|
|
301
557
|
db: {},
|
|
302
558
|
// Filled during execution
|
|
303
559
|
schema: {},
|
|
304
560
|
// Filled during execution
|
|
305
|
-
securityContext:
|
|
561
|
+
securityContext: s
|
|
306
562
|
};
|
|
307
563
|
if (t.dimensions)
|
|
308
564
|
for (const a of t.dimensions) {
|
|
309
|
-
const [
|
|
310
|
-
if (
|
|
311
|
-
const
|
|
312
|
-
n[a] =
|
|
565
|
+
const [i, c] = a.split("."), u = e.get(i);
|
|
566
|
+
if (u && u.dimensions[c]) {
|
|
567
|
+
const l = u.dimensions[c], d = b(l.sql, r);
|
|
568
|
+
n[a] = m`${d}`.as(a);
|
|
313
569
|
}
|
|
314
570
|
}
|
|
315
571
|
if (t.measures)
|
|
316
572
|
for (const a of t.measures) {
|
|
317
|
-
const [
|
|
318
|
-
if (
|
|
319
|
-
const
|
|
320
|
-
n[a] =
|
|
573
|
+
const [i, c] = a.split("."), u = e.get(i);
|
|
574
|
+
if (u && u.measures[c]) {
|
|
575
|
+
const l = u.measures[c], d = this.buildMeasureExpression(l, r);
|
|
576
|
+
n[a] = m`${d}`.as(a);
|
|
321
577
|
}
|
|
322
578
|
}
|
|
323
579
|
if (t.timeDimensions)
|
|
324
580
|
for (const a of t.timeDimensions) {
|
|
325
|
-
const [
|
|
326
|
-
if (
|
|
327
|
-
const
|
|
328
|
-
|
|
581
|
+
const [i, c] = a.dimension.split("."), u = e.get(i);
|
|
582
|
+
if (u && u.dimensions[c]) {
|
|
583
|
+
const l = u.dimensions[c], d = this.buildTimeDimensionExpression(
|
|
584
|
+
l.sql,
|
|
329
585
|
a.granularity,
|
|
330
|
-
|
|
586
|
+
r
|
|
331
587
|
);
|
|
332
|
-
n[a.dimension] =
|
|
588
|
+
n[a.dimension] = m`${d}`.as(a.dimension);
|
|
333
589
|
}
|
|
334
590
|
}
|
|
335
591
|
return n;
|
|
@@ -338,149 +594,272 @@ class ie {
|
|
|
338
594
|
* Build measure expression with aggregation (similar to single-cube approach)
|
|
339
595
|
*/
|
|
340
596
|
buildMeasureExpression(e, t) {
|
|
341
|
-
let
|
|
597
|
+
let s = b(e.sql, t);
|
|
342
598
|
if (e.filters && e.filters.length > 0) {
|
|
343
|
-
const n = e.filters.map((
|
|
344
|
-
|
|
599
|
+
const n = e.filters.map((r) => r(t));
|
|
600
|
+
s = m`CASE WHEN ${h(...n)} THEN ${s} END`;
|
|
345
601
|
}
|
|
602
|
+
if (!this.databaseAdapter)
|
|
603
|
+
throw new Error("DatabaseAdapter is required for measure aggregation");
|
|
346
604
|
switch (e.type) {
|
|
347
605
|
case "count":
|
|
348
|
-
return
|
|
606
|
+
return this.databaseAdapter.buildCount(s);
|
|
349
607
|
case "countDistinct":
|
|
350
|
-
return
|
|
608
|
+
return this.databaseAdapter.buildCountDistinct(s);
|
|
351
609
|
case "sum":
|
|
352
|
-
return
|
|
610
|
+
return this.databaseAdapter.buildSum(s);
|
|
353
611
|
case "avg":
|
|
354
|
-
return
|
|
612
|
+
return this.databaseAdapter.buildAvg(s);
|
|
355
613
|
case "min":
|
|
356
|
-
return
|
|
614
|
+
return this.databaseAdapter.buildMin(s);
|
|
357
615
|
case "max":
|
|
358
|
-
return
|
|
616
|
+
return this.databaseAdapter.buildMax(s);
|
|
359
617
|
case "number":
|
|
360
|
-
return
|
|
618
|
+
return s;
|
|
361
619
|
default:
|
|
362
|
-
return
|
|
620
|
+
return this.databaseAdapter.buildCount(s);
|
|
363
621
|
}
|
|
364
622
|
}
|
|
365
623
|
/**
|
|
366
624
|
* Build time dimension expression (similar to single-cube approach)
|
|
367
625
|
*/
|
|
368
|
-
buildTimeDimensionExpression(e, t,
|
|
369
|
-
const n = b(e,
|
|
626
|
+
buildTimeDimensionExpression(e, t, s) {
|
|
627
|
+
const n = b(e, s);
|
|
370
628
|
if (!t)
|
|
371
629
|
return n;
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
case "quarter":
|
|
376
|
-
return f`DATE_TRUNC('quarter', ${n}::timestamp)`;
|
|
377
|
-
case "month":
|
|
378
|
-
return f`DATE_TRUNC('month', ${n}::timestamp)`;
|
|
379
|
-
case "week":
|
|
380
|
-
return f`DATE_TRUNC('week', ${n}::timestamp)`;
|
|
381
|
-
case "day":
|
|
382
|
-
return f`DATE_TRUNC('day', ${n}::timestamp)`;
|
|
383
|
-
case "hour":
|
|
384
|
-
return f`DATE_TRUNC('hour', ${n}::timestamp)`;
|
|
385
|
-
case "minute":
|
|
386
|
-
return f`DATE_TRUNC('minute', ${n}::timestamp)`;
|
|
387
|
-
case "second":
|
|
388
|
-
return f`DATE_TRUNC('second', ${n}::timestamp)`;
|
|
389
|
-
default:
|
|
390
|
-
return n;
|
|
391
|
-
}
|
|
630
|
+
if (!this.databaseAdapter)
|
|
631
|
+
throw new Error("DatabaseAdapter is required for time dimension building");
|
|
632
|
+
return this.databaseAdapter.buildTimeDimension(t, n);
|
|
392
633
|
}
|
|
393
634
|
/**
|
|
394
635
|
* Build WHERE conditions for multi-cube query
|
|
395
636
|
*/
|
|
396
|
-
buildMultiCubeWhereConditions(e, t,
|
|
637
|
+
buildMultiCubeWhereConditions(e, t, s) {
|
|
397
638
|
const n = [];
|
|
398
|
-
if (t.filters)
|
|
399
|
-
for (const
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
639
|
+
if (t.filters)
|
|
640
|
+
for (const r of t.filters) {
|
|
641
|
+
const a = this.processMultiCubeFilter(r, e, s);
|
|
642
|
+
a && n.push(a);
|
|
643
|
+
}
|
|
644
|
+
if (t.timeDimensions) {
|
|
645
|
+
for (const r of t.timeDimensions)
|
|
646
|
+
if (r.dateRange) {
|
|
647
|
+
const [a, i] = r.dimension.split("."), c = e.get(a);
|
|
648
|
+
if (c && c.dimensions[i]) {
|
|
649
|
+
const u = c.dimensions[i], l = b(u.sql, s), d = this.buildDateRangeCondition(l, r.dateRange);
|
|
650
|
+
d && n.push(d);
|
|
405
651
|
}
|
|
406
652
|
}
|
|
407
653
|
}
|
|
408
654
|
return n;
|
|
409
655
|
}
|
|
410
656
|
/**
|
|
411
|
-
*
|
|
657
|
+
* Process a single filter for multi-cube queries (handles logical and simple filters)
|
|
412
658
|
*/
|
|
413
|
-
|
|
414
|
-
if (
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
659
|
+
processMultiCubeFilter(e, t, s) {
|
|
660
|
+
if ("and" in e || "or" in e) {
|
|
661
|
+
if (e.and) {
|
|
662
|
+
const n = e.and.map((r) => this.processMultiCubeFilter(r, t, s)).filter((r) => r !== null);
|
|
663
|
+
return n.length > 0 ? h(...n) : null;
|
|
664
|
+
}
|
|
665
|
+
if (e.or) {
|
|
666
|
+
const n = e.or.map((r) => this.processMultiCubeFilter(r, t, s)).filter((r) => r !== null);
|
|
667
|
+
return n.length > 0 ? j(...n) : null;
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
if ("member" in e) {
|
|
671
|
+
const [n] = e.member.split("."), r = t.get(n);
|
|
672
|
+
if (r)
|
|
673
|
+
return this.buildFilterCondition(e, r, s);
|
|
674
|
+
}
|
|
675
|
+
return null;
|
|
676
|
+
}
|
|
677
|
+
/**
|
|
678
|
+
* Filter condition builder with comprehensive operator support
|
|
679
|
+
*/
|
|
680
|
+
buildFilterCondition(e, t, s) {
|
|
681
|
+
if (!e.member || !e.operator)
|
|
682
|
+
return null;
|
|
683
|
+
const [n, r] = e.member.split(".");
|
|
684
|
+
if (n !== t.name)
|
|
685
|
+
return null;
|
|
686
|
+
const a = t.dimensions[r] || t.measures[r];
|
|
687
|
+
if (!a)
|
|
688
|
+
return null;
|
|
689
|
+
const i = b(a.sql, s), u = (e.values || []).filter((d) => d != null);
|
|
690
|
+
if (u.length === 0 && !["set", "notSet"].includes(e.operator))
|
|
691
|
+
return null;
|
|
692
|
+
const l = u[0];
|
|
693
|
+
switch (e.operator) {
|
|
694
|
+
case "equals":
|
|
695
|
+
if (u.length === 0)
|
|
696
|
+
return m`1 = 0`;
|
|
697
|
+
if (u.length === 1) {
|
|
698
|
+
const d = a.type === "time" && this.normalizeDate(l) || l;
|
|
699
|
+
return v(i, d);
|
|
700
|
+
} else if (a.type === "time") {
|
|
701
|
+
const d = u.map((f) => this.normalizeDate(f) || f);
|
|
702
|
+
return m`${i} IN (${m.join(d.map((f) => m`${f}`), m`, `)})`;
|
|
703
|
+
} else
|
|
704
|
+
return m`${i} IN (${m.join(u.map((d) => m`${d}`), m`, `)})`;
|
|
705
|
+
case "notEquals":
|
|
706
|
+
return u.length === 1 ? m`${i} <> ${l}` : u.length > 1 ? m`${i} NOT IN (${m.join(u.map((d) => m`${d}`), m`, `)})` : null;
|
|
707
|
+
case "contains":
|
|
708
|
+
if (!this.databaseAdapter)
|
|
709
|
+
throw new Error("DatabaseAdapter is required for string conditions");
|
|
710
|
+
return this.databaseAdapter.buildStringCondition(i, "contains", l);
|
|
711
|
+
case "notContains":
|
|
712
|
+
if (!this.databaseAdapter)
|
|
713
|
+
throw new Error("DatabaseAdapter is required for string conditions");
|
|
714
|
+
return this.databaseAdapter.buildStringCondition(i, "notContains", l);
|
|
715
|
+
case "startsWith":
|
|
716
|
+
if (!this.databaseAdapter)
|
|
717
|
+
throw new Error("DatabaseAdapter is required for string conditions");
|
|
718
|
+
return this.databaseAdapter.buildStringCondition(i, "startsWith", l);
|
|
719
|
+
case "endsWith":
|
|
720
|
+
if (!this.databaseAdapter)
|
|
721
|
+
throw new Error("DatabaseAdapter is required for string conditions");
|
|
722
|
+
return this.databaseAdapter.buildStringCondition(i, "endsWith", l);
|
|
723
|
+
case "gt":
|
|
724
|
+
return N(i, l);
|
|
725
|
+
case "gte":
|
|
726
|
+
return w(i, l);
|
|
727
|
+
case "lt":
|
|
728
|
+
return $(i, l);
|
|
729
|
+
case "lte":
|
|
730
|
+
return D(i, l);
|
|
731
|
+
case "set":
|
|
732
|
+
return z(i);
|
|
733
|
+
case "notSet":
|
|
734
|
+
return _(i);
|
|
735
|
+
case "inDateRange":
|
|
736
|
+
if (u.length >= 2) {
|
|
737
|
+
const d = this.normalizeDate(u[0]), f = this.normalizeDate(u[1]);
|
|
738
|
+
if (d && f)
|
|
739
|
+
return h(
|
|
740
|
+
w(i, d),
|
|
741
|
+
D(i, f)
|
|
742
|
+
);
|
|
421
743
|
}
|
|
744
|
+
return null;
|
|
745
|
+
case "beforeDate": {
|
|
746
|
+
const d = this.normalizeDate(l);
|
|
747
|
+
return d ? $(i, d) : null;
|
|
422
748
|
}
|
|
749
|
+
case "afterDate": {
|
|
750
|
+
const d = this.normalizeDate(l);
|
|
751
|
+
return d ? N(i, d) : null;
|
|
752
|
+
}
|
|
753
|
+
default:
|
|
754
|
+
return null;
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
/**
|
|
758
|
+
* Build date range condition for time dimensions
|
|
759
|
+
*/
|
|
760
|
+
buildDateRangeCondition(e, t) {
|
|
761
|
+
if (!t) return null;
|
|
762
|
+
if (Array.isArray(t) && t.length >= 2) {
|
|
763
|
+
const s = this.normalizeDate(t[0]), n = this.normalizeDate(t[1]);
|
|
764
|
+
return !s || !n ? null : h(
|
|
765
|
+
w(e, s),
|
|
766
|
+
D(e, n)
|
|
767
|
+
);
|
|
768
|
+
}
|
|
769
|
+
if (typeof t == "string") {
|
|
770
|
+
const s = this.normalizeDate(t);
|
|
771
|
+
if (!s) return null;
|
|
772
|
+
const n = new Date(s);
|
|
773
|
+
n.setUTCHours(0, 0, 0, 0);
|
|
774
|
+
const r = new Date(s);
|
|
775
|
+
return r.setUTCHours(23, 59, 59, 999), h(
|
|
776
|
+
w(e, n),
|
|
777
|
+
D(e, r)
|
|
778
|
+
);
|
|
779
|
+
}
|
|
780
|
+
return null;
|
|
781
|
+
}
|
|
782
|
+
/**
|
|
783
|
+
* Normalize date values to handle both string and Date objects
|
|
784
|
+
* For PostgreSQL timestamp fields, Drizzle expects Date objects
|
|
785
|
+
*/
|
|
786
|
+
normalizeDate(e) {
|
|
787
|
+
if (!e) return null;
|
|
788
|
+
if (e instanceof Date)
|
|
789
|
+
return isNaN(e.getTime()) ? null : e;
|
|
790
|
+
if (typeof e == "string") {
|
|
791
|
+
const t = new Date(e);
|
|
792
|
+
return isNaN(t.getTime()) ? null : t;
|
|
793
|
+
}
|
|
794
|
+
try {
|
|
795
|
+
const t = new Date(e);
|
|
796
|
+
if (!isNaN(t.getTime()))
|
|
797
|
+
return t;
|
|
798
|
+
} catch {
|
|
423
799
|
}
|
|
424
800
|
return null;
|
|
425
801
|
}
|
|
426
802
|
/**
|
|
427
803
|
* Build GROUP BY fields for multi-cube query
|
|
428
804
|
*/
|
|
429
|
-
buildMultiCubeGroupByFields(e, t,
|
|
805
|
+
buildMultiCubeGroupByFields(e, t, s) {
|
|
430
806
|
const n = [];
|
|
431
807
|
if (!(t.measures && t.measures.length > 0))
|
|
432
808
|
return [];
|
|
433
809
|
const a = {
|
|
434
810
|
db: {},
|
|
435
811
|
schema: {},
|
|
436
|
-
securityContext:
|
|
812
|
+
securityContext: s
|
|
437
813
|
};
|
|
438
814
|
if (t.dimensions)
|
|
439
|
-
for (const
|
|
440
|
-
const [c,
|
|
441
|
-
if (
|
|
442
|
-
const
|
|
443
|
-
n.push(
|
|
815
|
+
for (const i of t.dimensions) {
|
|
816
|
+
const [c, u] = i.split("."), l = e.get(c);
|
|
817
|
+
if (l && l.dimensions[u]) {
|
|
818
|
+
const d = l.dimensions[u], f = b(d.sql, a);
|
|
819
|
+
n.push(f);
|
|
444
820
|
}
|
|
445
821
|
}
|
|
446
822
|
if (t.timeDimensions)
|
|
447
|
-
for (const
|
|
448
|
-
const [c,
|
|
449
|
-
if (
|
|
450
|
-
const
|
|
451
|
-
|
|
452
|
-
|
|
823
|
+
for (const i of t.timeDimensions) {
|
|
824
|
+
const [c, u] = i.dimension.split("."), l = e.get(c);
|
|
825
|
+
if (l && l.dimensions[u]) {
|
|
826
|
+
const d = l.dimensions[u], f = this.buildTimeDimensionExpression(
|
|
827
|
+
d.sql,
|
|
828
|
+
i.granularity,
|
|
453
829
|
a
|
|
454
830
|
);
|
|
455
|
-
n.push(
|
|
831
|
+
n.push(f);
|
|
456
832
|
}
|
|
457
833
|
}
|
|
458
834
|
return n;
|
|
459
835
|
}
|
|
460
836
|
}
|
|
461
|
-
class
|
|
837
|
+
class T {
|
|
462
838
|
constructor(e) {
|
|
463
839
|
C(this, "multiCubeBuilder");
|
|
464
|
-
this
|
|
840
|
+
C(this, "databaseAdapter");
|
|
841
|
+
if (this.dbExecutor = e, this.databaseAdapter = e.databaseAdapter, !this.databaseAdapter)
|
|
842
|
+
throw new Error("DatabaseExecutor must have a databaseAdapter property");
|
|
843
|
+
this.multiCubeBuilder = new ae(this.databaseAdapter);
|
|
465
844
|
}
|
|
466
845
|
/**
|
|
467
846
|
* Unified query execution method that handles both single and multi-cube queries
|
|
468
847
|
*/
|
|
469
|
-
async execute(e, t,
|
|
848
|
+
async execute(e, t, s) {
|
|
470
849
|
try {
|
|
471
|
-
const n =
|
|
850
|
+
const n = Q(e, t);
|
|
472
851
|
if (!n.isValid)
|
|
473
852
|
throw new Error(`Query validation failed: ${n.errors.join(", ")}`);
|
|
474
|
-
const
|
|
475
|
-
if (
|
|
853
|
+
const r = this.multiCubeBuilder.analyzeCubeUsage(t);
|
|
854
|
+
if (r.size === 0)
|
|
476
855
|
throw new Error("No cubes found for query");
|
|
477
|
-
if (
|
|
478
|
-
const a = Array.from(
|
|
479
|
-
if (!
|
|
856
|
+
if (r.size === 1) {
|
|
857
|
+
const a = Array.from(r)[0], i = e.get(a);
|
|
858
|
+
if (!i)
|
|
480
859
|
throw new Error(`Cube '${a}' not found`);
|
|
481
|
-
return this.executeSingleCube(
|
|
860
|
+
return this.executeSingleCube(i, t, s);
|
|
482
861
|
} else
|
|
483
|
-
return this.executeMultiCube(e, t,
|
|
862
|
+
return this.executeMultiCube(e, t, s);
|
|
484
863
|
} catch (n) {
|
|
485
864
|
throw new Error(`Query execution failed: ${n instanceof Error ? n.message : "Unknown error"}`);
|
|
486
865
|
}
|
|
@@ -488,76 +867,67 @@ class $ {
|
|
|
488
867
|
/**
|
|
489
868
|
* Legacy interface for single cube queries
|
|
490
869
|
*/
|
|
491
|
-
async executeQuery(e, t,
|
|
870
|
+
async executeQuery(e, t, s) {
|
|
492
871
|
const n = /* @__PURE__ */ new Map();
|
|
493
|
-
return n.set(e.name, e), this.execute(n, t,
|
|
872
|
+
return n.set(e.name, e), this.execute(n, t, s);
|
|
494
873
|
}
|
|
495
874
|
/**
|
|
496
875
|
* Execute a single cube query
|
|
497
876
|
*/
|
|
498
|
-
async executeSingleCube(e, t,
|
|
499
|
-
return this.executeCube(e, t,
|
|
877
|
+
async executeSingleCube(e, t, s) {
|
|
878
|
+
return this.executeCube(e, t, s);
|
|
500
879
|
}
|
|
501
880
|
/**
|
|
502
881
|
* Execute a Cube query (dynamic query building)
|
|
503
882
|
*/
|
|
504
|
-
async executeCube(e, t,
|
|
883
|
+
async executeCube(e, t, s) {
|
|
505
884
|
try {
|
|
506
885
|
const n = {
|
|
507
886
|
db: this.dbExecutor.db,
|
|
508
887
|
schema: this.dbExecutor.schema,
|
|
509
|
-
securityContext:
|
|
510
|
-
},
|
|
511
|
-
let
|
|
512
|
-
if (
|
|
513
|
-
for (const
|
|
514
|
-
switch (
|
|
888
|
+
securityContext: s
|
|
889
|
+
}, r = e.sql(n), a = this.buildSelections(e, t, n);
|
|
890
|
+
let i = n.db.select(a).from(r.from);
|
|
891
|
+
if (r.joins)
|
|
892
|
+
for (const p of r.joins)
|
|
893
|
+
switch (p.type || "left") {
|
|
515
894
|
case "left":
|
|
516
|
-
|
|
895
|
+
i = i.leftJoin(p.table, p.on);
|
|
517
896
|
break;
|
|
518
897
|
case "inner":
|
|
519
|
-
|
|
898
|
+
i = i.innerJoin(p.table, p.on);
|
|
520
899
|
break;
|
|
521
900
|
case "right":
|
|
522
|
-
|
|
901
|
+
i = i.rightJoin(p.table, p.on);
|
|
523
902
|
break;
|
|
524
903
|
case "full":
|
|
525
|
-
|
|
904
|
+
i = i.fullJoin(p.table, p.on);
|
|
526
905
|
break;
|
|
527
906
|
}
|
|
528
|
-
|
|
907
|
+
r.where && (i = i.where(r.where));
|
|
529
908
|
const c = this.buildWhereConditions(e, t, n);
|
|
530
909
|
if (c.length > 0) {
|
|
531
|
-
const
|
|
532
|
-
|
|
910
|
+
const p = c.length === 1 ? c[0] : h(...c);
|
|
911
|
+
i = i.where(p);
|
|
533
912
|
}
|
|
534
|
-
const
|
|
535
|
-
|
|
536
|
-
const
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
r = r.limit(t.limit);
|
|
541
|
-
}
|
|
542
|
-
if (t.offset !== void 0) {
|
|
543
|
-
if (t.offset < 0)
|
|
544
|
-
throw new Error("Offset must be non-negative");
|
|
545
|
-
r = r.offset(t.offset);
|
|
546
|
-
}
|
|
547
|
-
const m = t.measures || [], d = await this.dbExecutor.execute(r, m), Q = Array.isArray(d) ? d.map((h) => {
|
|
548
|
-
const E = { ...h };
|
|
913
|
+
const u = this.buildGroupByFields(e, t, n);
|
|
914
|
+
u.length > 0 && (i = i.groupBy(...u));
|
|
915
|
+
const l = this.buildOrderBy(t);
|
|
916
|
+
l.length > 0 && (i = i.orderBy(...l)), i = this.applyLimitAndOffset(i, t);
|
|
917
|
+
const d = this.collectNumericFields(e, t), f = await this.dbExecutor.execute(i, d), I = Array.isArray(f) ? f.map((p) => {
|
|
918
|
+
const A = { ...p };
|
|
549
919
|
if (t.timeDimensions) {
|
|
550
|
-
for (const
|
|
551
|
-
if (
|
|
552
|
-
let g = E
|
|
553
|
-
typeof g == "string" && g.match(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/) && (g = g.replace(" ", "T"), !g.endsWith("Z") && !g.includes("+") && (g = g + "Z")), E
|
|
920
|
+
for (const E of t.timeDimensions)
|
|
921
|
+
if (E.dimension in A) {
|
|
922
|
+
let g = A[E.dimension];
|
|
923
|
+
typeof g == "string" && g.match(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/) && (g = g.replace(" ", "T"), !g.endsWith("Z") && !g.includes("+") && (g = g + "Z")), A[E.dimension] = g;
|
|
554
924
|
}
|
|
555
925
|
}
|
|
556
|
-
return
|
|
557
|
-
}) : [
|
|
926
|
+
return A;
|
|
927
|
+
}) : [f], U = this.generateAnnotations(e, t);
|
|
558
928
|
return {
|
|
559
|
-
data:
|
|
560
|
-
annotation:
|
|
929
|
+
data: I,
|
|
930
|
+
annotation: U
|
|
561
931
|
};
|
|
562
932
|
} catch (n) {
|
|
563
933
|
throw new Error(`Cube query execution failed: ${n instanceof Error ? n.message : "Unknown error"}`);
|
|
@@ -566,184 +936,224 @@ class $ {
|
|
|
566
936
|
/**
|
|
567
937
|
* Execute multi-cube query using JOIN resolution
|
|
568
938
|
*/
|
|
569
|
-
async executeMultiCube(e, t,
|
|
570
|
-
const n = this.buildMultiCubeQuery(e, t,
|
|
939
|
+
async executeMultiCube(e, t, s) {
|
|
940
|
+
const n = this.buildMultiCubeQuery(e, t, s), r = this.collectNumericFieldsMultiCube(e, t), a = await this.dbExecutor.execute(n, r), i = {
|
|
571
941
|
db: this.dbExecutor.db,
|
|
572
942
|
schema: this.dbExecutor.schema,
|
|
573
|
-
securityContext:
|
|
574
|
-
}, c = this.multiCubeBuilder.buildMultiCubeQueryPlan(e, t,
|
|
943
|
+
securityContext: s
|
|
944
|
+
}, c = this.multiCubeBuilder.buildMultiCubeQueryPlan(e, t, i), u = this.generateMultiCubeAnnotations(c, t);
|
|
575
945
|
return {
|
|
576
946
|
data: Array.isArray(a) ? a : [a],
|
|
577
|
-
annotation:
|
|
947
|
+
annotation: u
|
|
578
948
|
};
|
|
579
949
|
}
|
|
580
950
|
/**
|
|
581
951
|
* Generate raw SQL for debugging (without execution)
|
|
582
952
|
*/
|
|
583
|
-
async generateSQL(e, t,
|
|
584
|
-
return this.generateCubeSQL(e, t,
|
|
953
|
+
async generateSQL(e, t, s) {
|
|
954
|
+
return this.generateCubeSQL(e, t, s);
|
|
585
955
|
}
|
|
586
956
|
/**
|
|
587
957
|
* Generate raw SQL for multi-cube queries without execution
|
|
588
958
|
*/
|
|
589
|
-
async generateMultiCubeSQL(e, t,
|
|
590
|
-
const
|
|
959
|
+
async generateMultiCubeSQL(e, t, s) {
|
|
960
|
+
const r = this.buildMultiCubeQuery(e, t, s).toSQL();
|
|
591
961
|
return {
|
|
592
|
-
sql:
|
|
593
|
-
params:
|
|
962
|
+
sql: r.sql,
|
|
963
|
+
params: r.params
|
|
594
964
|
};
|
|
595
965
|
}
|
|
596
966
|
/**
|
|
597
967
|
* Build multi-cube query (extracted from executeMultiCube for reuse)
|
|
598
968
|
*/
|
|
599
|
-
buildMultiCubeQuery(e, t,
|
|
969
|
+
buildMultiCubeQuery(e, t, s) {
|
|
600
970
|
const n = {
|
|
601
971
|
db: this.dbExecutor.db,
|
|
602
972
|
schema: this.dbExecutor.schema,
|
|
603
|
-
securityContext:
|
|
604
|
-
},
|
|
605
|
-
let
|
|
973
|
+
securityContext: s
|
|
974
|
+
}, r = this.multiCubeBuilder.buildMultiCubeQueryPlan(e, t, n), a = r.primaryCube.sql(n);
|
|
975
|
+
let i = n.db.select(r.selections).from(a.from);
|
|
606
976
|
if (a.joins)
|
|
607
|
-
for (const
|
|
608
|
-
switch (
|
|
977
|
+
for (const l of a.joins)
|
|
978
|
+
switch (l.type || "left") {
|
|
609
979
|
case "left":
|
|
610
|
-
|
|
980
|
+
i = i.leftJoin(l.table, l.on);
|
|
611
981
|
break;
|
|
612
982
|
case "inner":
|
|
613
|
-
|
|
983
|
+
i = i.innerJoin(l.table, l.on);
|
|
614
984
|
break;
|
|
615
985
|
case "right":
|
|
616
|
-
|
|
986
|
+
i = i.rightJoin(l.table, l.on);
|
|
617
987
|
break;
|
|
618
988
|
case "full":
|
|
619
|
-
|
|
989
|
+
i = i.fullJoin(l.table, l.on);
|
|
620
990
|
break;
|
|
621
991
|
default:
|
|
622
|
-
|
|
992
|
+
i = i.leftJoin(l.table, l.on);
|
|
623
993
|
}
|
|
624
|
-
if (
|
|
625
|
-
for (const
|
|
626
|
-
const
|
|
994
|
+
if (r.joinCubes && r.joinCubes.length > 0)
|
|
995
|
+
for (const l of r.joinCubes) {
|
|
996
|
+
const d = l.cube.sql(n);
|
|
627
997
|
try {
|
|
628
|
-
switch (
|
|
998
|
+
switch (l.joinType || "left") {
|
|
629
999
|
case "left":
|
|
630
|
-
|
|
1000
|
+
i = i.leftJoin(d.from, l.joinCondition);
|
|
631
1001
|
break;
|
|
632
1002
|
case "inner":
|
|
633
|
-
|
|
1003
|
+
i = i.innerJoin(d.from, l.joinCondition);
|
|
634
1004
|
break;
|
|
635
1005
|
case "right":
|
|
636
|
-
|
|
1006
|
+
i = i.rightJoin(d.from, l.joinCondition);
|
|
637
1007
|
break;
|
|
638
1008
|
case "full":
|
|
639
|
-
|
|
1009
|
+
i = i.fullJoin(d.from, l.joinCondition);
|
|
640
1010
|
break;
|
|
641
1011
|
}
|
|
642
|
-
} catch (
|
|
643
|
-
console.warn(`Multi-cube join failed for ${
|
|
1012
|
+
} catch (f) {
|
|
1013
|
+
console.warn(`Multi-cube join failed for ${l.cube.name}: ${f instanceof Error ? f.message : "Unknown error"}`);
|
|
644
1014
|
}
|
|
645
1015
|
}
|
|
646
1016
|
const c = [];
|
|
647
|
-
if (a.where && c.push(a.where),
|
|
648
|
-
const
|
|
649
|
-
|
|
1017
|
+
if (a.where && c.push(a.where), r.whereConditions.length > 0 && c.push(...r.whereConditions), c.length > 0) {
|
|
1018
|
+
const l = c.length === 1 ? c[0] : h(...c);
|
|
1019
|
+
i = i.where(l);
|
|
650
1020
|
}
|
|
651
|
-
|
|
652
|
-
const
|
|
653
|
-
|
|
654
|
-
|
|
1021
|
+
r.groupByFields.length > 0 && (i = i.groupBy(...r.groupByFields));
|
|
1022
|
+
const u = this.buildOrderBy(t);
|
|
1023
|
+
return u.length > 0 && (i = i.orderBy(...u)), i = this.applyLimitAndOffset(i, t), i;
|
|
1024
|
+
}
|
|
1025
|
+
/**
|
|
1026
|
+
* Collect numeric field names (measures + numeric dimensions) for type conversion
|
|
1027
|
+
*/
|
|
1028
|
+
collectNumericFields(e, t) {
|
|
1029
|
+
const s = [];
|
|
1030
|
+
if (t.measures && s.push(...t.measures), t.dimensions)
|
|
1031
|
+
for (const n of t.dimensions) {
|
|
1032
|
+
const r = n.includes(".") ? n.split(".")[1] : n, a = e.dimensions[r];
|
|
1033
|
+
a && a.type === "number" && s.push(n);
|
|
1034
|
+
}
|
|
1035
|
+
return s;
|
|
1036
|
+
}
|
|
1037
|
+
/**
|
|
1038
|
+
* Collect numeric field names for multi-cube queries
|
|
1039
|
+
*/
|
|
1040
|
+
collectNumericFieldsMultiCube(e, t) {
|
|
1041
|
+
const s = [];
|
|
1042
|
+
if (t.measures && s.push(...t.measures), t.dimensions)
|
|
1043
|
+
for (const n of t.dimensions) {
|
|
1044
|
+
const r = n.includes(".") ? n.split(".")[1] : n;
|
|
1045
|
+
for (const a of e.values()) {
|
|
1046
|
+
const i = a.dimensions[r];
|
|
1047
|
+
if (i && i.type === "number") {
|
|
1048
|
+
s.push(n);
|
|
1049
|
+
break;
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
return s;
|
|
1054
|
+
}
|
|
1055
|
+
/**
|
|
1056
|
+
* Apply LIMIT and OFFSET to a query with validation
|
|
1057
|
+
* If offset is provided without limit, add a reasonable default limit
|
|
1058
|
+
*/
|
|
1059
|
+
applyLimitAndOffset(e, t) {
|
|
1060
|
+
let s = t.limit;
|
|
1061
|
+
t.offset !== void 0 && t.offset > 0 && s === void 0 && (s = 50);
|
|
1062
|
+
let n = e;
|
|
1063
|
+
if (s !== void 0) {
|
|
1064
|
+
if (s < 0)
|
|
655
1065
|
throw new Error("Limit must be non-negative");
|
|
656
|
-
|
|
1066
|
+
n = n.limit(s);
|
|
657
1067
|
}
|
|
658
1068
|
if (t.offset !== void 0) {
|
|
659
1069
|
if (t.offset < 0)
|
|
660
1070
|
throw new Error("Offset must be non-negative");
|
|
661
|
-
|
|
1071
|
+
n = n.offset(t.offset);
|
|
662
1072
|
}
|
|
663
|
-
return
|
|
1073
|
+
return n;
|
|
664
1074
|
}
|
|
665
1075
|
/**
|
|
666
1076
|
* Generate SQL for Cube
|
|
667
1077
|
*/
|
|
668
|
-
async generateCubeSQL(e, t,
|
|
1078
|
+
async generateCubeSQL(e, t, s) {
|
|
669
1079
|
const n = {
|
|
670
1080
|
db: this.dbExecutor.db,
|
|
671
1081
|
schema: this.dbExecutor.schema,
|
|
672
|
-
securityContext:
|
|
673
|
-
},
|
|
674
|
-
let
|
|
675
|
-
if (
|
|
676
|
-
for (const
|
|
677
|
-
switch (
|
|
1082
|
+
securityContext: s
|
|
1083
|
+
}, r = e.sql(n), a = this.buildSelections(e, t, n);
|
|
1084
|
+
let i = n.db.select(a).from(r.from);
|
|
1085
|
+
if (r.joins)
|
|
1086
|
+
for (const f of r.joins)
|
|
1087
|
+
switch (f.type || "left") {
|
|
678
1088
|
case "left":
|
|
679
|
-
|
|
1089
|
+
i = i.leftJoin(f.table, f.on);
|
|
680
1090
|
break;
|
|
681
1091
|
case "inner":
|
|
682
|
-
|
|
1092
|
+
i = i.innerJoin(f.table, f.on);
|
|
683
1093
|
break;
|
|
684
1094
|
case "right":
|
|
685
|
-
|
|
1095
|
+
i = i.rightJoin(f.table, f.on);
|
|
686
1096
|
break;
|
|
687
1097
|
case "full":
|
|
688
|
-
|
|
1098
|
+
i = i.fullJoin(f.table, f.on);
|
|
689
1099
|
break;
|
|
690
1100
|
}
|
|
691
|
-
|
|
1101
|
+
r.where && (i = i.where(r.where));
|
|
692
1102
|
const c = this.buildWhereConditions(e, t, n);
|
|
693
1103
|
if (c.length > 0) {
|
|
694
|
-
const
|
|
695
|
-
|
|
1104
|
+
const f = c.length === 1 ? c[0] : h(...c);
|
|
1105
|
+
i = i.where(f);
|
|
696
1106
|
}
|
|
697
|
-
const
|
|
698
|
-
|
|
699
|
-
const
|
|
700
|
-
if (
|
|
1107
|
+
const u = this.buildGroupByFields(e, t, n);
|
|
1108
|
+
u.length > 0 && (i = i.groupBy(...u));
|
|
1109
|
+
const l = this.buildOrderBy(t);
|
|
1110
|
+
if (l.length > 0 && (i = i.orderBy(...l)), t.limit !== void 0) {
|
|
701
1111
|
if (t.limit < 0)
|
|
702
1112
|
throw new Error("Limit must be non-negative");
|
|
703
|
-
|
|
1113
|
+
i = i.limit(t.limit);
|
|
704
1114
|
}
|
|
705
1115
|
if (t.offset !== void 0) {
|
|
706
1116
|
if (t.offset < 0)
|
|
707
1117
|
throw new Error("Offset must be non-negative");
|
|
708
|
-
|
|
1118
|
+
i = i.offset(t.offset);
|
|
709
1119
|
}
|
|
710
|
-
const
|
|
1120
|
+
const d = i.toSQL();
|
|
711
1121
|
return {
|
|
712
|
-
sql:
|
|
713
|
-
params:
|
|
1122
|
+
sql: d.sql,
|
|
1123
|
+
params: d.params
|
|
714
1124
|
};
|
|
715
1125
|
}
|
|
716
1126
|
/**
|
|
717
1127
|
* Build dynamic selections for Cube measures and dimensions
|
|
718
1128
|
*/
|
|
719
|
-
buildSelections(e, t,
|
|
1129
|
+
buildSelections(e, t, s) {
|
|
720
1130
|
const n = {};
|
|
721
1131
|
if (t.dimensions)
|
|
722
|
-
for (const
|
|
723
|
-
const [a,
|
|
724
|
-
if (a === e.name && e.dimensions[
|
|
725
|
-
const c = e.dimensions[
|
|
726
|
-
n[
|
|
1132
|
+
for (const r of t.dimensions) {
|
|
1133
|
+
const [a, i] = r.split(".");
|
|
1134
|
+
if (a === e.name && e.dimensions[i]) {
|
|
1135
|
+
const c = e.dimensions[i], u = b(c.sql, s);
|
|
1136
|
+
n[r] = m`${u}`.as(r);
|
|
727
1137
|
}
|
|
728
1138
|
}
|
|
729
1139
|
if (t.measures)
|
|
730
|
-
for (const
|
|
731
|
-
const [a,
|
|
732
|
-
if (a === e.name && e.measures[
|
|
733
|
-
const c = e.measures[
|
|
734
|
-
n[
|
|
1140
|
+
for (const r of t.measures) {
|
|
1141
|
+
const [a, i] = r.split(".");
|
|
1142
|
+
if (a === e.name && e.measures[i]) {
|
|
1143
|
+
const c = e.measures[i], u = this.buildMeasureExpression(c, s);
|
|
1144
|
+
n[r] = m`${u}`.as(r);
|
|
735
1145
|
}
|
|
736
1146
|
}
|
|
737
1147
|
if (t.timeDimensions)
|
|
738
|
-
for (const
|
|
739
|
-
const [a,
|
|
740
|
-
if (a === e.name && e.dimensions[
|
|
741
|
-
const c = e.dimensions[
|
|
1148
|
+
for (const r of t.timeDimensions) {
|
|
1149
|
+
const [a, i] = r.dimension.split(".");
|
|
1150
|
+
if (a === e.name && e.dimensions[i]) {
|
|
1151
|
+
const c = e.dimensions[i], u = this.buildTimeDimensionExpression(
|
|
742
1152
|
c.sql,
|
|
743
|
-
|
|
744
|
-
|
|
1153
|
+
r.granularity,
|
|
1154
|
+
s
|
|
745
1155
|
);
|
|
746
|
-
n[
|
|
1156
|
+
n[r.dimension] = m`${u}`.as(r.dimension);
|
|
747
1157
|
}
|
|
748
1158
|
}
|
|
749
1159
|
return Object.keys(n).length === 0 && (n.count = y()), n;
|
|
@@ -752,74 +1162,53 @@ class $ {
|
|
|
752
1162
|
* Build measure expression with aggregation and filters for Cube
|
|
753
1163
|
*/
|
|
754
1164
|
buildMeasureExpression(e, t) {
|
|
755
|
-
let
|
|
1165
|
+
let s = b(e.sql, t);
|
|
756
1166
|
if (e.filters && e.filters.length > 0) {
|
|
757
|
-
const n = e.filters.map((
|
|
758
|
-
|
|
1167
|
+
const n = e.filters.map((r) => r(t));
|
|
1168
|
+
s = m`CASE WHEN ${h(...n)} THEN ${s} END`;
|
|
759
1169
|
}
|
|
760
1170
|
switch (e.type) {
|
|
761
1171
|
case "count":
|
|
762
|
-
return y(
|
|
1172
|
+
return y(s);
|
|
763
1173
|
case "countDistinct":
|
|
764
|
-
return
|
|
1174
|
+
return H(s);
|
|
765
1175
|
case "sum":
|
|
766
|
-
return
|
|
1176
|
+
return J(s);
|
|
767
1177
|
case "avg":
|
|
768
|
-
return
|
|
1178
|
+
return K(s);
|
|
769
1179
|
case "min":
|
|
770
|
-
return
|
|
1180
|
+
return R(s);
|
|
771
1181
|
case "max":
|
|
772
|
-
return
|
|
1182
|
+
return Y(s);
|
|
773
1183
|
case "number":
|
|
774
|
-
return
|
|
1184
|
+
return s;
|
|
775
1185
|
default:
|
|
776
|
-
return y(
|
|
1186
|
+
return y(s);
|
|
777
1187
|
}
|
|
778
1188
|
}
|
|
779
1189
|
/**
|
|
780
|
-
* Build time dimension expression with granularity
|
|
1190
|
+
* Build time dimension expression with granularity using database adapter
|
|
781
1191
|
*/
|
|
782
|
-
buildTimeDimensionExpression(e, t,
|
|
783
|
-
const n = b(e,
|
|
784
|
-
|
|
785
|
-
return f`${n}`;
|
|
786
|
-
switch (t) {
|
|
787
|
-
case "year":
|
|
788
|
-
return f`DATE_TRUNC('year', ${n}::timestamp)`;
|
|
789
|
-
case "quarter":
|
|
790
|
-
return f`DATE_TRUNC('quarter', ${n}::timestamp)`;
|
|
791
|
-
case "month":
|
|
792
|
-
return f`DATE_TRUNC('month', ${n}::timestamp)`;
|
|
793
|
-
case "week":
|
|
794
|
-
return f`DATE_TRUNC('week', ${n}::timestamp)`;
|
|
795
|
-
case "day":
|
|
796
|
-
return f`DATE_TRUNC('day', ${n}::timestamp)::timestamp`;
|
|
797
|
-
case "hour":
|
|
798
|
-
return f`DATE_TRUNC('hour', ${n}::timestamp)`;
|
|
799
|
-
case "minute":
|
|
800
|
-
return f`DATE_TRUNC('minute', ${n}::timestamp)`;
|
|
801
|
-
case "second":
|
|
802
|
-
return f`DATE_TRUNC('second', ${n}::timestamp)`;
|
|
803
|
-
default:
|
|
804
|
-
return n;
|
|
805
|
-
}
|
|
1192
|
+
buildTimeDimensionExpression(e, t, s) {
|
|
1193
|
+
const n = b(e, s);
|
|
1194
|
+
return t ? this.databaseAdapter.buildTimeDimension(t, n) : m`${n}`;
|
|
806
1195
|
}
|
|
807
1196
|
/**
|
|
808
1197
|
* Build WHERE conditions from semantic query filters (Cube)
|
|
809
1198
|
*/
|
|
810
|
-
buildWhereConditions(e, t,
|
|
1199
|
+
buildWhereConditions(e, t, s) {
|
|
811
1200
|
const n = [];
|
|
812
1201
|
if (t.filters && t.filters.length > 0)
|
|
813
|
-
for (const
|
|
814
|
-
const a = this.processFilter(
|
|
1202
|
+
for (const r of t.filters) {
|
|
1203
|
+
const a = this.processFilter(r, e, s);
|
|
815
1204
|
a && n.push(a);
|
|
816
1205
|
}
|
|
817
1206
|
if (t.timeDimensions)
|
|
818
|
-
for (const
|
|
819
|
-
const [a,
|
|
820
|
-
if (a === e.name && e.dimensions[
|
|
821
|
-
const c = e.dimensions[
|
|
822
|
-
|
|
1207
|
+
for (const r of t.timeDimensions) {
|
|
1208
|
+
const [a, i] = r.dimension.split(".");
|
|
1209
|
+
if (a === e.name && e.dimensions[i] && r.dateRange) {
|
|
1210
|
+
const c = e.dimensions[i], u = b(c.sql, s), l = this.buildDateRangeCondition(u, r.dateRange);
|
|
1211
|
+
l && n.push(l);
|
|
823
1212
|
}
|
|
824
1213
|
}
|
|
825
1214
|
return n;
|
|
@@ -827,77 +1216,77 @@ class $ {
|
|
|
827
1216
|
/**
|
|
828
1217
|
* Process a single filter for Cube (basic or logical)
|
|
829
1218
|
*/
|
|
830
|
-
processFilter(e, t,
|
|
1219
|
+
processFilter(e, t, s) {
|
|
831
1220
|
if ("and" in e || "or" in e) {
|
|
832
|
-
const
|
|
833
|
-
if (
|
|
834
|
-
const
|
|
835
|
-
return
|
|
1221
|
+
const u = e;
|
|
1222
|
+
if (u.and) {
|
|
1223
|
+
const l = u.and.map((d) => this.processFilter(d, t, s)).filter((d) => d !== null);
|
|
1224
|
+
return l.length > 0 ? h(...l) : null;
|
|
836
1225
|
}
|
|
837
|
-
if (
|
|
838
|
-
const
|
|
839
|
-
return
|
|
1226
|
+
if (u.or) {
|
|
1227
|
+
const l = u.or.map((d) => this.processFilter(d, t, s)).filter((d) => d !== null);
|
|
1228
|
+
return l.length > 0 ? j(...l) : null;
|
|
840
1229
|
}
|
|
841
1230
|
}
|
|
842
|
-
const n = e, [
|
|
843
|
-
if (
|
|
844
|
-
const
|
|
845
|
-
if (!
|
|
846
|
-
const c = b(
|
|
1231
|
+
const n = e, [r, a] = n.member.split(".");
|
|
1232
|
+
if (r !== t.name) return null;
|
|
1233
|
+
const i = t.dimensions[a] || t.measures[a];
|
|
1234
|
+
if (!i) return null;
|
|
1235
|
+
const c = b(i.sql, s);
|
|
847
1236
|
return this.buildFilterCondition(c, n.operator, n.values);
|
|
848
1237
|
}
|
|
849
1238
|
/**
|
|
850
1239
|
* Build filter condition using Drizzle operators
|
|
851
1240
|
*/
|
|
852
|
-
buildFilterCondition(e, t,
|
|
853
|
-
if (!
|
|
854
|
-
return t === "equals" ?
|
|
855
|
-
const n =
|
|
1241
|
+
buildFilterCondition(e, t, s) {
|
|
1242
|
+
if (!s || s.length === 0)
|
|
1243
|
+
return t === "equals" ? m`FALSE` : null;
|
|
1244
|
+
const n = s.filter((a) => !(a == null || a === "" || typeof a == "string" && a.includes("\0")));
|
|
856
1245
|
if (n.length === 0 && !["set", "notSet"].includes(t))
|
|
857
|
-
return t === "equals" ?
|
|
858
|
-
const
|
|
1246
|
+
return t === "equals" ? m`FALSE` : null;
|
|
1247
|
+
const r = n[0];
|
|
859
1248
|
switch (t) {
|
|
860
1249
|
case "equals":
|
|
861
|
-
return n.length > 1 ?
|
|
1250
|
+
return n.length > 1 ? P(e, n) : n.length === 1 ? v(e, r) : m`FALSE`;
|
|
862
1251
|
case "notEquals":
|
|
863
|
-
return n.length > 1 ?
|
|
1252
|
+
return n.length > 1 ? V(e, n) : n.length === 1 ? G(e, r) : null;
|
|
864
1253
|
case "contains":
|
|
865
|
-
return
|
|
1254
|
+
return this.databaseAdapter.buildStringCondition(e, "contains", r);
|
|
866
1255
|
case "notContains":
|
|
867
|
-
return
|
|
1256
|
+
return this.databaseAdapter.buildStringCondition(e, "notContains", r);
|
|
868
1257
|
case "startsWith":
|
|
869
|
-
return
|
|
1258
|
+
return this.databaseAdapter.buildStringCondition(e, "startsWith", r);
|
|
870
1259
|
case "endsWith":
|
|
871
|
-
return
|
|
1260
|
+
return this.databaseAdapter.buildStringCondition(e, "endsWith", r);
|
|
872
1261
|
case "gt":
|
|
873
|
-
return
|
|
1262
|
+
return N(e, r);
|
|
874
1263
|
case "gte":
|
|
875
|
-
return w(e,
|
|
1264
|
+
return w(e, r);
|
|
876
1265
|
case "lt":
|
|
877
|
-
return
|
|
1266
|
+
return $(e, r);
|
|
878
1267
|
case "lte":
|
|
879
|
-
return
|
|
1268
|
+
return D(e, r);
|
|
880
1269
|
case "set":
|
|
881
|
-
return
|
|
1270
|
+
return z(e);
|
|
882
1271
|
case "notSet":
|
|
883
|
-
return
|
|
1272
|
+
return _(e);
|
|
884
1273
|
case "inDateRange":
|
|
885
1274
|
if (n.length >= 2) {
|
|
886
|
-
const a = this.normalizeDate(n[0]),
|
|
887
|
-
if (a &&
|
|
888
|
-
return
|
|
1275
|
+
const a = this.normalizeDate(n[0]), i = this.normalizeDate(n[1]);
|
|
1276
|
+
if (a && i)
|
|
1277
|
+
return h(
|
|
889
1278
|
w(e, a),
|
|
890
|
-
|
|
1279
|
+
D(e, i)
|
|
891
1280
|
);
|
|
892
1281
|
}
|
|
893
1282
|
return null;
|
|
894
1283
|
case "beforeDate": {
|
|
895
|
-
const a = this.normalizeDate(
|
|
896
|
-
return a ?
|
|
1284
|
+
const a = this.normalizeDate(r);
|
|
1285
|
+
return a ? $(e, a) : null;
|
|
897
1286
|
}
|
|
898
1287
|
case "afterDate": {
|
|
899
|
-
const a = this.normalizeDate(
|
|
900
|
-
return a ?
|
|
1288
|
+
const a = this.normalizeDate(r);
|
|
1289
|
+
return a ? N(e, a) : null;
|
|
901
1290
|
}
|
|
902
1291
|
default:
|
|
903
1292
|
return null;
|
|
@@ -909,27 +1298,27 @@ class $ {
|
|
|
909
1298
|
buildDateRangeCondition(e, t) {
|
|
910
1299
|
if (!t) return null;
|
|
911
1300
|
if (Array.isArray(t) && t.length >= 2) {
|
|
912
|
-
const
|
|
913
|
-
return !
|
|
914
|
-
w(e,
|
|
915
|
-
|
|
1301
|
+
const s = this.normalizeDate(t[0]), n = this.normalizeDate(t[1]);
|
|
1302
|
+
return !s || !n ? null : h(
|
|
1303
|
+
w(e, s),
|
|
1304
|
+
D(e, n)
|
|
916
1305
|
);
|
|
917
1306
|
}
|
|
918
1307
|
if (typeof t == "string") {
|
|
919
|
-
const
|
|
920
|
-
if (
|
|
921
|
-
return
|
|
922
|
-
w(e,
|
|
923
|
-
|
|
1308
|
+
const s = this.parseRelativeDateRange(t);
|
|
1309
|
+
if (s)
|
|
1310
|
+
return h(
|
|
1311
|
+
w(e, s.start),
|
|
1312
|
+
D(e, s.end)
|
|
924
1313
|
);
|
|
925
1314
|
const n = this.normalizeDate(t);
|
|
926
1315
|
if (!n) return null;
|
|
927
|
-
const
|
|
928
|
-
|
|
1316
|
+
const r = new Date(n);
|
|
1317
|
+
r.setUTCHours(0, 0, 0, 0);
|
|
929
1318
|
const a = new Date(n);
|
|
930
|
-
return a.setUTCHours(23, 59, 59, 999),
|
|
931
|
-
w(e,
|
|
932
|
-
|
|
1319
|
+
return a.setUTCHours(23, 59, 59, 999), h(
|
|
1320
|
+
w(e, r),
|
|
1321
|
+
D(e, a)
|
|
933
1322
|
);
|
|
934
1323
|
}
|
|
935
1324
|
return null;
|
|
@@ -938,30 +1327,30 @@ class $ {
|
|
|
938
1327
|
* Parse relative date range expressions like "last 7 days", "this month"
|
|
939
1328
|
*/
|
|
940
1329
|
parseRelativeDateRange(e) {
|
|
941
|
-
const t = /* @__PURE__ */ new Date(),
|
|
1330
|
+
const t = /* @__PURE__ */ new Date(), s = e.toLowerCase().trim(), n = s.match(/^last\s+(\d+)\s+days?$/);
|
|
942
1331
|
if (n) {
|
|
943
|
-
const
|
|
944
|
-
c.setDate(t.getDate() -
|
|
945
|
-
const
|
|
946
|
-
return
|
|
1332
|
+
const i = parseInt(n[1], 10), c = new Date(t);
|
|
1333
|
+
c.setDate(t.getDate() - i), c.setHours(0, 0, 0, 0);
|
|
1334
|
+
const u = new Date(t);
|
|
1335
|
+
return u.setHours(23, 59, 59, 999), { start: c, end: u };
|
|
947
1336
|
}
|
|
948
|
-
if (
|
|
949
|
-
const
|
|
950
|
-
return { start:
|
|
1337
|
+
if (s === "this month") {
|
|
1338
|
+
const i = new Date(t.getFullYear(), t.getMonth(), 1, 0, 0, 0, 0), c = new Date(t.getFullYear(), t.getMonth() + 1, 0, 23, 59, 59, 999);
|
|
1339
|
+
return { start: i, end: c };
|
|
951
1340
|
}
|
|
952
|
-
const
|
|
953
|
-
if (
|
|
954
|
-
const
|
|
955
|
-
return
|
|
1341
|
+
const r = s.match(/^last\s+(\d+)\s+months?$/);
|
|
1342
|
+
if (r) {
|
|
1343
|
+
const i = parseInt(r[1], 10), c = new Date(t.getFullYear(), t.getMonth() - i, 1, 0, 0, 0, 0), u = new Date(t);
|
|
1344
|
+
return u.setHours(23, 59, 59, 999), { start: c, end: u };
|
|
956
1345
|
}
|
|
957
|
-
if (
|
|
958
|
-
const
|
|
959
|
-
return { start:
|
|
1346
|
+
if (s === "this year") {
|
|
1347
|
+
const i = new Date(t.getFullYear(), 0, 1, 0, 0, 0, 0), c = new Date(t.getFullYear(), 11, 31, 23, 59, 59, 999);
|
|
1348
|
+
return { start: i, end: c };
|
|
960
1349
|
}
|
|
961
|
-
const a =
|
|
1350
|
+
const a = s.match(/^last\s+(\d+)\s+years?$/);
|
|
962
1351
|
if (a) {
|
|
963
|
-
const
|
|
964
|
-
return
|
|
1352
|
+
const i = parseInt(a[1], 10), c = new Date(t.getFullYear() - i, 0, 1, 0, 0, 0, 0), u = new Date(t);
|
|
1353
|
+
return u.setHours(23, 59, 59, 999), { start: c, end: u };
|
|
965
1354
|
}
|
|
966
1355
|
return null;
|
|
967
1356
|
}
|
|
@@ -974,8 +1363,8 @@ class $ {
|
|
|
974
1363
|
if (e instanceof Date)
|
|
975
1364
|
return isNaN(e.getTime()) ? null : e;
|
|
976
1365
|
if (typeof e == "string") {
|
|
977
|
-
const
|
|
978
|
-
return isNaN(
|
|
1366
|
+
const s = new Date(e);
|
|
1367
|
+
return isNaN(s.getTime()) ? null : s;
|
|
979
1368
|
}
|
|
980
1369
|
const t = new Date(e);
|
|
981
1370
|
return isNaN(t.getTime()) ? null : t;
|
|
@@ -983,26 +1372,26 @@ class $ {
|
|
|
983
1372
|
/**
|
|
984
1373
|
* Build GROUP BY fields from dimensions and time dimensions (Cube)
|
|
985
1374
|
*/
|
|
986
|
-
buildGroupByFields(e, t,
|
|
1375
|
+
buildGroupByFields(e, t, s) {
|
|
987
1376
|
const n = [];
|
|
988
1377
|
if (t.dimensions)
|
|
989
|
-
for (const
|
|
990
|
-
const [a,
|
|
991
|
-
if (a === e.name && e.dimensions[
|
|
992
|
-
const c = e.dimensions[
|
|
993
|
-
n.push(
|
|
1378
|
+
for (const r of t.dimensions) {
|
|
1379
|
+
const [a, i] = r.split(".");
|
|
1380
|
+
if (a === e.name && e.dimensions[i]) {
|
|
1381
|
+
const c = e.dimensions[i], u = b(c.sql, s);
|
|
1382
|
+
n.push(u);
|
|
994
1383
|
}
|
|
995
1384
|
}
|
|
996
1385
|
if (t.timeDimensions)
|
|
997
|
-
for (const
|
|
998
|
-
const [a,
|
|
999
|
-
if (a === e.name && e.dimensions[
|
|
1000
|
-
const c = e.dimensions[
|
|
1386
|
+
for (const r of t.timeDimensions) {
|
|
1387
|
+
const [a, i] = r.dimension.split(".");
|
|
1388
|
+
if (a === e.name && e.dimensions[i]) {
|
|
1389
|
+
const c = e.dimensions[i], u = this.buildTimeDimensionExpression(
|
|
1001
1390
|
c.sql,
|
|
1002
|
-
|
|
1003
|
-
|
|
1391
|
+
r.granularity,
|
|
1392
|
+
s
|
|
1004
1393
|
);
|
|
1005
|
-
n.push(
|
|
1394
|
+
n.push(u);
|
|
1006
1395
|
}
|
|
1007
1396
|
}
|
|
1008
1397
|
return n;
|
|
@@ -1011,128 +1400,128 @@ class $ {
|
|
|
1011
1400
|
* Build ORDER BY clause with automatic time dimension sorting
|
|
1012
1401
|
*/
|
|
1013
1402
|
buildOrderBy(e, t) {
|
|
1014
|
-
var
|
|
1015
|
-
const
|
|
1403
|
+
var r;
|
|
1404
|
+
const s = [], n = t || [
|
|
1016
1405
|
...e.measures || [],
|
|
1017
1406
|
...e.dimensions || [],
|
|
1018
|
-
...((
|
|
1407
|
+
...((r = e.timeDimensions) == null ? void 0 : r.map((a) => a.dimension)) || []
|
|
1019
1408
|
];
|
|
1020
1409
|
if (e.order && Object.keys(e.order).length > 0)
|
|
1021
|
-
for (const [a,
|
|
1410
|
+
for (const [a, i] of Object.entries(e.order)) {
|
|
1022
1411
|
if (!n.includes(a))
|
|
1023
1412
|
throw new Error(`Cannot order by '${a}': field is not selected in the query`);
|
|
1024
|
-
const c =
|
|
1025
|
-
|
|
1413
|
+
const c = i === "desc" ? m`DESC` : m`ASC`;
|
|
1414
|
+
s.push(m`${m.identifier(a)} ${c}`);
|
|
1026
1415
|
}
|
|
1027
1416
|
if (e.timeDimensions && e.timeDimensions.length > 0) {
|
|
1028
|
-
const a = new Set(Object.keys(e.order || {})),
|
|
1029
|
-
(c,
|
|
1417
|
+
const a = new Set(Object.keys(e.order || {})), i = [...e.timeDimensions].sort(
|
|
1418
|
+
(c, u) => c.dimension.localeCompare(u.dimension)
|
|
1030
1419
|
);
|
|
1031
|
-
for (const c of
|
|
1032
|
-
a.has(c.dimension) ||
|
|
1420
|
+
for (const c of i)
|
|
1421
|
+
a.has(c.dimension) || s.push(m`${m.identifier(c.dimension)} ASC`);
|
|
1033
1422
|
}
|
|
1034
|
-
return
|
|
1423
|
+
return s;
|
|
1035
1424
|
}
|
|
1036
1425
|
/**
|
|
1037
1426
|
* Generate annotations for UI metadata
|
|
1038
1427
|
*/
|
|
1039
1428
|
generateAnnotations(e, t) {
|
|
1040
|
-
const
|
|
1429
|
+
const s = {}, n = {}, r = {};
|
|
1041
1430
|
if (t.measures)
|
|
1042
1431
|
for (const a of t.measures) {
|
|
1043
|
-
const [
|
|
1044
|
-
if (
|
|
1045
|
-
const
|
|
1046
|
-
|
|
1047
|
-
title:
|
|
1048
|
-
shortTitle:
|
|
1049
|
-
type:
|
|
1432
|
+
const [i, c] = a.split(".");
|
|
1433
|
+
if (i === e.name && e.measures[c]) {
|
|
1434
|
+
const u = e.measures[c];
|
|
1435
|
+
s[a] = {
|
|
1436
|
+
title: u.title || c,
|
|
1437
|
+
shortTitle: u.title || c,
|
|
1438
|
+
type: u.type
|
|
1050
1439
|
};
|
|
1051
1440
|
}
|
|
1052
1441
|
}
|
|
1053
1442
|
if (t.dimensions)
|
|
1054
1443
|
for (const a of t.dimensions) {
|
|
1055
|
-
const [
|
|
1056
|
-
if (
|
|
1057
|
-
const
|
|
1444
|
+
const [i, c] = a.split(".");
|
|
1445
|
+
if (i === e.name && e.dimensions[c]) {
|
|
1446
|
+
const u = e.dimensions[c];
|
|
1058
1447
|
n[a] = {
|
|
1059
|
-
title:
|
|
1060
|
-
shortTitle:
|
|
1061
|
-
type:
|
|
1448
|
+
title: u.title || c,
|
|
1449
|
+
shortTitle: u.title || c,
|
|
1450
|
+
type: u.type
|
|
1062
1451
|
};
|
|
1063
1452
|
}
|
|
1064
1453
|
}
|
|
1065
1454
|
if (t.timeDimensions)
|
|
1066
1455
|
for (const a of t.timeDimensions) {
|
|
1067
|
-
const [
|
|
1068
|
-
if (
|
|
1069
|
-
const
|
|
1070
|
-
|
|
1071
|
-
title:
|
|
1072
|
-
shortTitle:
|
|
1073
|
-
type:
|
|
1456
|
+
const [i, c] = a.dimension.split(".");
|
|
1457
|
+
if (i === e.name && e.dimensions[c]) {
|
|
1458
|
+
const u = e.dimensions[c];
|
|
1459
|
+
r[a.dimension] = {
|
|
1460
|
+
title: u.title || c,
|
|
1461
|
+
shortTitle: u.title || c,
|
|
1462
|
+
type: u.type,
|
|
1074
1463
|
granularity: a.granularity
|
|
1075
1464
|
};
|
|
1076
1465
|
}
|
|
1077
1466
|
}
|
|
1078
1467
|
return {
|
|
1079
|
-
measures:
|
|
1468
|
+
measures: s,
|
|
1080
1469
|
dimensions: n,
|
|
1081
1470
|
segments: {},
|
|
1082
|
-
timeDimensions:
|
|
1471
|
+
timeDimensions: r
|
|
1083
1472
|
};
|
|
1084
1473
|
}
|
|
1085
1474
|
/**
|
|
1086
1475
|
* Generate annotations for multi-cube queries
|
|
1087
1476
|
*/
|
|
1088
1477
|
generateMultiCubeAnnotations(e, t) {
|
|
1089
|
-
const
|
|
1090
|
-
if (e.joinCubes && a.push(...e.joinCubes.map((
|
|
1091
|
-
for (const
|
|
1092
|
-
const [c,
|
|
1093
|
-
if (
|
|
1094
|
-
const
|
|
1095
|
-
i
|
|
1096
|
-
title:
|
|
1097
|
-
shortTitle:
|
|
1098
|
-
type:
|
|
1478
|
+
const s = {}, n = {}, r = {}, a = [e.primaryCube];
|
|
1479
|
+
if (e.joinCubes && a.push(...e.joinCubes.map((i) => i.cube)), t.measures)
|
|
1480
|
+
for (const i of t.measures) {
|
|
1481
|
+
const [c, u] = i.split("."), l = a.find((d) => d.name === c);
|
|
1482
|
+
if (l && l.measures[u]) {
|
|
1483
|
+
const d = l.measures[u];
|
|
1484
|
+
s[i] = {
|
|
1485
|
+
title: d.title || u,
|
|
1486
|
+
shortTitle: d.title || u,
|
|
1487
|
+
type: d.type
|
|
1099
1488
|
};
|
|
1100
1489
|
}
|
|
1101
1490
|
}
|
|
1102
1491
|
if (t.dimensions)
|
|
1103
|
-
for (const
|
|
1104
|
-
const [c,
|
|
1105
|
-
if (
|
|
1106
|
-
const
|
|
1107
|
-
n[
|
|
1108
|
-
title:
|
|
1109
|
-
shortTitle:
|
|
1110
|
-
type:
|
|
1492
|
+
for (const i of t.dimensions) {
|
|
1493
|
+
const [c, u] = i.split("."), l = a.find((d) => d.name === c);
|
|
1494
|
+
if (l && l.dimensions[u]) {
|
|
1495
|
+
const d = l.dimensions[u];
|
|
1496
|
+
n[i] = {
|
|
1497
|
+
title: d.title || u,
|
|
1498
|
+
shortTitle: d.title || u,
|
|
1499
|
+
type: d.type
|
|
1111
1500
|
};
|
|
1112
1501
|
}
|
|
1113
1502
|
}
|
|
1114
1503
|
if (t.timeDimensions)
|
|
1115
|
-
for (const
|
|
1116
|
-
const [c,
|
|
1117
|
-
if (
|
|
1118
|
-
const
|
|
1119
|
-
|
|
1120
|
-
title:
|
|
1121
|
-
shortTitle:
|
|
1122
|
-
type:
|
|
1123
|
-
granularity:
|
|
1504
|
+
for (const i of t.timeDimensions) {
|
|
1505
|
+
const [c, u] = i.dimension.split("."), l = a.find((d) => d.name === c);
|
|
1506
|
+
if (l && l.dimensions && l.dimensions[u]) {
|
|
1507
|
+
const d = l.dimensions[u];
|
|
1508
|
+
r[i.dimension] = {
|
|
1509
|
+
title: d.title || u,
|
|
1510
|
+
shortTitle: d.title || u,
|
|
1511
|
+
type: d.type,
|
|
1512
|
+
granularity: i.granularity
|
|
1124
1513
|
};
|
|
1125
1514
|
}
|
|
1126
1515
|
}
|
|
1127
1516
|
return {
|
|
1128
|
-
measures:
|
|
1517
|
+
measures: s,
|
|
1129
1518
|
dimensions: n,
|
|
1130
1519
|
segments: {},
|
|
1131
|
-
timeDimensions:
|
|
1520
|
+
timeDimensions: r
|
|
1132
1521
|
};
|
|
1133
1522
|
}
|
|
1134
1523
|
}
|
|
1135
|
-
class
|
|
1524
|
+
class x {
|
|
1136
1525
|
// 5 minutes in milliseconds
|
|
1137
1526
|
constructor(e) {
|
|
1138
1527
|
C(this, "cubes", /* @__PURE__ */ new Map());
|
|
@@ -1140,7 +1529,7 @@ class T {
|
|
|
1140
1529
|
C(this, "metadataCache");
|
|
1141
1530
|
C(this, "metadataCacheTimestamp");
|
|
1142
1531
|
C(this, "METADATA_CACHE_TTL", 5 * 60 * 1e3);
|
|
1143
|
-
e != null && e.databaseExecutor ? this.dbExecutor = e.databaseExecutor : e != null && e.drizzle && (this.dbExecutor =
|
|
1532
|
+
e != null && e.databaseExecutor ? this.dbExecutor = e.databaseExecutor : e != null && e.drizzle && (this.dbExecutor = L(
|
|
1144
1533
|
e.drizzle,
|
|
1145
1534
|
e.schema,
|
|
1146
1535
|
e.engineType
|
|
@@ -1155,8 +1544,8 @@ class T {
|
|
|
1155
1544
|
/**
|
|
1156
1545
|
* Set Drizzle instance and schema directly
|
|
1157
1546
|
*/
|
|
1158
|
-
setDrizzle(e, t,
|
|
1159
|
-
this.dbExecutor =
|
|
1547
|
+
setDrizzle(e, t, s) {
|
|
1548
|
+
this.dbExecutor = L(e, t, s);
|
|
1160
1549
|
}
|
|
1161
1550
|
/**
|
|
1162
1551
|
* Check if database executor is configured
|
|
@@ -1194,7 +1583,7 @@ class T {
|
|
|
1194
1583
|
async execute(e, t) {
|
|
1195
1584
|
if (!this.dbExecutor)
|
|
1196
1585
|
throw new Error("Database executor not configured");
|
|
1197
|
-
return new
|
|
1586
|
+
return new T(this.dbExecutor).execute(this.cubes, e, t);
|
|
1198
1587
|
}
|
|
1199
1588
|
/**
|
|
1200
1589
|
* Execute a multi-cube query
|
|
@@ -1205,10 +1594,10 @@ class T {
|
|
|
1205
1594
|
/**
|
|
1206
1595
|
* Execute a single cube query
|
|
1207
1596
|
*/
|
|
1208
|
-
async executeQuery(e, t,
|
|
1597
|
+
async executeQuery(e, t, s) {
|
|
1209
1598
|
if (!this.cubes.get(e))
|
|
1210
1599
|
throw new Error(`Cube '${e}' not found`);
|
|
1211
|
-
return this.execute(t,
|
|
1600
|
+
return this.execute(t, s);
|
|
1212
1601
|
}
|
|
1213
1602
|
/**
|
|
1214
1603
|
* Get metadata for all cubes (for API responses)
|
|
@@ -1218,7 +1607,7 @@ class T {
|
|
|
1218
1607
|
const e = Date.now();
|
|
1219
1608
|
if (this.metadataCache && this.metadataCacheTimestamp && e - this.metadataCacheTimestamp < this.METADATA_CACHE_TTL)
|
|
1220
1609
|
return this.metadataCache;
|
|
1221
|
-
const t = Array.from(this.cubes.values()).map((
|
|
1610
|
+
const t = Array.from(this.cubes.values()).map((s) => this.generateCubeMetadata(s));
|
|
1222
1611
|
return this.metadataCache = t, this.metadataCacheTimestamp = e, t;
|
|
1223
1612
|
}
|
|
1224
1613
|
/**
|
|
@@ -1226,25 +1615,25 @@ class T {
|
|
|
1226
1615
|
* Optimized version that minimizes object iterations
|
|
1227
1616
|
*/
|
|
1228
1617
|
generateCubeMetadata(e) {
|
|
1229
|
-
const t = Object.keys(e.measures),
|
|
1618
|
+
const t = Object.keys(e.measures), s = Object.keys(e.dimensions), n = new Array(t.length), r = new Array(s.length);
|
|
1230
1619
|
for (let a = 0; a < t.length; a++) {
|
|
1231
|
-
const
|
|
1620
|
+
const i = t[a], c = e.measures[i];
|
|
1232
1621
|
n[a] = {
|
|
1233
|
-
name: `${e.name}.${
|
|
1234
|
-
title: c.title ||
|
|
1235
|
-
shortTitle: c.title ||
|
|
1622
|
+
name: `${e.name}.${i}`,
|
|
1623
|
+
title: c.title || i,
|
|
1624
|
+
shortTitle: c.title || i,
|
|
1236
1625
|
type: c.type,
|
|
1237
1626
|
format: void 0,
|
|
1238
1627
|
// Measure doesn't have format field
|
|
1239
1628
|
description: c.description
|
|
1240
1629
|
};
|
|
1241
1630
|
}
|
|
1242
|
-
for (let a = 0; a <
|
|
1243
|
-
const
|
|
1244
|
-
|
|
1245
|
-
name: `${e.name}.${
|
|
1246
|
-
title: c.title ||
|
|
1247
|
-
shortTitle: c.title ||
|
|
1631
|
+
for (let a = 0; a < s.length; a++) {
|
|
1632
|
+
const i = s[a], c = e.dimensions[i];
|
|
1633
|
+
r[a] = {
|
|
1634
|
+
name: `${e.name}.${i}`,
|
|
1635
|
+
title: c.title || i,
|
|
1636
|
+
shortTitle: c.title || i,
|
|
1248
1637
|
type: c.type,
|
|
1249
1638
|
format: void 0,
|
|
1250
1639
|
// Dimension doesn't have format field
|
|
@@ -1256,7 +1645,7 @@ class T {
|
|
|
1256
1645
|
title: e.title || e.name,
|
|
1257
1646
|
description: e.description,
|
|
1258
1647
|
measures: n,
|
|
1259
|
-
dimensions:
|
|
1648
|
+
dimensions: r,
|
|
1260
1649
|
segments: []
|
|
1261
1650
|
// Add segments support later if needed
|
|
1262
1651
|
};
|
|
@@ -1264,13 +1653,13 @@ class T {
|
|
|
1264
1653
|
/**
|
|
1265
1654
|
* Get SQL for a query without executing it (debugging)
|
|
1266
1655
|
*/
|
|
1267
|
-
async generateSQL(e, t,
|
|
1656
|
+
async generateSQL(e, t, s) {
|
|
1268
1657
|
const n = this.getCube(e);
|
|
1269
1658
|
if (!n)
|
|
1270
1659
|
throw new Error(`Cube '${e}' not found`);
|
|
1271
1660
|
if (!this.dbExecutor)
|
|
1272
1661
|
throw new Error("Database executor not configured");
|
|
1273
|
-
return new
|
|
1662
|
+
return new T(this.dbExecutor).generateSQL(n, t, s);
|
|
1274
1663
|
}
|
|
1275
1664
|
/**
|
|
1276
1665
|
* Get SQL for a multi-cube query without executing it (debugging)
|
|
@@ -1278,7 +1667,7 @@ class T {
|
|
|
1278
1667
|
async generateMultiCubeSQL(e, t) {
|
|
1279
1668
|
if (!this.dbExecutor)
|
|
1280
1669
|
throw new Error("Database executor not configured");
|
|
1281
|
-
return new
|
|
1670
|
+
return new T(this.dbExecutor).generateMultiCubeSQL(this.cubes, e, t);
|
|
1282
1671
|
}
|
|
1283
1672
|
/**
|
|
1284
1673
|
* Check if a cube exists
|
|
@@ -1317,93 +1706,93 @@ class T {
|
|
|
1317
1706
|
* Ensures all referenced cubes and fields exist
|
|
1318
1707
|
*/
|
|
1319
1708
|
validateQuery(e) {
|
|
1320
|
-
return
|
|
1709
|
+
return Q(this.cubes, e);
|
|
1321
1710
|
}
|
|
1322
1711
|
}
|
|
1323
|
-
function
|
|
1324
|
-
const t = [],
|
|
1712
|
+
function Q(o, e) {
|
|
1713
|
+
const t = [], s = /* @__PURE__ */ new Set();
|
|
1325
1714
|
if (e.measures)
|
|
1326
1715
|
for (const n of e.measures) {
|
|
1327
|
-
const [
|
|
1328
|
-
if (!
|
|
1716
|
+
const [r, a] = n.split(".");
|
|
1717
|
+
if (!r || !a) {
|
|
1329
1718
|
t.push(`Invalid measure format: ${n}. Expected format: 'CubeName.fieldName'`);
|
|
1330
1719
|
continue;
|
|
1331
1720
|
}
|
|
1332
|
-
|
|
1333
|
-
const
|
|
1334
|
-
if (!
|
|
1335
|
-
t.push(`Cube '${
|
|
1721
|
+
s.add(r);
|
|
1722
|
+
const i = o.get(r);
|
|
1723
|
+
if (!i) {
|
|
1724
|
+
t.push(`Cube '${r}' not found (referenced in measure '${n}')`);
|
|
1336
1725
|
continue;
|
|
1337
1726
|
}
|
|
1338
|
-
|
|
1727
|
+
i.measures[a] || t.push(`Measure '${a}' not found on cube '${r}'`);
|
|
1339
1728
|
}
|
|
1340
1729
|
if (e.dimensions)
|
|
1341
1730
|
for (const n of e.dimensions) {
|
|
1342
|
-
const [
|
|
1343
|
-
if (!
|
|
1731
|
+
const [r, a] = n.split(".");
|
|
1732
|
+
if (!r || !a) {
|
|
1344
1733
|
t.push(`Invalid dimension format: ${n}. Expected format: 'CubeName.fieldName'`);
|
|
1345
1734
|
continue;
|
|
1346
1735
|
}
|
|
1347
|
-
|
|
1348
|
-
const
|
|
1349
|
-
if (!
|
|
1350
|
-
t.push(`Cube '${
|
|
1736
|
+
s.add(r);
|
|
1737
|
+
const i = o.get(r);
|
|
1738
|
+
if (!i) {
|
|
1739
|
+
t.push(`Cube '${r}' not found (referenced in dimension '${n}')`);
|
|
1351
1740
|
continue;
|
|
1352
1741
|
}
|
|
1353
|
-
|
|
1742
|
+
i.dimensions[a] || t.push(`Dimension '${a}' not found on cube '${r}'`);
|
|
1354
1743
|
}
|
|
1355
1744
|
if (e.timeDimensions)
|
|
1356
1745
|
for (const n of e.timeDimensions) {
|
|
1357
|
-
const [
|
|
1358
|
-
if (!
|
|
1746
|
+
const [r, a] = n.dimension.split(".");
|
|
1747
|
+
if (!r || !a) {
|
|
1359
1748
|
t.push(`Invalid timeDimension format: ${n.dimension}. Expected format: 'CubeName.fieldName'`);
|
|
1360
1749
|
continue;
|
|
1361
1750
|
}
|
|
1362
|
-
|
|
1363
|
-
const
|
|
1364
|
-
if (!
|
|
1365
|
-
t.push(`Cube '${
|
|
1751
|
+
s.add(r);
|
|
1752
|
+
const i = o.get(r);
|
|
1753
|
+
if (!i) {
|
|
1754
|
+
t.push(`Cube '${r}' not found (referenced in timeDimension '${n.dimension}')`);
|
|
1366
1755
|
continue;
|
|
1367
1756
|
}
|
|
1368
|
-
|
|
1757
|
+
i.dimensions[a] || t.push(`TimeDimension '${a}' not found on cube '${r}' (must be a dimension with time type)`);
|
|
1369
1758
|
}
|
|
1370
1759
|
if (e.filters)
|
|
1371
1760
|
for (const n of e.filters)
|
|
1372
|
-
|
|
1373
|
-
return
|
|
1761
|
+
k(n, o, t, s);
|
|
1762
|
+
return s.size === 0 && t.push("Query must reference at least one cube through measures, dimensions, or filters"), {
|
|
1374
1763
|
isValid: t.length === 0,
|
|
1375
1764
|
errors: t
|
|
1376
1765
|
};
|
|
1377
1766
|
}
|
|
1378
|
-
function
|
|
1379
|
-
if ("and" in
|
|
1380
|
-
const
|
|
1381
|
-
for (const c of
|
|
1382
|
-
|
|
1767
|
+
function k(o, e, t, s) {
|
|
1768
|
+
if ("and" in o || "or" in o) {
|
|
1769
|
+
const i = o.and || o.or || [];
|
|
1770
|
+
for (const c of i)
|
|
1771
|
+
k(c, e, t, s);
|
|
1383
1772
|
return;
|
|
1384
1773
|
}
|
|
1385
|
-
if (!("member" in
|
|
1774
|
+
if (!("member" in o)) {
|
|
1386
1775
|
t.push("Filter must have a member field");
|
|
1387
1776
|
return;
|
|
1388
1777
|
}
|
|
1389
|
-
const [n,
|
|
1390
|
-
if (!n || !
|
|
1391
|
-
t.push(`Invalid filter member format: ${
|
|
1778
|
+
const [n, r] = o.member.split(".");
|
|
1779
|
+
if (!n || !r) {
|
|
1780
|
+
t.push(`Invalid filter member format: ${o.member}. Expected format: 'CubeName.fieldName'`);
|
|
1392
1781
|
return;
|
|
1393
1782
|
}
|
|
1394
|
-
|
|
1783
|
+
s.add(n);
|
|
1395
1784
|
const a = e.get(n);
|
|
1396
1785
|
if (!a) {
|
|
1397
|
-
t.push(`Cube '${n}' not found (referenced in filter '${
|
|
1786
|
+
t.push(`Cube '${n}' not found (referenced in filter '${o.member}')`);
|
|
1398
1787
|
return;
|
|
1399
1788
|
}
|
|
1400
|
-
!a.dimensions[
|
|
1789
|
+
!a.dimensions[r] && !a.measures[r] && t.push(`Filter field '${r}' not found on cube '${n}' (must be a dimension or measure)`);
|
|
1401
1790
|
}
|
|
1402
|
-
function
|
|
1403
|
-
return new
|
|
1791
|
+
function ye(o) {
|
|
1792
|
+
return new x(o);
|
|
1404
1793
|
}
|
|
1405
|
-
const
|
|
1406
|
-
function
|
|
1794
|
+
const ce = new x();
|
|
1795
|
+
function ue(o) {
|
|
1407
1796
|
const e = {
|
|
1408
1797
|
valid: !0,
|
|
1409
1798
|
errors: [],
|
|
@@ -1411,7 +1800,7 @@ function re(s) {
|
|
|
1411
1800
|
cubes: []
|
|
1412
1801
|
};
|
|
1413
1802
|
try {
|
|
1414
|
-
const t =
|
|
1803
|
+
const t = Z(o);
|
|
1415
1804
|
if (!t)
|
|
1416
1805
|
return e.valid = !1, e.errors.push("Invalid YAML: empty or malformed content"), e;
|
|
1417
1806
|
if (t.cubes && Array.isArray(t.cubes))
|
|
@@ -1420,8 +1809,8 @@ function re(s) {
|
|
|
1420
1809
|
e.cubes = [t];
|
|
1421
1810
|
else
|
|
1422
1811
|
return e.valid = !1, e.errors.push('YAML must contain either a "cubes" array or cube properties at root level'), e;
|
|
1423
|
-
for (const
|
|
1424
|
-
const n =
|
|
1812
|
+
for (const s of e.cubes) {
|
|
1813
|
+
const n = le(s);
|
|
1425
1814
|
e.errors.push(...n);
|
|
1426
1815
|
}
|
|
1427
1816
|
e.valid = e.errors.length === 0;
|
|
@@ -1430,87 +1819,87 @@ function re(s) {
|
|
|
1430
1819
|
}
|
|
1431
1820
|
return e;
|
|
1432
1821
|
}
|
|
1433
|
-
function
|
|
1822
|
+
function le(o) {
|
|
1434
1823
|
const e = [];
|
|
1435
|
-
return
|
|
1436
|
-
t.name || e.push(`Dimension at index ${
|
|
1437
|
-
}),
|
|
1438
|
-
t.name || e.push(`Measure at index ${
|
|
1439
|
-
}),
|
|
1440
|
-
t.name || e.push(`Join at index ${
|
|
1824
|
+
return o.name || e.push("Cube name is required"), !o.sql && !o.sql_table && !o.sqlTable && e.push('Cube must have either "sql", "sql_table", or "sqlTable" property'), o.dimensions && o.dimensions.forEach((t, s) => {
|
|
1825
|
+
t.name || e.push(`Dimension at index ${s} is missing name`), t.type || e.push(`Dimension "${t.name}" is missing type`), t.sql || e.push(`Dimension "${t.name}" is missing sql`);
|
|
1826
|
+
}), o.measures && o.measures.forEach((t, s) => {
|
|
1827
|
+
t.name || e.push(`Measure at index ${s} is missing name`), t.type || e.push(`Measure "${t.name}" is missing type`), t.sql || e.push(`Measure "${t.name}" is missing sql`);
|
|
1828
|
+
}), o.joins && o.joins.forEach((t, s) => {
|
|
1829
|
+
t.name || e.push(`Join at index ${s} is missing name`), t.relationship || e.push(`Join "${t.name}" is missing relationship`), t.sql || e.push(`Join "${t.name}" is missing sql`);
|
|
1441
1830
|
}), e;
|
|
1442
1831
|
}
|
|
1443
|
-
function
|
|
1832
|
+
function de(o) {
|
|
1444
1833
|
const e = {};
|
|
1445
|
-
|
|
1446
|
-
e[
|
|
1834
|
+
o.dimensions && o.dimensions.forEach((i) => {
|
|
1835
|
+
e[i.name] = me(i);
|
|
1447
1836
|
});
|
|
1448
1837
|
const t = {};
|
|
1449
|
-
|
|
1450
|
-
t[
|
|
1838
|
+
o.measures && o.measures.forEach((i) => {
|
|
1839
|
+
t[i.name] = fe(i);
|
|
1451
1840
|
});
|
|
1452
|
-
const
|
|
1453
|
-
|
|
1454
|
-
i
|
|
1841
|
+
const s = {};
|
|
1842
|
+
o.joins && o.joins.forEach((i) => {
|
|
1843
|
+
s[i.name] = be(i);
|
|
1455
1844
|
});
|
|
1456
1845
|
const n = {};
|
|
1457
|
-
(
|
|
1458
|
-
n[c.name] =
|
|
1846
|
+
(o.pre_aggregations || o.preAggregations) && (o.pre_aggregations || o.preAggregations || []).forEach((c) => {
|
|
1847
|
+
n[c.name] = ge(c);
|
|
1459
1848
|
});
|
|
1460
|
-
let
|
|
1461
|
-
!
|
|
1462
|
-
const a =
|
|
1849
|
+
let r = o.sql;
|
|
1850
|
+
!r && (o.sql_table || o.sqlTable) && (r = `SELECT * FROM ${o.sql_table || o.sqlTable}`);
|
|
1851
|
+
const a = o.refresh_key || o.refreshKey;
|
|
1463
1852
|
return {
|
|
1464
|
-
name:
|
|
1465
|
-
title:
|
|
1466
|
-
description:
|
|
1467
|
-
sql:
|
|
1468
|
-
sqlAlias:
|
|
1469
|
-
dataSource:
|
|
1853
|
+
name: o.name,
|
|
1854
|
+
title: o.title,
|
|
1855
|
+
description: o.description,
|
|
1856
|
+
sql: r || "",
|
|
1857
|
+
sqlAlias: o.sql_alias || o.sqlAlias,
|
|
1858
|
+
dataSource: o.data_source || o.dataSource,
|
|
1470
1859
|
refreshKey: a ? {
|
|
1471
1860
|
every: a.every,
|
|
1472
1861
|
sql: a.sql
|
|
1473
1862
|
} : void 0,
|
|
1474
1863
|
dimensions: e,
|
|
1475
1864
|
measures: t,
|
|
1476
|
-
joins: Object.keys(
|
|
1865
|
+
joins: Object.keys(s).length > 0 ? s : void 0,
|
|
1477
1866
|
preAggregations: Object.keys(n).length > 0 ? n : void 0,
|
|
1478
|
-
meta:
|
|
1867
|
+
meta: o.meta
|
|
1479
1868
|
};
|
|
1480
1869
|
}
|
|
1481
|
-
function
|
|
1870
|
+
function me(o) {
|
|
1482
1871
|
return {
|
|
1483
|
-
name:
|
|
1484
|
-
title:
|
|
1485
|
-
description:
|
|
1486
|
-
type:
|
|
1487
|
-
sql:
|
|
1488
|
-
primaryKey:
|
|
1489
|
-
shown:
|
|
1490
|
-
format:
|
|
1491
|
-
meta:
|
|
1872
|
+
name: o.name,
|
|
1873
|
+
title: o.title,
|
|
1874
|
+
description: o.description,
|
|
1875
|
+
type: o.type,
|
|
1876
|
+
sql: o.sql,
|
|
1877
|
+
primaryKey: o.primary_key || o.primaryKey,
|
|
1878
|
+
shown: o.shown,
|
|
1879
|
+
format: o.format,
|
|
1880
|
+
meta: o.meta
|
|
1492
1881
|
};
|
|
1493
1882
|
}
|
|
1494
|
-
function
|
|
1495
|
-
var
|
|
1496
|
-
const e = (
|
|
1883
|
+
function fe(o) {
|
|
1884
|
+
var s;
|
|
1885
|
+
const e = (s = o.filters) == null ? void 0 : s.map((n) => ({
|
|
1497
1886
|
sql: n.sql
|
|
1498
|
-
})), t =
|
|
1887
|
+
})), t = o.rolling_window || o.rollingWindow;
|
|
1499
1888
|
return {
|
|
1500
|
-
name:
|
|
1501
|
-
title:
|
|
1502
|
-
description:
|
|
1503
|
-
type:
|
|
1504
|
-
sql:
|
|
1505
|
-
format:
|
|
1506
|
-
shown:
|
|
1889
|
+
name: o.name,
|
|
1890
|
+
title: o.title,
|
|
1891
|
+
description: o.description,
|
|
1892
|
+
type: o.type,
|
|
1893
|
+
sql: o.sql,
|
|
1894
|
+
format: o.format,
|
|
1895
|
+
shown: o.shown,
|
|
1507
1896
|
filters: e,
|
|
1508
1897
|
rollingWindow: t,
|
|
1509
|
-
meta:
|
|
1898
|
+
meta: o.meta
|
|
1510
1899
|
};
|
|
1511
1900
|
}
|
|
1512
|
-
function
|
|
1513
|
-
switch (
|
|
1901
|
+
function he(o) {
|
|
1902
|
+
switch (o) {
|
|
1514
1903
|
case "one_to_one":
|
|
1515
1904
|
return "hasOne";
|
|
1516
1905
|
case "one_to_many":
|
|
@@ -1521,8 +1910,8 @@ function ue(s) {
|
|
|
1521
1910
|
return "belongsTo";
|
|
1522
1911
|
}
|
|
1523
1912
|
}
|
|
1524
|
-
function
|
|
1525
|
-
switch (
|
|
1913
|
+
function pe(o) {
|
|
1914
|
+
switch (o) {
|
|
1526
1915
|
case "hasOne":
|
|
1527
1916
|
return "one_to_one";
|
|
1528
1917
|
case "hasMany":
|
|
@@ -1533,62 +1922,62 @@ function me(s) {
|
|
|
1533
1922
|
return "many_to_one";
|
|
1534
1923
|
}
|
|
1535
1924
|
}
|
|
1536
|
-
function
|
|
1925
|
+
function be(o) {
|
|
1537
1926
|
return {
|
|
1538
|
-
name:
|
|
1539
|
-
type:
|
|
1540
|
-
relationship:
|
|
1541
|
-
sql:
|
|
1927
|
+
name: o.name,
|
|
1928
|
+
type: o.type,
|
|
1929
|
+
relationship: he(o.relationship),
|
|
1930
|
+
sql: o.sql
|
|
1542
1931
|
};
|
|
1543
1932
|
}
|
|
1544
|
-
function
|
|
1545
|
-
const e =
|
|
1933
|
+
function ge(o) {
|
|
1934
|
+
const e = o.time_dimension || o.timeDimension, t = o.refresh_key || o.refreshKey;
|
|
1546
1935
|
return {
|
|
1547
|
-
name:
|
|
1548
|
-
measures:
|
|
1549
|
-
dimensions:
|
|
1936
|
+
name: o.name,
|
|
1937
|
+
measures: o.measures,
|
|
1938
|
+
dimensions: o.dimensions,
|
|
1550
1939
|
timeDimension: e,
|
|
1551
1940
|
refreshKey: t,
|
|
1552
|
-
indexes:
|
|
1941
|
+
indexes: o.indexes
|
|
1553
1942
|
};
|
|
1554
1943
|
}
|
|
1555
|
-
async function
|
|
1944
|
+
async function Ce() {
|
|
1556
1945
|
try {
|
|
1557
|
-
const { promises:
|
|
1946
|
+
const { promises: o } = await import("fs"), e = await o.readFile("non-existent-file.txt", "utf-8").catch((t) => t.message);
|
|
1558
1947
|
return !(typeof e == "string" && e.includes("not implemented"));
|
|
1559
1948
|
} catch {
|
|
1560
1949
|
return !1;
|
|
1561
1950
|
}
|
|
1562
1951
|
}
|
|
1563
|
-
function
|
|
1564
|
-
const e =
|
|
1952
|
+
function we(o) {
|
|
1953
|
+
const e = ue(o);
|
|
1565
1954
|
if (!e.valid)
|
|
1566
1955
|
throw new Error(`Invalid YAML cube definition:
|
|
1567
1956
|
${e.errors.join(`
|
|
1568
1957
|
`)}`);
|
|
1569
|
-
return e.cubes.map((t) =>
|
|
1958
|
+
return e.cubes.map((t) => de(t));
|
|
1570
1959
|
}
|
|
1571
|
-
async function
|
|
1572
|
-
if (!await
|
|
1960
|
+
async function Te(o) {
|
|
1961
|
+
if (!await Ce())
|
|
1573
1962
|
return console.log("ℹ️ YAML file loading not supported in this environment (Cloudflare Workers/Edge Runtime). Use inline YAML strings or build-time transformations instead."), [];
|
|
1574
1963
|
try {
|
|
1575
|
-
const { promises: t } = await import("fs"),
|
|
1576
|
-
return
|
|
1964
|
+
const { promises: t } = await import("fs"), s = await t.readFile(o, "utf-8");
|
|
1965
|
+
return we(s);
|
|
1577
1966
|
} catch (t) {
|
|
1578
|
-
return console.log(`ℹ️ Could not load YAML file ${
|
|
1967
|
+
return console.log(`ℹ️ Could not load YAML file ${o}:`, t instanceof Error ? t.message : t), [];
|
|
1579
1968
|
}
|
|
1580
1969
|
}
|
|
1581
|
-
function
|
|
1582
|
-
let e =
|
|
1970
|
+
function Se(o) {
|
|
1971
|
+
let e = o;
|
|
1583
1972
|
return e = e.replace(/\{CUBE\}/g, "${CUBE}"), e = e.replace(/\{([A-Za-z_][A-Za-z0-9_]*\.[A-Za-z_][A-Za-z0-9_]*)\}/g, "${$1}"), e = e.replace(/\{([A-Za-z_][A-Za-z0-9_]*)\}/g, "${$1}"), e = e.replace(/\$\$\{/g, "${"), e;
|
|
1584
1973
|
}
|
|
1585
|
-
function
|
|
1974
|
+
function xe(o) {
|
|
1586
1975
|
const e = {
|
|
1587
|
-
name:
|
|
1588
|
-
title:
|
|
1589
|
-
description:
|
|
1590
|
-
sql: typeof
|
|
1591
|
-
dimensions: Object.values(
|
|
1976
|
+
name: o.name,
|
|
1977
|
+
title: o.title,
|
|
1978
|
+
description: o.description,
|
|
1979
|
+
sql: typeof o.sql == "string" ? o.sql : void 0,
|
|
1980
|
+
dimensions: Object.values(o.dimensions).map((t) => ({
|
|
1592
1981
|
name: t.name,
|
|
1593
1982
|
title: t.title,
|
|
1594
1983
|
description: t.description,
|
|
@@ -1599,8 +1988,8 @@ function $e(s) {
|
|
|
1599
1988
|
format: t.format,
|
|
1600
1989
|
meta: t.meta
|
|
1601
1990
|
})),
|
|
1602
|
-
measures: Object.values(
|
|
1603
|
-
var
|
|
1991
|
+
measures: Object.values(o.measures).map((t) => {
|
|
1992
|
+
var s;
|
|
1604
1993
|
return {
|
|
1605
1994
|
name: t.name,
|
|
1606
1995
|
title: t.title,
|
|
@@ -1609,108 +1998,108 @@ function $e(s) {
|
|
|
1609
1998
|
sql: typeof t.sql == "string" ? t.sql : "",
|
|
1610
1999
|
format: t.format,
|
|
1611
2000
|
shown: t.shown,
|
|
1612
|
-
filters: (
|
|
2001
|
+
filters: (s = t.filters) == null ? void 0 : s.map((n) => ({
|
|
1613
2002
|
sql: typeof n.sql == "string" ? n.sql : ""
|
|
1614
2003
|
})),
|
|
1615
2004
|
rolling_window: t.rollingWindow,
|
|
1616
2005
|
meta: t.meta
|
|
1617
2006
|
};
|
|
1618
2007
|
}),
|
|
1619
|
-
joins:
|
|
2008
|
+
joins: o.joins ? Object.values(o.joins).map((t) => ({
|
|
1620
2009
|
name: t.name || "",
|
|
1621
2010
|
type: t.type,
|
|
1622
|
-
relationship:
|
|
2011
|
+
relationship: pe(t.relationship),
|
|
1623
2012
|
sql: typeof t.sql == "string" ? t.sql : ""
|
|
1624
2013
|
})) : void 0,
|
|
1625
|
-
meta:
|
|
2014
|
+
meta: o.meta
|
|
1626
2015
|
};
|
|
1627
|
-
return
|
|
2016
|
+
return X(e, {
|
|
1628
2017
|
indent: 2,
|
|
1629
2018
|
lineWidth: 120,
|
|
1630
2019
|
minContentWidth: 40
|
|
1631
2020
|
});
|
|
1632
2021
|
}
|
|
1633
|
-
const
|
|
1634
|
-
function
|
|
1635
|
-
return new
|
|
1636
|
-
drizzle:
|
|
1637
|
-
schema:
|
|
2022
|
+
const Fe = ce;
|
|
2023
|
+
function Me(o) {
|
|
2024
|
+
return new x({
|
|
2025
|
+
drizzle: o.drizzle,
|
|
2026
|
+
schema: o.schema
|
|
1638
2027
|
});
|
|
1639
2028
|
}
|
|
1640
|
-
const
|
|
2029
|
+
const Le = {
|
|
1641
2030
|
/**
|
|
1642
2031
|
* Create a simple query builder
|
|
1643
2032
|
*/
|
|
1644
2033
|
query: () => {
|
|
1645
|
-
const
|
|
2034
|
+
const o = (e, t = [], s = [], n = [], r, a) => ({
|
|
1646
2035
|
measures: e,
|
|
1647
2036
|
dimensions: t,
|
|
1648
|
-
filters:
|
|
2037
|
+
filters: s,
|
|
1649
2038
|
timeDimensions: n,
|
|
1650
|
-
limit:
|
|
2039
|
+
limit: r,
|
|
1651
2040
|
order: a
|
|
1652
2041
|
});
|
|
1653
2042
|
return {
|
|
1654
2043
|
measures: (e) => ({
|
|
1655
2044
|
dimensions: (t = []) => ({
|
|
1656
|
-
filters: (
|
|
2045
|
+
filters: (s = []) => ({
|
|
1657
2046
|
timeDimensions: (n = []) => ({
|
|
1658
|
-
limit: (
|
|
1659
|
-
order: (a) =>
|
|
2047
|
+
limit: (r) => ({
|
|
2048
|
+
order: (a) => o(e, t, s, n, r, a)
|
|
1660
2049
|
}),
|
|
1661
|
-
order: (
|
|
2050
|
+
order: (r) => o(e, t, s, n, void 0, r)
|
|
1662
2051
|
}),
|
|
1663
2052
|
limit: (n) => ({
|
|
1664
|
-
order: (
|
|
2053
|
+
order: (r) => o(e, t, s, [], n, r)
|
|
1665
2054
|
}),
|
|
1666
|
-
order: (n) =>
|
|
2055
|
+
order: (n) => o(e, t, s, [], void 0, n)
|
|
1667
2056
|
}),
|
|
1668
|
-
timeDimensions: (
|
|
2057
|
+
timeDimensions: (s = []) => ({
|
|
1669
2058
|
filters: (n = []) => ({
|
|
1670
|
-
limit: (
|
|
1671
|
-
order: (a) =>
|
|
2059
|
+
limit: (r) => ({
|
|
2060
|
+
order: (a) => o(e, t, n, s, r, a)
|
|
1672
2061
|
}),
|
|
1673
|
-
order: (
|
|
2062
|
+
order: (r) => o(e, t, n, s, void 0, r)
|
|
1674
2063
|
}),
|
|
1675
2064
|
limit: (n) => ({
|
|
1676
|
-
order: (
|
|
2065
|
+
order: (r) => o(e, t, [], s, n, r)
|
|
1677
2066
|
}),
|
|
1678
|
-
order: (n) =>
|
|
2067
|
+
order: (n) => o(e, t, [], s, void 0, n)
|
|
1679
2068
|
}),
|
|
1680
|
-
limit: (
|
|
1681
|
-
order: (n) =>
|
|
2069
|
+
limit: (s) => ({
|
|
2070
|
+
order: (n) => o(e, t, [], [], s, n)
|
|
1682
2071
|
}),
|
|
1683
|
-
order: (
|
|
2072
|
+
order: (s) => o(e, t, [], [], void 0, s)
|
|
1684
2073
|
}),
|
|
1685
2074
|
filters: (t = []) => ({
|
|
1686
|
-
dimensions: (
|
|
2075
|
+
dimensions: (s = []) => ({
|
|
1687
2076
|
timeDimensions: (n = []) => ({
|
|
1688
|
-
limit: (
|
|
1689
|
-
order: (a) =>
|
|
2077
|
+
limit: (r) => ({
|
|
2078
|
+
order: (a) => o(e, s, t, n, r, a)
|
|
1690
2079
|
}),
|
|
1691
|
-
order: (
|
|
2080
|
+
order: (r) => o(e, s, t, n, void 0, r)
|
|
1692
2081
|
}),
|
|
1693
2082
|
limit: (n) => ({
|
|
1694
|
-
order: (
|
|
2083
|
+
order: (r) => o(e, s, t, [], n, r)
|
|
1695
2084
|
}),
|
|
1696
|
-
order: (n) =>
|
|
2085
|
+
order: (n) => o(e, s, t, [], void 0, n)
|
|
1697
2086
|
}),
|
|
1698
|
-
timeDimensions: (
|
|
2087
|
+
timeDimensions: (s = []) => ({
|
|
1699
2088
|
dimensions: (n = []) => ({
|
|
1700
|
-
limit: (
|
|
1701
|
-
order: (a) =>
|
|
2089
|
+
limit: (r) => ({
|
|
2090
|
+
order: (a) => o(e, n, t, s, r, a)
|
|
1702
2091
|
}),
|
|
1703
|
-
order: (
|
|
2092
|
+
order: (r) => o(e, n, t, s, void 0, r)
|
|
1704
2093
|
}),
|
|
1705
2094
|
limit: (n) => ({
|
|
1706
|
-
order: (
|
|
2095
|
+
order: (r) => o(e, [], t, s, n, r)
|
|
1707
2096
|
}),
|
|
1708
|
-
order: (n) =>
|
|
2097
|
+
order: (n) => o(e, [], t, s, void 0, n)
|
|
1709
2098
|
}),
|
|
1710
|
-
limit: (
|
|
1711
|
-
order: (n) =>
|
|
2099
|
+
limit: (s) => ({
|
|
2100
|
+
order: (n) => o(e, [], t, [], s, n)
|
|
1712
2101
|
}),
|
|
1713
|
-
order: (
|
|
2102
|
+
order: (s) => o(e, [], t, [], void 0, s)
|
|
1714
2103
|
})
|
|
1715
2104
|
})
|
|
1716
2105
|
};
|
|
@@ -1719,55 +2108,55 @@ const Ae = {
|
|
|
1719
2108
|
* Create filters
|
|
1720
2109
|
*/
|
|
1721
2110
|
filters: {
|
|
1722
|
-
equals: (
|
|
1723
|
-
notEquals: (
|
|
1724
|
-
contains: (
|
|
1725
|
-
greaterThan: (
|
|
1726
|
-
lessThan: (
|
|
1727
|
-
inDateRange: (
|
|
1728
|
-
member:
|
|
2111
|
+
equals: (o, e) => ({ member: o, operator: "equals", values: [e] }),
|
|
2112
|
+
notEquals: (o, e) => ({ member: o, operator: "notEquals", values: [e] }),
|
|
2113
|
+
contains: (o, e) => ({ member: o, operator: "contains", values: [e] }),
|
|
2114
|
+
greaterThan: (o, e) => ({ member: o, operator: "gt", values: [e] }),
|
|
2115
|
+
lessThan: (o, e) => ({ member: o, operator: "lt", values: [e] }),
|
|
2116
|
+
inDateRange: (o, e, t) => ({
|
|
2117
|
+
member: o,
|
|
1729
2118
|
operator: "inDateRange",
|
|
1730
2119
|
values: [e, t]
|
|
1731
2120
|
}),
|
|
1732
|
-
set: (
|
|
1733
|
-
notSet: (
|
|
2121
|
+
set: (o) => ({ member: o, operator: "set", values: [] }),
|
|
2122
|
+
notSet: (o) => ({ member: o, operator: "notSet", values: [] })
|
|
1734
2123
|
},
|
|
1735
2124
|
/**
|
|
1736
2125
|
* Create time dimensions
|
|
1737
2126
|
*/
|
|
1738
2127
|
timeDimensions: {
|
|
1739
|
-
create: (
|
|
1740
|
-
dimension:
|
|
2128
|
+
create: (o, e, t) => ({
|
|
2129
|
+
dimension: o,
|
|
1741
2130
|
granularity: e,
|
|
1742
2131
|
dateRange: t
|
|
1743
2132
|
})
|
|
1744
2133
|
}
|
|
1745
2134
|
};
|
|
1746
2135
|
export {
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
2136
|
+
S as BaseDatabaseExecutor,
|
|
2137
|
+
ae as MultiCubeBuilder,
|
|
2138
|
+
ie as MySQLExecutor,
|
|
2139
|
+
ne as PostgresExecutor,
|
|
2140
|
+
T as QueryExecutor,
|
|
2141
|
+
se as SQLiteExecutor,
|
|
2142
|
+
x as SemanticLayerCompiler,
|
|
2143
|
+
Le as SemanticLayerUtils,
|
|
2144
|
+
Se as convertCubeReferences,
|
|
2145
|
+
L as createDatabaseExecutor,
|
|
2146
|
+
Me as createDrizzleSemanticLayer,
|
|
2147
|
+
oe as createMultiCubeContext,
|
|
2148
|
+
re as createMySQLExecutor,
|
|
2149
|
+
F as createPostgresExecutor,
|
|
1761
2150
|
M as createSQLiteExecutor,
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
2151
|
+
ye as createSemanticLayer,
|
|
2152
|
+
Fe as defaultSemanticLayer,
|
|
2153
|
+
Ee as defineCube,
|
|
2154
|
+
$e as defineLegacyCube,
|
|
2155
|
+
we as loadYamlCubes,
|
|
2156
|
+
Te as loadYamlCubesFromFile,
|
|
2157
|
+
ue as parseYamlCubes,
|
|
1769
2158
|
b as resolveSqlExpression,
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
2159
|
+
xe as semanticCubeToYaml,
|
|
2160
|
+
ce as semanticLayer,
|
|
2161
|
+
de as yamlCubeToSemanticCube
|
|
1773
2162
|
};
|