From edd0c867179564cd3b389b9ca803248e1e2f82b5 Mon Sep 17 00:00:00 2001 From: Konstantin Burkalev Date: Tue, 25 Nov 2025 18:22:57 +0200 Subject: [PATCH 1/2] fix(schema-compiler): Fix matching for pre-aggs with custom granularities --- .../cubejs-schema-compiler/src/adapter/BaseTimeDimension.ts | 4 ++++ .../cubejs-schema-compiler/src/adapter/PreAggregations.ts | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/cubejs-schema-compiler/src/adapter/BaseTimeDimension.ts b/packages/cubejs-schema-compiler/src/adapter/BaseTimeDimension.ts index 0cdf2557f1515..5ff52a4fa6ffd 100644 --- a/packages/cubejs-schema-compiler/src/adapter/BaseTimeDimension.ts +++ b/packages/cubejs-schema-compiler/src/adapter/BaseTimeDimension.ts @@ -279,6 +279,10 @@ export class BaseTimeDimension extends BaseFilter { return this.granularityObj ? this.granularityObj.resolvedGranularity() : null; } + public resolvedGranularityAsIs() { + return this.granularityObj ? this.granularityObj.granularity : null; + } + public wildcardRange() { return [FROM_PARTITION_RANGE, TO_PARTITION_RANGE]; } diff --git a/packages/cubejs-schema-compiler/src/adapter/PreAggregations.ts b/packages/cubejs-schema-compiler/src/adapter/PreAggregations.ts index d7fd3d3479d3f..015ed0bea7745 100644 --- a/packages/cubejs-schema-compiler/src/adapter/PreAggregations.ts +++ b/packages/cubejs-schema-compiler/src/adapter/PreAggregations.ts @@ -566,7 +566,7 @@ export class PreAggregations { public static timeDimensionsAsIs(timeDimensions: BaseTimeDimension[] | undefined): [expressionPath: string, resolvedGranularity: string | null][] { return timeDimensions && R.sortBy( ([exprPath]) => exprPath, - timeDimensions.map(d => [d.expressionPath(), d.resolvedGranularity()] as [string, string | null]), + timeDimensions.map(d => [d.expressionPath(), d.resolvedGranularityAsIs()] as [string, string | null]), ) || []; } From 7085805b1ece40354bc798364d765e922fbe6399 Mon Sep 17 00:00:00 2001 From: Konstantin Burkalev Date: Tue, 25 Nov 2025 20:21:35 +0200 Subject: [PATCH 2/2] add tests --- .../postgres/pre-aggregations.test.ts | 34 ++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/packages/cubejs-schema-compiler/test/integration/postgres/pre-aggregations.test.ts b/packages/cubejs-schema-compiler/test/integration/postgres/pre-aggregations.test.ts index eab0d3a137e5d..d9f0bd5e1dac8 100644 --- a/packages/cubejs-schema-compiler/test/integration/postgres/pre-aggregations.test.ts +++ b/packages/cubejs-schema-compiler/test/integration/postgres/pre-aggregations.test.ts @@ -262,6 +262,12 @@ describe('PreAggregations', () => { granularity: 'halfYear', allowNonStrictDateRangeMatch: false }, + countAnotherCountCustomGranularityNonStrict: { + measures: [countAnother], + timeDimension: createdAt, + granularity: 'halfYear', + allowNonStrictDateRangeMatch: true + }, sourceAndIdRollup: { measures: [count], dimensions: [sourceAndId, source], @@ -1451,7 +1457,7 @@ describe('PreAggregations', () => { }); }); - it('pre-aggregation with custom granularity should match its own references', async () => { + it('pre-aggregation with custom granularity should match its own references (allowNonStrictDateRangeMatch=false)', async () => { await compiler.compile(); const preAggregationId = 'visitors.countAnotherCountCustomGranularity'; @@ -1477,6 +1483,32 @@ describe('PreAggregations', () => { expect(preAggregationFromQuery.preAggregationId).toBe(preAggregationId); }); + it('pre-aggregation with custom granularity should match its own references (allowNonStrictDateRangeMatch=true)', async () => { + await compiler.compile(); + + const preAggregationId = 'visitors.countAnotherCountCustomGranularityNonStrict'; + const preAggregations = cubeEvaluator.preAggregations({ preAggregationIds: [preAggregationId] }); + + const preAggregation = preAggregations[0]; + if (preAggregation === undefined) { + throw expect(preAggregation).toBeDefined(); + } + + const query = new PostgresQuery({ joinGraph, cubeEvaluator, compiler }, { + ...preAggregation.references, + preAggregationId: preAggregation.id, + timezone: 'UTC', + }); + + const preAggregationsDescription: any = query.preAggregations?.preAggregationsDescription(); + const preAggregationFromQuery = preAggregationsDescription.find(p => p.preAggregationId === preAggregation.id); + if (preAggregationFromQuery === undefined) { + throw expect(preAggregationFromQuery).toBeDefined(); + } + + expect(preAggregationFromQuery.preAggregationId).toBe(preAggregationId); + }); + it('leaf measure pre-aggregation', async () => { await compiler.compile();