@cubejs-client/core 0.35.0 → 0.36.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cubejs-client-core.esm.js +91 -253
- package/dist/cubejs-client-core.esm.js.map +1 -1
- package/dist/cubejs-client-core.js +104 -395
- package/dist/cubejs-client-core.js.map +1 -1
- package/dist/cubejs-client-core.umd.js +104 -395
- package/dist/cubejs-client-core.umd.js.map +1 -1
- package/index.d.ts +4 -1
- package/package.json +2 -2
- package/src/index.js +11 -0
|
@@ -43,7 +43,6 @@ function removeEmptyQueryFields(_query) {
|
|
|
43
43
|
return null;
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
|
-
|
|
47
46
|
if (key === 'order' && value) {
|
|
48
47
|
if (Array.isArray(value) && !value.length) {
|
|
49
48
|
return null;
|
|
@@ -51,13 +50,13 @@ function removeEmptyQueryFields(_query) {
|
|
|
51
50
|
return null;
|
|
52
51
|
}
|
|
53
52
|
}
|
|
54
|
-
|
|
55
53
|
return [key, value];
|
|
56
54
|
}).filter(Boolean));
|
|
57
55
|
}
|
|
58
56
|
function validateQuery(_query) {
|
|
59
57
|
const query = _query || {};
|
|
60
|
-
return removeEmptyQueryFields({
|
|
58
|
+
return removeEmptyQueryFields({
|
|
59
|
+
...query,
|
|
61
60
|
filters: (query.filters || []).filter(f => f.operator),
|
|
62
61
|
timeDimensions: (query.timeDimensions || []).filter(td => !(!td.dateRange && !td.granularity))
|
|
63
62
|
});
|
|
@@ -67,7 +66,6 @@ function areQueriesEqual(query1 = {}, query2 = {}) {
|
|
|
67
66
|
}
|
|
68
67
|
function defaultOrder(query) {
|
|
69
68
|
const granularity = (query.timeDimensions || []).find(d => d.granularity);
|
|
70
|
-
|
|
71
69
|
if (granularity) {
|
|
72
70
|
return {
|
|
73
71
|
[granularity.dimension]: 'asc'
|
|
@@ -81,7 +79,6 @@ function defaultOrder(query) {
|
|
|
81
79
|
[query.dimensions[0]]: 'asc'
|
|
82
80
|
};
|
|
83
81
|
}
|
|
84
|
-
|
|
85
82
|
return {};
|
|
86
83
|
}
|
|
87
84
|
function defaultHeuristics(newState, oldQuery = {}, options) {
|
|
@@ -99,130 +96,134 @@ function defaultHeuristics(newState, oldQuery = {}, options) {
|
|
|
99
96
|
...props
|
|
100
97
|
};
|
|
101
98
|
let newQuery = null;
|
|
102
|
-
|
|
103
99
|
if (!areQueriesEqual(query, oldQuery)) {
|
|
104
100
|
newQuery = query;
|
|
105
101
|
}
|
|
106
|
-
|
|
107
102
|
if (Array.isArray(newQuery) || Array.isArray(oldQuery)) {
|
|
108
103
|
return newState;
|
|
109
104
|
}
|
|
110
|
-
|
|
111
105
|
if (newQuery) {
|
|
112
106
|
if ((oldQuery.timeDimensions || []).length === 1 && (newQuery.timeDimensions || []).length === 1 && newQuery.timeDimensions[0].granularity && oldQuery.timeDimensions[0].granularity !== newQuery.timeDimensions[0].granularity) {
|
|
113
|
-
state = {
|
|
107
|
+
state = {
|
|
108
|
+
...state,
|
|
114
109
|
sessionGranularity: newQuery.timeDimensions[0].granularity
|
|
115
110
|
};
|
|
116
111
|
}
|
|
117
|
-
|
|
118
112
|
if ((oldQuery.measures || []).length === 0 && (newQuery.measures || []).length > 0 || (oldQuery.measures || []).length === 1 && (newQuery.measures || []).length === 1 && oldQuery.measures[0] !== newQuery.measures[0]) {
|
|
119
113
|
const [td] = newQuery.timeDimensions || [];
|
|
120
114
|
const defaultTimeDimension = meta.defaultTimeDimensionNameFor(newQuery.measures[0]);
|
|
121
|
-
newQuery = {
|
|
115
|
+
newQuery = {
|
|
116
|
+
...newQuery,
|
|
122
117
|
timeDimensions: defaultTimeDimension ? [{
|
|
123
118
|
dimension: defaultTimeDimension,
|
|
124
119
|
granularity: td && td.granularity || granularity,
|
|
125
120
|
dateRange: td && td.dateRange
|
|
126
121
|
}] : []
|
|
127
122
|
};
|
|
128
|
-
return {
|
|
123
|
+
return {
|
|
124
|
+
...state,
|
|
129
125
|
pivotConfig: null,
|
|
130
126
|
shouldApplyHeuristicOrder: true,
|
|
131
127
|
query: newQuery,
|
|
132
128
|
chartType: defaultTimeDimension ? 'line' : 'number'
|
|
133
129
|
};
|
|
134
130
|
}
|
|
135
|
-
|
|
136
131
|
if ((oldQuery.dimensions || []).length === 0 && (newQuery.dimensions || []).length > 0) {
|
|
137
|
-
newQuery = {
|
|
138
|
-
|
|
132
|
+
newQuery = {
|
|
133
|
+
...newQuery,
|
|
134
|
+
timeDimensions: (newQuery.timeDimensions || []).map(td => ({
|
|
135
|
+
...td,
|
|
139
136
|
granularity: undefined
|
|
140
137
|
}))
|
|
141
138
|
};
|
|
142
|
-
return {
|
|
139
|
+
return {
|
|
140
|
+
...state,
|
|
143
141
|
pivotConfig: null,
|
|
144
142
|
shouldApplyHeuristicOrder: true,
|
|
145
143
|
query: newQuery,
|
|
146
144
|
chartType: 'table'
|
|
147
145
|
};
|
|
148
146
|
}
|
|
149
|
-
|
|
150
147
|
if ((oldQuery.dimensions || []).length > 0 && (newQuery.dimensions || []).length === 0) {
|
|
151
|
-
newQuery = {
|
|
152
|
-
|
|
148
|
+
newQuery = {
|
|
149
|
+
...newQuery,
|
|
150
|
+
timeDimensions: (newQuery.timeDimensions || []).map(td => ({
|
|
151
|
+
...td,
|
|
153
152
|
granularity: td.granularity || granularity
|
|
154
153
|
}))
|
|
155
154
|
};
|
|
156
|
-
return {
|
|
155
|
+
return {
|
|
156
|
+
...state,
|
|
157
157
|
pivotConfig: null,
|
|
158
158
|
shouldApplyHeuristicOrder: true,
|
|
159
159
|
query: newQuery,
|
|
160
160
|
chartType: (newQuery.timeDimensions || []).length ? 'line' : 'number'
|
|
161
161
|
};
|
|
162
162
|
}
|
|
163
|
-
|
|
164
163
|
if (((oldQuery.dimensions || []).length > 0 || (oldQuery.measures || []).length > 0) && (newQuery.dimensions || []).length === 0 && (newQuery.measures || []).length === 0) {
|
|
165
|
-
newQuery = {
|
|
164
|
+
newQuery = {
|
|
165
|
+
...newQuery,
|
|
166
166
|
timeDimensions: [],
|
|
167
167
|
filters: []
|
|
168
168
|
};
|
|
169
|
-
return {
|
|
169
|
+
return {
|
|
170
|
+
...state,
|
|
170
171
|
pivotConfig: null,
|
|
171
172
|
shouldApplyHeuristicOrder: true,
|
|
172
173
|
query: newQuery,
|
|
173
174
|
sessionGranularity: null
|
|
174
175
|
};
|
|
175
176
|
}
|
|
176
|
-
|
|
177
177
|
return state;
|
|
178
178
|
}
|
|
179
|
-
|
|
180
179
|
if (state.chartType) {
|
|
181
180
|
const newChartType = state.chartType;
|
|
182
|
-
|
|
183
181
|
if ((newChartType === 'line' || newChartType === 'area') && (oldQuery.timeDimensions || []).length === 1 && !oldQuery.timeDimensions[0].granularity) {
|
|
184
182
|
const [td] = oldQuery.timeDimensions;
|
|
185
|
-
return {
|
|
183
|
+
return {
|
|
184
|
+
...state,
|
|
186
185
|
pivotConfig: null,
|
|
187
|
-
query: {
|
|
188
|
-
|
|
186
|
+
query: {
|
|
187
|
+
...oldQuery,
|
|
188
|
+
timeDimensions: [{
|
|
189
|
+
...td,
|
|
189
190
|
granularity
|
|
190
191
|
}]
|
|
191
192
|
}
|
|
192
193
|
};
|
|
193
194
|
}
|
|
194
|
-
|
|
195
195
|
if ((newChartType === 'pie' || newChartType === 'table' || newChartType === 'number') && (oldQuery.timeDimensions || []).length === 1 && oldQuery.timeDimensions[0].granularity) {
|
|
196
196
|
const [td] = oldQuery.timeDimensions;
|
|
197
|
-
return {
|
|
197
|
+
return {
|
|
198
|
+
...state,
|
|
198
199
|
pivotConfig: null,
|
|
199
200
|
shouldApplyHeuristicOrder: true,
|
|
200
|
-
query: {
|
|
201
|
-
|
|
201
|
+
query: {
|
|
202
|
+
...oldQuery,
|
|
203
|
+
timeDimensions: [{
|
|
204
|
+
...td,
|
|
202
205
|
granularity: undefined
|
|
203
206
|
}]
|
|
204
207
|
}
|
|
205
208
|
};
|
|
206
209
|
}
|
|
207
210
|
}
|
|
208
|
-
|
|
209
211
|
return state;
|
|
210
212
|
}
|
|
211
213
|
function isQueryPresent(query) {
|
|
212
214
|
if (!query) {
|
|
213
215
|
return false;
|
|
214
216
|
}
|
|
215
|
-
|
|
216
217
|
return (Array.isArray(query) ? query : [query]).every(q => q.measures && q.measures.length || q.dimensions && q.dimensions.length || q.timeDimensions && q.timeDimensions.length);
|
|
217
218
|
}
|
|
218
219
|
function movePivotItem(pivotConfig, sourceIndex, destinationIndex, sourceAxis, destinationAxis) {
|
|
219
|
-
const nextPivotConfig = {
|
|
220
|
+
const nextPivotConfig = {
|
|
221
|
+
...pivotConfig,
|
|
220
222
|
x: [...pivotConfig.x],
|
|
221
223
|
y: [...pivotConfig.y]
|
|
222
224
|
};
|
|
223
225
|
const id = pivotConfig[sourceAxis][sourceIndex];
|
|
224
226
|
const lastIndex = nextPivotConfig[destinationAxis].length - 1;
|
|
225
|
-
|
|
226
227
|
if (id === 'measures') {
|
|
227
228
|
destinationIndex = lastIndex + 1;
|
|
228
229
|
} else if (sourceAxis === destinationAxis && destinationIndex >= lastIndex && nextPivotConfig[destinationAxis][lastIndex] === 'measures') {
|
|
@@ -230,7 +231,6 @@ function movePivotItem(pivotConfig, sourceIndex, destinationIndex, sourceAxis, d
|
|
|
230
231
|
} else if (sourceAxis !== destinationAxis && destinationIndex > lastIndex && nextPivotConfig[destinationAxis][lastIndex] === 'measures') {
|
|
231
232
|
destinationIndex = lastIndex;
|
|
232
233
|
}
|
|
233
|
-
|
|
234
234
|
nextPivotConfig[sourceAxis].splice(sourceIndex, 1);
|
|
235
235
|
nextPivotConfig[destinationAxis].splice(destinationIndex, 0, id);
|
|
236
236
|
return nextPivotConfig;
|
|
@@ -246,7 +246,6 @@ function flattenFilters(filters = []) {
|
|
|
246
246
|
if (filter.or || filter.and) {
|
|
247
247
|
return [...memo, ...flattenFilters(filter.or || filter.and)];
|
|
248
248
|
}
|
|
249
|
-
|
|
250
249
|
return [...memo, filter];
|
|
251
250
|
}, []);
|
|
252
251
|
}
|
|
@@ -266,14 +265,16 @@ function getOrderMembersFromOrder(orderMembers, order) {
|
|
|
266
265
|
entries.forEach(([memberId, currentOrder]) => {
|
|
267
266
|
if (currentOrder !== 'none' && indexedOrderMembers[memberId]) {
|
|
268
267
|
ids.add(memberId);
|
|
269
|
-
nextOrderMembers.push({
|
|
268
|
+
nextOrderMembers.push({
|
|
269
|
+
...indexedOrderMembers[memberId],
|
|
270
270
|
order: currentOrder
|
|
271
271
|
});
|
|
272
272
|
}
|
|
273
273
|
});
|
|
274
274
|
orderMembers.forEach(member => {
|
|
275
275
|
if (!ids.has(member.id)) {
|
|
276
|
-
nextOrderMembers.push({
|
|
276
|
+
nextOrderMembers.push({
|
|
277
|
+
...member,
|
|
277
278
|
order: member.order || 'none'
|
|
278
279
|
});
|
|
279
280
|
}
|
|
@@ -282,23 +283,22 @@ function getOrderMembersFromOrder(orderMembers, order) {
|
|
|
282
283
|
}
|
|
283
284
|
function aliasSeries(values, index, pivotConfig, duplicateMeasures) {
|
|
284
285
|
const nonNullValues = values.filter(value => value != null);
|
|
285
|
-
|
|
286
286
|
if (pivotConfig && pivotConfig.aliasSeries && pivotConfig.aliasSeries[index]) {
|
|
287
287
|
return [pivotConfig.aliasSeries[index], ...nonNullValues];
|
|
288
288
|
} else if (duplicateMeasures.has(nonNullValues[0])) {
|
|
289
289
|
return [index, ...nonNullValues];
|
|
290
290
|
}
|
|
291
|
-
|
|
292
291
|
return nonNullValues;
|
|
293
292
|
}
|
|
294
293
|
|
|
295
|
-
dayjs.extend(quarterOfYear);
|
|
296
|
-
// So the function below has been added.
|
|
294
|
+
dayjs.extend(quarterOfYear);
|
|
297
295
|
|
|
298
|
-
|
|
296
|
+
// When granularity is week, weekStart Value must be 1. However, since the client can change it globally (https://day.js.org/docs/en/i18n/changing-locale)
|
|
297
|
+
// So the function below has been added.
|
|
298
|
+
const internalDayjs = (...args) => dayjs(...args).locale({
|
|
299
|
+
...en,
|
|
299
300
|
weekStart: 1
|
|
300
301
|
});
|
|
301
|
-
|
|
302
302
|
const TIME_SERIES = {
|
|
303
303
|
day: range => range.by('d').map(d => d.format('YYYY-MM-DDT00:00:00.000')),
|
|
304
304
|
month: range => range.snapTo('month').by('M').map(d => d.format('YYYY-MM-01T00:00:00.000')),
|
|
@@ -311,23 +311,19 @@ const TIME_SERIES = {
|
|
|
311
311
|
};
|
|
312
312
|
const DateRegex = /^\d\d\d\d-\d\d-\d\d$/;
|
|
313
313
|
const LocalDateRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z?$/;
|
|
314
|
-
|
|
315
314
|
const groupByToPairs = keyFn => {
|
|
316
315
|
const acc = new Map();
|
|
317
316
|
return data => {
|
|
318
317
|
data.forEach(row => {
|
|
319
318
|
const key = keyFn(row);
|
|
320
|
-
|
|
321
319
|
if (!acc.has(key)) {
|
|
322
320
|
acc.set(key, []);
|
|
323
321
|
}
|
|
324
|
-
|
|
325
322
|
acc.get(key).push(row);
|
|
326
323
|
});
|
|
327
324
|
return Array.from(acc.entries());
|
|
328
325
|
};
|
|
329
326
|
};
|
|
330
|
-
|
|
331
327
|
const unnest = arr => {
|
|
332
328
|
const res = [];
|
|
333
329
|
arr.forEach(subArr => {
|
|
@@ -335,18 +331,15 @@ const unnest = arr => {
|
|
|
335
331
|
});
|
|
336
332
|
return res;
|
|
337
333
|
};
|
|
338
|
-
|
|
339
334
|
const dayRange = (from, to) => ({
|
|
340
335
|
by: value => {
|
|
341
336
|
const results = [];
|
|
342
337
|
let start = internalDayjs(from);
|
|
343
338
|
const end = internalDayjs(to);
|
|
344
|
-
|
|
345
339
|
while (start.isBefore(end) || start.isSame(end)) {
|
|
346
340
|
results.push(start);
|
|
347
341
|
start = start.add(1, value);
|
|
348
342
|
}
|
|
349
|
-
|
|
350
343
|
return results;
|
|
351
344
|
},
|
|
352
345
|
snapTo: value => dayRange(internalDayjs(from).startOf(value), internalDayjs(to).endOf(value)),
|
|
@@ -358,52 +351,43 @@ const QUERY_TYPE = {
|
|
|
358
351
|
COMPARE_DATE_RANGE_QUERY: 'compareDateRangeQuery',
|
|
359
352
|
BLENDING_QUERY: 'blendingQuery'
|
|
360
353
|
};
|
|
361
|
-
|
|
362
354
|
class ResultSet {
|
|
363
355
|
static measureFromAxis(axisValues) {
|
|
364
356
|
return axisValues[axisValues.length - 1];
|
|
365
357
|
}
|
|
366
|
-
|
|
367
358
|
static timeDimensionMember(td) {
|
|
368
359
|
return `${td.dimension}.${td.granularity}`;
|
|
369
360
|
}
|
|
370
|
-
|
|
371
361
|
static deserialize(data, options = {}) {
|
|
372
362
|
return new ResultSet(data.loadResponse, options);
|
|
373
363
|
}
|
|
374
|
-
|
|
375
364
|
constructor(loadResponse, options = {}) {
|
|
376
365
|
this.loadResponse = loadResponse;
|
|
377
|
-
|
|
378
366
|
if (this.loadResponse.queryType != null) {
|
|
379
367
|
this.queryType = loadResponse.queryType;
|
|
380
368
|
this.loadResponses = loadResponse.results;
|
|
381
369
|
} else {
|
|
382
370
|
this.queryType = QUERY_TYPE.REGULAR_QUERY;
|
|
383
|
-
this.loadResponse.pivotQuery = {
|
|
371
|
+
this.loadResponse.pivotQuery = {
|
|
372
|
+
...loadResponse.query,
|
|
384
373
|
queryType: this.queryType
|
|
385
374
|
};
|
|
386
375
|
this.loadResponses = [loadResponse];
|
|
387
376
|
}
|
|
388
|
-
|
|
389
377
|
if (!Object.values(QUERY_TYPE).includes(this.queryType)) {
|
|
390
378
|
throw new Error('Unknown query type');
|
|
391
379
|
}
|
|
392
|
-
|
|
393
380
|
this.parseDateMeasures = options.parseDateMeasures;
|
|
394
381
|
this.options = options;
|
|
395
382
|
this.backwardCompatibleData = [];
|
|
396
383
|
}
|
|
397
|
-
|
|
398
384
|
drillDown(drillDownLocator, pivotConfig) {
|
|
399
385
|
if (this.queryType === QUERY_TYPE.COMPARE_DATE_RANGE_QUERY) {
|
|
400
386
|
throw new Error('compareDateRange drillDown query is not currently supported');
|
|
401
387
|
}
|
|
402
|
-
|
|
403
388
|
if (this.queryType === QUERY_TYPE.BLENDING_QUERY) {
|
|
404
389
|
throw new Error('Data blending drillDown query is not currently supported');
|
|
405
390
|
}
|
|
406
|
-
|
|
407
391
|
const {
|
|
408
392
|
query
|
|
409
393
|
} = this.loadResponses[0];
|
|
@@ -423,15 +407,12 @@ class ResultSet {
|
|
|
423
407
|
measures
|
|
424
408
|
} = this.loadResponses[0].annotation;
|
|
425
409
|
let [, measureName] = values.find(([member]) => member === 'measures') || [];
|
|
426
|
-
|
|
427
410
|
if (measureName === undefined) {
|
|
428
411
|
[measureName] = Object.keys(measures);
|
|
429
412
|
}
|
|
430
|
-
|
|
431
413
|
if (!(measures[measureName] && measures[measureName].drillMembers || []).length) {
|
|
432
414
|
return null;
|
|
433
415
|
}
|
|
434
|
-
|
|
435
416
|
const filters = [{
|
|
436
417
|
member: measureName,
|
|
437
418
|
operator: 'measureFilter'
|
|
@@ -439,17 +420,14 @@ class ResultSet {
|
|
|
439
420
|
const timeDimensions = [];
|
|
440
421
|
values.filter(([member]) => member !== 'measures').forEach(([member, value]) => {
|
|
441
422
|
const [cubeName, dimension, granularity] = member.split('.');
|
|
442
|
-
|
|
443
423
|
if (granularity !== undefined) {
|
|
444
424
|
const range = dayRange(value, value).snapTo(granularity);
|
|
445
425
|
const originalTimeDimension = query.timeDimensions.find(td => td.dimension);
|
|
446
426
|
let dateRange = [range.start, range.end];
|
|
447
|
-
|
|
448
427
|
if (originalTimeDimension?.dateRange) {
|
|
449
428
|
const [originalStart, originalEnd] = originalTimeDimension.dateRange;
|
|
450
429
|
dateRange = [dayjs(originalStart) > range.start ? dayjs(originalStart) : range.start, dayjs(originalEnd) < range.end ? dayjs(originalEnd) : range.end];
|
|
451
430
|
}
|
|
452
|
-
|
|
453
431
|
timeDimensions.push({
|
|
454
432
|
dimension: [cubeName, dimension].join('.'),
|
|
455
433
|
dateRange: dateRange.map(dt => dt.format('YYYY-MM-DDTHH:mm:ss.SSS'))
|
|
@@ -467,12 +445,11 @@ class ResultSet {
|
|
|
467
445
|
});
|
|
468
446
|
}
|
|
469
447
|
});
|
|
470
|
-
|
|
471
448
|
if (timeDimensions.length === 0 && query.timeDimensions.length > 0 && query.timeDimensions[0].granularity == null) {
|
|
472
449
|
timeDimensions.push(query.timeDimensions[0]);
|
|
473
450
|
}
|
|
474
|
-
|
|
475
|
-
|
|
451
|
+
return {
|
|
452
|
+
...measures[measureName].drillMembersGrouped,
|
|
476
453
|
filters,
|
|
477
454
|
...(segments.length > 0 ? {
|
|
478
455
|
segments
|
|
@@ -482,7 +459,6 @@ class ResultSet {
|
|
|
482
459
|
timezone: query.timezone
|
|
483
460
|
};
|
|
484
461
|
}
|
|
485
|
-
|
|
486
462
|
series(pivotConfig) {
|
|
487
463
|
return this.seriesNames(pivotConfig).map(({
|
|
488
464
|
title,
|
|
@@ -501,22 +477,18 @@ class ResultSet {
|
|
|
501
477
|
}))
|
|
502
478
|
}));
|
|
503
479
|
}
|
|
504
|
-
|
|
505
480
|
axisValues(axis, resultIndex = 0) {
|
|
506
481
|
const {
|
|
507
482
|
query
|
|
508
483
|
} = this.loadResponses[resultIndex];
|
|
509
484
|
return row => {
|
|
510
485
|
const value = measure => axis.filter(d => d !== 'measures').map(d => row[d] != null ? row[d] : null).concat(measure ? [measure] : []);
|
|
511
|
-
|
|
512
486
|
if (axis.find(d => d === 'measures') && (query.measures || []).length) {
|
|
513
487
|
return query.measures.map(value);
|
|
514
488
|
}
|
|
515
|
-
|
|
516
489
|
return [value()];
|
|
517
490
|
};
|
|
518
491
|
}
|
|
519
|
-
|
|
520
492
|
axisValuesString(axisValues, delimiter) {
|
|
521
493
|
const formatValue = v => {
|
|
522
494
|
if (v == null) {
|
|
@@ -527,10 +499,8 @@ class ResultSet {
|
|
|
527
499
|
return v;
|
|
528
500
|
}
|
|
529
501
|
};
|
|
530
|
-
|
|
531
502
|
return axisValues.map(formatValue).join(delimiter || ', ');
|
|
532
503
|
}
|
|
533
|
-
|
|
534
504
|
static getNormalizedPivotConfig(query = {}, pivotConfig = null) {
|
|
535
505
|
const defaultPivotConfig = {
|
|
536
506
|
x: [],
|
|
@@ -551,85 +521,64 @@ class ResultSet {
|
|
|
551
521
|
y: []
|
|
552
522
|
});
|
|
553
523
|
pivotConfig = mergeDeepLeft(pivotConfig, defaultPivotConfig);
|
|
554
|
-
|
|
555
524
|
const substituteTimeDimensionMembers = axis => axis.map(subDim => timeDimensions.find(td => td.dimension === subDim) && !dimensions.find(d => d === subDim) ? ResultSet.timeDimensionMember(query.timeDimensions.find(td => td.dimension === subDim)) : subDim);
|
|
556
|
-
|
|
557
525
|
pivotConfig.x = substituteTimeDimensionMembers(pivotConfig.x);
|
|
558
526
|
pivotConfig.y = substituteTimeDimensionMembers(pivotConfig.y);
|
|
559
527
|
const allIncludedDimensions = pivotConfig.x.concat(pivotConfig.y);
|
|
560
528
|
const allDimensions = timeDimensions.map(td => ResultSet.timeDimensionMember(td)).concat(dimensions);
|
|
561
|
-
|
|
562
529
|
const dimensionFilter = key => allDimensions.includes(key) || key === 'measures';
|
|
563
|
-
|
|
564
530
|
pivotConfig.x = pivotConfig.x.concat(allDimensions.filter(d => !allIncludedDimensions.includes(d) && d !== 'compareDateRange')).filter(dimensionFilter);
|
|
565
531
|
pivotConfig.y = pivotConfig.y.filter(dimensionFilter);
|
|
566
|
-
|
|
567
532
|
if (!pivotConfig.x.concat(pivotConfig.y).find(d => d === 'measures')) {
|
|
568
533
|
pivotConfig.y.push('measures');
|
|
569
534
|
}
|
|
570
|
-
|
|
571
535
|
if (dimensions.includes('compareDateRange') && !pivotConfig.y.concat(pivotConfig.x).includes('compareDateRange')) {
|
|
572
536
|
pivotConfig.y.unshift('compareDateRange');
|
|
573
537
|
}
|
|
574
|
-
|
|
575
538
|
if (!measures.length) {
|
|
576
539
|
pivotConfig.x = pivotConfig.x.filter(d => d !== 'measures');
|
|
577
540
|
pivotConfig.y = pivotConfig.y.filter(d => d !== 'measures');
|
|
578
541
|
}
|
|
579
|
-
|
|
580
542
|
return pivotConfig;
|
|
581
543
|
}
|
|
582
|
-
|
|
583
544
|
normalizePivotConfig(pivotConfig) {
|
|
584
545
|
return ResultSet.getNormalizedPivotConfig(this.loadResponse.pivotQuery, pivotConfig);
|
|
585
546
|
}
|
|
586
|
-
|
|
587
547
|
timeSeries(timeDimension, resultIndex) {
|
|
588
548
|
if (!timeDimension.granularity) {
|
|
589
549
|
return null;
|
|
590
550
|
}
|
|
591
|
-
|
|
592
551
|
let {
|
|
593
552
|
dateRange
|
|
594
553
|
} = timeDimension;
|
|
595
|
-
|
|
596
554
|
if (!dateRange) {
|
|
597
555
|
const member = ResultSet.timeDimensionMember(timeDimension);
|
|
598
556
|
const dates = pipe(map(row => row[member] && internalDayjs(row[member])), filter(Boolean))(this.timeDimensionBackwardCompatibleData(resultIndex));
|
|
599
557
|
dateRange = dates.length && [reduce(minBy(d => d.toDate()), dates[0], dates), reduce(maxBy(d => d.toDate()), dates[0], dates)] || null;
|
|
600
558
|
}
|
|
601
|
-
|
|
602
559
|
if (!dateRange) {
|
|
603
560
|
return null;
|
|
604
561
|
}
|
|
605
|
-
|
|
606
562
|
const padToDay = timeDimension.dateRange ? timeDimension.dateRange.find(d => d.match(DateRegex)) : !['hour', 'minute', 'second'].includes(timeDimension.granularity);
|
|
607
563
|
const [start, end] = dateRange;
|
|
608
564
|
const range = dayRange(start, end);
|
|
609
|
-
|
|
610
565
|
if (!TIME_SERIES[timeDimension.granularity]) {
|
|
611
566
|
throw new Error(`Unsupported time granularity: ${timeDimension.granularity}`);
|
|
612
567
|
}
|
|
613
|
-
|
|
614
568
|
return TIME_SERIES[timeDimension.granularity](padToDay ? range.snapTo('d') : range);
|
|
615
569
|
}
|
|
616
|
-
|
|
617
570
|
pivot(pivotConfig) {
|
|
618
571
|
pivotConfig = this.normalizePivotConfig(pivotConfig);
|
|
619
572
|
const {
|
|
620
573
|
pivotQuery: query
|
|
621
574
|
} = this.loadResponse;
|
|
622
|
-
|
|
623
575
|
const pivotImpl = (resultIndex = 0) => {
|
|
624
576
|
let groupByXAxis = groupByToPairs(({
|
|
625
577
|
xValues
|
|
626
578
|
}) => this.axisValuesString(xValues));
|
|
627
|
-
|
|
628
579
|
const measureValue = (row, measure) => row[measure] || 0;
|
|
629
|
-
|
|
630
580
|
if (pivotConfig.fillMissingDates && pivotConfig.x.length === 1 && equals(pivotConfig.x, (query.timeDimensions || []).filter(td => Boolean(td.granularity)).map(td => ResultSet.timeDimensionMember(td)))) {
|
|
631
581
|
const series = this.loadResponses.map(loadResponse => this.timeSeries(loadResponse.query.timeDimensions[0], resultIndex));
|
|
632
|
-
|
|
633
582
|
if (series[0]) {
|
|
634
583
|
groupByXAxis = rows => {
|
|
635
584
|
const byXValues = groupBy(({
|
|
@@ -642,7 +591,6 @@ class ResultSet {
|
|
|
642
591
|
};
|
|
643
592
|
}
|
|
644
593
|
}
|
|
645
|
-
|
|
646
594
|
const xGrouped = pipe(map(row => this.axisValues(pivotConfig.x, resultIndex)(row).map(xValues => ({
|
|
647
595
|
xValues,
|
|
648
596
|
row
|
|
@@ -688,11 +636,9 @@ class ResultSet {
|
|
|
688
636
|
};
|
|
689
637
|
});
|
|
690
638
|
};
|
|
691
|
-
|
|
692
639
|
const pivots = this.loadResponses.length > 1 ? this.loadResponses.map((_, index) => pivotImpl(index)) : [];
|
|
693
640
|
return pivots.length ? this.mergePivots(pivots, pivotConfig.joinDateRange) : pivotImpl();
|
|
694
641
|
}
|
|
695
|
-
|
|
696
642
|
mergePivots(pivots, joinDateRange) {
|
|
697
643
|
const minLengthPivot = pivots.reduce((memo, current) => memo != null && current.length >= memo.length ? memo : current, null);
|
|
698
644
|
return minLengthPivot.map((_, index) => {
|
|
@@ -703,12 +649,10 @@ class ResultSet {
|
|
|
703
649
|
};
|
|
704
650
|
});
|
|
705
651
|
}
|
|
706
|
-
|
|
707
652
|
pivotedRows(pivotConfig) {
|
|
708
653
|
// TODO
|
|
709
654
|
return this.chartPivot(pivotConfig);
|
|
710
655
|
}
|
|
711
|
-
|
|
712
656
|
chartPivot(pivotConfig) {
|
|
713
657
|
const validate = value => {
|
|
714
658
|
if (this.parseDateMeasures && LocalDateRegex.test(value)) {
|
|
@@ -716,19 +660,15 @@ class ResultSet {
|
|
|
716
660
|
} else if (!Number.isNaN(Number.parseFloat(value))) {
|
|
717
661
|
return Number.parseFloat(value);
|
|
718
662
|
}
|
|
719
|
-
|
|
720
663
|
return value;
|
|
721
664
|
};
|
|
722
|
-
|
|
723
665
|
const duplicateMeasures = new Set();
|
|
724
|
-
|
|
725
666
|
if (this.queryType === QUERY_TYPE.BLENDING_QUERY) {
|
|
726
667
|
const allMeasures = flatten(this.loadResponses.map(({
|
|
727
668
|
query
|
|
728
669
|
}) => query.measures));
|
|
729
670
|
allMeasures.filter((e, i, a) => a.indexOf(e) !== i).forEach(m => duplicateMeasures.add(m));
|
|
730
671
|
}
|
|
731
|
-
|
|
732
672
|
return this.pivot(pivotConfig).map(({
|
|
733
673
|
xValues,
|
|
734
674
|
yValuesArray
|
|
@@ -744,7 +684,6 @@ class ResultSet {
|
|
|
744
684
|
};
|
|
745
685
|
});
|
|
746
686
|
}
|
|
747
|
-
|
|
748
687
|
tablePivot(pivotConfig) {
|
|
749
688
|
const normalizedPivotConfig = this.normalizePivotConfig(pivotConfig || {});
|
|
750
689
|
const isMeasuresPresent = normalizedPivotConfig.x.concat(normalizedPivotConfig.y).includes('measures');
|
|
@@ -753,15 +692,14 @@ class ResultSet {
|
|
|
753
692
|
yValuesArray
|
|
754
693
|
}) => fromPairs(normalizedPivotConfig.x.map((key, index) => [key, xValues[index]]).concat(isMeasuresPresent ? yValuesArray.map(([yValues, measure]) => [yValues.length ? yValues.join() : 'value', measure]) : [])));
|
|
755
694
|
}
|
|
756
|
-
|
|
757
695
|
tableColumns(pivotConfig) {
|
|
758
696
|
const normalizedPivotConfig = this.normalizePivotConfig(pivotConfig || {});
|
|
759
697
|
const annotations = pipe(pluck('annotation'), reduce(mergeDeepLeft(), {}))(this.loadResponses);
|
|
760
|
-
const flatMeta = Object.values(annotations).reduce((a, b) => ({
|
|
698
|
+
const flatMeta = Object.values(annotations).reduce((a, b) => ({
|
|
699
|
+
...a,
|
|
761
700
|
...b
|
|
762
701
|
}), {});
|
|
763
702
|
const schema = {};
|
|
764
|
-
|
|
765
703
|
const extractFields = key => {
|
|
766
704
|
const {
|
|
767
705
|
title,
|
|
@@ -779,7 +717,6 @@ class ResultSet {
|
|
|
779
717
|
meta
|
|
780
718
|
};
|
|
781
719
|
};
|
|
782
|
-
|
|
783
720
|
const pivot = this.pivot(normalizedPivotConfig);
|
|
784
721
|
(pivot[0] && pivot[0].yValuesArray || []).forEach(([yValues]) => {
|
|
785
722
|
if (yValues.length > 0) {
|
|
@@ -794,12 +731,10 @@ class ResultSet {
|
|
|
794
731
|
});
|
|
795
732
|
}
|
|
796
733
|
});
|
|
797
|
-
|
|
798
734
|
const toColumns = (item = {}, path = []) => {
|
|
799
735
|
if (Object.keys(item).length === 0) {
|
|
800
736
|
return [];
|
|
801
737
|
}
|
|
802
|
-
|
|
803
738
|
return Object.values(item).map(({
|
|
804
739
|
key,
|
|
805
740
|
...currentItem
|
|
@@ -811,17 +746,17 @@ class ResultSet {
|
|
|
811
746
|
...fields
|
|
812
747
|
} = extractFields(currentItem.memberId);
|
|
813
748
|
const dimensionValue = key !== currentItem.memberId || title == null ? key : '';
|
|
814
|
-
|
|
815
749
|
if (!children.length) {
|
|
816
|
-
return {
|
|
750
|
+
return {
|
|
751
|
+
...fields,
|
|
817
752
|
key,
|
|
818
753
|
dataIndex: [...path, key].join(),
|
|
819
754
|
title: [title, dimensionValue].join(' ').trim(),
|
|
820
755
|
shortTitle: dimensionValue || shortTitle
|
|
821
756
|
};
|
|
822
757
|
}
|
|
823
|
-
|
|
824
|
-
|
|
758
|
+
return {
|
|
759
|
+
...fields,
|
|
825
760
|
key,
|
|
826
761
|
title: [title, dimensionValue].join(' ').trim(),
|
|
827
762
|
shortTitle: dimensionValue || shortTitle,
|
|
@@ -829,16 +764,15 @@ class ResultSet {
|
|
|
829
764
|
};
|
|
830
765
|
});
|
|
831
766
|
};
|
|
832
|
-
|
|
833
767
|
let otherColumns = [];
|
|
834
|
-
|
|
835
768
|
if (!pivot.length && normalizedPivotConfig.y.includes('measures')) {
|
|
836
|
-
otherColumns = (this.loadResponses[0].query.measures || []).map(key => ({
|
|
769
|
+
otherColumns = (this.loadResponses[0].query.measures || []).map(key => ({
|
|
770
|
+
...extractFields(key),
|
|
837
771
|
dataIndex: key
|
|
838
772
|
}));
|
|
839
|
-
}
|
|
840
|
-
|
|
773
|
+
}
|
|
841
774
|
|
|
775
|
+
// Syntatic column to display the measure value
|
|
842
776
|
if (!normalizedPivotConfig.y.length && normalizedPivotConfig.x.includes('measures')) {
|
|
843
777
|
otherColumns.push({
|
|
844
778
|
key: 'value',
|
|
@@ -848,7 +782,6 @@ class ResultSet {
|
|
|
848
782
|
type: 'string'
|
|
849
783
|
});
|
|
850
784
|
}
|
|
851
|
-
|
|
852
785
|
return normalizedPivotConfig.x.map(key => {
|
|
853
786
|
if (key === 'measures') {
|
|
854
787
|
return {
|
|
@@ -859,35 +792,30 @@ class ResultSet {
|
|
|
859
792
|
type: 'string'
|
|
860
793
|
};
|
|
861
794
|
}
|
|
862
|
-
|
|
863
|
-
|
|
795
|
+
return {
|
|
796
|
+
...extractFields(key),
|
|
864
797
|
dataIndex: key
|
|
865
798
|
};
|
|
866
799
|
}).concat(toColumns(schema)).concat(otherColumns);
|
|
867
800
|
}
|
|
868
|
-
|
|
869
801
|
totalRow(pivotConfig) {
|
|
870
802
|
return this.chartPivot(pivotConfig)[0];
|
|
871
803
|
}
|
|
872
|
-
|
|
873
804
|
categories(pivotConfig) {
|
|
874
805
|
// TODO
|
|
875
806
|
return this.chartPivot(pivotConfig);
|
|
876
807
|
}
|
|
877
|
-
|
|
878
808
|
seriesNames(pivotConfig) {
|
|
879
809
|
pivotConfig = this.normalizePivotConfig(pivotConfig);
|
|
880
810
|
const measures = pipe(pluck('annotation'), pluck('measures'), mergeAll)(this.loadResponses);
|
|
881
811
|
const seriesNames = unnest(this.loadResponses.map((_, index) => pipe(map(this.axisValues(pivotConfig.y, index)), unnest, uniq)(this.timeDimensionBackwardCompatibleData(index))));
|
|
882
812
|
const duplicateMeasures = new Set();
|
|
883
|
-
|
|
884
813
|
if (this.queryType === QUERY_TYPE.BLENDING_QUERY) {
|
|
885
814
|
const allMeasures = flatten(this.loadResponses.map(({
|
|
886
815
|
query
|
|
887
816
|
}) => query.measures));
|
|
888
817
|
allMeasures.filter((e, i, a) => a.indexOf(e) !== i).forEach(m => duplicateMeasures.add(m));
|
|
889
818
|
}
|
|
890
|
-
|
|
891
819
|
return seriesNames.map((axisValues, i) => {
|
|
892
820
|
const aliasedAxis = aliasSeries(axisValues, i, pivotConfig, duplicateMeasures);
|
|
893
821
|
return {
|
|
@@ -898,97 +826,80 @@ class ResultSet {
|
|
|
898
826
|
};
|
|
899
827
|
});
|
|
900
828
|
}
|
|
901
|
-
|
|
902
829
|
query() {
|
|
903
830
|
if (this.queryType !== QUERY_TYPE.REGULAR_QUERY) {
|
|
904
831
|
throw new Error(`Method is not supported for a '${this.queryType}' query type. Please use decompose`);
|
|
905
832
|
}
|
|
906
|
-
|
|
907
833
|
return this.loadResponses[0].query;
|
|
908
834
|
}
|
|
909
|
-
|
|
910
835
|
pivotQuery() {
|
|
911
836
|
return this.loadResponse.pivotQuery || null;
|
|
912
837
|
}
|
|
913
|
-
|
|
914
838
|
totalRows() {
|
|
915
839
|
return this.loadResponses[0].total;
|
|
916
840
|
}
|
|
917
|
-
|
|
918
841
|
rawData() {
|
|
919
842
|
if (this.queryType !== QUERY_TYPE.REGULAR_QUERY) {
|
|
920
843
|
throw new Error(`Method is not supported for a '${this.queryType}' query type. Please use decompose`);
|
|
921
844
|
}
|
|
922
|
-
|
|
923
845
|
return this.loadResponses[0].data;
|
|
924
846
|
}
|
|
925
|
-
|
|
926
847
|
annotation() {
|
|
927
848
|
if (this.queryType !== QUERY_TYPE.REGULAR_QUERY) {
|
|
928
849
|
throw new Error(`Method is not supported for a '${this.queryType}' query type. Please use decompose`);
|
|
929
850
|
}
|
|
930
|
-
|
|
931
851
|
return this.loadResponses[0].annotation;
|
|
932
852
|
}
|
|
933
|
-
|
|
934
853
|
timeDimensionBackwardCompatibleData(resultIndex) {
|
|
935
854
|
if (resultIndex === undefined) {
|
|
936
855
|
throw new Error('resultIndex is required');
|
|
937
856
|
}
|
|
938
|
-
|
|
939
857
|
if (!this.backwardCompatibleData[resultIndex]) {
|
|
940
858
|
const {
|
|
941
859
|
data,
|
|
942
860
|
query
|
|
943
861
|
} = this.loadResponses[resultIndex];
|
|
944
862
|
const timeDimensions = (query.timeDimensions || []).filter(td => Boolean(td.granularity));
|
|
945
|
-
this.backwardCompatibleData[resultIndex] = data.map(row => ({
|
|
863
|
+
this.backwardCompatibleData[resultIndex] = data.map(row => ({
|
|
864
|
+
...row,
|
|
946
865
|
...fromPairs(Object.keys(row).filter(field => timeDimensions.find(d => d.dimension === field) && !row[ResultSet.timeDimensionMember(timeDimensions.find(d => d.dimension === field))]).map(field => [ResultSet.timeDimensionMember(timeDimensions.find(d => d.dimension === field)), row[field]]))
|
|
947
866
|
}));
|
|
948
867
|
}
|
|
949
|
-
|
|
950
868
|
return this.backwardCompatibleData[resultIndex];
|
|
951
869
|
}
|
|
952
|
-
|
|
953
870
|
decompose() {
|
|
954
871
|
return this.loadResponses.map(result => new ResultSet({
|
|
955
872
|
queryType: QUERY_TYPE.REGULAR_QUERY,
|
|
956
|
-
pivotQuery: {
|
|
873
|
+
pivotQuery: {
|
|
874
|
+
...result.query,
|
|
957
875
|
queryType: QUERY_TYPE.REGULAR_QUERY
|
|
958
876
|
},
|
|
959
877
|
results: [result]
|
|
960
878
|
}, this.options));
|
|
961
879
|
}
|
|
962
|
-
|
|
963
880
|
serialize() {
|
|
964
881
|
return {
|
|
965
882
|
loadResponse: clone(this.loadResponse)
|
|
966
883
|
};
|
|
967
884
|
}
|
|
968
|
-
|
|
969
885
|
}
|
|
970
886
|
|
|
971
887
|
class SqlQuery {
|
|
972
888
|
constructor(sqlQuery) {
|
|
973
889
|
this.sqlQuery = sqlQuery;
|
|
974
890
|
}
|
|
975
|
-
|
|
976
891
|
rawQuery() {
|
|
977
892
|
return this.sqlQuery.sql;
|
|
978
893
|
}
|
|
979
|
-
|
|
980
894
|
sql() {
|
|
981
895
|
return this.rawQuery().sql[0];
|
|
982
896
|
}
|
|
983
|
-
|
|
984
897
|
}
|
|
985
898
|
|
|
986
899
|
/**
|
|
987
900
|
* @module @cubejs-client/core
|
|
988
901
|
*/
|
|
989
|
-
|
|
990
902
|
const memberMap = memberArray => fromPairs(memberArray.map(m => [m.name, m]));
|
|
991
|
-
|
|
992
903
|
const operators = {
|
|
993
904
|
string: [{
|
|
994
905
|
name: 'contains',
|
|
@@ -1072,10 +983,10 @@ const operators = {
|
|
|
1072
983
|
title: 'before or on date'
|
|
1073
984
|
}]
|
|
1074
985
|
};
|
|
986
|
+
|
|
1075
987
|
/**
|
|
1076
988
|
* Contains information about available cubes and it's members.
|
|
1077
989
|
*/
|
|
1078
|
-
|
|
1079
990
|
class Meta {
|
|
1080
991
|
constructor(metaResponse) {
|
|
1081
992
|
this.meta = metaResponse;
|
|
@@ -1089,21 +1000,17 @@ class Meta {
|
|
|
1089
1000
|
segments: memberMap(c.segments)
|
|
1090
1001
|
}]));
|
|
1091
1002
|
}
|
|
1092
|
-
|
|
1093
1003
|
membersForQuery(query, memberType) {
|
|
1094
1004
|
return unnest$1(this.cubes.map(c => c[memberType])).sort((a, b) => a.title > b.title ? 1 : -1);
|
|
1095
1005
|
}
|
|
1096
|
-
|
|
1097
1006
|
membersGroupedByCube() {
|
|
1098
1007
|
const memberKeys = ['measures', 'dimensions', 'segments', 'timeDimensions'];
|
|
1099
1008
|
return this.cubes.reduce((memo, cube) => {
|
|
1100
1009
|
memberKeys.forEach(key => {
|
|
1101
1010
|
let members = cube[key];
|
|
1102
|
-
|
|
1103
1011
|
if (key === 'timeDimensions') {
|
|
1104
1012
|
members = cube.dimensions.filter(m => m.type === 'time');
|
|
1105
1013
|
}
|
|
1106
|
-
|
|
1107
1014
|
memo[key] = [...memo[key], {
|
|
1108
1015
|
cubeName: cube.name,
|
|
1109
1016
|
cubeTitle: cube.title,
|
|
@@ -1120,60 +1027,47 @@ class Meta {
|
|
|
1120
1027
|
timeDimensions: []
|
|
1121
1028
|
});
|
|
1122
1029
|
}
|
|
1123
|
-
|
|
1124
1030
|
resolveMember(memberName, memberType) {
|
|
1125
1031
|
const [cube] = memberName.split('.');
|
|
1126
|
-
|
|
1127
1032
|
if (!this.cubesMap[cube]) {
|
|
1128
1033
|
return {
|
|
1129
1034
|
title: memberName,
|
|
1130
1035
|
error: `Cube not found ${cube} for path '${memberName}'`
|
|
1131
1036
|
};
|
|
1132
1037
|
}
|
|
1133
|
-
|
|
1134
1038
|
const memberTypes = Array.isArray(memberType) ? memberType : [memberType];
|
|
1135
1039
|
const member = memberTypes.map(type => this.cubesMap[cube][type] && this.cubesMap[cube][type][memberName]).find(m => m);
|
|
1136
|
-
|
|
1137
1040
|
if (!member) {
|
|
1138
1041
|
return {
|
|
1139
1042
|
title: memberName,
|
|
1140
1043
|
error: `Path not found '${memberName}'`
|
|
1141
1044
|
};
|
|
1142
1045
|
}
|
|
1143
|
-
|
|
1144
1046
|
return member;
|
|
1145
1047
|
}
|
|
1146
|
-
|
|
1147
1048
|
defaultTimeDimensionNameFor(memberName) {
|
|
1148
1049
|
const [cube] = memberName.split('.');
|
|
1149
|
-
|
|
1150
1050
|
if (!this.cubesMap[cube]) {
|
|
1151
1051
|
return null;
|
|
1152
1052
|
}
|
|
1153
|
-
|
|
1154
1053
|
return Object.keys(this.cubesMap[cube].dimensions || {}).find(d => this.cubesMap[cube].dimensions[d].type === 'time');
|
|
1155
1054
|
}
|
|
1156
|
-
|
|
1157
1055
|
filterOperatorsForMember(memberName, memberType) {
|
|
1158
1056
|
const member = this.resolveMember(memberName, memberType);
|
|
1159
1057
|
return operators[member.type] || operators.string;
|
|
1160
1058
|
}
|
|
1161
|
-
|
|
1162
1059
|
}
|
|
1163
1060
|
|
|
1164
1061
|
class ProgressResult {
|
|
1165
1062
|
constructor(progressResponse) {
|
|
1166
1063
|
this.progressResponse = progressResponse;
|
|
1167
1064
|
}
|
|
1168
|
-
|
|
1169
1065
|
stage() {
|
|
1170
1066
|
return this.progressResponse.stage;
|
|
1171
1067
|
}
|
|
1172
|
-
|
|
1173
1068
|
timeElapsed() {
|
|
1174
1069
|
return this.progressResponse.timeElapsed;
|
|
1175
1070
|
}
|
|
1176
|
-
|
|
1177
1071
|
}
|
|
1178
1072
|
|
|
1179
1073
|
class HttpTransport {
|
|
@@ -1190,7 +1084,6 @@ class HttpTransport {
|
|
|
1190
1084
|
this.headers = headers;
|
|
1191
1085
|
this.credentials = credentials;
|
|
1192
1086
|
}
|
|
1193
|
-
|
|
1194
1087
|
request(method, {
|
|
1195
1088
|
baseRequestId,
|
|
1196
1089
|
...params
|
|
@@ -1198,19 +1091,19 @@ class HttpTransport {
|
|
|
1198
1091
|
let spanCounter = 1;
|
|
1199
1092
|
const searchParams = new URLSearchParams(params && Object.keys(params).map(k => ({
|
|
1200
1093
|
[k]: typeof params[k] === 'object' ? JSON.stringify(params[k]) : params[k]
|
|
1201
|
-
})).reduce((a, b) => ({
|
|
1094
|
+
})).reduce((a, b) => ({
|
|
1095
|
+
...a,
|
|
1202
1096
|
...b
|
|
1203
1097
|
}), {}));
|
|
1204
1098
|
let url = `${this.apiUrl}/${method}${searchParams.toString().length ? `?${searchParams}` : ''}`;
|
|
1205
1099
|
const requestMethod = this.method || (url.length < 2000 ? 'GET' : 'POST');
|
|
1206
|
-
|
|
1207
1100
|
if (requestMethod === 'POST') {
|
|
1208
1101
|
url = `${this.apiUrl}/${method}`;
|
|
1209
1102
|
this.headers['Content-Type'] = 'application/json';
|
|
1210
|
-
}
|
|
1211
|
-
// remember to add {'Content-Type': 'application/json'} to the header.
|
|
1212
|
-
|
|
1103
|
+
}
|
|
1213
1104
|
|
|
1105
|
+
// Currently, all methods make GET requests. If a method makes a request with a body payload,
|
|
1106
|
+
// remember to add {'Content-Type': 'application/json'} to the header.
|
|
1214
1107
|
const runRequest = () => fetch(url, {
|
|
1215
1108
|
method: requestMethod,
|
|
1216
1109
|
headers: {
|
|
@@ -1221,25 +1114,20 @@ class HttpTransport {
|
|
|
1221
1114
|
credentials: this.credentials,
|
|
1222
1115
|
body: requestMethod === 'POST' ? JSON.stringify(params) : null
|
|
1223
1116
|
});
|
|
1224
|
-
|
|
1225
1117
|
return {
|
|
1226
1118
|
/* eslint no-unsafe-finally: off */
|
|
1227
1119
|
async subscribe(callback) {
|
|
1228
1120
|
let result = {
|
|
1229
1121
|
error: 'network Error' // add default error message
|
|
1230
|
-
|
|
1231
1122
|
};
|
|
1232
|
-
|
|
1233
1123
|
try {
|
|
1234
1124
|
result = await runRequest();
|
|
1235
1125
|
} finally {
|
|
1236
1126
|
return callback(result, () => this.subscribe(callback));
|
|
1237
1127
|
}
|
|
1238
1128
|
}
|
|
1239
|
-
|
|
1240
1129
|
};
|
|
1241
1130
|
}
|
|
1242
|
-
|
|
1243
1131
|
}
|
|
1244
1132
|
|
|
1245
1133
|
class RequestError extends Error {
|
|
@@ -1248,20 +1136,18 @@ class RequestError extends Error {
|
|
|
1248
1136
|
this.response = response;
|
|
1249
1137
|
this.status = status;
|
|
1250
1138
|
}
|
|
1251
|
-
|
|
1252
1139
|
}
|
|
1253
1140
|
|
|
1254
1141
|
let mutexCounter = 0;
|
|
1255
1142
|
const MUTEX_ERROR = 'Mutex has been changed';
|
|
1143
|
+
|
|
1256
1144
|
/**
|
|
1257
1145
|
* Query result dataset formats enum.
|
|
1258
1146
|
*/
|
|
1259
|
-
|
|
1260
1147
|
const ResultType = {
|
|
1261
1148
|
DEFAULT: 'default',
|
|
1262
1149
|
COMPACT: 'compact'
|
|
1263
1150
|
};
|
|
1264
|
-
|
|
1265
1151
|
function mutexPromise(promise) {
|
|
1266
1152
|
return new Promise(async (resolve, reject) => {
|
|
1267
1153
|
try {
|
|
@@ -1273,20 +1159,16 @@ function mutexPromise(promise) {
|
|
|
1273
1159
|
}
|
|
1274
1160
|
});
|
|
1275
1161
|
}
|
|
1276
|
-
|
|
1277
1162
|
class CubeApi {
|
|
1278
1163
|
constructor(apiToken, options) {
|
|
1279
1164
|
if (apiToken !== null && !Array.isArray(apiToken) && typeof apiToken === 'object') {
|
|
1280
1165
|
options = apiToken;
|
|
1281
1166
|
apiToken = undefined;
|
|
1282
1167
|
}
|
|
1283
|
-
|
|
1284
1168
|
options = options || {};
|
|
1285
|
-
|
|
1286
1169
|
if (!options.transport && !options.apiUrl) {
|
|
1287
1170
|
throw new Error('The `apiUrl` option is required');
|
|
1288
1171
|
}
|
|
1289
|
-
|
|
1290
1172
|
this.apiToken = apiToken;
|
|
1291
1173
|
this.apiUrl = options.apiUrl;
|
|
1292
1174
|
this.method = options.method;
|
|
@@ -1301,52 +1183,41 @@ class CubeApi {
|
|
|
1301
1183
|
});
|
|
1302
1184
|
this.pollInterval = options.pollInterval || 5;
|
|
1303
1185
|
this.parseDateMeasures = options.parseDateMeasures;
|
|
1186
|
+
this.castNumerics = typeof options.castNumerics === 'boolean' ? options.castNumerics : false;
|
|
1304
1187
|
this.updateAuthorizationPromise = null;
|
|
1305
1188
|
}
|
|
1306
|
-
|
|
1307
1189
|
request(method, params) {
|
|
1308
1190
|
return this.transport.request(method, {
|
|
1309
1191
|
baseRequestId: v4(),
|
|
1310
1192
|
...params
|
|
1311
1193
|
});
|
|
1312
1194
|
}
|
|
1313
|
-
|
|
1314
1195
|
loadMethod(request, toResult, options, callback) {
|
|
1315
1196
|
const mutexValue = ++mutexCounter;
|
|
1316
|
-
|
|
1317
1197
|
if (typeof options === 'function' && !callback) {
|
|
1318
1198
|
callback = options;
|
|
1319
1199
|
options = undefined;
|
|
1320
1200
|
}
|
|
1321
|
-
|
|
1322
1201
|
options = options || {};
|
|
1323
1202
|
const mutexKey = options.mutexKey || 'default';
|
|
1324
|
-
|
|
1325
1203
|
if (options.mutexObj) {
|
|
1326
1204
|
options.mutexObj[mutexKey] = mutexValue;
|
|
1327
1205
|
}
|
|
1328
|
-
|
|
1329
1206
|
const requestPromise = this.updateTransportAuthorization().then(() => request());
|
|
1330
1207
|
let skipAuthorizationUpdate = true;
|
|
1331
1208
|
let unsubscribed = false;
|
|
1332
|
-
|
|
1333
1209
|
const checkMutex = async () => {
|
|
1334
1210
|
const requestInstance = await requestPromise;
|
|
1335
|
-
|
|
1336
1211
|
if (options.mutexObj && options.mutexObj[mutexKey] !== mutexValue) {
|
|
1337
1212
|
unsubscribed = true;
|
|
1338
|
-
|
|
1339
1213
|
if (requestInstance.unsubscribe) {
|
|
1340
1214
|
await requestInstance.unsubscribe();
|
|
1341
1215
|
}
|
|
1342
|
-
|
|
1343
1216
|
throw MUTEX_ERROR;
|
|
1344
1217
|
}
|
|
1345
1218
|
};
|
|
1346
|
-
|
|
1347
1219
|
const loadImpl = async (response, next) => {
|
|
1348
1220
|
const requestInstance = await requestPromise;
|
|
1349
|
-
|
|
1350
1221
|
const subscribeNext = async () => {
|
|
1351
1222
|
if (options.subscribe && !unsubscribed) {
|
|
1352
1223
|
if (requestInstance.unsubscribe) {
|
|
@@ -1356,100 +1227,74 @@ class CubeApi {
|
|
|
1356
1227
|
return next();
|
|
1357
1228
|
}
|
|
1358
1229
|
}
|
|
1359
|
-
|
|
1360
1230
|
return null;
|
|
1361
1231
|
};
|
|
1362
|
-
|
|
1363
1232
|
const continueWait = async wait => {
|
|
1364
1233
|
if (!unsubscribed) {
|
|
1365
1234
|
if (wait) {
|
|
1366
1235
|
await new Promise(resolve => setTimeout(() => resolve(), this.pollInterval * 1000));
|
|
1367
1236
|
}
|
|
1368
|
-
|
|
1369
1237
|
return next();
|
|
1370
1238
|
}
|
|
1371
|
-
|
|
1372
1239
|
return null;
|
|
1373
1240
|
};
|
|
1374
|
-
|
|
1375
1241
|
if (options.subscribe && !skipAuthorizationUpdate) {
|
|
1376
1242
|
await this.updateTransportAuthorization();
|
|
1377
1243
|
}
|
|
1378
|
-
|
|
1379
1244
|
skipAuthorizationUpdate = false;
|
|
1380
|
-
|
|
1381
1245
|
if (response.status === 502) {
|
|
1382
1246
|
await checkMutex();
|
|
1383
1247
|
return continueWait(true);
|
|
1384
1248
|
}
|
|
1385
|
-
|
|
1386
1249
|
let body = {};
|
|
1387
1250
|
let text = '';
|
|
1388
|
-
|
|
1389
1251
|
try {
|
|
1390
1252
|
text = await response.text();
|
|
1391
1253
|
body = JSON.parse(text);
|
|
1392
1254
|
} catch (_) {
|
|
1393
1255
|
body.error = text;
|
|
1394
1256
|
}
|
|
1395
|
-
|
|
1396
1257
|
if (body.error === 'Continue wait') {
|
|
1397
1258
|
await checkMutex();
|
|
1398
|
-
|
|
1399
1259
|
if (options.progressCallback) {
|
|
1400
1260
|
options.progressCallback(new ProgressResult(body));
|
|
1401
1261
|
}
|
|
1402
|
-
|
|
1403
1262
|
return continueWait();
|
|
1404
1263
|
}
|
|
1405
|
-
|
|
1406
1264
|
if (response.status !== 200) {
|
|
1407
1265
|
await checkMutex();
|
|
1408
|
-
|
|
1409
1266
|
if (!options.subscribe && requestInstance.unsubscribe) {
|
|
1410
1267
|
await requestInstance.unsubscribe();
|
|
1411
1268
|
}
|
|
1412
|
-
|
|
1413
1269
|
const error = new RequestError(body.error, body, response.status); // TODO error class
|
|
1414
|
-
|
|
1415
1270
|
if (callback) {
|
|
1416
1271
|
callback(error);
|
|
1417
1272
|
} else {
|
|
1418
1273
|
throw error;
|
|
1419
1274
|
}
|
|
1420
|
-
|
|
1421
1275
|
return subscribeNext();
|
|
1422
1276
|
}
|
|
1423
|
-
|
|
1424
1277
|
await checkMutex();
|
|
1425
|
-
|
|
1426
1278
|
if (!options.subscribe && requestInstance.unsubscribe) {
|
|
1427
1279
|
await requestInstance.unsubscribe();
|
|
1428
1280
|
}
|
|
1429
|
-
|
|
1430
1281
|
const result = toResult(body);
|
|
1431
|
-
|
|
1432
1282
|
if (callback) {
|
|
1433
1283
|
callback(null, result);
|
|
1434
1284
|
} else {
|
|
1435
1285
|
return result;
|
|
1436
1286
|
}
|
|
1437
|
-
|
|
1438
1287
|
return subscribeNext();
|
|
1439
1288
|
};
|
|
1440
|
-
|
|
1441
1289
|
const promise = requestPromise.then(requestInstance => mutexPromise(requestInstance.subscribe(loadImpl)));
|
|
1442
|
-
|
|
1443
1290
|
if (callback) {
|
|
1444
1291
|
return {
|
|
1445
1292
|
unsubscribe: async () => {
|
|
1446
1293
|
const requestInstance = await requestPromise;
|
|
1447
1294
|
unsubscribed = true;
|
|
1448
|
-
|
|
1449
1295
|
if (requestInstance.unsubscribe) {
|
|
1450
1296
|
return requestInstance.unsubscribe();
|
|
1451
1297
|
}
|
|
1452
|
-
|
|
1453
1298
|
return null;
|
|
1454
1299
|
}
|
|
1455
1300
|
};
|
|
@@ -1457,22 +1302,18 @@ class CubeApi {
|
|
|
1457
1302
|
return promise;
|
|
1458
1303
|
}
|
|
1459
1304
|
}
|
|
1460
|
-
|
|
1461
1305
|
async updateTransportAuthorization() {
|
|
1462
1306
|
if (this.updateAuthorizationPromise) {
|
|
1463
1307
|
await this.updateAuthorizationPromise;
|
|
1464
1308
|
return;
|
|
1465
1309
|
}
|
|
1466
|
-
|
|
1467
1310
|
if (typeof this.apiToken === 'function') {
|
|
1468
1311
|
this.updateAuthorizationPromise = new Promise(async (resolve, reject) => {
|
|
1469
1312
|
try {
|
|
1470
1313
|
const token = await this.apiToken();
|
|
1471
|
-
|
|
1472
1314
|
if (this.transport.authorization !== token) {
|
|
1473
1315
|
this.transport.authorization = token;
|
|
1474
1316
|
}
|
|
1475
|
-
|
|
1476
1317
|
resolve();
|
|
1477
1318
|
} catch (error) {
|
|
1478
1319
|
reject(error);
|
|
@@ -1483,6 +1324,7 @@ class CubeApi {
|
|
|
1483
1324
|
await this.updateAuthorizationPromise;
|
|
1484
1325
|
}
|
|
1485
1326
|
}
|
|
1327
|
+
|
|
1486
1328
|
/**
|
|
1487
1329
|
* Add system properties to a query object.
|
|
1488
1330
|
* @param {Query} query
|
|
@@ -1490,17 +1332,17 @@ class CubeApi {
|
|
|
1490
1332
|
* @returns {void}
|
|
1491
1333
|
* @private
|
|
1492
1334
|
*/
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
1335
|
patchQueryInternal(query, responseFormat) {
|
|
1496
1336
|
if (responseFormat === ResultType.COMPACT && query.responseFormat !== ResultType.COMPACT) {
|
|
1497
|
-
return {
|
|
1337
|
+
return {
|
|
1338
|
+
...query,
|
|
1498
1339
|
responseFormat: ResultType.COMPACT
|
|
1499
1340
|
};
|
|
1500
1341
|
} else {
|
|
1501
1342
|
return query;
|
|
1502
1343
|
}
|
|
1503
1344
|
}
|
|
1345
|
+
|
|
1504
1346
|
/**
|
|
1505
1347
|
* Process result fetched from the gateway#load method according
|
|
1506
1348
|
* to the network protocol.
|
|
@@ -1508,19 +1350,17 @@ class CubeApi {
|
|
|
1508
1350
|
* @returns ResultSet
|
|
1509
1351
|
* @private
|
|
1510
1352
|
*/
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
1353
|
loadResponseInternal(response, options = {}) {
|
|
1514
1354
|
if (response.results.length) {
|
|
1515
1355
|
if (options.castNumerics) {
|
|
1516
1356
|
response.results.forEach(result => {
|
|
1517
|
-
const numericMembers = Object.entries({
|
|
1357
|
+
const numericMembers = Object.entries({
|
|
1358
|
+
...result.annotation.measures,
|
|
1518
1359
|
...result.annotation.dimensions
|
|
1519
1360
|
}).map(([k, v]) => {
|
|
1520
1361
|
if (v.type === 'number') {
|
|
1521
1362
|
return k;
|
|
1522
1363
|
}
|
|
1523
|
-
|
|
1524
1364
|
return undefined;
|
|
1525
1365
|
}).filter(Boolean);
|
|
1526
1366
|
result.data = result.data.map(row => {
|
|
@@ -1533,7 +1373,6 @@ class CubeApi {
|
|
|
1533
1373
|
});
|
|
1534
1374
|
});
|
|
1535
1375
|
}
|
|
1536
|
-
|
|
1537
1376
|
if (response.results[0].query.responseFormat && response.results[0].query.responseFormat === ResultType.COMPACT) {
|
|
1538
1377
|
response.results.forEach((result, j) => {
|
|
1539
1378
|
const data = [];
|
|
@@ -1548,13 +1387,15 @@ class CubeApi {
|
|
|
1548
1387
|
});
|
|
1549
1388
|
}
|
|
1550
1389
|
}
|
|
1551
|
-
|
|
1552
1390
|
return new ResultSet(response, {
|
|
1553
1391
|
parseDateMeasures: this.parseDateMeasures
|
|
1554
1392
|
});
|
|
1555
1393
|
}
|
|
1556
|
-
|
|
1557
1394
|
load(query, options, callback, responseFormat = ResultType.DEFAULT) {
|
|
1395
|
+
options = {
|
|
1396
|
+
castNumerics: this.castNumerics,
|
|
1397
|
+
...options
|
|
1398
|
+
};
|
|
1558
1399
|
if (responseFormat === ResultType.COMPACT) {
|
|
1559
1400
|
if (Array.isArray(query)) {
|
|
1560
1401
|
query = query.map(q => this.patchQueryInternal(q, ResultType.COMPACT));
|
|
@@ -1562,14 +1403,16 @@ class CubeApi {
|
|
|
1562
1403
|
query = this.patchQueryInternal(query, ResultType.COMPACT);
|
|
1563
1404
|
}
|
|
1564
1405
|
}
|
|
1565
|
-
|
|
1566
1406
|
return this.loadMethod(() => this.request('load', {
|
|
1567
1407
|
query,
|
|
1568
1408
|
queryType: 'multi'
|
|
1569
1409
|
}), response => this.loadResponseInternal(response, options), options, callback);
|
|
1570
1410
|
}
|
|
1571
|
-
|
|
1572
1411
|
subscribe(query, options, callback, responseFormat = ResultType.DEFAULT) {
|
|
1412
|
+
options = {
|
|
1413
|
+
castNumerics: this.castNumerics,
|
|
1414
|
+
...options
|
|
1415
|
+
};
|
|
1573
1416
|
if (responseFormat === ResultType.COMPACT) {
|
|
1574
1417
|
if (Array.isArray(query)) {
|
|
1575
1418
|
query = query.map(q => this.patchQueryInternal(q, ResultType.COMPACT));
|
|
@@ -1577,33 +1420,28 @@ class CubeApi {
|
|
|
1577
1420
|
query = this.patchQueryInternal(query, ResultType.COMPACT);
|
|
1578
1421
|
}
|
|
1579
1422
|
}
|
|
1580
|
-
|
|
1581
1423
|
return this.loadMethod(() => this.request('subscribe', {
|
|
1582
1424
|
query,
|
|
1583
1425
|
queryType: 'multi'
|
|
1584
|
-
}), response => this.loadResponseInternal(response, options), {
|
|
1426
|
+
}), response => this.loadResponseInternal(response, options), {
|
|
1427
|
+
...options,
|
|
1585
1428
|
subscribe: true
|
|
1586
1429
|
}, callback);
|
|
1587
1430
|
}
|
|
1588
|
-
|
|
1589
1431
|
sql(query, options, callback) {
|
|
1590
1432
|
return this.loadMethod(() => this.request('sql', {
|
|
1591
1433
|
query
|
|
1592
1434
|
}), response => Array.isArray(response) ? response.map(body => new SqlQuery(body)) : new SqlQuery(response), options, callback);
|
|
1593
1435
|
}
|
|
1594
|
-
|
|
1595
1436
|
meta(options, callback) {
|
|
1596
1437
|
return this.loadMethod(() => this.request('meta'), body => new Meta(body), options, callback);
|
|
1597
1438
|
}
|
|
1598
|
-
|
|
1599
1439
|
dryRun(query, options, callback) {
|
|
1600
1440
|
return this.loadMethod(() => this.request('dry-run', {
|
|
1601
1441
|
query
|
|
1602
1442
|
}), response => response, options, callback);
|
|
1603
1443
|
}
|
|
1604
|
-
|
|
1605
1444
|
}
|
|
1606
|
-
|
|
1607
1445
|
var index = ((apiToken, options) => new CubeApi(apiToken, options));
|
|
1608
1446
|
|
|
1609
1447
|
export default index;
|