@cubejs-client/core 1.3.14 → 1.3.16
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.js → cubejs-client-core.cjs.js} +1016 -411
- package/dist/cubejs-client-core.cjs.js.map +1 -0
- package/dist/cubejs-client-core.umd.js +2901 -12088
- package/dist/cubejs-client-core.umd.js.map +1 -1
- package/dist/src/HttpTransport.d.ts +54 -0
- package/dist/src/HttpTransport.d.ts.map +1 -0
- package/dist/src/HttpTransport.js +55 -0
- package/dist/src/Meta.d.ts +62 -0
- package/dist/src/Meta.d.ts.map +1 -0
- package/dist/src/Meta.js +150 -0
- package/dist/src/ProgressResult.d.ts +8 -0
- package/dist/src/ProgressResult.d.ts.map +1 -0
- package/dist/src/ProgressResult.js +11 -0
- package/dist/src/RequestError.d.ts +6 -0
- package/dist/src/RequestError.d.ts.map +1 -0
- package/dist/src/RequestError.js +7 -0
- package/dist/src/ResultSet.d.ts +430 -0
- package/dist/src/ResultSet.d.ts.map +1 -0
- package/dist/src/ResultSet.js +952 -0
- package/dist/src/SqlQuery.d.ts +17 -0
- package/dist/src/SqlQuery.d.ts.map +1 -0
- package/dist/src/SqlQuery.js +11 -0
- package/dist/src/index.d.ts +194 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +411 -0
- package/dist/src/index.umd.d.ts +3 -0
- package/dist/src/index.umd.d.ts.map +1 -0
- package/dist/src/index.umd.js +6 -0
- package/dist/src/time.d.ts +70 -0
- package/dist/src/time.d.ts.map +1 -0
- package/dist/src/time.js +249 -0
- package/dist/src/types.d.ts +424 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +1 -0
- package/dist/src/utils.d.ts +19 -0
- package/dist/src/utils.d.ts.map +1 -0
- package/dist/src/utils.js +294 -0
- package/dist/test/CubeApi.test.d.ts +7 -0
- package/dist/test/CubeApi.test.d.ts.map +1 -0
- package/dist/test/CubeApi.test.js +279 -0
- package/dist/test/HttpTransport.test.d.ts +2 -0
- package/dist/test/HttpTransport.test.d.ts.map +1 -0
- package/dist/test/HttpTransport.test.js +244 -0
- package/dist/test/ResultSet.test.d.ts +7 -0
- package/dist/test/ResultSet.test.d.ts.map +1 -0
- package/dist/test/ResultSet.test.js +1725 -0
- package/dist/test/compare-date-range.test.d.ts +2 -0
- package/dist/test/compare-date-range.test.d.ts.map +1 -0
- package/dist/test/compare-date-range.test.js +742 -0
- package/dist/test/data-blending.test.d.ts +2 -0
- package/dist/test/data-blending.test.d.ts.map +1 -0
- package/dist/test/data-blending.test.js +423 -0
- package/dist/test/default-heuristics.test.d.ts +2 -0
- package/dist/test/default-heuristics.test.d.ts.map +1 -0
- package/dist/test/default-heuristics.test.js +108 -0
- package/dist/test/drill-down.test.d.ts +2 -0
- package/dist/test/drill-down.test.d.ts.map +1 -0
- package/dist/test/drill-down.test.js +373 -0
- package/dist/test/fixtures/datablending/load-responses.json +261 -0
- package/dist/test/granularity.test.d.ts +2 -0
- package/dist/test/granularity.test.d.ts.map +1 -0
- package/dist/test/granularity.test.js +218 -0
- package/dist/test/helpers.d.ts +283 -0
- package/dist/test/helpers.d.ts.map +1 -0
- package/dist/test/helpers.js +974 -0
- package/dist/test/index.test.d.ts +7 -0
- package/dist/test/index.test.d.ts.map +1 -0
- package/dist/test/index.test.js +370 -0
- package/dist/test/table.test.d.ts +2 -0
- package/dist/test/table.test.d.ts.map +1 -0
- package/dist/test/table.test.js +757 -0
- package/dist/test/utils.test.d.ts +2 -0
- package/dist/test/utils.test.d.ts.map +1 -0
- package/dist/test/utils.test.js +32 -0
- package/package.json +26 -21
- package/dist/cubejs-client-core.esm.js +0 -1639
- package/dist/cubejs-client-core.esm.js.map +0 -1
- package/dist/cubejs-client-core.js.map +0 -1
- package/index.d.ts +0 -1338
- package/src/HttpTransport.js +0 -60
- package/src/HttpTransport.test.js +0 -117
- package/src/Meta.js +0 -142
- package/src/ProgressResult.js +0 -13
- package/src/RequestError.js +0 -7
- package/src/ResultSet.js +0 -746
- package/src/SqlQuery.js +0 -13
- package/src/index.js +0 -398
- package/src/index.test.js +0 -454
- package/src/index.umd.js +0 -8
- package/src/tests/ResultSet.test.js +0 -1655
- package/src/tests/compare-date-range.test.js +0 -753
- package/src/tests/data-blending.test.js +0 -432
- package/src/tests/default-heuristics.test.js +0 -118
- package/src/tests/drill-down.test.js +0 -402
- package/src/tests/fixtures/datablending/load-responses.json +0 -261
- package/src/tests/granularity.test.js +0 -225
- package/src/tests/table.test.js +0 -791
- package/src/tests/utils.test.js +0 -35
- package/src/time.js +0 -296
- package/src/utils.js +0 -368
package/src/tests/utils.test.js
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import 'jest';
|
|
2
|
-
|
|
3
|
-
import { defaultOrder } from '../utils';
|
|
4
|
-
import { dayRange, TIME_SERIES } from '../time';
|
|
5
|
-
|
|
6
|
-
describe('utils', () => {
|
|
7
|
-
test('default order', () => {
|
|
8
|
-
const query = {
|
|
9
|
-
measures: ['Orders.count'],
|
|
10
|
-
timeDimensions: [
|
|
11
|
-
{
|
|
12
|
-
dimension: 'Orders.createdAt',
|
|
13
|
-
granularity: 'day',
|
|
14
|
-
},
|
|
15
|
-
],
|
|
16
|
-
};
|
|
17
|
-
expect(defaultOrder(query)).toStrictEqual({
|
|
18
|
-
'Orders.createdAt': 'asc',
|
|
19
|
-
});
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
test('time series', () => {
|
|
23
|
-
const range = dayRange('2021-01-01 00:00:00.000', '2021-01-07 00:00:00.000');
|
|
24
|
-
|
|
25
|
-
expect(TIME_SERIES.day(range)).toStrictEqual([
|
|
26
|
-
'2021-01-01T00:00:00.000',
|
|
27
|
-
'2021-01-02T00:00:00.000',
|
|
28
|
-
'2021-01-03T00:00:00.000',
|
|
29
|
-
'2021-01-04T00:00:00.000',
|
|
30
|
-
'2021-01-05T00:00:00.000',
|
|
31
|
-
'2021-01-06T00:00:00.000',
|
|
32
|
-
'2021-01-07T00:00:00.000',
|
|
33
|
-
]);
|
|
34
|
-
});
|
|
35
|
-
});
|
package/src/time.js
DELETED
|
@@ -1,296 +0,0 @@
|
|
|
1
|
-
import dayjs from 'dayjs';
|
|
2
|
-
import quarterOfYear from 'dayjs/plugin/quarterOfYear';
|
|
3
|
-
import duration from 'dayjs/plugin/duration';
|
|
4
|
-
import isoWeek from 'dayjs/plugin/isoWeek';
|
|
5
|
-
import en from 'dayjs/locale/en';
|
|
6
|
-
|
|
7
|
-
dayjs.extend(quarterOfYear);
|
|
8
|
-
dayjs.extend(duration);
|
|
9
|
-
dayjs.extend(isoWeek);
|
|
10
|
-
|
|
11
|
-
export const GRANULARITIES = [
|
|
12
|
-
{ name: undefined, title: 'w/o grouping' },
|
|
13
|
-
{ name: 'second', title: 'Second' },
|
|
14
|
-
{ name: 'minute', title: 'Minute' },
|
|
15
|
-
{ name: 'hour', title: 'Hour' },
|
|
16
|
-
{ name: 'day', title: 'Day' },
|
|
17
|
-
{ name: 'week', title: 'Week' },
|
|
18
|
-
{ name: 'month', title: 'Month' },
|
|
19
|
-
{ name: 'quarter', title: 'Quarter' },
|
|
20
|
-
{ name: 'year', title: 'Year' },
|
|
21
|
-
];
|
|
22
|
-
|
|
23
|
-
export const DEFAULT_GRANULARITY = 'day';
|
|
24
|
-
|
|
25
|
-
// When granularity is week, weekStart Value must be 1. However, since the client can change it globally
|
|
26
|
-
// (https://day.js.org/docs/en/i18n/changing-locale) So the function below has been added.
|
|
27
|
-
export const internalDayjs = (...args) => dayjs(...args).locale({ ...en, weekStart: 1 });
|
|
28
|
-
|
|
29
|
-
export const TIME_SERIES = {
|
|
30
|
-
day: (range) => range.by('d').map(d => d.format('YYYY-MM-DDT00:00:00.000')),
|
|
31
|
-
month: (range) => range.snapTo('month').by('M').map(d => d.format('YYYY-MM-01T00:00:00.000')),
|
|
32
|
-
year: (range) => range.snapTo('year').by('y').map(d => d.format('YYYY-01-01T00:00:00.000')),
|
|
33
|
-
hour: (range) => range.by('h').map(d => d.format('YYYY-MM-DDTHH:00:00.000')),
|
|
34
|
-
minute: (range) => range.by('m').map(d => d.format('YYYY-MM-DDTHH:mm:00.000')),
|
|
35
|
-
second: (range) => range.by('s').map(d => d.format('YYYY-MM-DDTHH:mm:ss.000')),
|
|
36
|
-
week: (range) => range.snapTo('week').by('w').map(d => d.startOf('week').format('YYYY-MM-DDT00:00:00.000')),
|
|
37
|
-
quarter: (range) => range.snapTo('quarter').by('quarter').map(d => d.startOf('quarter').format(
|
|
38
|
-
'YYYY-MM-DDT00:00:00.000'
|
|
39
|
-
)),
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
export const isPredefinedGranularity = (granularity) => !!TIME_SERIES[granularity];
|
|
43
|
-
|
|
44
|
-
export const DateRegex = /^\d\d\d\d-\d\d-\d\d$/;
|
|
45
|
-
export const LocalDateRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z?$/;
|
|
46
|
-
|
|
47
|
-
export const dayRange = (from, to) => ({
|
|
48
|
-
by: (value) => {
|
|
49
|
-
const results = [];
|
|
50
|
-
|
|
51
|
-
let start = internalDayjs(from);
|
|
52
|
-
const end = internalDayjs(to);
|
|
53
|
-
|
|
54
|
-
while (start.isBefore(end) || start.isSame(end)) {
|
|
55
|
-
results.push(start);
|
|
56
|
-
start = start.add(1, value);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
return results;
|
|
60
|
-
},
|
|
61
|
-
snapTo: (value) => dayRange(internalDayjs(from).startOf(value), internalDayjs(to).endOf(value)),
|
|
62
|
-
start: internalDayjs(from),
|
|
63
|
-
end: internalDayjs(to),
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Parse PostgreSQL-like interval string into object
|
|
68
|
-
* E.g. '2 years 15 months 100 weeks 99 hours 15 seconds'
|
|
69
|
-
* Negative units are also supported
|
|
70
|
-
* E.g. '-2 months 5 days -10 hours'
|
|
71
|
-
*
|
|
72
|
-
* TODO: It's copy/paste of parseSqlInterval from @cubejs-backend/shared [time.ts]
|
|
73
|
-
* It's not referenced to omit imports of moment.js staff.
|
|
74
|
-
* Probably one day we should choose one implementation and reuse it in other places.
|
|
75
|
-
*/
|
|
76
|
-
export function parseSqlInterval(intervalStr) {
|
|
77
|
-
const interval = {};
|
|
78
|
-
const parts = intervalStr.split(/\s+/);
|
|
79
|
-
|
|
80
|
-
for (let i = 0; i < parts.length; i += 2) {
|
|
81
|
-
const value = parseInt(parts[i], 10);
|
|
82
|
-
const unit = parts[i + 1];
|
|
83
|
-
|
|
84
|
-
// Remove ending 's' (e.g., 'days' -> 'day')
|
|
85
|
-
const singularUnit = unit.endsWith('s') ? unit.slice(0, -1) : unit;
|
|
86
|
-
interval[singularUnit] = value;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
return interval;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Adds interval to provided date.
|
|
94
|
-
* TODO: It's copy/paste of addInterval from @cubejs-backend/shared [time.ts]
|
|
95
|
-
* but operates with dayjs instead of moment.js
|
|
96
|
-
* @param {dayjs} date
|
|
97
|
-
* @param interval
|
|
98
|
-
* @returns {dayjs}
|
|
99
|
-
*/
|
|
100
|
-
export function addInterval(date, interval) {
|
|
101
|
-
let res = date.clone();
|
|
102
|
-
|
|
103
|
-
Object.entries(interval).forEach(([key, value]) => {
|
|
104
|
-
res = res.add(value, key);
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
return res;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Adds interval to provided date.
|
|
112
|
-
* TODO: It's copy/paste of subtractInterval from @cubejs-backend/shared [time.ts]
|
|
113
|
-
* but operates with dayjs instead of moment.js
|
|
114
|
-
* @param {dayjs} date
|
|
115
|
-
* @param interval
|
|
116
|
-
* @returns {dayjs}
|
|
117
|
-
*/
|
|
118
|
-
export function subtractInterval(date, interval) {
|
|
119
|
-
let res = date.clone();
|
|
120
|
-
|
|
121
|
-
Object.entries(interval).forEach(([key, value]) => {
|
|
122
|
-
res = res.subtract(value, key);
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
return res;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Returns the closest date prior to date parameter aligned with the origin point
|
|
130
|
-
* TODO: It's copy/paste of alignToOrigin from @cubejs-backend/shared [time.ts]
|
|
131
|
-
* but operates with dayjs instead of moment.js
|
|
132
|
-
*/
|
|
133
|
-
function alignToOrigin(startDate, interval, origin) {
|
|
134
|
-
let alignedDate = startDate.clone();
|
|
135
|
-
let intervalOp;
|
|
136
|
-
let isIntervalNegative = false;
|
|
137
|
-
|
|
138
|
-
let offsetDate = addInterval(origin, interval);
|
|
139
|
-
|
|
140
|
-
// The easiest way to check the interval sign
|
|
141
|
-
if (offsetDate.isBefore(origin)) {
|
|
142
|
-
isIntervalNegative = true;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
offsetDate = origin.clone();
|
|
146
|
-
|
|
147
|
-
if (startDate.isBefore(origin)) {
|
|
148
|
-
intervalOp = isIntervalNegative ? addInterval : subtractInterval;
|
|
149
|
-
|
|
150
|
-
while (offsetDate.isAfter(startDate)) {
|
|
151
|
-
offsetDate = intervalOp(offsetDate, interval);
|
|
152
|
-
}
|
|
153
|
-
alignedDate = offsetDate;
|
|
154
|
-
} else {
|
|
155
|
-
intervalOp = isIntervalNegative ? subtractInterval : addInterval;
|
|
156
|
-
|
|
157
|
-
while (offsetDate.isBefore(startDate)) {
|
|
158
|
-
alignedDate = offsetDate.clone();
|
|
159
|
-
offsetDate = intervalOp(offsetDate, interval);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
if (offsetDate.isSame(startDate)) {
|
|
163
|
-
alignedDate = offsetDate;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
return alignedDate;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* Returns the time series points for the custom interval
|
|
172
|
-
* TODO: It's almost a copy/paste of timeSeriesFromCustomInterval from
|
|
173
|
-
* @cubejs-backend/shared [time.ts] but operates with dayjs instead of moment.js
|
|
174
|
-
*/
|
|
175
|
-
export const timeSeriesFromCustomInterval = (from, to, granularity) => {
|
|
176
|
-
const intervalParsed = parseSqlInterval(granularity.interval);
|
|
177
|
-
const start = internalDayjs(from);
|
|
178
|
-
const end = internalDayjs(to);
|
|
179
|
-
let origin = granularity.origin ? internalDayjs(granularity.origin) : internalDayjs().startOf('year');
|
|
180
|
-
if (granularity.offset) {
|
|
181
|
-
origin = addInterval(origin, parseSqlInterval(granularity.offset));
|
|
182
|
-
}
|
|
183
|
-
let alignedStart = alignToOrigin(start, intervalParsed, origin);
|
|
184
|
-
|
|
185
|
-
const dates = [];
|
|
186
|
-
|
|
187
|
-
while (alignedStart.isBefore(end) || alignedStart.isSame(end)) {
|
|
188
|
-
dates.push(alignedStart.format('YYYY-MM-DDTHH:mm:ss.000'));
|
|
189
|
-
alignedStart = addInterval(alignedStart, intervalParsed);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
return dates;
|
|
193
|
-
};
|
|
194
|
-
|
|
195
|
-
/**
|
|
196
|
-
* Returns the lowest time unit for the interval
|
|
197
|
-
* @protected
|
|
198
|
-
* @param {string} interval
|
|
199
|
-
* @returns {string}
|
|
200
|
-
*/
|
|
201
|
-
export const diffTimeUnitForInterval = (interval) => {
|
|
202
|
-
if (/second/i.test(interval)) {
|
|
203
|
-
return 'second';
|
|
204
|
-
} else if (/minute/i.test(interval)) {
|
|
205
|
-
return 'minute';
|
|
206
|
-
} else if (/hour/i.test(interval)) {
|
|
207
|
-
return 'hour';
|
|
208
|
-
} else if (/day/i.test(interval)) {
|
|
209
|
-
return 'day';
|
|
210
|
-
} else if (/week/i.test(interval)) {
|
|
211
|
-
return 'day';
|
|
212
|
-
} else if (/month/i.test(interval)) {
|
|
213
|
-
return 'month';
|
|
214
|
-
} else if (/quarter/i.test(interval)) {
|
|
215
|
-
return 'month';
|
|
216
|
-
} else /* if (/year/i.test(interval)) */ {
|
|
217
|
-
return 'year';
|
|
218
|
-
}
|
|
219
|
-
};
|
|
220
|
-
|
|
221
|
-
const granularityOrder = ['year', 'quarter', 'month', 'week', 'day', 'hour', 'minute', 'second'];
|
|
222
|
-
|
|
223
|
-
export const minGranularityForIntervals = (i1, i2) => {
|
|
224
|
-
const g1 = diffTimeUnitForInterval(i1);
|
|
225
|
-
const g2 = diffTimeUnitForInterval(i2);
|
|
226
|
-
const g1pos = granularityOrder.indexOf(g1);
|
|
227
|
-
const g2pos = granularityOrder.indexOf(g2);
|
|
228
|
-
|
|
229
|
-
if (g1pos > g2pos) {
|
|
230
|
-
return g1;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
return g2;
|
|
234
|
-
};
|
|
235
|
-
|
|
236
|
-
export const granularityFor = (dateStr) => {
|
|
237
|
-
const dayjsDate = internalDayjs(dateStr);
|
|
238
|
-
const month = dayjsDate.month();
|
|
239
|
-
const date = dayjsDate.date();
|
|
240
|
-
const hours = dayjsDate.hour();
|
|
241
|
-
const minutes = dayjsDate.minute();
|
|
242
|
-
const seconds = dayjsDate.second();
|
|
243
|
-
const milliseconds = dayjsDate.millisecond();
|
|
244
|
-
const weekDay = dayjsDate.isoWeekday();
|
|
245
|
-
|
|
246
|
-
if (
|
|
247
|
-
month === 0 &&
|
|
248
|
-
date === 1 &&
|
|
249
|
-
hours === 0 &&
|
|
250
|
-
minutes === 0 &&
|
|
251
|
-
seconds === 0 &&
|
|
252
|
-
milliseconds === 0
|
|
253
|
-
) {
|
|
254
|
-
return 'year';
|
|
255
|
-
} else if (
|
|
256
|
-
date === 1 &&
|
|
257
|
-
hours === 0 &&
|
|
258
|
-
minutes === 0 &&
|
|
259
|
-
seconds === 0 &&
|
|
260
|
-
milliseconds === 0
|
|
261
|
-
) {
|
|
262
|
-
return 'month';
|
|
263
|
-
} else if (
|
|
264
|
-
weekDay === 1 &&
|
|
265
|
-
hours === 0 &&
|
|
266
|
-
minutes === 0 &&
|
|
267
|
-
seconds === 0 &&
|
|
268
|
-
milliseconds === 0
|
|
269
|
-
) {
|
|
270
|
-
return 'week';
|
|
271
|
-
} else if (
|
|
272
|
-
hours === 0 &&
|
|
273
|
-
minutes === 0 &&
|
|
274
|
-
seconds === 0 &&
|
|
275
|
-
milliseconds === 0
|
|
276
|
-
) {
|
|
277
|
-
return 'day';
|
|
278
|
-
} else if (
|
|
279
|
-
minutes === 0 &&
|
|
280
|
-
seconds === 0 &&
|
|
281
|
-
milliseconds === 0
|
|
282
|
-
) {
|
|
283
|
-
return 'hour';
|
|
284
|
-
} else if (
|
|
285
|
-
seconds === 0 &&
|
|
286
|
-
milliseconds === 0
|
|
287
|
-
) {
|
|
288
|
-
return 'minute';
|
|
289
|
-
} else if (
|
|
290
|
-
milliseconds === 0
|
|
291
|
-
) {
|
|
292
|
-
return 'second';
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
return 'second'; // TODO return 'millisecond';
|
|
296
|
-
};
|
package/src/utils.js
DELETED
|
@@ -1,368 +0,0 @@
|
|
|
1
|
-
import { clone, equals, fromPairs, indexBy, prop, toPairs } from 'ramda';
|
|
2
|
-
import { DEFAULT_GRANULARITY } from './time';
|
|
3
|
-
|
|
4
|
-
export function removeEmptyQueryFields(_query) {
|
|
5
|
-
const query = _query || {};
|
|
6
|
-
|
|
7
|
-
return fromPairs(
|
|
8
|
-
toPairs(query)
|
|
9
|
-
.map(([key, value]) => {
|
|
10
|
-
if (
|
|
11
|
-
['measures', 'dimensions', 'segments', 'timeDimensions', 'filters'].includes(key)
|
|
12
|
-
) {
|
|
13
|
-
if (Array.isArray(value) && value.length === 0) {
|
|
14
|
-
return null;
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
if (key === 'order' && value) {
|
|
19
|
-
if (Array.isArray(value) && !value.length) {
|
|
20
|
-
return null;
|
|
21
|
-
} else if (!Object.keys(value).length) {
|
|
22
|
-
return null;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
return [key, value];
|
|
27
|
-
})
|
|
28
|
-
.filter(Boolean)
|
|
29
|
-
);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export function validateQuery(_query) {
|
|
33
|
-
const query = _query || {};
|
|
34
|
-
|
|
35
|
-
return removeEmptyQueryFields({
|
|
36
|
-
...query,
|
|
37
|
-
filters: (query.filters || []).filter((f) => f.operator),
|
|
38
|
-
timeDimensions: (query.timeDimensions || []).filter(
|
|
39
|
-
(td) => !(!td.dateRange && !td.granularity)
|
|
40
|
-
),
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export function areQueriesEqual(query1 = {}, query2 = {}) {
|
|
45
|
-
return (
|
|
46
|
-
equals(
|
|
47
|
-
Object.entries((query1 && query1.order) || {}),
|
|
48
|
-
Object.entries((query2 && query2.order) || {})
|
|
49
|
-
) && equals(query1, query2)
|
|
50
|
-
);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export function defaultOrder(query) {
|
|
54
|
-
const granularity = (query.timeDimensions || []).find((d) => d.granularity);
|
|
55
|
-
|
|
56
|
-
if (granularity) {
|
|
57
|
-
return {
|
|
58
|
-
[granularity.dimension]: 'asc',
|
|
59
|
-
};
|
|
60
|
-
} else if (
|
|
61
|
-
(query.measures || []).length > 0 &&
|
|
62
|
-
(query.dimensions || []).length > 0
|
|
63
|
-
) {
|
|
64
|
-
return {
|
|
65
|
-
[query.measures[0]]: 'desc',
|
|
66
|
-
};
|
|
67
|
-
} else if ((query.dimensions || []).length > 0) {
|
|
68
|
-
return {
|
|
69
|
-
[query.dimensions[0]]: 'asc',
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
return {};
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export function defaultHeuristics(newState, oldQuery = {}, options) {
|
|
77
|
-
const { query, ...props } = clone(newState);
|
|
78
|
-
const { meta, sessionGranularity } = options;
|
|
79
|
-
const granularity = sessionGranularity || DEFAULT_GRANULARITY;
|
|
80
|
-
|
|
81
|
-
let state = {
|
|
82
|
-
query,
|
|
83
|
-
...props,
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
let newQuery = null;
|
|
87
|
-
if (!areQueriesEqual(query, oldQuery)) {
|
|
88
|
-
newQuery = query;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
if (Array.isArray(newQuery) || Array.isArray(oldQuery)) {
|
|
92
|
-
return newState;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
if (newQuery) {
|
|
96
|
-
if (
|
|
97
|
-
(oldQuery.timeDimensions || []).length === 1 &&
|
|
98
|
-
(newQuery.timeDimensions || []).length === 1 &&
|
|
99
|
-
newQuery.timeDimensions[0].granularity &&
|
|
100
|
-
oldQuery.timeDimensions[0].granularity !==
|
|
101
|
-
newQuery.timeDimensions[0].granularity
|
|
102
|
-
) {
|
|
103
|
-
state = {
|
|
104
|
-
...state,
|
|
105
|
-
sessionGranularity: newQuery.timeDimensions[0].granularity,
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
if (
|
|
110
|
-
((oldQuery.measures || []).length === 0 &&
|
|
111
|
-
(newQuery.measures || []).length > 0) ||
|
|
112
|
-
((oldQuery.measures || []).length === 1 &&
|
|
113
|
-
(newQuery.measures || []).length === 1 &&
|
|
114
|
-
oldQuery.measures[0] !== newQuery.measures[0])
|
|
115
|
-
) {
|
|
116
|
-
const [td] = newQuery.timeDimensions || [];
|
|
117
|
-
const defaultTimeDimension = meta.defaultTimeDimensionNameFor(
|
|
118
|
-
newQuery.measures[0]
|
|
119
|
-
);
|
|
120
|
-
newQuery = {
|
|
121
|
-
...newQuery,
|
|
122
|
-
timeDimensions: defaultTimeDimension
|
|
123
|
-
? [
|
|
124
|
-
{
|
|
125
|
-
dimension: defaultTimeDimension,
|
|
126
|
-
granularity: (td && td.granularity) || granularity,
|
|
127
|
-
dateRange: td && td.dateRange,
|
|
128
|
-
},
|
|
129
|
-
]
|
|
130
|
-
: [],
|
|
131
|
-
};
|
|
132
|
-
|
|
133
|
-
return {
|
|
134
|
-
...state,
|
|
135
|
-
pivotConfig: null,
|
|
136
|
-
shouldApplyHeuristicOrder: true,
|
|
137
|
-
query: newQuery,
|
|
138
|
-
chartType: defaultTimeDimension ? 'line' : 'number',
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
if (
|
|
143
|
-
(oldQuery.dimensions || []).length === 0 &&
|
|
144
|
-
(newQuery.dimensions || []).length > 0
|
|
145
|
-
) {
|
|
146
|
-
newQuery = {
|
|
147
|
-
...newQuery,
|
|
148
|
-
timeDimensions: (newQuery.timeDimensions || []).map((td) => ({
|
|
149
|
-
...td,
|
|
150
|
-
granularity: undefined,
|
|
151
|
-
})),
|
|
152
|
-
};
|
|
153
|
-
|
|
154
|
-
return {
|
|
155
|
-
...state,
|
|
156
|
-
pivotConfig: null,
|
|
157
|
-
shouldApplyHeuristicOrder: true,
|
|
158
|
-
query: newQuery,
|
|
159
|
-
chartType: 'table',
|
|
160
|
-
};
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
if (
|
|
164
|
-
(oldQuery.dimensions || []).length > 0 &&
|
|
165
|
-
(newQuery.dimensions || []).length === 0
|
|
166
|
-
) {
|
|
167
|
-
newQuery = {
|
|
168
|
-
...newQuery,
|
|
169
|
-
timeDimensions: (newQuery.timeDimensions || []).map((td) => ({
|
|
170
|
-
...td,
|
|
171
|
-
granularity: td.granularity || granularity,
|
|
172
|
-
})),
|
|
173
|
-
};
|
|
174
|
-
|
|
175
|
-
return {
|
|
176
|
-
...state,
|
|
177
|
-
pivotConfig: null,
|
|
178
|
-
shouldApplyHeuristicOrder: true,
|
|
179
|
-
query: newQuery,
|
|
180
|
-
chartType: (newQuery.timeDimensions || []).length ? 'line' : 'number',
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
if (
|
|
185
|
-
((oldQuery.dimensions || []).length > 0 ||
|
|
186
|
-
(oldQuery.measures || []).length > 0) &&
|
|
187
|
-
(newQuery.dimensions || []).length === 0 &&
|
|
188
|
-
(newQuery.measures || []).length === 0
|
|
189
|
-
) {
|
|
190
|
-
newQuery = {
|
|
191
|
-
...newQuery,
|
|
192
|
-
timeDimensions: [],
|
|
193
|
-
filters: [],
|
|
194
|
-
};
|
|
195
|
-
|
|
196
|
-
return {
|
|
197
|
-
...state,
|
|
198
|
-
pivotConfig: null,
|
|
199
|
-
shouldApplyHeuristicOrder: true,
|
|
200
|
-
query: newQuery,
|
|
201
|
-
sessionGranularity: null,
|
|
202
|
-
};
|
|
203
|
-
}
|
|
204
|
-
return state;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
if (state.chartType) {
|
|
208
|
-
const newChartType = state.chartType;
|
|
209
|
-
if (
|
|
210
|
-
(newChartType === 'line' || newChartType === 'area') &&
|
|
211
|
-
(oldQuery.timeDimensions || []).length === 1 &&
|
|
212
|
-
!oldQuery.timeDimensions[0].granularity
|
|
213
|
-
) {
|
|
214
|
-
const [td] = oldQuery.timeDimensions;
|
|
215
|
-
return {
|
|
216
|
-
...state,
|
|
217
|
-
pivotConfig: null,
|
|
218
|
-
query: {
|
|
219
|
-
...oldQuery,
|
|
220
|
-
timeDimensions: [{ ...td, granularity }],
|
|
221
|
-
},
|
|
222
|
-
};
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
if (
|
|
226
|
-
(newChartType === 'pie' ||
|
|
227
|
-
newChartType === 'table' ||
|
|
228
|
-
newChartType === 'number') &&
|
|
229
|
-
(oldQuery.timeDimensions || []).length === 1 &&
|
|
230
|
-
oldQuery.timeDimensions[0].granularity
|
|
231
|
-
) {
|
|
232
|
-
const [td] = oldQuery.timeDimensions;
|
|
233
|
-
return {
|
|
234
|
-
...state,
|
|
235
|
-
pivotConfig: null,
|
|
236
|
-
shouldApplyHeuristicOrder: true,
|
|
237
|
-
query: {
|
|
238
|
-
...oldQuery,
|
|
239
|
-
timeDimensions: [{ ...td, granularity: undefined }],
|
|
240
|
-
},
|
|
241
|
-
};
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
return state;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
export function isQueryPresent(query) {
|
|
249
|
-
if (!query) {
|
|
250
|
-
return false;
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
return (Array.isArray(query) ? query : [query]).every(
|
|
254
|
-
(q) => (q.measures && q.measures.length) ||
|
|
255
|
-
(q.dimensions && q.dimensions.length) ||
|
|
256
|
-
(q.timeDimensions && q.timeDimensions.length)
|
|
257
|
-
);
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
export function movePivotItem(
|
|
261
|
-
pivotConfig,
|
|
262
|
-
sourceIndex,
|
|
263
|
-
destinationIndex,
|
|
264
|
-
sourceAxis,
|
|
265
|
-
destinationAxis
|
|
266
|
-
) {
|
|
267
|
-
const nextPivotConfig = {
|
|
268
|
-
...pivotConfig,
|
|
269
|
-
x: [...pivotConfig.x],
|
|
270
|
-
y: [...pivotConfig.y],
|
|
271
|
-
};
|
|
272
|
-
const id = pivotConfig[sourceAxis][sourceIndex];
|
|
273
|
-
const lastIndex = nextPivotConfig[destinationAxis].length - 1;
|
|
274
|
-
|
|
275
|
-
if (id === 'measures') {
|
|
276
|
-
destinationIndex = lastIndex + 1;
|
|
277
|
-
} else if (
|
|
278
|
-
sourceAxis === destinationAxis &&
|
|
279
|
-
destinationIndex >= lastIndex &&
|
|
280
|
-
nextPivotConfig[destinationAxis][lastIndex] === 'measures'
|
|
281
|
-
) {
|
|
282
|
-
destinationIndex = lastIndex - 1;
|
|
283
|
-
} else if (
|
|
284
|
-
sourceAxis !== destinationAxis &&
|
|
285
|
-
destinationIndex > lastIndex &&
|
|
286
|
-
nextPivotConfig[destinationAxis][lastIndex] === 'measures'
|
|
287
|
-
) {
|
|
288
|
-
destinationIndex = lastIndex;
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
nextPivotConfig[sourceAxis].splice(sourceIndex, 1);
|
|
292
|
-
nextPivotConfig[destinationAxis].splice(destinationIndex, 0, id);
|
|
293
|
-
|
|
294
|
-
return nextPivotConfig;
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
export function moveItemInArray(list, sourceIndex, destinationIndex) {
|
|
298
|
-
const result = [...list];
|
|
299
|
-
const [removed] = result.splice(sourceIndex, 1);
|
|
300
|
-
result.splice(destinationIndex, 0, removed);
|
|
301
|
-
|
|
302
|
-
return result;
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
export function flattenFilters(filters = []) {
|
|
306
|
-
return filters.reduce((memo, filter) => {
|
|
307
|
-
if (filter.or || filter.and) {
|
|
308
|
-
return [...memo, ...flattenFilters(filter.or || filter.and)];
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
return [...memo, filter];
|
|
312
|
-
}, []);
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
export function getQueryMembers(query = {}) {
|
|
316
|
-
const keys = ['measures', 'dimensions', 'segments'];
|
|
317
|
-
const members = new Set();
|
|
318
|
-
|
|
319
|
-
keys.forEach((key) => (query[key] || []).forEach((member) => members.add(member)));
|
|
320
|
-
(query.timeDimensions || []).forEach((td) => members.add(td.dimension));
|
|
321
|
-
|
|
322
|
-
flattenFilters(query.filters).forEach((filter) => members.add(filter.dimension || filter.member));
|
|
323
|
-
|
|
324
|
-
return [...members];
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
export function getOrderMembersFromOrder(orderMembers, order) {
|
|
328
|
-
const ids = new Set();
|
|
329
|
-
const indexedOrderMembers = indexBy(prop('id'), orderMembers);
|
|
330
|
-
const entries = Array.isArray(order) ? order : Object.entries(order || {});
|
|
331
|
-
const nextOrderMembers = [];
|
|
332
|
-
|
|
333
|
-
entries.forEach(([memberId, currentOrder]) => {
|
|
334
|
-
if (currentOrder !== 'none' && indexedOrderMembers[memberId]) {
|
|
335
|
-
ids.add(memberId);
|
|
336
|
-
nextOrderMembers.push({
|
|
337
|
-
...indexedOrderMembers[memberId],
|
|
338
|
-
order: currentOrder,
|
|
339
|
-
});
|
|
340
|
-
}
|
|
341
|
-
});
|
|
342
|
-
orderMembers.forEach((member) => {
|
|
343
|
-
if (!ids.has(member.id)) {
|
|
344
|
-
nextOrderMembers.push({
|
|
345
|
-
...member,
|
|
346
|
-
order: member.order || 'none',
|
|
347
|
-
});
|
|
348
|
-
}
|
|
349
|
-
});
|
|
350
|
-
|
|
351
|
-
return nextOrderMembers;
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
export function aliasSeries(values, index, pivotConfig, duplicateMeasures) {
|
|
355
|
-
const nonNullValues = values.filter((value) => value != null);
|
|
356
|
-
|
|
357
|
-
if (
|
|
358
|
-
pivotConfig &&
|
|
359
|
-
pivotConfig.aliasSeries &&
|
|
360
|
-
pivotConfig.aliasSeries[index]
|
|
361
|
-
) {
|
|
362
|
-
return [pivotConfig.aliasSeries[index], ...nonNullValues];
|
|
363
|
-
} else if (duplicateMeasures.has(nonNullValues[0])) {
|
|
364
|
-
return [index, ...nonNullValues];
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
return nonNullValues;
|
|
368
|
-
}
|