Skip to content

Commit 0c563b0

Browse files
committed
refactor findMinGranularityDimension()
1 parent 55da718 commit 0c563b0

File tree

3 files changed

+69
-70
lines changed

3 files changed

+69
-70
lines changed

packages/cubejs-backend-shared/src/time.ts

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export type TimeSeriesOptions = {
1212
};
1313
type ParsedInterval = Partial<Record<unitOfTime.DurationConstructor, number>>;
1414

15-
export const GRANULARITY_LEVELS: Record<string, number> = {
15+
const GRANULARITY_LEVELS: Record<string, number> = {
1616
second: 1,
1717
minute: 2,
1818
hour: 3,
@@ -24,6 +24,55 @@ export const GRANULARITY_LEVELS: Record<string, number> = {
2424
MAX: 1000,
2525
};
2626

27+
export type DimensionToCompareGranularity = {
28+
dimension: string;
29+
expressionName?: string;
30+
granularityObj?: {
31+
minGranularity(): string;
32+
}
33+
};
34+
35+
/**
36+
* Actually dimensions type is (BaseDimension|BaseTimeDimension)[], but can not ref due to cyclic dependencies refs.
37+
*/
38+
export function findMinGranularityDimension(id: string, dimensions: DimensionToCompareGranularity[]): { index: number, dimension: DimensionToCompareGranularity | undefined } | null {
39+
const equalIgnoreCase = (a: any, b: any): boolean => (
40+
typeof a === 'string' && typeof b === 'string' && a.toUpperCase() === b.toUpperCase()
41+
);
42+
43+
let minGranularity = GRANULARITY_LEVELS.MAX;
44+
let index = -1;
45+
let minGranularityIndex = -1;
46+
let field;
47+
let minGranularityField;
48+
49+
dimensions.forEach((d, i) => {
50+
if (equalIgnoreCase(d.dimension, id) || equalIgnoreCase(d.expressionName, id)) {
51+
field = d;
52+
index = i;
53+
54+
if ('granularityObj' in d && d.granularityObj) {
55+
const gr = GRANULARITY_LEVELS[d.granularityObj?.minGranularity()];
56+
if (gr < minGranularity) {
57+
minGranularityIndex = i;
58+
minGranularityField = d;
59+
minGranularity = gr;
60+
}
61+
}
62+
}
63+
});
64+
65+
if (minGranularityIndex > -1) {
66+
return { index: minGranularityIndex, dimension: minGranularityField };
67+
}
68+
69+
if (index > -1) {
70+
return { index, dimension: field };
71+
}
72+
73+
return null;
74+
}
75+
2776
export const TIME_SERIES: Record<string, (range: DateRange, timestampPrecision: number) => QueryDateRange[]> = {
2877
day: (range: DateRange, digits) => Array.from(range.snapTo('day').by('day'))
2978
.map(d => [d.format(`YYYY-MM-DDT00:00:00.${'0'.repeat(digits)}`), d.format(`YYYY-MM-DDT23:59:59.${'9'.repeat(digits)}`)]),

packages/cubejs-schema-compiler/src/adapter/BaseQuery.js

Lines changed: 12 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ import {
2222
localTimestampToUtc,
2323
timeSeries as timeSeriesBase,
2424
timeSeriesFromCustomInterval,
25-
parseSqlInterval, GRANULARITY_LEVELS
25+
parseSqlInterval,
26+
findMinGranularityDimension
2627
} from '@cubejs-backend/shared';
2728

2829
import { CubeSymbols } from '../compiler/CubeSymbols';
@@ -2606,31 +2607,14 @@ export class BaseQuery {
26062607
return null;
26072608
}
26082609

2609-
let minGranularity = GRANULARITY_LEVELS.MAX;
2610-
let minGranularityIndex = -1;
2611-
2612-
this.dimensionsForSelect()
2610+
const dimensionsForSelect = this.dimensionsForSelect()
26132611
// Not all time dimensions are used in select list, some are just filters,
26142612
// but they exist in this.timeDimensions, so need to filter them out
2615-
.filter(d => d.selectColumns())
2616-
.forEach((d, i) => {
2617-
if (equalIgnoreCase(d.dimension, id) || equalIgnoreCase(d.expressionName, id)) {
2618-
index = i;
2619-
2620-
const gr = GRANULARITY_LEVELS[d.granularityObj?.minGranularity()];
2621-
if (gr < minGranularity) {
2622-
minGranularityIndex = i;
2623-
minGranularity = gr;
2624-
}
2625-
}
2626-
});
2613+
.filter(d => d.selectColumns());
26272614

2628-
if (minGranularityIndex > -1) {
2629-
return minGranularityIndex + 1;
2630-
}
2631-
2632-
if (index > -1) {
2633-
return index + 1;
2615+
const found = findMinGranularityDimension(id, dimensionsForSelect);
2616+
if (found?.index > -1) {
2617+
return found.index + 1;
26342618
}
26352619

26362620
index = this.measures.findIndex(
@@ -2682,31 +2666,15 @@ export class BaseQuery {
26822666
return null;
26832667
}
26842668

2685-
let minGranularity = GRANULARITY_LEVELS.MAX;
2686-
let minGranularityField;
2687-
2688-
this.dimensionsForSelect()
2669+
const dimensionsForSelect = this.dimensionsForSelect()
26892670
// Not all time dimensions are used in select list, some are just filters,
26902671
// but they exist in this.timeDimensions, so need to filter them out
2691-
.filter(d => d.selectColumns())
2692-
.forEach((d) => {
2693-
if (equalIgnoreCase(d.dimension, id) || equalIgnoreCase(d.expressionName, id)) {
2694-
field = d;
2695-
2696-
const gr = GRANULARITY_LEVELS[d.granularityObj?.minGranularity()];
2697-
if (gr < minGranularity) {
2698-
minGranularityField = d;
2699-
minGranularity = gr;
2700-
}
2701-
}
2702-
});
2672+
.filter(d => d.selectColumns());
27032673

2704-
if (minGranularityField) {
2705-
return minGranularityField.aliasName();
2706-
}
2674+
const found = findMinGranularityDimension(id, dimensionsForSelect);
27072675

2708-
if (field) {
2709-
return field.aliasName();
2676+
if (found?.dimension) {
2677+
return found.dimension.aliasName();
27102678
}
27112679

27122680
field = this.measures.find(

packages/cubejs-schema-compiler/src/adapter/ElasticSearchQuery.ts

Lines changed: 7 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* eslint-disable max-classes-per-file */
22
import R from 'ramda';
33

4-
import { GRANULARITY_LEVELS } from '@cubejs-backend/shared';
4+
import { findMinGranularityDimension } from '@cubejs-backend/shared';
55
import { BaseQuery } from './BaseQuery';
66
import { BaseFilter } from './BaseFilter';
77
import { BaseMeasure } from './BaseMeasure';
@@ -129,33 +129,15 @@ export class ElasticSearchQuery extends BaseQuery {
129129
return null;
130130
}
131131

132-
let minGranularity = GRANULARITY_LEVELS.MAX;
133-
let minGranularityField: BaseTimeDimension | BaseDimension | undefined;
134-
135-
this.dimensionsForSelect()
132+
const dimensionsForSelect = this.dimensionsForSelect()
136133
// Not all time dimensions are used in select list, some are just filters,
137134
// but they exist in this.timeDimensions, so need to filter them out
138-
.filter(d => d.selectColumns())
139-
.forEach((d) => {
140-
if (equalIgnoreCase(d.dimension, id) || equalIgnoreCase(d.expressionName, id)) {
141-
field = d;
142-
143-
if ('granularityObj' in d && d.granularityObj) {
144-
const gr = GRANULARITY_LEVELS[d.granularityObj.minGranularity()];
145-
if (gr < minGranularity) {
146-
minGranularityField = d;
147-
minGranularity = gr;
148-
}
149-
}
150-
}
151-
});
152-
153-
if (minGranularityField) {
154-
return minGranularityField.dimensionSql();
155-
}
135+
.filter(d => d.selectColumns());
156136

157-
if (field) {
158-
return (field as BaseDimension).dimensionSql();
137+
const found = findMinGranularityDimension(id, dimensionsForSelect);
138+
139+
if (found?.dimension) {
140+
return (found.dimension as BaseDimension).dimensionSql();
159141
}
160142

161143
field = this.measures.find(

0 commit comments

Comments
 (0)