From b480372e6c5b3b81fdbbd19b5a14c54499673736 Mon Sep 17 00:00:00 2001 From: Konstantin Burkalev Date: Tue, 12 Nov 2024 17:17:58 +0200 Subject: [PATCH 1/4] fix typo --- packages/cubejs-schema-compiler/src/adapter/PreAggregations.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cubejs-schema-compiler/src/adapter/PreAggregations.js b/packages/cubejs-schema-compiler/src/adapter/PreAggregations.js index 4495281416a00..634ea4a980641 100644 --- a/packages/cubejs-schema-compiler/src/adapter/PreAggregations.js +++ b/packages/cubejs-schema-compiler/src/adapter/PreAggregations.js @@ -961,7 +961,7 @@ export class PreAggregations { } ); if (referencedPreAggregations.length === 0) { - throw new UserError(`rollupLambda '${cube}.${preAggregationName}' should reference at least on rollup`); + throw new UserError(`rollupLambda '${cube}.${preAggregationName}' should reference at least one rollup`); } referencedPreAggregations.forEach((referencedPreAggregation, i) => { if (i === referencedPreAggregations.length - 1 && preAggObj.preAggregation.unionWithSourceData && preAggObj.cube !== referencedPreAggregations[i].cube) { From f3b26c3982a46df5255e79268125112fb03378b6 Mon Sep 17 00:00:00 2001 From: Konstantin Burkalev Date: Tue, 12 Nov 2024 20:16:52 +0200 Subject: [PATCH 2/4] fix(schema-compiler): fix undefined columns for pre lambda agg queries referencing dims from joined cubes --- .../src/adapter/PreAggregations.js | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/packages/cubejs-schema-compiler/src/adapter/PreAggregations.js b/packages/cubejs-schema-compiler/src/adapter/PreAggregations.js index 634ea4a980641..f37483efcc8e5 100644 --- a/packages/cubejs-schema-compiler/src/adapter/PreAggregations.js +++ b/packages/cubejs-schema-compiler/src/adapter/PreAggregations.js @@ -1192,7 +1192,22 @@ export class PreAggregations { const targetMeasuresReferences = this.measureAliasesRenderedReference(preAggregationForQuery); const columnsFor = (targetReferences, references, preAggregation) => Object.keys(targetReferences).map( - member => `${references[this.query.cubeEvaluator.pathFromArray([preAggregation.cube, member.split('.')[1]])]} ${targetReferences[member]}` + member => { + const [memberCube, memberProp] = member.split('.'); + let refKey = references[this.query.cubeEvaluator.pathFromArray([preAggregation.cube, memberProp])]; + + if (refKey) { + return `${refKey} ${targetReferences[member]}`; + } + + // Preaggregation may reference the joined cube dimensions/measures + if (this.query.cubeEvaluator.cubeFromPath(preAggregation.cube).joins[memberCube]) { + refKey = references[this.query.cubeEvaluator.pathFromArray([memberCube, memberProp])]; + return `${refKey} ${targetReferences[member]}`; + } + + throw new Error(`Preaggregation "${preAggregation.preAggregationName}" referenced property "${memberCube}.${memberProp}" not found in cube "${preAggregation.cube}"`); + } ); const tables = preAggregationForQuery.referencedPreAggregations.map(preAggregation => { From a513da33aa8f9972ff12d5a6c4310b7030d31e9a Mon Sep 17 00:00:00 2001 From: Konstantin Burkalev Date: Tue, 12 Nov 2024 21:48:31 +0200 Subject: [PATCH 3/4] add tests --- .../test/unit/pre-aggregations.test.ts | 129 ++++++++++++++++++ 1 file changed, 129 insertions(+) diff --git a/packages/cubejs-schema-compiler/test/unit/pre-aggregations.test.ts b/packages/cubejs-schema-compiler/test/unit/pre-aggregations.test.ts index 8d5c7bd211b28..cb6d653b4b23c 100644 --- a/packages/cubejs-schema-compiler/test/unit/pre-aggregations.test.ts +++ b/packages/cubejs-schema-compiler/test/unit/pre-aggregations.test.ts @@ -92,6 +92,135 @@ describe('pre-aggregations', () => { expect(cubeEvaluator.cubeFromPath('Orders').preAggregations.ordersRollupJoin.scheduledRefresh).toEqual(undefined); }); + it('query rollupLambda', async () => { + const { compiler, cubeEvaluator, joinGraph } = prepareCompiler( + ` + cube(\`Users\`, { + sql: \`SELECT * FROM public.users\`, + + preAggregations: { + usersRollup: { + dimensions: [CUBE.id], + }, + }, + + measures: { + count: { + type: \`count\`, + }, + }, + + dimensions: { + id: { + sql: \`id\`, + type: \`string\`, + primaryKey: true, + }, + + name: { + sql: \`name\`, + type: \`string\`, + }, + }, + }); + + cube('Orders', { + sql: \`SELECT * FROM orders\`, + + preAggregations: { + ordersRollupLambda: { + type: \`rollupLambda\`, + rollups: [simple1, simple2], + }, + simple1: { + measures: [CUBE.count], + dimensions: [CUBE.status, Users.name], + timeDimension: CUBE.created_at, + granularity: 'day', + partitionGranularity: 'day', + buildRangeStart: { + sql: \`SELECT NOW() - INTERVAL '1000 day'\`, + }, + buildRangeEnd: { + sql: \`SELECT NOW()\` + }, + }, + simple2: { + measures: [CUBE.count], + dimensions: [CUBE.status, Users.name], + timeDimension: CUBE.created_at, + granularity: 'day', + partitionGranularity: 'day', + buildRangeStart: { + sql: \`SELECT NOW() - INTERVAL '1000 day'\`, + }, + buildRangeEnd: { + sql: \`SELECT NOW()\` + }, + }, + }, + + joins: { + Users: { + relationship: \`belongsTo\`, + sql: \`\${CUBE.userId} = \${Users.id}\`, + }, + }, + + measures: { + count: { + type: \`count\`, + }, + }, + + dimensions: { + id: { + sql: \`id\`, + type: \`number\`, + primaryKey: true, + }, + userId: { + sql: \`user_id\`, + type: \`number\`, + }, + status: { + sql: \`status\`, + type: \`string\`, + }, + created_at: { + sql: \`created_at\`, + type: \`time\`, + }, + }, + }); + ` + ); + + await compiler.compile(); + + const query = new PostgresQuery({ joinGraph, cubeEvaluator, compiler }, { + measures: [ + 'Orders.count' + ], + }); + + const queryAndParams = query.buildSqlAndParams(); + console.log(queryAndParams); + expect(queryAndParams[0].includes('undefined')).toBeFalsy(); + expect(queryAndParams[0].includes('"orders__status" "orders__status"')).toBeTruthy(); + expect(queryAndParams[0].includes('"users__name" "users__name"')).toBeTruthy(); + expect(queryAndParams[0].includes('"orders__created_at_day" "orders__created_at_day"')).toBeTruthy(); + expect(queryAndParams[0].includes('"orders__count" "orders__count"')).toBeTruthy(); + expect(queryAndParams[0].includes('UNION ALL')).toBeTruthy(); + + const preAggregationsDescription: any = query.preAggregations?.preAggregationsDescription(); + console.log(JSON.stringify(preAggregationsDescription, null, 2)); + + expect(preAggregationsDescription.length).toEqual(2); + expect(preAggregationsDescription[0].preAggregationId).toEqual("Orders.simple1"); + expect(preAggregationsDescription[1].preAggregationId).toEqual("Orders.simple2"); + }); + // @link https://github.com/cube-js/cube/issues/6623 it('view and pre-aggregation granularity', async () => { const { compiler, cubeEvaluator, joinGraph } = prepareYamlCompiler( From 34d00932c23bf42ed7d6f5496ebe3f8fe2b1d99a Mon Sep 17 00:00:00 2001 From: Konstantin Burkalev Date: Fri, 22 Nov 2024 20:29:49 +0200 Subject: [PATCH 4/4] =?UTF-8?q?change=20order=20of=C2=A0the=C2=A0reference?= =?UTF-8?q?s=20lookup?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/adapter/PreAggregations.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/cubejs-schema-compiler/src/adapter/PreAggregations.js b/packages/cubejs-schema-compiler/src/adapter/PreAggregations.js index f37483efcc8e5..0597ede0b15cf 100644 --- a/packages/cubejs-schema-compiler/src/adapter/PreAggregations.js +++ b/packages/cubejs-schema-compiler/src/adapter/PreAggregations.js @@ -1193,20 +1193,21 @@ export class PreAggregations { const columnsFor = (targetReferences, references, preAggregation) => Object.keys(targetReferences).map( member => { - const [memberCube, memberProp] = member.split('.'); - let refKey = references[this.query.cubeEvaluator.pathFromArray([preAggregation.cube, memberProp])]; + const [, memberProp] = member.split('.'); + + let refKey = references[member]; if (refKey) { return `${refKey} ${targetReferences[member]}`; } - // Preaggregation may reference the joined cube dimensions/measures - if (this.query.cubeEvaluator.cubeFromPath(preAggregation.cube).joins[memberCube]) { - refKey = references[this.query.cubeEvaluator.pathFromArray([memberCube, memberProp])]; + refKey = references[this.query.cubeEvaluator.pathFromArray([preAggregation.cube, memberProp])]; + + if (refKey) { return `${refKey} ${targetReferences[member]}`; } - throw new Error(`Preaggregation "${preAggregation.preAggregationName}" referenced property "${memberCube}.${memberProp}" not found in cube "${preAggregation.cube}"`); + throw new Error(`Preaggregation "${preAggregation.preAggregationName}" referenced property "${member}" not found in cube "${preAggregation.cube}"`); } );