From 354942e0ab59dd066cd33b2a090d96e136035d92 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Mar 2026 17:45:31 +0100 Subject: [PATCH 1/2] chore(deps): Bump svgo from 2.8.0 to 2.8.2 (#10459) Bumps [svgo](https://github.com/svg/svgo) from 2.8.0 to 2.8.2. - [Release notes](https://github.com/svg/svgo/releases) - [Commits](https://github.com/svg/svgo/compare/v2.8.0...v2.8.2) --- updated-dependencies: - dependency-name: svgo dependency-version: 2.8.2 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- yarn.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/yarn.lock b/yarn.lock index ffb1ead51bd04..e0dac048fd449 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8024,11 +8024,6 @@ resolved "https://registry.yarnpkg.com/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz#db4ecfd499a9765ab24002c3b696d02e6d32a12c" integrity sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA== -"@trysound/sax@0.2.0": - version "0.2.0" - resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" - integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA== - "@tufjs/canonical-json@2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz#a52f61a3d7374833fca945b2549bc30a2dd40d0a" @@ -23097,6 +23092,11 @@ sax@>=0.6.0, sax@^1.2.4: resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== +sax@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.5.0.tgz#b5549b671069b7aa392df55ec7574cf411179eb8" + integrity sha512-21IYA3Q5cQf089Z6tgaUTr7lDAyzoTPx5HRtbhsME8Udispad8dC/+sziTNugOEx54ilvatQ9YCzl4KQLPcRHA== + saxes@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/saxes/-/saxes-6.0.0.tgz#fe5b4a4768df4f14a201b1ba6a65c1f3d9988cc5" @@ -24347,16 +24347,16 @@ svg-tags@^1.0.0: integrity sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q= svgo@^2.7.0: - version "2.8.0" - resolved "https://registry.yarnpkg.com/svgo/-/svgo-2.8.0.tgz#4ff80cce6710dc2795f0c7c74101e6764cfccd24" - integrity sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg== + version "2.8.2" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-2.8.2.tgz#8e99b7ba5ac9ed7e3a446063865f61e03223fe6b" + integrity sha512-TyzE4NVGLUFy+H/Uy4N6c3G0HEeprsVfge6Lmq+0FdQQ/zqoVYB62IsBZORsiL+o96s6ff/V6/3UQo/C0cgCAA== dependencies: - "@trysound/sax" "0.2.0" commander "^7.2.0" css-select "^4.1.3" css-tree "^1.1.3" csso "^4.2.0" picocolors "^1.0.0" + sax "^1.5.0" stable "^0.1.8" symbol-observable@4.0.0, symbol-observable@^4.0.0: From 7160283c7dac5d5696cf683b8e59418e58453821 Mon Sep 17 00:00:00 2001 From: waralexrom <108349432+waralexrom@users.noreply.github.com> Date: Fri, 6 Mar 2026 19:51:19 +0100 Subject: [PATCH 2/2] fix(cube): Issue with rollup pre-aggragations matching for views (#10474) --- .../src/adapter/PreAggregations.ts | 8 +- ...e-aggregations-calculated-measures.test.ts | 246 +++++++++++++++++- 2 files changed, 246 insertions(+), 8 deletions(-) diff --git a/packages/cubejs-schema-compiler/src/adapter/PreAggregations.ts b/packages/cubejs-schema-compiler/src/adapter/PreAggregations.ts index 2982c3970f73d..16899de004b31 100644 --- a/packages/cubejs-schema-compiler/src/adapter/PreAggregations.ts +++ b/packages/cubejs-schema-compiler/src/adapter/PreAggregations.ts @@ -784,9 +784,15 @@ export class PreAggregations { const canUse = (( windowGranularityMatches(references) ) && ( + (references.rollups.length > 0 && R.all( (m: string) => references.measures.indexOf(m) !== -1, - references.rollups.length > 0 ? transformedQuery.leafMeasures : transformedQuery.leafMeasuresFullPaths, + transformedQuery.leafMeasures, + ) + ) + || R.all( + (m: string) => references.measures.indexOf(m) !== -1, + transformedQuery.leafMeasuresFullPaths, ) || (transformedQuery.isAdditive && R.all( m => backAliasMeasures.indexOf(m) !== -1, transformedQuery.measures, diff --git a/packages/cubejs-schema-compiler/test/integration/postgres/pre-aggregations-calculated-measures.test.ts b/packages/cubejs-schema-compiler/test/integration/postgres/pre-aggregations-calculated-measures.test.ts index d5e9bde869db0..18d38586c2087 100644 --- a/packages/cubejs-schema-compiler/test/integration/postgres/pre-aggregations-calculated-measures.test.ts +++ b/packages/cubejs-schema-compiler/test/integration/postgres/pre-aggregations-calculated-measures.test.ts @@ -1,13 +1,8 @@ -import { - getEnv, -} from '@cubejs-backend/shared'; -import R from 'ramda'; -import { UserError } from '../../../src/compiler/UserError'; import { PostgresQuery } from '../../../src/adapter/PostgresQuery'; -import { prepareJsCompiler } from '../../unit/PrepareCompiler'; +import { prepareJsCompiler, prepareCompiler } from '../../unit/PrepareCompiler'; import { dbRunner } from './PostgresDBRunner'; -describe('PreAggregationsMultiStage', () => { +describe('PreAggregationsCalulatedMeasures', () => { jest.setTimeout(200000); const { compiler, joinGraph, cubeEvaluator } = prepareJsCompiler(` @@ -136,9 +131,246 @@ describe('PreAggregationsMultiStage', () => { }) + cube('facts', { + sql: 'select * from visitor_checkins', + sqlAlias: 'f', + measures: { + count: { type: 'count' }, + total_cost: { sql: 'id', type: 'sum' }, + avg_cost: { sql: \`\${CUBE.total_cost} / \${CUBE.count}\`, type: 'number' }, + }, + dimensions: { + id: { type: 'number', sql: 'id', primaryKey: true }, + line_item_id: { type: 'number', sql: 'visitor_id' }, + day: { type: 'time', sql: 'created_at' }, + }, + preAggregations: { + facts_rollup: { + type: 'rollup', + measures: [CUBE.count, CUBE.total_cost, CUBE.avg_cost], + dimensions: [CUBE.line_item_id], + timeDimension: CUBE.day, + granularity: 'day', + } + } + }) + + cube('line_items', { + sql: 'select * from visitors', + sqlAlias: 'li', + joins: { + facts: { + relationship: 'one_to_many', + sql: \`\${CUBE.id} = \${facts.line_item_id}\` + }, + campaigns: { + relationship: 'many_to_one', + sql: \`\${CUBE.id} = \${campaigns.id}\` + } + }, + measures: { + count: { type: 'count' } + }, + dimensions: { + id: { type: 'number', sql: 'id', primaryKey: true }, + name: { type: 'string', sql: 'source' }, + }, + preAggregations: { + li_rollup: { + type: 'rollup', + dimensions: [CUBE.id, CUBE.name], + }, + combined_rollup_join: { + type: 'rollupJoin', + measures: [line_items.facts.count, line_items.facts.total_cost, line_items.facts.avg_cost], + dimensions: [CUBE.name, campaigns.campaign_name], + timeDimension: line_items.facts.day, + granularity: 'day', + rollups: [campaigns.campaigns_rollup, facts.facts_rollup, CUBE.li_rollup], + } + } + }) + + cube('campaigns', { + sql: "select 1 as id, 'camp1' as campaign_name", + sqlAlias: 'c', + measures: { + count: { type: 'count' } + }, + dimensions: { + id: { type: 'number', sql: 'id', primaryKey: true }, + campaign_name: { type: 'string', sql: 'campaign_name' }, + }, + preAggregations: { + campaigns_rollup: { + type: 'rollup', + dimensions: [CUBE.id, CUBE.campaign_name], + } + } + }) + + view('my_view', { + cubes: [ + { join_path: line_items.facts, includes: '*', prefix: true }, + { join_path: line_items, includes: '*', prefix: true }, + { join_path: line_items.campaigns, includes: '*', prefix: true }, + ] + }) `); + it('rollupJoin matching with additive measures through view', async () => { + await compiler.compile(); + + const query = new PostgresQuery( + { joinGraph, cubeEvaluator, compiler }, + { + measures: [ + 'my_view.facts_count', + 'my_view.facts_total_cost', + ], + timeDimensions: [{ + dimension: 'my_view.facts_day', + granularity: 'day', + }], + timezone: 'America/Los_Angeles', + preAggregationsSchema: '', + } + ); + + const matchedPreAgg = query.preAggregations?.findPreAggregationForQuery(); + + const sqlAndParams = query.buildSqlAndParams(); + expect(sqlAndParams[0]).toContain('campaigns_rollup'); + expect(sqlAndParams[0]).toContain('facts_rollup'); + expect(sqlAndParams[0]).toContain('li_rollup'); + expect(matchedPreAgg).toBeDefined(); + expect(matchedPreAgg?.preAggregationName).toEqual('combined_rollup_join'); + return dbRunner.evaluateQueryWithPreAggregations(query).then(res => { + expect(res).toEqual( + + [ + { + my_view__facts_day_day: '2017-01-02T00:00:00.000Z', + my_view__facts_count: '1', + my_view__facts_total_cost: '1' + }, + { + my_view__facts_day_day: '2017-01-03T00:00:00.000Z', + my_view__facts_count: '1', + my_view__facts_total_cost: '2' + }, + { + my_view__facts_day_day: '2017-01-04T00:00:00.000Z', + my_view__facts_count: '3', + my_view__facts_total_cost: '12' + }, + { + my_view__facts_day_day: '2017-01-05T00:00:00.000Z', + my_view__facts_count: '1', + my_view__facts_total_cost: '6' + }, + { + my_view__facts_day_day: null, + my_view__facts_count: null, + my_view__facts_total_cost: null + } + ] + + ); + }); + }); + + it('rollupJoin matching with additive measures', async () => { + await compiler.compile(); + + const query = new PostgresQuery( + { joinGraph, cubeEvaluator, compiler }, + { + measures: [ + 'facts.count', + 'facts.total_cost', + ], + dimensions: ['line_items.name'], + timezone: 'America/Los_Angeles', + preAggregationsSchema: '', + } + ); + + const matchedPreAgg = query.preAggregations?.findPreAggregationForQuery(); + + const sqlAndParams = query.buildSqlAndParams(); + expect(sqlAndParams[0]).toContain('campaigns_rollup'); + expect(sqlAndParams[0]).toContain('facts_rollup'); + expect(sqlAndParams[0]).toContain('li_rollup'); + expect(matchedPreAgg).toBeDefined(); + expect(matchedPreAgg?.preAggregationName).toEqual('combined_rollup_join'); + return dbRunner.evaluateQueryWithPreAggregations(query).then(res => { + expect(res).toEqual( + + [ + { li__name: null, f__count: null, f__total_cost: null }, + { li__name: 'some', f__count: '5', f__total_cost: '15' }, + { li__name: 'google', f__count: '1', f__total_cost: '6' } + ] + + ); + }); + }); + + it('rollupJoin matching with calculated measures through view', async () => { + await compiler.compile(); + + const query = new PostgresQuery( + { joinGraph, cubeEvaluator, compiler }, + { + measures: [ + 'my_view.facts_avg_cost', + ], + timeDimensions: [{ + dimension: 'my_view.facts_day', + granularity: 'day', + }], + timezone: 'America/Los_Angeles', + preAggregationsSchema: '', + } + ); + + const matchedPreAgg = query.preAggregations?.findPreAggregationForQuery(); + + const sqlAndParams = query.buildSqlAndParams(); + expect(sqlAndParams[0]).toContain('campaigns_rollup'); + expect(sqlAndParams[0]).toContain('facts_rollup'); + expect(sqlAndParams[0]).toContain('li_rollup'); + expect(matchedPreAgg).toBeDefined(); + expect(matchedPreAgg?.preAggregationName).toEqual('combined_rollup_join'); + return dbRunner.evaluateQueryWithPreAggregations(query).then(res => { + expect(res).toEqual( + + [ + { + my_view__facts_day_day: '2017-01-02T00:00:00.000Z', + my_view__facts_avg_cost: '1.00000000000000000000' + }, + { + my_view__facts_day_day: '2017-01-03T00:00:00.000Z', + my_view__facts_avg_cost: '2.0000000000000000' + }, + { + my_view__facts_day_day: '2017-01-04T00:00:00.000Z', + my_view__facts_avg_cost: '4.0000000000000000' + }, + { + my_view__facts_day_day: '2017-01-05T00:00:00.000Z', + my_view__facts_avg_cost: '6.0000000000000000' + }, + { my_view__facts_day_day: null, my_view__facts_avg_cost: null } + ] + + ); + }); + }); + it('calculated measure pre-aggregation', () => compiler.compile().then(() => { const query = new PostgresQuery({ joinGraph, cubeEvaluator, compiler }, { measures: [