Skip to content

Commit 12a65ce

Browse files
committed
feat(schema-compiler): Allow passing function that returns an array of time dimensions as pre-aggregation timeDimensions property
1 parent f228325 commit 12a65ce

File tree

4 files changed

+183
-5
lines changed

4 files changed

+183
-5
lines changed

packages/cubejs-schema-compiler/src/compiler/CubeEvaluator.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -696,14 +696,22 @@ export class CubeEvaluator extends CubeSymbols {
696696
dimension: this.evaluateReferences(cube, aggregation.timeDimensionReference),
697697
granularity: aggregation.granularity
698698
});
699-
} else if (aggregation.timeDimensionReferences) {
699+
} else if (Array.isArray(aggregation.timeDimensionReferences)) {
700700
// eslint-disable-next-line guard-for-in
701701
for (const timeDimensionReference of aggregation.timeDimensionReferences) {
702702
timeDimensions.push({
703703
dimension: this.evaluateReferences(cube, timeDimensionReference.dimension),
704704
granularity: timeDimensionReference.granularity
705705
});
706706
}
707+
} else if (aggregation.timeDimensionReferences) {
708+
const evaluatedRefs: any[] = this.evaluateReferences(cube, aggregation.timeDimensionReferences, { returnRaw: true });
709+
for (const timeDimensionReference of evaluatedRefs) {
710+
timeDimensions.push({
711+
dimension: timeDimensionReference.dimension.toString(),
712+
granularity: timeDimensionReference.granularity
713+
});
714+
}
707715
}
708716

709717
return {

packages/cubejs-schema-compiler/src/compiler/CubeSymbols.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,11 @@ export class CubeSymbols {
515515
cubeAliasFn: (cube) => cubeEvaluator.pathFromArray(fullPath(cubeEvaluator.joinHints(), [cube])),
516516
collectJoinHints: options.collectJoinHints,
517517
});
518+
519+
if (options.returnRaw) {
520+
return arrayOrSingle;
521+
}
522+
518523
if (!Array.isArray(arrayOrSingle)) {
519524
return arrayOrSingle.toString();
520525
}

packages/cubejs-schema-compiler/src/compiler/CubeValidator.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -473,10 +473,13 @@ const RollUpSchema = condition(
473473
// Rollup with multiple time dimensions
474474
inherit(BasePreAggregation, {
475475
type: Joi.any().valid('rollup').required(),
476-
timeDimensions: Joi.array().items(Joi.object().keys({
477-
dimension: Joi.func(),
478-
granularity: GranularitySchema,
479-
})),
476+
timeDimensions: Joi.alternatives().try(
477+
Joi.array().items(Joi.object().keys({
478+
dimension: Joi.func(),
479+
granularity: GranularitySchema,
480+
})),
481+
Joi.func(),
482+
),
480483
allowNonStrictDateRangeMatch: Joi.bool(),
481484
measures: Joi.func(),
482485
dimensions: Joi.func(),

packages/cubejs-schema-compiler/test/unit/pre-aggregations.test.ts

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,168 @@ describe('pre-aggregations', () => {
9292
expect(cubeEvaluator.cubeFromPath('Orders').preAggregations.ordersRollupJoin.scheduledRefresh).toEqual(undefined);
9393
});
9494

95+
it('Rollup with pre-agg with hardcoded multiple time dimensions', async () => {
96+
const { compiler, cubeEvaluator, joinGraph } = prepareCompiler(
97+
`
98+
cube(\`Users\`, {
99+
sql: \`SELECT * FROM public.users\`,
100+
101+
preAggregations: {
102+
staticMultiple: {
103+
dimensions: [CUBE.status],
104+
measures: [CUBE.count],
105+
timeDimensions: [
106+
{ dimension: CUBE.createdAt, granularity: \`day\` },
107+
{ dimension: CUBE.modifiedAt, granularity: \`day\` },
108+
]
109+
}
110+
},
111+
112+
measures: {
113+
count: {
114+
type: \`count\`,
115+
},
116+
},
117+
118+
dimensions: {
119+
id: {
120+
sql: \`id\`,
121+
type: \`string\`,
122+
primaryKey: true,
123+
},
124+
125+
name: {
126+
sql: \`name\`,
127+
type: \`string\`,
128+
},
129+
130+
userId: {
131+
sql: \`user_id\`,
132+
type: \`number\`,
133+
},
134+
status: {
135+
sql: \`status\`,
136+
type: \`string\`,
137+
},
138+
139+
createdAt: {
140+
type: \`time\`,
141+
sql: \`created_at\`
142+
},
143+
144+
modifiedAt: {
145+
type: \`time\`,
146+
sql: \`modified_at\`
147+
}
148+
},
149+
});
150+
`
151+
);
152+
153+
await compiler.compile();
154+
155+
const query = new PostgresQuery({ joinGraph, cubeEvaluator, compiler }, {
156+
dimensions: ['Users.status'],
157+
measures: ['Users.count'],
158+
timeDimensions: [{
159+
dimension: 'Users.createdAt',
160+
dateRange: ['2023-01-20', '2024-01-20'],
161+
granularity: 'day'
162+
}]
163+
});
164+
165+
const preAggregationsDescription: any = query.preAggregations?.preAggregationsDescription();
166+
167+
const queryAndParams = query.buildSqlAndParams();
168+
console.log(queryAndParams);
169+
expect(queryAndParams[0].includes('undefined')).toBeFalsy();
170+
expect(queryAndParams[0].includes('pre_aggregations')).toBeTruthy();
171+
172+
expect(preAggregationsDescription.length).toEqual(1);
173+
expect(preAggregationsDescription[0].preAggregationId).toEqual('Users.staticMultiple');
174+
});
175+
176+
it('Rollup with pre-agg with dynamic multiple time dimensions', async () => {
177+
const { compiler, cubeEvaluator, joinGraph } = prepareCompiler(
178+
`
179+
cube(\`Users\`, {
180+
sql: \`SELECT * FROM public.users\`,
181+
182+
preAggregations: {
183+
dynamicMultiple: {
184+
dimensions: [CUBE.status],
185+
measures: [CUBE.count],
186+
timeDimensions: (CUBE) => [
187+
{dimension: CUBE.createdAt, granularity: 'day'},
188+
{dimension: CUBE.modifiedAt, granularity: 'day'},
189+
]
190+
},
191+
},
192+
193+
measures: {
194+
count: {
195+
type: \`count\`,
196+
},
197+
},
198+
199+
dimensions: {
200+
id: {
201+
sql: \`id\`,
202+
type: \`string\`,
203+
primaryKey: true,
204+
},
205+
206+
name: {
207+
sql: \`name\`,
208+
type: \`string\`,
209+
},
210+
211+
userId: {
212+
sql: \`user_id\`,
213+
type: \`number\`,
214+
},
215+
status: {
216+
sql: \`status\`,
217+
type: \`string\`,
218+
},
219+
220+
createdAt: {
221+
type: \`time\`,
222+
sql: \`created_at\`
223+
},
224+
225+
modifiedAt: {
226+
type: \`time\`,
227+
sql: \`modified_at\`
228+
}
229+
},
230+
});
231+
`
232+
);
233+
234+
await compiler.compile();
235+
236+
const query = new PostgresQuery({ joinGraph, cubeEvaluator, compiler }, {
237+
dimensions: ['Users.status'],
238+
measures: ['Users.count'],
239+
timeDimensions: [{
240+
dimension: 'Users.createdAt',
241+
dateRange: ['2023-01-20', '2024-01-20'],
242+
granularity: 'day'
243+
}]
244+
});
245+
246+
const preAggregationsDescription: any = query.preAggregations?.preAggregationsDescription();
247+
248+
const queryAndParams = query.buildSqlAndParams();
249+
console.log(queryAndParams);
250+
expect(queryAndParams[0].includes('undefined')).toBeFalsy();
251+
expect(queryAndParams[0].includes('pre_aggregations')).toBeTruthy();
252+
253+
expect(preAggregationsDescription.length).toEqual(1);
254+
expect(preAggregationsDescription[0].preAggregationId).toEqual('Users.dynamicMultiple');
255+
});
256+
95257
it('query rollupLambda', async () => {
96258
const { compiler, cubeEvaluator, joinGraph } = prepareCompiler(
97259
`

0 commit comments

Comments
 (0)