@cubejs-backend/schema-compiler 1.3.11 → 1.3.13

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.
Files changed (42) hide show
  1. package/dist/src/adapter/BaseDimension.d.ts +3 -3
  2. package/dist/src/adapter/BaseDimension.d.ts.map +1 -1
  3. package/dist/src/adapter/BaseDimension.js.map +1 -1
  4. package/dist/src/adapter/BaseFilter.d.ts +5 -1
  5. package/dist/src/adapter/BaseFilter.d.ts.map +1 -1
  6. package/dist/src/adapter/BaseFilter.js +13 -3
  7. package/dist/src/adapter/BaseFilter.js.map +1 -1
  8. package/dist/src/adapter/BaseGroupFilter.d.ts +2 -2
  9. package/dist/src/adapter/BaseGroupFilter.d.ts.map +1 -1
  10. package/dist/src/adapter/BaseGroupFilter.js.map +1 -1
  11. package/dist/src/adapter/BaseMeasure.d.ts +4 -4
  12. package/dist/src/adapter/BaseMeasure.js.map +1 -1
  13. package/dist/src/adapter/BaseQuery.d.ts +119 -35
  14. package/dist/src/adapter/BaseQuery.d.ts.map +1 -1
  15. package/dist/src/adapter/BaseQuery.js +226 -43
  16. package/dist/src/adapter/BaseQuery.js.map +1 -1
  17. package/dist/src/adapter/BaseSegment.d.ts +2 -2
  18. package/dist/src/adapter/BaseSegment.js.map +1 -1
  19. package/dist/src/adapter/BaseTimeDimension.d.ts +1 -1
  20. package/dist/src/adapter/CubeStoreQuery.d.ts +6 -6
  21. package/dist/src/adapter/CubeStoreQuery.d.ts.map +1 -1
  22. package/dist/src/adapter/CubeStoreQuery.js +3 -4
  23. package/dist/src/adapter/CubeStoreQuery.js.map +1 -1
  24. package/dist/src/adapter/HiveQuery.d.ts +7 -2
  25. package/dist/src/adapter/HiveQuery.d.ts.map +1 -1
  26. package/dist/src/adapter/HiveQuery.js +2 -2
  27. package/dist/src/adapter/HiveQuery.js.map +1 -1
  28. package/dist/src/adapter/PreAggregations.d.ts +130 -209
  29. package/dist/src/adapter/PreAggregations.d.ts.map +1 -1
  30. package/dist/src/adapter/PreAggregations.js +205 -148
  31. package/dist/src/adapter/PreAggregations.js.map +1 -1
  32. package/dist/src/compiler/CubeEvaluator.d.ts +37 -9
  33. package/dist/src/compiler/CubeEvaluator.d.ts.map +1 -1
  34. package/dist/src/compiler/CubeEvaluator.js +13 -2
  35. package/dist/src/compiler/CubeEvaluator.js.map +1 -1
  36. package/dist/src/compiler/CubeSymbols.d.ts +1 -1
  37. package/dist/src/compiler/CubeSymbols.d.ts.map +1 -1
  38. package/dist/src/compiler/CubeSymbols.js.map +1 -1
  39. package/dist/src/compiler/CubeValidator.d.ts.map +1 -1
  40. package/dist/src/compiler/CubeValidator.js +16 -7
  41. package/dist/src/compiler/CubeValidator.js.map +1 -1
  42. package/package.json +6 -6
@@ -5,15 +5,16 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.PreAggregations = void 0;
7
7
  const ramda_1 = __importDefault(require("ramda"));
8
- const shared_1 = require("@cubejs-backend/shared");
9
8
  const CubeSymbols_1 = require("../compiler/CubeSymbols");
10
9
  const UserError_1 = require("../compiler/UserError");
10
+ const BaseMeasure_1 = require("./BaseMeasure");
11
11
  class PreAggregations {
12
- /**
13
- * @param {import('../adapter/BaseQuery').BaseQuery} query
14
- * @param historyQueries
15
- * @param cubeLatticeCache
16
- */
12
+ query;
13
+ historyQueries;
14
+ cubeLatticeCache;
15
+ cubeLattices;
16
+ hasCumulativeMeasuresValue = false;
17
+ preAggregationForQuery = undefined;
17
18
  constructor(query, historyQueries, cubeLatticeCache) {
18
19
  this.query = query;
19
20
  this.historyQueries = historyQueries;
@@ -21,7 +22,7 @@ class PreAggregations {
21
22
  this.cubeLattices = {};
22
23
  }
23
24
  /**
24
- * @return {unknown[]}
25
+ * It returns full pre-aggregation object (with keyQueries, previewSql, loadSql, and so on.
25
26
  */
26
27
  preAggregationsDescription() {
27
28
  const preAggregations = [this.preAggregationsDescriptionLocal()].concat(this.query.subQueryDimensions.map(d => this.query.subQueryDescription(d).subQuery)
@@ -41,7 +42,7 @@ class PreAggregations {
41
42
  return ramda_1.default.pipe(ramda_1.default.map(cube => {
42
43
  const { preAggregations } = this.collectOriginalSqlPreAggregations(() => this.query.cubeSql(cube));
43
44
  return ramda_1.default.unnest(preAggregations.map(p => this.preAggregationDescriptionsFor(p)));
44
- }), ramda_1.default.filter(ramda_1.default.identity), ramda_1.default.unnest)(this.preAggregationCubes());
45
+ }), ramda_1.default.filter((x) => Boolean(x)), ramda_1.default.unnest)(this.preAggregationCubes());
45
46
  }
46
47
  return [];
47
48
  }
@@ -52,10 +53,10 @@ class PreAggregations {
52
53
  preAggregationDescriptionsFor(foundPreAggregation) {
53
54
  let preAggregations = [foundPreAggregation];
54
55
  if (foundPreAggregation.preAggregation.type === 'rollupJoin') {
55
- preAggregations = foundPreAggregation.preAggregationsToJoin;
56
+ preAggregations = foundPreAggregation.preAggregationsToJoin || [];
56
57
  }
57
58
  if (foundPreAggregation.preAggregation.type === 'rollupLambda') {
58
- preAggregations = foundPreAggregation.referencedPreAggregations;
59
+ preAggregations = foundPreAggregation.referencedPreAggregations || [];
59
60
  }
60
61
  return preAggregations.map(preAggregation => {
61
62
  if (this.canPartitionsBeUsed(preAggregation)) {
@@ -66,28 +67,29 @@ class PreAggregations {
66
67
  }).reduce((a, b) => a.concat(b), []);
67
68
  }
68
69
  canPartitionsBeUsed(foundPreAggregation) {
69
- return foundPreAggregation.preAggregation.partitionGranularity &&
70
- foundPreAggregation.references.timeDimensions &&
71
- foundPreAggregation.references.timeDimensions.length;
70
+ return !!foundPreAggregation.preAggregation.partitionGranularity &&
71
+ !!foundPreAggregation.references.timeDimensions?.length;
72
72
  }
73
73
  addPartitionRangeTo(foundPreAggregation, dimension, range, boundaryDateRange) {
74
- return Object.assign({}, foundPreAggregation, {
75
- preAggregation: Object.assign({}, foundPreAggregation.preAggregation, {
74
+ return {
75
+ ...foundPreAggregation,
76
+ preAggregation: {
77
+ ...foundPreAggregation.preAggregation,
76
78
  partitionTimeDimensions: [{
77
79
  dimension,
78
80
  dateRange: range,
79
81
  boundaryDateRange
80
82
  }],
81
- })
82
- });
83
+ }
84
+ };
83
85
  }
84
86
  partitionDimension(foundPreAggregation) {
85
87
  const { dimension } = foundPreAggregation.references.timeDimensions[0];
86
88
  const partitionDimension = this.query.newTimeDimension({
87
89
  dimension,
88
90
  granularity: this.castGranularity(foundPreAggregation.preAggregation.partitionGranularity),
89
- dateRange: this.query.timeDimensions[0] && this.query.timeDimensions[0].dateRange,
90
- boundaryDateRange: this.query.timeDimensions[0] && this.query.timeDimensions[0].boundaryDateRange
91
+ dateRange: this.query.timeDimensions[0]?.dateRange,
92
+ boundaryDateRange: this.query.timeDimensions[0]?.boundaryDateRange
91
93
  });
92
94
  return { dimension, partitionDimension };
93
95
  }
@@ -96,7 +98,7 @@ class PreAggregations {
96
98
  const descriptions = query !== this.query ? query.preAggregations.preAggregationsDescription() : [];
97
99
  return descriptions.concat(this.preAggregationDescriptionFor(cube, foundPreAggregation));
98
100
  }
99
- get hasCumulativeMeasures() {
101
+ hasCumulativeMeasures() {
100
102
  if (!this.hasCumulativeMeasuresValue) {
101
103
  this.hasCumulativeMeasuresValue = PreAggregations.hasCumulativeMeasures(this.query);
102
104
  }
@@ -128,10 +130,10 @@ class PreAggregations {
128
130
  const tableName = this.preAggregationTableName(cube, preAggregationName, preAggregation);
129
131
  const invalidateKeyQueries = this.query.preAggregationInvalidateKeyQueries(cube, preAggregation, preAggregationName);
130
132
  const queryForSqlEvaluation = this.query.preAggregationQueryForSqlEvaluation(cube, preAggregation);
131
- const partitionInvalidateKeyQueries = queryForSqlEvaluation.partitionInvalidateKeyQueries?.(cube, preAggregation);
132
133
  const allBackAliasMembers = this.query.allBackAliasMembers();
133
- const matchedTimeDimension = preAggregation.partitionGranularity && !this.hasCumulativeMeasures &&
134
- this.query.timeDimensions.find(td => {
134
+ let matchedTimeDimension;
135
+ if (preAggregation.partitionGranularity && !this.hasCumulativeMeasures()) {
136
+ matchedTimeDimension = this.query.timeDimensions.find(td => {
135
137
  if (!td.dateRange) {
136
138
  return false;
137
139
  }
@@ -139,7 +141,6 @@ class PreAggregations {
139
141
  foundPreAggregation.references.timeDimensions;
140
142
  const timeDimensionReference = timeDimensionsReference[0];
141
143
  // timeDimensionsReference[*].dimension can contain full join path, so we should trim it
142
- // TODO check full join path match here
143
144
  const timeDimensionReferenceDimension = CubeSymbols_1.CubeSymbols.joinHintFromPath(timeDimensionReference.dimension).path;
144
145
  if (td.dimension === timeDimensionReferenceDimension) {
145
146
  return true;
@@ -147,17 +148,21 @@ class PreAggregations {
147
148
  // Handling for views
148
149
  return td.dimension === allBackAliasMembers[timeDimensionReferenceDimension];
149
150
  });
150
- const filters = preAggregation.partitionGranularity && this.query.filters.filter(td => {
151
- // TODO support all date operators
152
- if (td.isDateOperator() && td.camelizeOperator === 'inDateRange') {
153
- if (td.dimension === foundPreAggregation.references.timeDimensions[0].dimension) {
154
- return true;
151
+ }
152
+ let filters;
153
+ if (preAggregation.partitionGranularity) {
154
+ filters = this.query.filters?.filter((td) => {
155
+ // TODO support all date operators
156
+ if (td.isDateOperator() && 'camelizeOperator' in td && td.camelizeOperator === 'inDateRange') {
157
+ if (td.dimension === foundPreAggregation.references.timeDimensions[0].dimension) {
158
+ return true;
159
+ }
160
+ // Handling for views
161
+ return td.dimension === allBackAliasMembers[foundPreAggregation.references.timeDimensions[0].dimension];
155
162
  }
156
- // Handling for views
157
- return td.dimension === allBackAliasMembers[foundPreAggregation.references.timeDimensions[0].dimension];
158
- }
159
- return false;
160
- });
163
+ return false;
164
+ });
165
+ }
161
166
  const uniqueKeyColumnsDefault = () => null;
162
167
  const uniqueKeyColumns = ({
163
168
  rollup: () => queryForSqlEvaluation.preAggregationUniqueKeyColumns(cube, preAggregation),
@@ -166,12 +171,11 @@ class PreAggregations {
166
171
  const aggregationsColumns = this.aggregationsColumns(cube, preAggregation);
167
172
  return {
168
173
  preAggregationId: `${cube}.${preAggregationName}`,
169
- timezone: this.query.options && this.query.options.timezone,
174
+ timezone: this.query.options?.timezone,
170
175
  timestampFormat: queryForSqlEvaluation.timestampFormat(),
171
176
  timestampPrecision: queryForSqlEvaluation.timestampPrecision(),
172
177
  tableName,
173
178
  invalidateKeyQueries,
174
- partitionInvalidateKeyQueries,
175
179
  type: preAggregation.type,
176
180
  external: preAggregation.external,
177
181
  previewSql: queryForSqlEvaluation.preAggregationPreviewSql(tableName),
@@ -182,15 +186,17 @@ class PreAggregations {
182
186
  uniqueKeyColumns,
183
187
  aggregationsColumns,
184
188
  dataSource: queryForSqlEvaluation.dataSource,
185
- // in fact we can reference preAggregation.granularity however accessing timeDimensions is more strict and consistent
189
+ // in fact, we can reference preAggregation.granularity however accessing timeDimensions is more strict and consistent
186
190
  granularity: references.timeDimensions[0]?.granularity,
187
191
  partitionGranularity: preAggregation.partitionGranularity,
188
- updateWindowSeconds: preAggregation.refreshKey && preAggregation.refreshKey.updateWindow &&
192
+ updateWindowSeconds: preAggregation.refreshKey &&
193
+ 'updateWindow' in preAggregation.refreshKey &&
194
+ preAggregation.refreshKey?.updateWindow &&
189
195
  queryForSqlEvaluation.parseSecondDuration(preAggregation.refreshKey.updateWindow),
190
196
  preAggregationStartEndQueries: (preAggregation.partitionGranularity || references.timeDimensions[0]?.granularity) &&
191
197
  this.refreshRangeQuery(cube).preAggregationStartEndQueries(cube, preAggregation),
192
- matchedTimeDimensionDateRange: preAggregation.partitionGranularity && (matchedTimeDimension && matchedTimeDimension.boundaryDateRangeFormatted() ||
193
- filters && filters[0] && filters[0].formattedDateRange() // TODO intersect all date ranges
198
+ matchedTimeDimensionDateRange: preAggregation.partitionGranularity && (matchedTimeDimension?.boundaryDateRangeFormatted() ||
199
+ filters?.[0]?.formattedDateRange() // TODO intersect all date ranges
194
200
  ),
195
201
  indexesSql: Object.keys(preAggregation.indexes || {})
196
202
  .map(index => {
@@ -198,7 +204,7 @@ class PreAggregations {
198
204
  const indexName = this.preAggregationTableName(cube, `${foundPreAggregation.sqlAlias || preAggregationName}_${index}`, preAggregation, true);
199
205
  return {
200
206
  indexName,
201
- sql: queryForSqlEvaluation.indexSql(cube, preAggregation, preAggregation.indexes[index], indexName, tableName)
207
+ sql: queryForSqlEvaluation.indexSql(cube, preAggregation, preAggregation.indexes?.[index], indexName, tableName)
202
208
  };
203
209
  }),
204
210
  createTableIndexes: Object.keys(preAggregation.indexes || {})
@@ -207,8 +213,8 @@ class PreAggregations {
207
213
  const indexName = this.preAggregationTableName(cube, `${foundPreAggregation.sqlAlias || preAggregationName}_${index}`, preAggregation, true);
208
214
  return {
209
215
  indexName,
210
- type: preAggregation.indexes[index].type,
211
- columns: queryForSqlEvaluation.evaluateIndexColumns(cube, preAggregation.indexes[index])
216
+ type: preAggregation.indexes?.[index].type,
217
+ columns: queryForSqlEvaluation.evaluateIndexColumns(cube, preAggregation.indexes?.[index])
212
218
  };
213
219
  }),
214
220
  readOnly: preAggregation.readOnly || queryForSqlEvaluation.preAggregationReadOnly(cube, preAggregation),
@@ -218,7 +224,7 @@ class PreAggregations {
218
224
  lastRollupLambda: preAggregation.lastRollupLambda,
219
225
  };
220
226
  }
221
- preAggregationTableName(cube, preAggregationName, preAggregation, skipSchema) {
227
+ preAggregationTableName(cube, preAggregationName, preAggregation, skipSchema = false) {
222
228
  const name = preAggregation.sqlAlias || preAggregationName;
223
229
  return this.query.preAggregationTableName(cube, name, skipSchema);
224
230
  }
@@ -238,10 +244,10 @@ class PreAggregations {
238
244
  }
239
245
  static transformQueryToCanUseForm(query) {
240
246
  const flattenDimensionMembers = this.flattenDimensionMembers(query);
241
- const sortedDimensions = this.squashDimensions(query, flattenDimensionMembers);
247
+ const sortedDimensions = this.squashDimensions(flattenDimensionMembers);
242
248
  const allBackAliasMembers = query.allBackAliasMembers();
243
- const measures = query.measures.concat(query.measureFilters);
244
- const measurePaths = ramda_1.default.uniq(this.flattenMembers(measures).map(m => m.expressionPath()));
249
+ const measures = [...query.measures, ...query.measureFilters];
250
+ const measurePaths = ramda_1.default.uniq(this.flattenMembers(measures).filter((m) => m instanceof BaseMeasure_1.BaseMeasure).map(m => m.expressionPath()));
245
251
  const collectLeafMeasures = query.collectLeafMeasures.bind(query);
246
252
  const dimensionsList = query.dimensions.map(dim => dim.expressionPath());
247
253
  const segmentsList = query.segments.map(s => s.expressionPath());
@@ -270,7 +276,7 @@ class PreAggregations {
270
276
  sortedUsedCubePrimaryKeys.sort();
271
277
  }
272
278
  const measureToLeafMeasures = {};
273
- const leafMeasurePaths = ramda_1.default.pipe(ramda_1.default.map(m => {
279
+ const leafMeasurePaths = ramda_1.default.pipe(ramda_1.default.map((m) => {
274
280
  const leafMeasures = query.collectFrom([m], collectLeafMeasures, 'collectLeafMeasures');
275
281
  measureToLeafMeasures[m.measure] = leafMeasures.map((measure) => {
276
282
  const baseMeasure = query.newMeasure(measure);
@@ -297,7 +303,7 @@ class PreAggregations {
297
303
  const ownedTimeDimensionsWithRollupGranularity = PreAggregations.sortTimeDimensionsWithRollupGranularity(ownedTimeDimensions);
298
304
  const ownedTimeDimensionsAsIs = PreAggregations.timeDimensionsAsIs(ownedTimeDimensions);
299
305
  const hasNoTimeDimensionsWithoutGranularity = !query.timeDimensions.filter(d => !d.granularity).length;
300
- const allFiltersWithinSelectedDimensions = ramda_1.default.all(d => dimensionsList.indexOf(d) !== -1)(ramda_1.default.flatten(query.filters.map(f => f.getMembers())).map(f => query.cubeEvaluator.pathFromArray(f.path())));
306
+ const allFiltersWithinSelectedDimensions = ramda_1.default.all((d) => dimensionsList.indexOf(d) !== -1)(ramda_1.default.flatten(query.filters.map(f => f.getMembers())).map(f => query.cubeEvaluator.pathFromArray(f.path())));
301
307
  const isAdditive = ramda_1.default.all(m => m.isAdditive(), query.measures);
302
308
  const hasMultiStage = ramda_1.default.any(m => m.isMultiStage(), query.measures);
303
309
  const leafMeasures = leafMeasurePaths.map(path => query.newMeasure(path));
@@ -339,23 +345,16 @@ class PreAggregations {
339
345
  hasMultiStage
340
346
  };
341
347
  }
342
- /**
343
- *
344
- * @param query
345
- * @param members
346
- * @param {Map<string, Array<string>>} cubeToJoinPrefix
347
- * @returns {Array<string>}
348
- */
349
348
  static ownedMembers(query, members) {
350
349
  return ramda_1.default.pipe(ramda_1.default.uniq, ramda_1.default.sortBy(ramda_1.default.identity))(query
351
350
  .collectFrom(members, query.collectMemberNamesFor.bind(query), 'collectMemberNamesFor')
352
351
  .filter(d => query.cubeEvaluator.byPathAnyType(d).ownedByCube));
353
352
  }
354
353
  static sortTimeDimensionsWithRollupGranularity(timeDimensions) {
355
- return timeDimensions && ramda_1.default.sortBy(ramda_1.default.prop(0), timeDimensions.map(d => [d.expressionPath(), d.rollupGranularity()])) || [];
354
+ return timeDimensions && ramda_1.default.sortBy(([exprPath]) => exprPath, timeDimensions.map(d => [d.expressionPath(), d.rollupGranularity()])) || [];
356
355
  }
357
356
  static timeDimensionsAsIs(timeDimensions) {
358
- return timeDimensions && ramda_1.default.sortBy(ramda_1.default.prop(0), timeDimensions.map(d => [d.expressionPath(), d.resolvedGranularity()])) || [];
357
+ return timeDimensions && ramda_1.default.sortBy(([exprPath]) => exprPath, timeDimensions.map(d => [d.expressionPath(), d.resolvedGranularity()])) || [];
359
358
  }
360
359
  static collectFilterDimensionsWithSingleValueEqual(filters, map) {
361
360
  // eslint-disable-next-line no-restricted-syntax
@@ -374,6 +373,7 @@ class PreAggregations {
374
373
  }
375
374
  return map;
376
375
  }
376
+ // FIXME: It seems to be not used at all
377
377
  static transformedQueryToReferences(query) {
378
378
  return {
379
379
  measures: query.measures,
@@ -381,25 +381,18 @@ class PreAggregations {
381
381
  timeDimensions: query.sortedTimeDimensions.map(([dimension, granularity]) => ({ dimension, granularity }))
382
382
  };
383
383
  }
384
- canUsePreAggregationFn(query, refs) {
384
+ canUsePreAggregationFn(query, refs = null) {
385
385
  return PreAggregations.canUsePreAggregationForTransformedQueryFn(PreAggregations.transformQueryToCanUseForm(query), refs);
386
386
  }
387
387
  /**
388
388
  * Returns function to determine whether pre-aggregation can be used or not
389
389
  * for specified query, or its value for `refs` if specified.
390
- * @param {Object} transformedQuery transformed query
391
- * @param {PreAggregationReferences?} refs pre-aggs reference
392
- * @returns {function(preagg: Object): boolean}
393
390
  */
394
- static canUsePreAggregationForTransformedQueryFn(transformedQuery, refs) {
391
+ static canUsePreAggregationForTransformedQueryFn(transformedQuery, refs = null) {
395
392
  // TODO this needs to check not only members list, but their join paths as well:
396
393
  // query can have same members as pre-agg, but different calculated join path
397
- // `refs` will come from preagg references, and would contain full join paths
394
+ // `refs` will come from pre-agg references, and would contain full join paths
398
395
  // TODO remove this in favor of matching with join path
399
- /**
400
- * @param {PreAggregationReferences} references
401
- * @returns {PreAggregationReferences}
402
- */
403
396
  function trimmedReferences(references) {
404
397
  const timeDimensionsTrimmed = references
405
398
  .timeDimensions
@@ -413,27 +406,25 @@ class PreAggregations {
413
406
  const dimensionsTrimmed = references
414
407
  .dimensions
415
408
  .map(d => CubeSymbols_1.CubeSymbols.joinHintFromPath(d).path);
409
+ const multipliedMeasuresTrimmed = references
410
+ .multipliedMeasures?.map(m => CubeSymbols_1.CubeSymbols.joinHintFromPath(m).path) || [];
416
411
  return {
417
412
  ...references,
418
413
  dimensions: dimensionsTrimmed,
419
414
  measures: measuresTrimmed,
420
415
  timeDimensions: timeDimensionsTrimmed,
416
+ multipliedMeasures: multipliedMeasuresTrimmed,
421
417
  };
422
418
  }
423
419
  /**
424
420
  * Returns an array of 2-elements arrays with the dimension and granularity
425
421
  * sorted by the concatenated dimension + granularity key.
426
- * @param {Array<{dimension: string, granularity: string}>} timeDimensions
427
- * @returns {Array<Array<string>>}
428
422
  */
429
423
  const sortTimeDimensions = (timeDimensions) => (timeDimensions &&
430
424
  ramda_1.default.sortBy(d => d.join('.'), timeDimensions.map(d => [
431
425
  d.dimension,
432
426
  d.granularity || 'day', // TODO granularity shouldn't be null?
433
427
  ])) || []);
434
- /**
435
- * @type {Set<string>}
436
- */
437
428
  const filterDimensionsSingleValueEqual = transformedQuery.filterDimensionsSingleValueEqual && (transformedQuery.filterDimensionsSingleValueEqual instanceof Set
438
429
  ? transformedQuery.filterDimensionsSingleValueEqual
439
430
  : new Set(Object.keys(transformedQuery.filterDimensionsSingleValueEqual || {})));
@@ -442,8 +433,6 @@ class PreAggregations {
442
433
  transformedQuery.allBackAliasMembers[r] || r));
443
434
  /**
444
435
  * Determine whether pre-aggregation can be used or not.
445
- * @param {PreAggregationReferences} references
446
- * @returns {boolean}
447
436
  */
448
437
  const canUsePreAggregationNotAdditive = (references) => {
449
438
  // TODO remove this in favor of matching with join path
@@ -499,12 +488,6 @@ class PreAggregations {
499
488
  return expandGranularity(dimension, resolvedGranularity)
500
489
  .map((newGranularity) => [dimension, newGranularity]);
501
490
  };
502
- /**
503
- * Determine whether pre-aggregation can be used or not.
504
- * TODO: revisit cumulative leaf measure matches.
505
- * @param {PreAggregationReferences} references
506
- * @returns {boolean}
507
- */
508
491
  const canUsePreAggregationLeafMeasureAdditive = (references) => {
509
492
  /**
510
493
  * Array of 2-element arrays with dimension and granularity.
@@ -518,12 +501,22 @@ class PreAggregations {
518
501
  : transformedQuery.ownedTimeDimensionsWithRollupGranularity.map(expandTimeDimension);
519
502
  // TODO remove this in favor of matching with join path
520
503
  const referencesTrimmed = trimmedReferences(references);
504
+ // Even if there are no multiplied measures in the query (because no multiplier dimensions are requested)
505
+ // but the same measures are multiplied in the pre-aggregation, we can't use pre-aggregation
506
+ // for such queries.
507
+ if (referencesTrimmed.multipliedMeasures) {
508
+ const backAliasMultipliedMeasures = backAlias(referencesTrimmed.multipliedMeasures);
509
+ if (transformedQuery.leafMeasures.some(m => referencesTrimmed.multipliedMeasures?.includes(m)) ||
510
+ transformedQuery.measures.some(m => backAliasMultipliedMeasures.includes(m))) {
511
+ return false;
512
+ }
513
+ }
521
514
  const dimensionsMatch = (dimensions, doBackAlias) => ramda_1.default.all(d => (doBackAlias ?
522
515
  backAlias(referencesTrimmed.dimensions) :
523
516
  (referencesTrimmed.dimensions)).indexOf(d) !== -1, dimensions);
524
- const timeDimensionsMatch = (timeDimensionsList, doBackAlias) => ramda_1.default.allPass(timeDimensionsList.map(tds => ramda_1.default.anyPass(tds.map(td => {
517
+ const timeDimensionsMatch = (timeDimensionsList, doBackAlias) => ramda_1.default.allPass(timeDimensionsList.map(tds => ramda_1.default.anyPass(tds.map((td) => {
525
518
  if (td[1] === '*') {
526
- return ramda_1.default.any(tdtc => tdtc[0] === td[0]); // need to match the dimension at least
519
+ return ramda_1.default.any((tdtc) => tdtc[0] === td[0]); // need to match the dimension at least
527
520
  }
528
521
  else {
529
522
  return ramda_1.default.contains(td);
@@ -532,44 +525,47 @@ class PreAggregations {
532
525
  backAlias(sortTimeDimensions(referencesTrimmed.timeDimensions)) :
533
526
  (sortTimeDimensions(referencesTrimmed.timeDimensions)));
534
527
  if (transformedQuery.ungrouped) {
535
- const allReferenceCubes = ramda_1.default.pipe(ramda_1.default.map(m => (m.dimension || m).split('.')[0]), ramda_1.default.uniq, ramda_1.default.sortBy(ramda_1.default.identity))(referencesTrimmed.measures.concat(referencesTrimmed.dimensions).concat(referencesTrimmed.timeDimensions));
528
+ const allReferenceCubes = ramda_1.default.pipe(ramda_1.default.map((name) => name?.split('.')[0]), ramda_1.default.uniq, ramda_1.default.sortBy(ramda_1.default.identity))([
529
+ ...referencesTrimmed.measures,
530
+ ...referencesTrimmed.dimensions,
531
+ ...referencesTrimmed.timeDimensions.map(td => td.dimension),
532
+ ]);
536
533
  if (!ramda_1.default.equals(transformedQuery.sortedAllCubeNames, allReferenceCubes) ||
537
534
  !(dimensionsMatch(transformedQuery.sortedUsedCubePrimaryKeys, true) || dimensionsMatch(transformedQuery.sortedUsedCubePrimaryKeys, false))) {
538
535
  return false;
539
536
  }
540
537
  }
541
538
  const backAliasMeasures = backAlias(referencesTrimmed.measures);
542
- return ((windowGranularityMatches(references)) && (ramda_1.default.all(m => referencesTrimmed.measures.indexOf(m) !== -1, transformedQuery.leafMeasures) || ramda_1.default.all(m => backAliasMeasures.indexOf(m) !== -1, transformedQuery.measures)) && (dimensionsMatch(transformedQuery.sortedDimensions, true) && timeDimensionsMatch(queryTimeDimensionsList, true) ||
539
+ return ((windowGranularityMatches(references)) && (ramda_1.default.all((m) => referencesTrimmed.measures.indexOf(m) !== -1, transformedQuery.leafMeasures) || ramda_1.default.all(m => backAliasMeasures.indexOf(m) !== -1, transformedQuery.measures)) && (dimensionsMatch(transformedQuery.sortedDimensions, true) && timeDimensionsMatch(queryTimeDimensionsList, true) ||
543
540
  dimensionsMatch(transformedQuery.ownedDimensions, false) && timeDimensionsMatch(ownedQueryTimeDimensionsList, false)));
544
541
  };
545
- /**
546
- * Determine whether pre-aggregation can be used or not.
547
- * @returns {boolean}
548
- */
549
- const canUseFn = (transformedQuery.leafMeasureAdditive && !transformedQuery.hasMultipliedMeasures && !transformedQuery.hasMultiStage || transformedQuery.ungrouped) ? (r) => canUsePreAggregationLeafMeasureAdditive(r) ||
550
- canUsePreAggregationNotAdditive(r)
542
+ const canUseFn = (transformedQuery.leafMeasureAdditive && !transformedQuery.hasMultipliedMeasures && !transformedQuery.hasMultiStage || transformedQuery.ungrouped) ? ((r) => canUsePreAggregationLeafMeasureAdditive(r) ||
543
+ canUsePreAggregationNotAdditive(r))
551
544
  : canUsePreAggregationNotAdditive;
552
545
  if (refs) {
546
+ // @ts-ignore TS think it is boolean here
553
547
  return canUseFn(refs);
554
548
  }
555
549
  else {
556
550
  return canUseFn;
557
551
  }
558
552
  }
559
- static squashDimensions(query, flattenDimensionMembers) {
560
- return ramda_1.default.pipe(ramda_1.default.uniq, ramda_1.default.sortBy(ramda_1.default.identity))(flattenDimensionMembers.map(d => d.expressionPath()));
553
+ static squashDimensions(flattenDimensionMembers) {
554
+ return ramda_1.default.pipe(ramda_1.default.uniq, ramda_1.default.sortBy(ramda_1.default.identity))(flattenDimensionMembers
555
+ .filter((member) => typeof member.expressionPath === 'function')
556
+ .map(d => d.expressionPath()));
561
557
  }
562
558
  static flattenMembers(members) {
563
559
  return ramda_1.default.flatten(members.map(m => m.getMembers()));
564
560
  }
565
561
  static flattenDimensionMembers(query) {
566
- return this.flattenMembers(query.dimensions
567
- .concat(query.filters)
568
- .concat(query.segments));
562
+ return this.flattenMembers([
563
+ ...query.dimensions,
564
+ ...query.filters,
565
+ ...query.segments,
566
+ ]);
569
567
  }
570
- // eslint-disable-next-line no-unused-vars
571
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
572
- getCubeLattice(cube, preAggregationName, preAggregation) {
568
+ getCubeLattice(_cube, _preAggregationName, _preAggregation) {
573
569
  throw new UserError_1.UserError('Auto rollups supported only in Enterprise version');
574
570
  }
575
571
  /**
@@ -577,22 +573,32 @@ class PreAggregations {
577
573
  * from the list of potentially applicable pre-aggs). The order of the
578
574
  * potentially applicable pre-aggs is the same as the order in which these
579
575
  * pre-aggs appear in the schema file.
580
- * @returns {Object}
581
576
  */
582
577
  findPreAggregationForQuery() {
583
578
  if (!this.preAggregationForQuery) {
584
- this.preAggregationForQuery =
585
- this
586
- .rollupMatchResults()
587
- // Refresh worker can access specific pre-aggregations even in case those hidden by others
588
- .find(p => p.canUsePreAggregation && (!this.query.options.preAggregationId || p.preAggregationId === this.query.options.preAggregationId));
579
+ if (this.query.useNativeSqlPlanner && this.query.canUseNativeSqlPlannerPreAggregation) {
580
+ this.preAggregationForQuery = this.query.findPreAggregationForQueryRust();
581
+ }
582
+ else {
583
+ this.preAggregationForQuery =
584
+ this
585
+ .rollupMatchResults()
586
+ // Refresh worker can access specific pre-aggregations even in case those hidden by others
587
+ .find(p => p.canUsePreAggregation && (!this.query.options.preAggregationId || p.preAggregationId === this.query.options.preAggregationId));
588
+ }
589
589
  }
590
590
  return this.preAggregationForQuery;
591
591
  }
592
592
  findAutoRollupPreAggregationsForCube(cube, preAggregations) {
593
- if (ramda_1.default.any(m => m.path() && m.path()[0] === cube, this.query.measures) ||
593
+ if (this.query.measures.some((m) => {
594
+ const path = m.path();
595
+ return path !== null && path[0] === cube;
596
+ }) ||
594
597
  !this.query.measures.length && !this.query.timeDimensions.length &&
595
- ramda_1.default.all(d => d.path() && d.path()[0] === cube, this.query.dimensions)) {
598
+ this.query.dimensions.every((d) => {
599
+ const path = d.path();
600
+ return path !== null && path[0] === cube;
601
+ })) {
596
602
  return ramda_1.default.pipe(ramda_1.default.toPairs,
597
603
  // eslint-disable-next-line no-unused-vars
598
604
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -600,7 +606,7 @@ class PreAggregations {
600
606
  const cubeLattice = this.getCubeLattice(cube, preAggregationName, preAggregation);
601
607
  const optimalPreAggregation = cubeLattice.findOptimalPreAggregationFromLattice(this.query);
602
608
  return optimalPreAggregation && {
603
- preAggregationName: preAggregationName + this.autoRollupNameSuffix(cube, optimalPreAggregation),
609
+ preAggregationName: preAggregationName + this.autoRollupNameSuffix(optimalPreAggregation),
604
610
  preAggregation: Object.assign(optimalPreAggregation, preAggregation),
605
611
  cube,
606
612
  canUsePreAggregation: true,
@@ -611,14 +617,13 @@ class PreAggregations {
611
617
  return [];
612
618
  }
613
619
  /**
614
- * Returns an array of potentially applicable for the query preaggs in the
620
+ * Returns an array of potentially applicable for the query pre-aggs in the
615
621
  * same order they appear in the schema file.
616
- * @returns {Array<Object>}
617
622
  */
618
623
  rollupMatchResults() {
619
624
  const { query } = this;
620
625
  const canUsePreAggregation = this.canUsePreAggregationFn(query);
621
- return ramda_1.default.pipe(ramda_1.default.map(cube => {
626
+ return ramda_1.default.pipe(ramda_1.default.map((cube) => {
622
627
  const preAggregations = this.query.cubeEvaluator.preAggregationsForCube(cube);
623
628
  let rollupPreAggregations = this.findRollupPreAggregationsForCube(cube, canUsePreAggregation, preAggregations);
624
629
  rollupPreAggregations = rollupPreAggregations.concat(this.findAutoRollupPreAggregationsForCube(cube, preAggregations));
@@ -631,6 +636,21 @@ class PreAggregations {
631
636
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
632
637
  ramda_1.default.filter(([k, a]) => a.type === 'rollup' || a.type === 'rollupJoin' || a.type === 'rollupLambda'), ramda_1.default.map(([preAggregationName, preAggregation]) => this.evaluatedPreAggregationObj(cube, preAggregationName, preAggregation, canUsePreAggregation)))(preAggregations);
633
638
  }
639
+ getRollupPreAggregationByName(cube, preAggregationName) {
640
+ const canUsePreAggregation = () => true;
641
+ const preAggregation = ramda_1.default.pipe(ramda_1.default.toPairs, ramda_1.default.filter(([_, a]) => a.type === 'rollup' || a.type === 'rollupJoin' || a.type === 'rollupLambda'), ramda_1.default.find(([k, _]) => k === preAggregationName))(this.query.cubeEvaluator.preAggregationsForCube(cube));
642
+ if (preAggregation) {
643
+ const tableName = this.preAggregationTableName(cube, preAggregation[0], preAggregation[1]);
644
+ const preAggObj = preAggregation ? this.evaluatedPreAggregationObj(cube, preAggregation[0], preAggregation[1], canUsePreAggregation) : {};
645
+ return {
646
+ tableName,
647
+ ...preAggObj
648
+ };
649
+ }
650
+ else {
651
+ return {};
652
+ }
653
+ }
634
654
  // TODO check multiplication factor didn't change
635
655
  buildRollupJoin(preAggObj, preAggObjsToJoin) {
636
656
  return this.query.cacheValue(['buildRollupJoin', JSON.stringify(preAggObj), JSON.stringify(preAggObjsToJoin)], () => {
@@ -768,14 +788,21 @@ class PreAggregations {
768
788
  return preAggregation.preAggregation.partitionGranularity;
769
789
  }
770
790
  static memberNameMismatchValidation(preAggA, preAggB, memberType) {
771
- const preAggAMemberNames = PreAggregations.memberShortNames(preAggA.references[memberType], memberType === 'timeDimensions');
772
- const preAggBMemberNames = PreAggregations.memberShortNames(preAggB.references[memberType], memberType === 'timeDimensions');
791
+ const preAggAMemberNames = PreAggregations.memberShortNames(preAggA.references[memberType]);
792
+ const preAggBMemberNames = PreAggregations.memberShortNames(preAggB.references[memberType]);
773
793
  if (!ramda_1.default.equals(preAggAMemberNames, preAggBMemberNames)) {
774
794
  throw new UserError_1.UserError(`Names for ${memberType} doesn't match between '${preAggA.cube}.${preAggA.preAggregationName}' and '${preAggB.cube}.${preAggB.preAggregationName}': ${JSON.stringify(preAggAMemberNames)} does not equal to ${JSON.stringify(preAggBMemberNames)}`);
775
795
  }
776
796
  }
777
- static memberShortNames(memberArray, isTimeDimension) {
778
- return memberArray.map(member => (isTimeDimension ? `${member.dimension.split('.')[1]}.${member.granularity}` : member.split('.')[1]));
797
+ static memberShortNames(memberArray) {
798
+ return memberArray.map(member => {
799
+ if (typeof member !== 'string') {
800
+ return `${member.dimension.split('.')[1]}.${member.granularity}`;
801
+ }
802
+ else {
803
+ return member.split('.')[1];
804
+ }
805
+ });
779
806
  }
780
807
  rollupMatchResultDescriptions() {
781
808
  return this.rollupMatchResults().map(p => ({
@@ -789,7 +816,7 @@ class PreAggregations {
789
816
  return PreAggregations.transformQueryToCanUseForm(this.query);
790
817
  }
791
818
  static hasCumulativeMeasures(query) {
792
- const measures = (query.measures.concat(query.measureFilters));
819
+ const measures = [...query.measures, ...query.measureFilters];
793
820
  const collectLeafMeasures = query.collectLeafMeasures.bind(query);
794
821
  return ramda_1.default.pipe(ramda_1.default.map(m => query.collectFrom([m], collectLeafMeasures, 'collectLeafMeasures')), ramda_1.default.unnest, ramda_1.default.uniq, ramda_1.default.map(p => query.newMeasure(p)), ramda_1.default.any(m => m.isCumulative()))(measures);
795
822
  }
@@ -816,11 +843,11 @@ class PreAggregations {
816
843
  preAggregationQuery: true,
817
844
  });
818
845
  }
819
- rollupPreAggregationQuery(cube, aggregation) {
846
+ rollupPreAggregationQuery(cube, aggregation, context = {}) {
820
847
  // `this.evaluateAllReferences` will retain not only members, but their join path as well, and pass join hints
821
848
  // to subquery. Otherwise, members in subquery would regenerate new join tree from clean state,
822
849
  // and it can be different from expected by join path in pre-aggregation declaration
823
- const references = this.evaluateAllReferences(cube, aggregation);
850
+ const references = this.evaluateAllReferences(cube, aggregation, null, context);
824
851
  const cubeQuery = this.query.newSubQueryForCube(cube, {});
825
852
  return this.query.newSubQueryForCube(cube, {
826
853
  rowLimit: null,
@@ -861,7 +888,7 @@ class PreAggregations {
861
888
  return toMerge ? { ...d, dateRange: toMerge.dateRange, boundaryDateRange: toMerge.boundaryDateRange } : d;
862
889
  });
863
890
  }
864
- autoRollupNameSuffix(cube, aggregation) {
891
+ autoRollupNameSuffix(aggregation) {
865
892
  // eslint-disable-next-line prefer-template
866
893
  return '_' + aggregation.dimensions.concat(aggregation.timeDimensions.map(d => `${d.dimension}${d.granularity.substring(0, 1)}`)).map(s => {
867
894
  const path = s.split('.');
@@ -870,19 +897,17 @@ class PreAggregations {
870
897
  .replace(/[.]/g, '')
871
898
  .toLowerCase();
872
899
  }
873
- /**
874
- *
875
- * @param {string} cube
876
- * @param aggregation
877
- * @param {string} [preAggregationName]
878
- * @returns {PreAggregationReferences}
879
- */
880
- evaluateAllReferences(cube, aggregation, preAggregationName) {
900
+ evaluateAllReferences(cube, aggregation, preAggregationName = null, context = {}) {
881
901
  // TODO build a join tree for all references, so they would always include full join path
882
902
  // Even for preaggregation references without join path
883
903
  // It is necessary to be able to match query and preaggregation based on full join tree
884
904
  const evaluateReferences = () => {
885
905
  const references = this.query.cubeEvaluator.evaluatePreAggregationReferences(cube, aggregation);
906
+ if (!context.inPreAggEvaluation) {
907
+ const preAggQuery = this.query.preAggregationQueryForSqlEvaluation(cube, aggregation, { inPreAggEvaluation: true });
908
+ const aggregateMeasures = preAggQuery?.fullKeyQueryAggregateMeasures({ hasMultipliedForPreAggregation: true });
909
+ references.multipliedMeasures = aggregateMeasures?.multipliedMeasures?.map(m => m.measure);
910
+ }
886
911
  if (aggregation.type === 'rollupLambda') {
887
912
  if (references.rollups.length > 0) {
888
913
  const [firstLambdaCube] = this.query.cubeEvaluator.parsePath('preAggregations', references.rollups[0]);
@@ -909,7 +934,7 @@ class PreAggregations {
909
934
  // eslint-disable-next-line prefer-const
910
935
  let { preAggregationName, preAggregation } = preAggregationDescription;
911
936
  // @todo Dont use sqlAlias directly, we needed to move it in preAggregationTableName
912
- if (preAggregation && preAggregation.sqlAlias) {
937
+ if (preAggregation?.sqlAlias) {
913
938
  preAggregationName = preAggregation.sqlAlias;
914
939
  }
915
940
  return this.query.preAggregationTableName(preAggregationDescription.cube, preAggregationName);
@@ -984,10 +1009,9 @@ class PreAggregations {
984
1009
  toJoin = [sqlAndAlias(preAggregationForQuery)];
985
1010
  }
986
1011
  const from = this.query.joinSql(toJoin);
987
- const replacedFilters = filters || this.query.segments
988
- .concat(this.query.filters).concat(this.query.timeDimensions.map(dimension => dimension.dateRange && ({
989
- filterToWhere: () => this.query.timeRangeFilter(this.query.dimensionSql(dimension), dimension.localDateTimeFromParam(), dimension.localDateTimeToParam()),
990
- }))).filter(f => !!f);
1012
+ const replacedFilters = filters || [...this.query.segments, ...this.query.filters, ...(this.query.timeDimensions.map(dimension => dimension.dateRange && ({
1013
+ filterToWhere: () => this.query.timeRangeFilter(this.query.dimensionSql(dimension), dimension.localDateTimeFromParam(), dimension.localDateTimeToParam()),
1014
+ })))].filter(f => !!f);
991
1015
  const renderedReference = {
992
1016
  ...(this.measuresRenderedReference(preAggregationForQuery)),
993
1017
  ...(this.dimensionsRenderedReference(preAggregationForQuery)),
@@ -1007,43 +1031,76 @@ class PreAggregations {
1007
1031
  });
1008
1032
  }
1009
1033
  measuresRenderedReference(preAggregationForQuery) {
1010
- return ramda_1.default.pipe(ramda_1.default.map(path => {
1034
+ const measures = this.rollupMeasures(preAggregationForQuery);
1035
+ return Object.fromEntries(measures
1036
+ .flatMap(path => {
1011
1037
  const measure = this.query.newMeasure(path);
1038
+ const measurePath = measure.path();
1039
+ const column = this.query.ungrouped ? measure.aliasName() : (this.query.aggregateOnGroupedColumn(measure.measureDefinition(), measure.aliasName(), !this.query.safeEvaluateSymbolContext().overTimeSeriesAggregate, path) || `sum(${measure.aliasName()})`);
1040
+ if (measurePath === null) {
1041
+ return [[path, column]];
1042
+ }
1043
+ const memberPath = this.query.cubeEvaluator.pathFromArray(measurePath);
1044
+ // Return both full join path and measure path
1012
1045
  return [
1013
- path,
1014
- this.query.ungrouped ? measure.aliasName() : (this.query.aggregateOnGroupedColumn(measure.measureDefinition(), measure.aliasName(), !this.query.safeEvaluateSymbolContext().overTimeSeriesAggregate, path) || `sum(${measure.aliasName()})`),
1046
+ [path, column],
1047
+ [memberPath, column],
1015
1048
  ];
1016
- }), ramda_1.default.fromPairs)(this.rollupMeasures(preAggregationForQuery));
1049
+ }));
1017
1050
  }
1018
1051
  measureAliasesRenderedReference(preAggregationForQuery) {
1019
- return ramda_1.default.pipe(ramda_1.default.map(path => {
1052
+ const measures = this.rollupMeasures(preAggregationForQuery);
1053
+ return Object.fromEntries(measures
1054
+ .flatMap(path => {
1020
1055
  const measure = this.query.newMeasure(path);
1056
+ const measurePath = measure.path();
1057
+ const alias = measure.aliasName();
1058
+ if (measurePath === null) {
1059
+ return [[path, alias]];
1060
+ }
1061
+ const memberPath = this.query.cubeEvaluator.pathFromArray(measurePath);
1062
+ // Return both full join path and measure path
1021
1063
  return [
1022
- path,
1023
- measure.aliasName(),
1064
+ [path, alias],
1065
+ [memberPath, alias],
1024
1066
  ];
1025
- }), ramda_1.default.fromPairs)(this.rollupMeasures(preAggregationForQuery));
1067
+ }));
1026
1068
  }
1027
1069
  dimensionsRenderedReference(preAggregationForQuery) {
1028
- return ramda_1.default.pipe(ramda_1.default.map(path => {
1070
+ const dimensions = this.rollupDimensions(preAggregationForQuery);
1071
+ return Object.fromEntries(dimensions
1072
+ .flatMap(path => {
1029
1073
  const dimension = this.query.newDimension(path);
1074
+ const dimensionPath = dimension.path();
1075
+ const column = this.query.escapeColumnName(dimension.unescapedAliasName());
1076
+ if (dimensionPath === null) {
1077
+ return [[path, column]];
1078
+ }
1079
+ const memberPath = this.query.cubeEvaluator.pathFromArray(dimensionPath);
1080
+ // Return both full join path and dimension path
1030
1081
  return [
1031
- path,
1032
- this.query.escapeColumnName(dimension.unescapedAliasName()),
1082
+ [path, column],
1083
+ [memberPath, column],
1033
1084
  ];
1034
- }), ramda_1.default.fromPairs)(this.rollupDimensions(preAggregationForQuery));
1085
+ }));
1035
1086
  }
1036
1087
  timeDimensionsRenderedReference(rollupGranularity, preAggregationForQuery) {
1037
- return ramda_1.default.pipe(ramda_1.default.map((td) => {
1088
+ const timeDimensions = this.rollupTimeDimensions(preAggregationForQuery);
1089
+ return Object.fromEntries(timeDimensions
1090
+ .flatMap(td => {
1038
1091
  const timeDimension = this.query.newTimeDimension(td);
1092
+ const column = this.query.escapeColumnName(timeDimension.unescapedAliasName(rollupGranularity));
1093
+ const memberPath = this.query.cubeEvaluator.pathFromArray(timeDimension.path());
1094
+ // Return both full join path and dimension path
1039
1095
  return [
1040
- td.dimension,
1041
- this.query.escapeColumnName(timeDimension.unescapedAliasName(rollupGranularity)),
1096
+ [td.dimension, column],
1097
+ [memberPath, column],
1042
1098
  ];
1043
- }), ramda_1.default.fromPairs)(this.rollupTimeDimensions(preAggregationForQuery));
1099
+ }));
1044
1100
  }
1045
1101
  rollupMembers(preAggregationForQuery, type) {
1046
1102
  return preAggregationForQuery.preAggregation.type === 'autoRollup' ?
1103
+ // TODO proper types
1047
1104
  preAggregationForQuery.preAggregation[type] :
1048
1105
  this.evaluateAllReferences(preAggregationForQuery.cube, preAggregationForQuery.preAggregation, preAggregationForQuery.preAggregationName)[type];
1049
1106
  }