Skip to content

Commit 41b49f4

Browse files
authored
fix(schema-compiler): Undefined columns for lambda pre-aggregation queries referencing dimensions from joined cubes (#8946)
* fix typo * fix(schema-compiler): fix undefined columns for pre lambda agg queries referencing dims from joined cubes * add tests * change order of the references lookup
1 parent a3ed6ea commit 41b49f4

File tree

2 files changed

+147
-2
lines changed

2 files changed

+147
-2
lines changed

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

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -965,7 +965,7 @@ export class PreAggregations {
965965
}
966966
);
967967
if (referencedPreAggregations.length === 0) {
968-
throw new UserError(`rollupLambda '${cube}.${preAggregationName}' should reference at least on rollup`);
968+
throw new UserError(`rollupLambda '${cube}.${preAggregationName}' should reference at least one rollup`);
969969
}
970970
referencedPreAggregations.forEach((referencedPreAggregation, i) => {
971971
if (i === referencedPreAggregations.length - 1 && preAggObj.preAggregation.unionWithSourceData && preAggObj.cube !== referencedPreAggregations[i].cube) {
@@ -1197,7 +1197,23 @@ export class PreAggregations {
11971197
const targetMeasuresReferences = this.measureAliasesRenderedReference(preAggregationForQuery);
11981198

11991199
const columnsFor = (targetReferences, references, preAggregation) => Object.keys(targetReferences).map(
1200-
member => `${references[this.query.cubeEvaluator.pathFromArray([preAggregation.cube, member.split('.')[1]])]} ${targetReferences[member]}`
1200+
member => {
1201+
const [, memberProp] = member.split('.');
1202+
1203+
let refKey = references[member];
1204+
1205+
if (refKey) {
1206+
return `${refKey} ${targetReferences[member]}`;
1207+
}
1208+
1209+
refKey = references[this.query.cubeEvaluator.pathFromArray([preAggregation.cube, memberProp])];
1210+
1211+
if (refKey) {
1212+
return `${refKey} ${targetReferences[member]}`;
1213+
}
1214+
1215+
throw new Error(`Preaggregation "${preAggregation.preAggregationName}" referenced property "${member}" not found in cube "${preAggregation.cube}"`);
1216+
}
12011217
);
12021218

12031219
const tables = preAggregationForQuery.referencedPreAggregations.map(preAggregation => {

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

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

95+
it('query rollupLambda', async () => {
96+
const { compiler, cubeEvaluator, joinGraph } = prepareCompiler(
97+
`
98+
cube(\`Users\`, {
99+
sql: \`SELECT * FROM public.users\`,
100+
101+
preAggregations: {
102+
usersRollup: {
103+
dimensions: [CUBE.id],
104+
},
105+
},
106+
107+
measures: {
108+
count: {
109+
type: \`count\`,
110+
},
111+
},
112+
113+
dimensions: {
114+
id: {
115+
sql: \`id\`,
116+
type: \`string\`,
117+
primaryKey: true,
118+
},
119+
120+
name: {
121+
sql: \`name\`,
122+
type: \`string\`,
123+
},
124+
},
125+
});
126+
127+
cube('Orders', {
128+
sql: \`SELECT * FROM orders\`,
129+
130+
preAggregations: {
131+
ordersRollupLambda: {
132+
type: \`rollupLambda\`,
133+
rollups: [simple1, simple2],
134+
},
135+
simple1: {
136+
measures: [CUBE.count],
137+
dimensions: [CUBE.status, Users.name],
138+
timeDimension: CUBE.created_at,
139+
granularity: 'day',
140+
partitionGranularity: 'day',
141+
buildRangeStart: {
142+
sql: \`SELECT NOW() - INTERVAL '1000 day'\`,
143+
},
144+
buildRangeEnd: {
145+
sql: \`SELECT NOW()\`
146+
},
147+
},
148+
simple2: {
149+
measures: [CUBE.count],
150+
dimensions: [CUBE.status, Users.name],
151+
timeDimension: CUBE.created_at,
152+
granularity: 'day',
153+
partitionGranularity: 'day',
154+
buildRangeStart: {
155+
sql: \`SELECT NOW() - INTERVAL '1000 day'\`,
156+
},
157+
buildRangeEnd: {
158+
sql: \`SELECT NOW()\`
159+
},
160+
},
161+
},
162+
163+
joins: {
164+
Users: {
165+
relationship: \`belongsTo\`,
166+
sql: \`\${CUBE.userId} = \${Users.id}\`,
167+
},
168+
},
169+
170+
measures: {
171+
count: {
172+
type: \`count\`,
173+
},
174+
},
175+
176+
dimensions: {
177+
id: {
178+
sql: \`id\`,
179+
type: \`number\`,
180+
primaryKey: true,
181+
},
182+
userId: {
183+
sql: \`user_id\`,
184+
type: \`number\`,
185+
},
186+
status: {
187+
sql: \`status\`,
188+
type: \`string\`,
189+
},
190+
created_at: {
191+
sql: \`created_at\`,
192+
type: \`time\`,
193+
},
194+
},
195+
});
196+
`
197+
);
198+
199+
await compiler.compile();
200+
201+
const query = new PostgresQuery({ joinGraph, cubeEvaluator, compiler }, {
202+
measures: [
203+
'Orders.count'
204+
],
205+
});
206+
207+
const queryAndParams = query.buildSqlAndParams();
208+
console.log(queryAndParams);
209+
expect(queryAndParams[0].includes('undefined')).toBeFalsy();
210+
expect(queryAndParams[0].includes('"orders__status" "orders__status"')).toBeTruthy();
211+
expect(queryAndParams[0].includes('"users__name" "users__name"')).toBeTruthy();
212+
expect(queryAndParams[0].includes('"orders__created_at_day" "orders__created_at_day"')).toBeTruthy();
213+
expect(queryAndParams[0].includes('"orders__count" "orders__count"')).toBeTruthy();
214+
expect(queryAndParams[0].includes('UNION ALL')).toBeTruthy();
215+
216+
const preAggregationsDescription: any = query.preAggregations?.preAggregationsDescription();
217+
console.log(JSON.stringify(preAggregationsDescription, null, 2));
218+
219+
expect(preAggregationsDescription.length).toEqual(2);
220+
expect(preAggregationsDescription[0].preAggregationId).toEqual("Orders.simple1");
221+
expect(preAggregationsDescription[1].preAggregationId).toEqual("Orders.simple2");
222+
});
223+
95224
// @link https://github.com/cube-js/cube/issues/6623
96225
it('view and pre-aggregation granularity', async () => {
97226
const { compiler, cubeEvaluator, joinGraph } = prepareYamlCompiler(

0 commit comments

Comments
 (0)