@cubejs-client/core 0.29.53 → 0.30.4

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/index.d.ts CHANGED
@@ -808,6 +808,36 @@ declare module '@cubejs-client/core' {
808
808
  total?: boolean;
809
809
  }
810
810
 
811
+ export type QueryRecordType<T extends DeeplyReadonly<Query | Query[]>> =
812
+ T extends DeeplyReadonly<Query[]> ? QueryArrayRecordType<T> :
813
+ T extends DeeplyReadonly<Query> ? SingleQueryRecordType<T> :
814
+ never;
815
+
816
+ type QueryArrayRecordType<T extends DeeplyReadonly<Query[]>> =
817
+ T extends readonly [infer First, ...infer Rest]
818
+ ? SingleQueryRecordType<First> | QueryArrayRecordType<Rest>
819
+ : never;
820
+
821
+ // If we can't infer any members at all, then return any.
822
+ type SingleQueryRecordType<T extends DeeplyReadonly<Query>> = ExtractMembers<T> extends never
823
+ ? any
824
+ : { [K in string & ExtractMembers<T>]: string | number | boolean | null };
825
+
826
+ type ExtractMembers<T extends DeeplyReadonly<Query>> =
827
+ | ( T extends { dimensions: readonly (infer Names)[]; } ? Names : never )
828
+ | ( T extends { measures: readonly (infer Names)[]; } ? Names : never )
829
+ | ( T extends { timeDimensions: (infer U); } ? ExtractTimeMembers<U> : never );
830
+
831
+ type ExtractTimeMembers<T> =
832
+ T extends readonly [infer First, ...infer Rest]
833
+ ? ExtractTimeMember<First> | ExtractTimeMembers<Rest>
834
+ : never;
835
+
836
+ type ExtractTimeMember<T> =
837
+ T extends { dimension: infer Dimension, granularity: infer Granularity }
838
+ ? Dimension | `${Dimension & string}.${Granularity & string}`
839
+ : never;
840
+
811
841
  export class ProgressResult {
812
842
  stage(): string;
813
843
  timeElapsed(): string;
@@ -983,7 +1013,10 @@ declare module '@cubejs-client/core' {
983
1013
  * @order 2
984
1014
  */
985
1015
  export class CubejsApi {
986
- load(query: DeeplyReadonly<Query | Query[]>, options?: LoadMethodOptions): Promise<ResultSet>;
1016
+ load<QueryType extends DeeplyReadonly<Query | Query[]>>(
1017
+ query: QueryType,
1018
+ options?: LoadMethodOptions,
1019
+ ): Promise<ResultSet<QueryRecordType<QueryType>>>;
987
1020
  /**
988
1021
  * Fetch data for the passed `query`.
989
1022
  *
@@ -1008,13 +1041,18 @@ declare module '@cubejs-client/core' {
1008
1041
  * ```
1009
1042
  * @param query - [Query object](query-format)
1010
1043
  */
1011
- load(query: DeeplyReadonly<Query | Query[]>, options?: LoadMethodOptions, callback?: LoadMethodCallback<ResultSet>): void;
1012
- load(
1013
- query: DeeplyReadonly<Query | Query[]>,
1044
+ load<QueryType extends DeeplyReadonly<Query | Query[]>>(
1045
+ query: QueryType,
1046
+ options?: LoadMethodOptions,
1047
+ callback?: LoadMethodCallback<ResultSet<QueryRecordType<QueryType>>>,
1048
+ ): void;
1049
+
1050
+ load<QueryType extends DeeplyReadonly<Query | Query[]>>(
1051
+ query: QueryType,
1014
1052
  options?: LoadMethodOptions,
1015
1053
  callback?: LoadMethodCallback<ResultSet>,
1016
1054
  responseFormat?: string
1017
- ): Promise<ResultSet>;
1055
+ ): Promise<ResultSet<QueryRecordType<QueryType>>>;
1018
1056
 
1019
1057
  /**
1020
1058
  * Allows you to fetch data and receive updates over time. See [Real-Time Data Fetch](real-time-data-fetch)
@@ -1040,7 +1078,11 @@ declare module '@cubejs-client/core' {
1040
1078
  * );
1041
1079
  * ```
1042
1080
  */
1043
- subscribe(query: DeeplyReadonly<Query | Query[]>, options: LoadMethodOptions | null, callback: LoadMethodCallback<ResultSet>): void;
1081
+ subscribe<QueryType extends DeeplyReadonly<Query | Query[]>>(
1082
+ query: QueryType,
1083
+ options: LoadMethodOptions | null,
1084
+ callback: LoadMethodCallback<ResultSet<QueryRecordType<QueryType>>>,
1085
+ ): void;
1044
1086
 
1045
1087
  sql(query: DeeplyReadonly<Query | Query[]>, options?: LoadMethodOptions): Promise<SqlQuery>;
1046
1088
  /**
@@ -1171,6 +1213,8 @@ declare module '@cubejs-client/core' {
1171
1213
  export function getQueryMembers(query: DeeplyReadonly<Query>): string[];
1172
1214
 
1173
1215
  export function areQueriesEqual(query1: DeeplyReadonly<Query> | null, query2: DeeplyReadonly<Query> | null): boolean;
1216
+
1217
+ export function validateQuery(query: DeeplyReadonly<Query> | null | undefined): Query;
1174
1218
 
1175
1219
  export type ProgressResponse = {
1176
1220
  stage: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cubejs-client/core",
3
- "version": "0.29.53",
3
+ "version": "0.30.4",
4
4
  "engines": {},
5
5
  "repository": {
6
6
  "type": "git",
@@ -46,5 +46,5 @@
46
46
  "eslint-plugin-node": "^5.2.1",
47
47
  "jest": "^26.0.1"
48
48
  },
49
- "gitHead": "b2815b43b973199420267695877b57eb6d744978"
49
+ "gitHead": "b7df8f6a3cfe104e639e0f7607868afa193ed0a3"
50
50
  }
package/src/index.js CHANGED
@@ -368,15 +368,4 @@ class CubejsApi {
368
368
  export default (apiToken, options) => new CubejsApi(apiToken, options);
369
369
 
370
370
  export { CubejsApi, HttpTransport, ResultSet };
371
- export {
372
- areQueriesEqual,
373
- defaultHeuristics,
374
- movePivotItem,
375
- isQueryPresent,
376
- moveItemInArray,
377
- defaultOrder,
378
- flattenFilters,
379
- getQueryMembers,
380
- getOrderMembersFromOrder,
381
- GRANULARITIES
382
- } from './utils';
371
+ export * from './utils';
package/src/utils.js CHANGED
@@ -1,4 +1,4 @@
1
- import { indexBy, prop, clone, equals } from 'ramda';
1
+ import { indexBy, prop, clone, equals, fromPairs, toPairs } from 'ramda';
2
2
 
3
3
  export const DEFAULT_GRANULARITY = 'day';
4
4
 
@@ -14,10 +14,52 @@ export const GRANULARITIES = [
14
14
  { name: 'year', title: 'Year' },
15
15
  ];
16
16
 
17
+ export function removeEmptyQueryFields(_query) {
18
+ const query = _query || {};
19
+
20
+ return fromPairs(
21
+ toPairs(query)
22
+ .map(([key, value]) => {
23
+ if (
24
+ ['measures', 'dimensions', 'segments', 'timeDimensions', 'filters'].includes(key)
25
+ ) {
26
+ if (Array.isArray(value) && value.length === 0) {
27
+ return null;
28
+ }
29
+ }
30
+
31
+ if (key === 'order' && value) {
32
+ if (Array.isArray(value) && !value.length) {
33
+ return null;
34
+ } else if (!Object.keys(value).length) {
35
+ return null;
36
+ }
37
+ }
38
+
39
+ return [key, value];
40
+ })
41
+ .filter(Boolean)
42
+ );
43
+ }
44
+
45
+ export function validateQuery(_query) {
46
+ const query = _query || {};
47
+
48
+ return removeEmptyQueryFields({
49
+ ...query,
50
+ filters: (query.filters || []).filter((f) => f.operator),
51
+ timeDimensions: (query.timeDimensions || []).filter(
52
+ (td) => !(!td.dateRange && !td.granularity)
53
+ ),
54
+ });
55
+ }
56
+
17
57
  export function areQueriesEqual(query1 = {}, query2 = {}) {
18
58
  return (
19
- equals(Object.entries((query1 && query1.order) || {}), Object.entries((query2 && query2.order) || {})) &&
20
- equals(query1, query2)
59
+ equals(
60
+ Object.entries((query1 && query1.order) || {}),
61
+ Object.entries((query2 && query2.order) || {})
62
+ ) && equals(query1, query2)
21
63
  );
22
64
  }
23
65
 
@@ -28,7 +70,10 @@ export function defaultOrder(query) {
28
70
  return {
29
71
  [granularity.dimension]: 'asc',
30
72
  };
31
- } else if ((query.measures || []).length > 0 && (query.dimensions || []).length > 0) {
73
+ } else if (
74
+ (query.measures || []).length > 0 &&
75
+ (query.dimensions || []).length > 0
76
+ ) {
32
77
  return {
33
78
  [query.measures[0]]: 'desc',
34
79
  };
@@ -65,7 +110,8 @@ export function defaultHeuristics(newState, oldQuery = {}, options) {
65
110
  (oldQuery.timeDimensions || []).length === 1 &&
66
111
  (newQuery.timeDimensions || []).length === 1 &&
67
112
  newQuery.timeDimensions[0].granularity &&
68
- oldQuery.timeDimensions[0].granularity !== newQuery.timeDimensions[0].granularity
113
+ oldQuery.timeDimensions[0].granularity !==
114
+ newQuery.timeDimensions[0].granularity
69
115
  ) {
70
116
  state = {
71
117
  ...state,
@@ -74,13 +120,16 @@ export function defaultHeuristics(newState, oldQuery = {}, options) {
74
120
  }
75
121
 
76
122
  if (
77
- ((oldQuery.measures || []).length === 0 && (newQuery.measures || []).length > 0) ||
123
+ ((oldQuery.measures || []).length === 0 &&
124
+ (newQuery.measures || []).length > 0) ||
78
125
  ((oldQuery.measures || []).length === 1 &&
79
126
  (newQuery.measures || []).length === 1 &&
80
127
  oldQuery.measures[0] !== newQuery.measures[0])
81
128
  ) {
82
129
  const [td] = newQuery.timeDimensions || [];
83
- const defaultTimeDimension = meta.defaultTimeDimensionNameFor(newQuery.measures[0]);
130
+ const defaultTimeDimension = meta.defaultTimeDimensionNameFor(
131
+ newQuery.measures[0]
132
+ );
84
133
  newQuery = {
85
134
  ...newQuery,
86
135
  timeDimensions: defaultTimeDimension
@@ -103,10 +152,16 @@ export function defaultHeuristics(newState, oldQuery = {}, options) {
103
152
  };
104
153
  }
105
154
 
106
- if ((oldQuery.dimensions || []).length === 0 && (newQuery.dimensions || []).length > 0) {
155
+ if (
156
+ (oldQuery.dimensions || []).length === 0 &&
157
+ (newQuery.dimensions || []).length > 0
158
+ ) {
107
159
  newQuery = {
108
160
  ...newQuery,
109
- timeDimensions: (newQuery.timeDimensions || []).map((td) => ({ ...td, granularity: undefined })),
161
+ timeDimensions: (newQuery.timeDimensions || []).map((td) => ({
162
+ ...td,
163
+ granularity: undefined,
164
+ })),
110
165
  };
111
166
 
112
167
  return {
@@ -118,7 +173,10 @@ export function defaultHeuristics(newState, oldQuery = {}, options) {
118
173
  };
119
174
  }
120
175
 
121
- if ((oldQuery.dimensions || []).length > 0 && (newQuery.dimensions || []).length === 0) {
176
+ if (
177
+ (oldQuery.dimensions || []).length > 0 &&
178
+ (newQuery.dimensions || []).length === 0
179
+ ) {
122
180
  newQuery = {
123
181
  ...newQuery,
124
182
  timeDimensions: (newQuery.timeDimensions || []).map((td) => ({
@@ -137,7 +195,8 @@ export function defaultHeuristics(newState, oldQuery = {}, options) {
137
195
  }
138
196
 
139
197
  if (
140
- ((oldQuery.dimensions || []).length > 0 || (oldQuery.measures || []).length > 0) &&
198
+ ((oldQuery.dimensions || []).length > 0 ||
199
+ (oldQuery.measures || []).length > 0) &&
141
200
  (newQuery.dimensions || []).length === 0 &&
142
201
  (newQuery.measures || []).length === 0
143
202
  ) {
@@ -177,7 +236,9 @@ export function defaultHeuristics(newState, oldQuery = {}, options) {
177
236
  }
178
237
 
179
238
  if (
180
- (newChartType === 'pie' || newChartType === 'table' || newChartType === 'number') &&
239
+ (newChartType === 'pie' ||
240
+ newChartType === 'table' ||
241
+ newChartType === 'number') &&
181
242
  (oldQuery.timeDimensions || []).length === 1 &&
182
243
  oldQuery.timeDimensions[0].granularity
183
244
  ) {
@@ -209,7 +270,13 @@ export function isQueryPresent(query) {
209
270
  );
210
271
  }
211
272
 
212
- export function movePivotItem(pivotConfig, sourceIndex, destinationIndex, sourceAxis, destinationAxis) {
273
+ export function movePivotItem(
274
+ pivotConfig,
275
+ sourceIndex,
276
+ destinationIndex,
277
+ sourceAxis,
278
+ destinationAxis
279
+ ) {
213
280
  const nextPivotConfig = {
214
281
  ...pivotConfig,
215
282
  x: [...pivotConfig.x],
@@ -220,7 +287,10 @@ export function movePivotItem(pivotConfig, sourceIndex, destinationIndex, source
220
287
 
221
288
  if (id === 'measures') {
222
289
  destinationIndex = lastIndex + 1;
223
- } else if (destinationIndex >= lastIndex && nextPivotConfig[destinationAxis][lastIndex] === 'measures') {
290
+ } else if (
291
+ destinationIndex >= lastIndex &&
292
+ nextPivotConfig[destinationAxis][lastIndex] === 'measures'
293
+ ) {
224
294
  destinationIndex = lastIndex - 1;
225
295
  }
226
296
 
@@ -290,7 +360,11 @@ export function getOrderMembersFromOrder(orderMembers, order) {
290
360
  export function aliasSeries(values, index, pivotConfig, duplicateMeasures) {
291
361
  const nonNullValues = values.filter((value) => value != null);
292
362
 
293
- if (pivotConfig && pivotConfig.aliasSeries && pivotConfig.aliasSeries[index]) {
363
+ if (
364
+ pivotConfig &&
365
+ pivotConfig.aliasSeries &&
366
+ pivotConfig.aliasSeries[index]
367
+ ) {
294
368
  return [pivotConfig.aliasSeries[index], ...nonNullValues];
295
369
  } else if (duplicateMeasures.has(nonNullValues[0])) {
296
370
  return [index, ...nonNullValues];