From 39d3b20d114d6003562e0cdad0e98389056bb3a5 Mon Sep 17 00:00:00 2001 From: Dmitry Patsura Date: Tue, 1 Sep 2026 19:29:31 +0200 Subject: [PATCH 1/5] fix(query-orchestrator): keep Interactive priority on user query paths (#11715) --- .../PreAggregationPartitionRangeLoader.ts | 1 + .../src/orchestrator/QueryCache.ts | 10 +++ .../test/unit/QueryCache.abstract.ts | 87 ++++++++++++++++++- 3 files changed, 97 insertions(+), 1 deletion(-) diff --git a/packages/cubejs-query-orchestrator/src/orchestrator/PreAggregationPartitionRangeLoader.ts b/packages/cubejs-query-orchestrator/src/orchestrator/PreAggregationPartitionRangeLoader.ts index a19e1924f9220..33b3183ede8c8 100644 --- a/packages/cubejs-query-orchestrator/src/orchestrator/PreAggregationPartitionRangeLoader.ts +++ b/packages/cubejs-query-orchestrator/src/orchestrator/PreAggregationPartitionRangeLoader.ts @@ -393,6 +393,7 @@ export class PreAggregationPartitionRangeLoader { { requestId: this.requestId, skipRefreshKeyWaitForRenew: false, + priority: this.priority(QueuePriority.Interactive), dataSource: this.dataSource, external: false, useCsvQuery: true, diff --git a/packages/cubejs-query-orchestrator/src/orchestrator/QueryCache.ts b/packages/cubejs-query-orchestrator/src/orchestrator/QueryCache.ts index c0d4d726e1bc6..09423af332ab5 100644 --- a/packages/cubejs-query-orchestrator/src/orchestrator/QueryCache.ts +++ b/packages/cubejs-query-orchestrator/src/orchestrator/QueryCache.ts @@ -86,6 +86,8 @@ export type QueryWithParams = [ export type LoadRefreshKeyOptions = { requestId?: string; skipRefreshKeyWaitForRenew?: boolean; + /** Inherited from the query the keys are refreshed for: a blocked request waits on them too */ + priority?: number; dataSource: string }; @@ -340,6 +342,7 @@ export class QueryCache { values, { cacheKey: [query, values], + priority: queuePriority, external: queryBody.external, requestId: queryBody.requestId, dataSource: queryBody.dataSource, @@ -362,6 +365,7 @@ export class QueryCache { renewalThreshold, { forceNoCache, + priority: queuePriority, external: queryBody.external, requestId: queryBody.requestId, dataSource: queryBody.dataSource, @@ -381,6 +385,7 @@ export class QueryCache { renewalThreshold, { forceNoCache, + priority: queuePriority, external: queryBody.external, requestId: queryBody.requestId, dataSource: queryBody.dataSource, @@ -391,6 +396,8 @@ export class QueryCache { // Keep the cycle after the foreground renewal: concurrent passes race on a cold cache. // It remains necessary when skipRefreshKeyWaitForRenew serves a stale key from a warm cache. + // It re-runs the same query at Background while the renewal above ran at the request's own + // priority, because the request is no longer blocked on the result by the time it fires. this.startRenewCycle( query, values, @@ -921,6 +928,7 @@ export class QueryCache { options: { requestId?: string, skipRefreshKeyWaitForRenew?: boolean, + priority?: number, external?: boolean, forceNoCache?: boolean, dataSource: string, @@ -957,6 +965,7 @@ export class QueryCache { ], waitForRenew: true, forceNoCache: options.forceNoCache, + priority: options.priority, external: options.external, requestId: options.requestId, dataSource: options.dataSource, @@ -1001,6 +1010,7 @@ export class QueryCache { expireSecs, { waitForRenew: !options.skipRefreshKeyWaitForRenew, + priority: options.priority, requestId: options.requestId, dataSource: options.dataSource, }, diff --git a/packages/cubejs-query-orchestrator/test/unit/QueryCache.abstract.ts b/packages/cubejs-query-orchestrator/test/unit/QueryCache.abstract.ts index d68d43a91ac2a..ea81b80dc185e 100644 --- a/packages/cubejs-query-orchestrator/test/unit/QueryCache.abstract.ts +++ b/packages/cubejs-query-orchestrator/test/unit/QueryCache.abstract.ts @@ -1,5 +1,6 @@ import crypto from 'crypto'; -import { createCancelablePromise, pausePromise } from '@cubejs-backend/shared'; +import { CacheMode, createCancelablePromise, pausePromise } from '@cubejs-backend/shared'; +import { QueuePriority } from '@cubejs-backend/base-driver'; import { CacheKey, CacheKeyItem, ContinueWaitError, QueryCache, QueryCacheOptions } from '../../src'; @@ -468,6 +469,90 @@ export const QueryCacheTest = (name: string, options: QueryCacheTestOptions) => renewQuerySpy.mockRestore(); } }); + + // The queue fast track only engages at `QueuePriority.Interactive`, so a request-blocked + // query that loses its priority on the way down silently falls back to the slow path. + it.each<{ type: string, cacheMode?: CacheMode, queuePriority?: number, expected: number }>([ + { type: 'the default', cacheMode: undefined, queuePriority: undefined, expected: QueuePriority.Interactive }, + { type: 'an explicit queuePriority', cacheMode: undefined, queuePriority: 42, expected: 42 }, + { type: 'must-revalidate', cacheMode: 'must-revalidate', queuePriority: undefined, expected: QueuePriority.Interactive }, + ])('submits the main query and its refresh key with $type priority', async ({ cacheMode, queuePriority, expected }) => { + const suffix = crypto.randomBytes(8).toString('hex'); + const mainQuery = `SELECT priority-main-${suffix}`; + const cacheKeyQuery = `SELECT priority-refresh-key-${suffix}`; + + const querySpy = jest.spyOn(cache, 'queryWithRetryAndRelease').mockImplementation(async (query) => { + if (query === mainQuery) { + return [{ result: 'ok' }]; + } + + return [{ refresh_key: suffix }]; + }); + const renewCycleSpy = jest.spyOn(cache, 'startRenewCycle').mockImplementation(() => undefined); + + try { + await cache.cachedQueryResult( + { + query: mainQuery, + values: [], + cacheMode, + queuePriority, + cacheKeyQueries: [[cacheKeyQuery, []]], + requestId: `priority-req-${suffix}`, + dataSource: 'default', + }, + [], + ); + + const priorityOf = (targetQuery: string) => querySpy.mock.calls + .filter(([query]) => query === targetQuery) + .map(([, , queryOptions]) => queryOptions.priority); + + expect(priorityOf(mainQuery)).toEqual([expected]); + expect(priorityOf(cacheKeyQuery)).toEqual([expected]); + } finally { + renewCycleSpy.mockRestore(); + querySpy.mockRestore(); + } + }); + + // The branch that bypasses the cache: `cacheKeyQueriesFrom` always returns an array, so + // an empty `cacheKeyQueries` still renews — only these two query shapes reach it. + it.each([ + { type: 'an external query that skips the cache and queue', queryBody: { external: true } }, + { type: 'a persistent query', queryBody: { persistent: true } }, + ])('submits $type with Interactive priority', async ({ queryBody }) => { + const localCache = new QueryCacheOpened( + crypto.randomBytes(16).toString('hex'), + () => { + throw new Error('driverFactory is not implemented, mock should be used...'); + }, + jest.fn(), + { ...options, skipExternalCacheAndQueue: true }, + ); + const querySpy = jest.spyOn(localCache, 'queryWithRetryAndRelease') + .mockImplementation(async () => [{ result: 'ok' }]); + + try { + await localCache.cachedQueryResult( + { + ...queryBody, + query: 'SELECT skip-cache-main', + values: [], + cacheKeyQueries: [], + requestId: 'skip-cache-req', + dataSource: 'default', + }, + [], + ); + + expect(querySpy.mock.calls.map(([, , queryOptions]) => queryOptions.priority)) + .toEqual([QueuePriority.Interactive]); + } finally { + querySpy.mockRestore(); + await localCache.cleanup(); + } + }); }); describe('local refresh key', () => { From 4029495feb0cadfee20c56f565d94430852f5b27 Mon Sep 17 00:00:00 2001 From: waralexrom <108349432+waralexrom@users.noreply.github.com> Date: Tue, 1 Sep 2026 19:38:04 +0200 Subject: [PATCH 2/5] fix(tesseract): calendar sql granularities crash every query; to_date ignores the calendar (#11709) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(schema-compiler): reject sql granularities under a name of their own (CORE-780) A granularity declared with `sql` carries no interval — the validator forbids combining `sql` with `interval`. `resolveGranularity()` supplies a synthetic `1 ` interval for predefined names only, so a `sql` granularity named after something else resolved without one, and `Granularity` read it unguarded. `granularityHierarchies()` builds a `Granularity` for every custom granularity of every time dimension in the model, and pre-aggregation matching runs it on every request regardless of the SQL planner. A single such granularity anywhere in the model therefore failed every query of the deployment, including queries that never referenced the cube declaring it. Such a granularity is now rejected at compile time, naming the granularity and the predefined names it may take. The check is reported outside the cube schema so it stands on its own: rejecting the granularity within the schema lists it among the reasons every other dimension alternative failed, which buries it. As defense in depth, `granularityHierarchies()` skips granularities that have no interval to derive a hierarchy from — rollups can only match those by name, which a missing hierarchy entry already expresses — and `Granularity` reports a readable error instead of reading the interval unguarded. Co-Authored-By: Claude Opus 5 (1M context) * fix(tesseract): bound a to_date window by the calendar, not by interval math A calendar cube's granularity is honored where the time dimension is projected, but a `to_date` rolling window bounded itself with `date_bin(interval, point, origin)` — the granularity's synthetic `1 ` interval anchored at the start of the current year. A retail week-to-date therefore reset on the weekday that year started on rather than on the week the calendar defines, silently, with no error to notice. The period a point belongs to cannot be derived from the point: only the calendar knows it. The series driving such a window is now read off the calendar cube, pairing every point with the period it falls into, and both bounds take it from there — the window's join condition and the lower bound widening the scan of its source. The period ends where the next one starts, read from the next point of the series, because a 4-5-4 month runs 28 or 35 days against a nominal `1 month`. Rolling windows share one series, so its points carry one boundary column per granularity and each window reads its own: week-to-date and month-to-date over the same calendar resolve independently. A regular trailing window on that series is unaffected. Series that no calendar window drives are untouched. Co-Authored-By: Claude Opus 5 (1M context) * docs: revert the calendar granularity note Documenting the naming rule belongs with the docs owners, not here. Co-Authored-By: Claude Opus 5 (1M context) * fix(tesseract): let the calendar series look past its own range restriction A period ends where the next one starts, and the point opening that next period may sit outside the queried range — a range closing exactly on a period end left the last point with no next row to read, falling back to the nominal interval it was there to replace. A 35-day retail month closing the range came back four days short. The period bounds are now derived over the unrestricted calendar and the range is applied outside that select, so the point past the range still bounds the last one inside it. Both selects render through the sql templates, so dialects overriding statement rendering apply to the calendar series too. Also addresses review notes: - a granularity named `Week` with `sql` resolves, because predefined names are matched case-insensitively; the new rejection matched case-sensitively and would have failed a model that works today - the predefined names quoted in that message now come from the set backing the check, rather than a fourth copy of it - a cube whose granularities were rejected is no longer recorded as valid - `granularityHierarchies()` skips a granularity that resolves without an interval, but keeps reporting one that does not resolve at all - `Granularity` no longer blames `sql` for an interval missing for another reason - a calendar period dimension without a granularity is an internal error rather than a column name the consuming side cannot match - the ordering the time series' granularity list rests on is now stated where the list is declared and where the loops it depends on run Co-Authored-By: Claude Opus 5 (1M context) * test(tesseract): cover calendar to_date windows in the planner suite The feature was only covered from the schema compiler's Postgres suite, which leaves the planner's own integration suite silent about it. The retail calendar fixture there already runs 4-5-4 months, so the case a nominal interval cannot reproduce needs nothing but exposing that column as a granularity. `month` is exposed on the primary key dimension only: an existing test reads `retail_date` at `month` and must keep seeing a natural one. Five cases, all failing before the window learned to read its bounds off the calendar — the retail month then bucketed the rolling measure by calendar months while the plain measure kept retail ones, so the two axes never met and half of each row came back NULL: - week-to-date resetting on the retail week rather than the ISO one - month-to-date resetting on the retail month rather than the first of the month - a 5-week month grouped by itself, where a nominal bound folds the next one in - a range closing exactly on a period end, whose bounding point is outside it - both windows at once, the weekly one restarting while the monthly accumulates Co-Authored-By: Claude Opus 5 (1M context) * fix(tesseract): keep the calendar period a range opens inside of The series restricted itself with the aligned date range, whose start `get_range_for_time_series` snaps to the granularity's interval — for a calendar granularity, anchored at the start of the current year, the very arithmetic the period bounds no longer use. That point lands inside the period the range opens in, and `date_from >= range_from` then drops that period from the series: a month-to-date over a range opening on 2024-04-01 lost the retail month running 2024-03-03..2024-04-06 entirely, reporting NULL where the period had five orders. The calendar branch now takes the range as stated and keeps a period by overlap rather than by where it starts, which is also what the generated series does — it starts at the aligned point and labels it with that period's start. Two of the existing cases had nothing but NULLs after the boundary they were pinning, so a bound that collapsed to an empty window for the rest of the range would have satisfied them; both now extend far enough for the new period to count again. Co-Authored-By: Claude Opus 5 (1M context) --------- Co-authored-by: Claude Opus 5 (1M context) --- .../src/adapter/BaseQuery.js | 20 +- .../src/adapter/Granularity.ts | 7 + .../src/compiler/CubeValidator.ts | 33 ++- .../postgres/calendar-to-date.test.ts | 188 ++++++++++++++++ .../unit/calendar-sql-granularity.test.ts | 144 +++++++++++++ .../logical_plan/multistage/time_series.rs | 54 ++++- .../filter/operators/filter_sql_context.rs | 53 ++--- .../operators/to_date_rolling_window.rs | 15 +- .../cubesqlplanner/src/physical_plan/join.rs | 14 +- .../cubesqlplanner/src/physical_plan/mod.rs | 2 +- .../src/physical_plan/time_series.rs | 204 +++++++++++++++++- .../processors/multi_stage_time_series.rs | 65 +++++- .../planner/planners/multi_stage/member.rs | 11 + .../multi_stage/member_query_planner.rs | 83 ++++++- .../multi_stage/multi_stage_query_planner.rs | 69 +++++- .../src/planner/sql_templates/plan.rs | 18 ++ .../common/integration_calendar.yaml | 16 ++ .../src/tests/integration/calendar.rs | 160 ++++++++++++++ ..._to_date_range_ending_on_a_period_end.snap | 8 + ...dar__to_date_range_opening_mid_period.snap | 9 + ...calendar__to_date_retail_month_by_day.snap | 17 ++ ..._to_date_retail_month_by_retail_month.snap | 10 + ..._calendar__to_date_retail_week_by_day.snap | 18 ++ ...ndar__to_date_week_and_month_together.snap | 16 ++ 24 files changed, 1175 insertions(+), 59 deletions(-) create mode 100644 packages/cubejs-schema-compiler/test/integration/postgres/calendar-to-date.test.ts create mode 100644 packages/cubejs-schema-compiler/test/unit/calendar-sql-granularity.test.ts create mode 100644 rust/cube/cubesqlplanner/cubesqlplanner/src/tests/integration/snapshots/cubesqlplanner__tests__integration__calendar__to_date_range_ending_on_a_period_end.snap create mode 100644 rust/cube/cubesqlplanner/cubesqlplanner/src/tests/integration/snapshots/cubesqlplanner__tests__integration__calendar__to_date_range_opening_mid_period.snap create mode 100644 rust/cube/cubesqlplanner/cubesqlplanner/src/tests/integration/snapshots/cubesqlplanner__tests__integration__calendar__to_date_retail_month_by_day.snap create mode 100644 rust/cube/cubesqlplanner/cubesqlplanner/src/tests/integration/snapshots/cubesqlplanner__tests__integration__calendar__to_date_retail_month_by_retail_month.snap create mode 100644 rust/cube/cubesqlplanner/cubesqlplanner/src/tests/integration/snapshots/cubesqlplanner__tests__integration__calendar__to_date_retail_week_by_day.snap create mode 100644 rust/cube/cubesqlplanner/cubesqlplanner/src/tests/integration/snapshots/cubesqlplanner__tests__integration__calendar__to_date_week_and_month_together.snap diff --git a/packages/cubejs-schema-compiler/src/adapter/BaseQuery.js b/packages/cubejs-schema-compiler/src/adapter/BaseQuery.js index 5f478fbaf9b11..2536bc655f061 100644 --- a/packages/cubejs-schema-compiler/src/adapter/BaseQuery.js +++ b/packages/cubejs-schema-compiler/src/adapter/BaseQuery.js @@ -1917,11 +1917,21 @@ export class BaseQuery { // If we have custom granularities in time dimension if (td.granularities) { for (const granularityName of Object.keys(td.granularities)) { - const grObj = new Granularity(this, { dimension: dimensionKey, granularity: granularityName }); - hierarchies[`${dimensionKey}.${granularityName}`] = [ - granularityName, - ...standardGranularitiesParents[grObj.minGranularity()], - ]; + const granularity = this.cubeEvaluator.resolveGranularity([cube, tdName, 'granularities', granularityName]); + + // A granularity that only overrides the SQL of its time dimension has no + // interval to derive a hierarchy from. Such a granularity can only be + // matched by a rollup declaring it by name, which is what a missing + // hierarchy entry already means. + // An unresolvable granularity is a different matter and keeps + // reporting itself from the constructor below. + if (!granularity || granularity.interval) { + const grObj = new Granularity(this, { dimension: dimensionKey, granularity: granularityName }); + hierarchies[`${dimensionKey}.${granularityName}`] = [ + granularityName, + ...standardGranularitiesParents[grObj.minGranularity()], + ]; + } } } } diff --git a/packages/cubejs-schema-compiler/src/adapter/Granularity.ts b/packages/cubejs-schema-compiler/src/adapter/Granularity.ts index 4e7d452fd6d99..98b0a75b96d71 100644 --- a/packages/cubejs-schema-compiler/src/adapter/Granularity.ts +++ b/packages/cubejs-schema-compiler/src/adapter/Granularity.ts @@ -48,6 +48,13 @@ export class Granularity { throw new UserError(`Granularity "${timeDimension.granularity}" does not exist in dimension ${timeDimension.dimension}`); } + if (!customGranularity.interval) { + const cause = customGranularity.sql + ? 'is defined with \'sql\', which is only supported for predefined granularities' + : 'has no interval'; + throw new UserError(`Granularity "${this.granularity}" of dimension ${timeDimension.dimension} ${cause}`); + } + this.granularityInterval = customGranularity.interval; if (customGranularity.origin) { diff --git a/packages/cubejs-schema-compiler/src/compiler/CubeValidator.ts b/packages/cubejs-schema-compiler/src/compiler/CubeValidator.ts index a7452ea2bff33..5ac0cfd00d911 100644 --- a/packages/cubejs-schema-compiler/src/compiler/CubeValidator.ts +++ b/packages/cubejs-schema-compiler/src/compiler/CubeValidator.ts @@ -1,5 +1,6 @@ import Joi from 'joi'; import cronParser from 'cron-parser'; +import { isPredefinedGranularity, TIME_SERIES } from '@cubejs-backend/shared'; import { CubeSymbols, CubeDefinition, ToString } from './CubeSymbols'; import type { ErrorReporter } from './ErrorReporter'; @@ -109,6 +110,8 @@ const everyCronTimeZone = Joi.string().custom((value, helper) => { } }); +const PREDEFINED_GRANULARITY_NAMES = Object.keys(TIME_SERIES).sort(); + const GranularityInterval = Joi.string().pattern(/^\d+\s+(second|minute|hour|day|week|month|quarter|year)s?(\s\d+\s+(second|minute|hour|day|week|month|quarter|year)s?){0,7}$/, 'granularity interval'); // Do not allow negative intervals for granularities, while offsets could be negative const GranularityOffset = Joi.string().pattern(/^-?(\d+\s+)(second|minute|hour|day|week|month|quarter|year)s?(\s-?\d+\s+(second|minute|hour|day|week|month|quarter|year)s?){0,7}$/, 'granularity offset'); @@ -1417,20 +1420,48 @@ export class CubeValidator implements CompilerInterface { }; const result = cube.isView ? viewSchema.validate(cube, options) : cubeSchema.validate(cube, options); + let valid = result.error == null; + if (cube.isView) { // We need to verify that leaf cubes in view are present only once this.validateUniqueLeafCubes(cube.name, cube.cubes, errorReporter); + } else if (!this.validateGranularitySql(cube, errorReporter)) { + valid = false; } if (result.error != null) { errorReporter.error(formatErrorMessage(result.error)); - } else { + } + + if (valid) { this.validCubes.set(cube.name, true); } return result; } + // Reported outside the cube schema so the message stands on its own: a + // granularity rejected by the schema is listed among the reasons every other + // dimension alternative failed, which buries it. + private validateGranularitySql(cube, errorReporter: ErrorReporter): boolean { + let valid = true; + + for (const [dimensionName, dimension] of Object.entries(cube.dimensions || {})) { + for (const [name, granularity] of Object.entries(dimension?.granularities || {})) { + // Predefined names are resolved case-insensitively, so `Week` names a + // granularity that resolves and must keep doing so. + if (granularity?.sql && !isPredefinedGranularity(name.toLowerCase())) { + errorReporter.error( + `dimensions.${dimensionName}.granularities.${name}: a granularity defined with 'sql' must be named after one of the predefined granularities (${PREDEFINED_GRANULARITY_NAMES.join(', ')}). Define '${name}' with 'interval' instead` + ); + valid = false; + } + } + } + + return valid; + } + public validateViewGroup(viewGroup, errorReporter: ErrorReporter) { const options = { nonEnumerables: true, diff --git a/packages/cubejs-schema-compiler/test/integration/postgres/calendar-to-date.test.ts b/packages/cubejs-schema-compiler/test/integration/postgres/calendar-to-date.test.ts new file mode 100644 index 0000000000000..dffe2ec780a32 --- /dev/null +++ b/packages/cubejs-schema-compiler/test/integration/postgres/calendar-to-date.test.ts @@ -0,0 +1,188 @@ +import { getEnv } from '@cubejs-backend/shared'; +import { PostgresQuery } from '../../../src/adapter'; +import { prepareYamlCompiler } from '../../unit/PrepareCompiler'; +import { dbRunner } from './PostgresDBRunner'; + +describe('Calendar cube to-date rolling window', () => { + jest.setTimeout(200000); + + // Fiscal weeks start on Sunday 2023-12-17 and run for 7 days, so they line up + // with neither the ISO week nor any interval anchored at the start of a year. + // language=YAML + const { compiler, joinGraph, cubeEvaluator } = prepareYamlCompiler(` +cubes: + - name: fiscal_calendar + calendar: true + sql: > + SELECT (DATE '2023-12-17' + (gs.n - 1))::date AS cal_date, + (DATE '2023-12-17' + ((gs.n - 1) / 7) * 7)::date AS wk_start_dt, + CASE + WHEN gs.n - 1 < 28 THEN DATE '2023-12-17' + WHEN gs.n - 1 < 63 THEN DATE '2024-01-14' + ELSE DATE '2024-02-18' + END::date AS mo_start_dt + FROM generate_series(1, 91) AS gs(n) + dimensions: + - name: date_key + sql: cal_date + type: time + primary_key: true + - name: date + sql: cal_date + type: time + granularities: + - name: week + sql: "{CUBE}.wk_start_dt" + - name: month + sql: "{CUBE}.mo_start_dt" + + - name: sales + sql: > + SELECT gs.n::int AS id, + (DATE '2023-12-17' + (gs.n - 1))::date AS date, + 10 AS amount + FROM generate_series(1, 91) AS gs(n) + joins: + - name: fiscal_calendar + sql: "{CUBE}.date = {fiscal_calendar.date_key}" + relationship: many_to_one + dimensions: + - name: id + sql: id + type: number + primary_key: true + measures: + - name: wtd_amount + sql: amount + type: sum + rolling_window: + type: to_date + granularity: week + + - name: mtd_amount + sql: amount + type: sum + rolling_window: + type: to_date + granularity: month + + - name: trailing_amount + sql: amount + type: sum + rolling_window: + trailing: 3 day + offset: end +`); + + async function runQueryTest(q: any, expectedResult: any) { + // Calendars are working only with Tesseract SQL planner + if (!getEnv('nativeSqlPlanner')) { + return; + } + + await compiler.compile(); + const query = new PostgresQuery( + { joinGraph, cubeEvaluator, compiler }, + { ...q, timezone: 'UTC', preAggregationsSchema: '' } + ); + + const res = await dbRunner.testQuery(query.buildSqlAndParams()); + + expect(res).toEqual(expectedResult); + } + + it('accumulates within the calendar week, not within a natural one', async () => runQueryTest({ + measures: ['sales.wtd_amount'], + timeDimensions: [{ + dimension: 'fiscal_calendar.date', + granularity: 'day', + dateRange: ['2023-12-19', '2023-12-26'], + }], + order: [{ id: 'fiscal_calendar.date' }], + }, [ + // Fiscal week of 2023-12-17 accumulates through 2023-12-23... + { fiscal_calendar__date_day: '2023-12-19T00:00:00.000Z', sales__wtd_amount: '30' }, + { fiscal_calendar__date_day: '2023-12-20T00:00:00.000Z', sales__wtd_amount: '40' }, + { fiscal_calendar__date_day: '2023-12-21T00:00:00.000Z', sales__wtd_amount: '50' }, + { fiscal_calendar__date_day: '2023-12-22T00:00:00.000Z', sales__wtd_amount: '60' }, + { fiscal_calendar__date_day: '2023-12-23T00:00:00.000Z', sales__wtd_amount: '70' }, + // ...and resets on 2023-12-24, where the next fiscal week starts. + { fiscal_calendar__date_day: '2023-12-24T00:00:00.000Z', sales__wtd_amount: '10' }, + { fiscal_calendar__date_day: '2023-12-25T00:00:00.000Z', sales__wtd_amount: '20' }, + { fiscal_calendar__date_day: '2023-12-26T00:00:00.000Z', sales__wtd_amount: '30' }, + ])); + + it('bounds each window by its own calendar period', async () => runQueryTest({ + measures: ['sales.wtd_amount', 'sales.mtd_amount'], + timeDimensions: [{ + dimension: 'fiscal_calendar.date', + granularity: 'day', + dateRange: ['2023-12-23', '2023-12-25'], + }], + order: [{ id: 'fiscal_calendar.date' }], + }, [ + // Fiscal weeks are 7 days; the fiscal month running from 2023-12-17 is 28. + { fiscal_calendar__date_day: '2023-12-23T00:00:00.000Z', sales__wtd_amount: '70', sales__mtd_amount: '70' }, + { fiscal_calendar__date_day: '2023-12-24T00:00:00.000Z', sales__wtd_amount: '10', sales__mtd_amount: '80' }, + { fiscal_calendar__date_day: '2023-12-25T00:00:00.000Z', sales__wtd_amount: '20', sales__mtd_amount: '90' }, + ])); + + it('ends a period where the calendar ends it, not one nominal interval later', async () => runQueryTest({ + measures: ['sales.mtd_amount'], + timeDimensions: [{ + dimension: 'fiscal_calendar.date', + granularity: 'month', + dateRange: ['2023-12-17', '2024-03-16'], + }], + order: [{ id: 'fiscal_calendar.date' }], + }, [ + // 28, 35 and 28 days at 10 a day. A nominal `1 month` upper bound would + // reach past the 28-day period and fold the next one into it. + { fiscal_calendar__date_month: '2023-12-17T00:00:00.000Z', sales__mtd_amount: '280' }, + { fiscal_calendar__date_month: '2024-01-14T00:00:00.000Z', sales__mtd_amount: '350' }, + { fiscal_calendar__date_month: '2024-02-18T00:00:00.000Z', sales__mtd_amount: '280' }, + ])); + + it('leaves a regular window on the same series alone', async () => runQueryTest({ + measures: ['sales.trailing_amount', 'sales.mtd_amount'], + timeDimensions: [{ + dimension: 'fiscal_calendar.date', + granularity: 'day', + dateRange: ['2023-12-22', '2023-12-25'], + }], + order: [{ id: 'fiscal_calendar.date' }], + }, [ + // The trailing window keeps counting across the fiscal boundary the + // to-date window resets on. + { fiscal_calendar__date_day: '2023-12-22T00:00:00.000Z', sales__trailing_amount: '30', sales__mtd_amount: '60' }, + { fiscal_calendar__date_day: '2023-12-23T00:00:00.000Z', sales__trailing_amount: '30', sales__mtd_amount: '70' }, + { fiscal_calendar__date_day: '2023-12-24T00:00:00.000Z', sales__trailing_amount: '30', sales__mtd_amount: '80' }, + { fiscal_calendar__date_day: '2023-12-25T00:00:00.000Z', sales__trailing_amount: '30', sales__mtd_amount: '90' }, + ])); + + it('ends the last period in range on the calendar too', async () => runQueryTest({ + measures: ['sales.mtd_amount'], + timeDimensions: [{ + dimension: 'fiscal_calendar.date', + granularity: 'month', + dateRange: ['2024-01-14', '2024-02-17'], + }], + }, [ + // The range ends exactly where this 35-day period does, so the period that + // bounds it is outside the range: reading the end off the next series point + // only works if the series looks past its own restriction. + { fiscal_calendar__date_month: '2024-01-14T00:00:00.000Z', sales__mtd_amount: '350' }, + ])); + + it('resolves the series range at query time when none is given', async () => runQueryTest({ + measures: ['sales.wtd_amount'], + timeDimensions: [{ + dimension: 'fiscal_calendar.date', + granularity: 'week', + }], + order: [{ id: 'fiscal_calendar.date' }], + }, Array.from({ length: 13 }, (_, i) => ({ + fiscal_calendar__date_week: new Date(Date.UTC(2023, 11, 17 + i * 7)).toISOString(), + sales__wtd_amount: '70', + })))); +}); diff --git a/packages/cubejs-schema-compiler/test/unit/calendar-sql-granularity.test.ts b/packages/cubejs-schema-compiler/test/unit/calendar-sql-granularity.test.ts new file mode 100644 index 0000000000000..6e3caa96aca03 --- /dev/null +++ b/packages/cubejs-schema-compiler/test/unit/calendar-sql-granularity.test.ts @@ -0,0 +1,144 @@ +import { PostgresQuery } from '../../src/adapter/PostgresQuery'; +import { prepareYamlCompiler } from './PrepareCompiler'; + +describe('Calendar cube granularities defined with sql', () => { + // language=YAML + const modelWith = (granularity: string) => ` +cubes: + - name: fiscal_calendar + calendar: true + sql: > + SELECT '2023-12-17'::DATE AS cal_date, '2023-12-17'::DATE AS wk_start_dt UNION ALL + SELECT '2023-12-24'::DATE, '2023-12-24'::DATE + dimensions: + - name: date_key + sql: cal_date + type: time + primary_key: true + - name: date + sql: cal_date + type: time + granularities: +${granularity} + + - name: sales + sql: > + SELECT 1 AS id, '2023-12-24'::DATE AS date, 100 AS amount + joins: + - name: fiscal_calendar + sql: "{CUBE}.date = {fiscal_calendar.date_key}" + relationship: many_to_one + dimensions: + - name: id + sql: id + type: number + primary_key: true + measures: + - name: total_amount + sql: amount + type: sum +`; + + const sqlOverride = (name: string) => ` - name: ${name} + sql: "{CUBE}.wk_start_dt"`; + + const compile = async (granularity: string) => { + const compilers = prepareYamlCompiler(modelWith(granularity)); + await compilers.compiler.compile(); + return compilers; + }; + + it('rejects a sql override named after a non-predefined granularity', async () => { + await expect(compile(sqlOverride('fiscal_week'))).rejects.toThrow( + /granularity defined with 'sql' must be named after one of the predefined granularities/ + ); + }); + + it('accepts a sql override whose predefined name differs in case', async () => { + // Predefined names resolve case-insensitively, so this one resolves today. + await expect(compile(sqlOverride('Week'))).resolves.toBeDefined(); + }); + + describe.each([ + ['legacy planner', false], + ['native planner', true], + ])('%s', (_name, useNativeSqlPlanner) => { + const newQuery = (compilers: any, query: any) => new PostgresQuery( + compilers, + { ...query, timezone: 'UTC', useNativeSqlPlanner } + ); + + it('keeps queries that do not touch the calendar cube working', async () => { + const compilers = await compile(sqlOverride('week')); + const query = newQuery(compilers, { measures: ['sales.total_amount'] }); + + expect(() => query.preAggregations.canUseTransformedQuery()).not.toThrow(); + expect(() => query.buildSqlAndParams()).not.toThrow(); + }); + + it('keeps queries using the overridden granularity working', async () => { + const compilers = await compile(sqlOverride('week')); + const query = newQuery(compilers, { + measures: ['sales.total_amount'], + timeDimensions: [{ dimension: 'fiscal_calendar.date', granularity: 'week' }], + }); + + expect(() => query.preAggregations.canUseTransformedQuery()).not.toThrow(); + expect(() => query.buildSqlAndParams()).not.toThrow(); + }); + + it('keeps hierarchies of interval based granularities', async () => { + const compilers = await compile(` - name: fortnight + interval: 2 week + origin: "2025-01-01"`); + const query = newQuery(compilers, { measures: ['sales.total_amount'] }); + + expect(query.granularityHierarchies()['fiscal_calendar.date.fortnight']) + .toEqual(['fortnight', 'day', 'hour', 'minute', 'second']); + }); + }); + + describe('granularity without an interval reaching the query', () => { + // Validation rejects such a granularity, so it is injected into the compiled + // model to check that it stays contained to the queries that ask for it. + const compileWithInjected = async () => { + const compilers = await compile(sqlOverride('week')); + const dimension: any = compilers.cubeEvaluator.symbols.fiscal_calendar.date; + dimension.granularities.fiscal_week = { sql: () => 'wk_start_dt' }; + return compilers; + }; + + it('does not affect queries that do not use it', async () => { + const compilers = await compileWithInjected(); + const query = new PostgresQuery(compilers, { + measures: ['sales.total_amount'], + timezone: 'UTC', + }); + + expect(() => query.preAggregations.canUseTransformedQuery()).not.toThrow(); + expect(query.granularityHierarchies()['fiscal_calendar.date.fiscal_week']).toBeUndefined(); + }); + + it('fails with a readable error when a query uses it', async () => { + const compilers = await compileWithInjected(); + + expect(() => new PostgresQuery(compilers, { + measures: ['sales.total_amount'], + timeDimensions: [{ dimension: 'fiscal_calendar.date', granularity: 'fiscal_week' }], + timezone: 'UTC', + })).toThrow(/is defined with 'sql', which is only supported for predefined granularities/); + }); + }); + + it('renders the calendar sql for the overridden granularity', async () => { + const compilers = await compile(sqlOverride('week')); + const query = new PostgresQuery(compilers, { + measures: ['sales.total_amount'], + timeDimensions: [{ dimension: 'fiscal_calendar.date', granularity: 'week' }], + timezone: 'UTC', + useNativeSqlPlanner: true, + }); + + expect(query.buildSqlAndParams()[0]).toContain('wk_start_dt'); + }); +}); diff --git a/rust/cube/cubesqlplanner/cubesqlplanner/src/logical_plan/multistage/time_series.rs b/rust/cube/cubesqlplanner/cubesqlplanner/src/logical_plan/multistage/time_series.rs index 10864a5d1ef20..308e037f2c15b 100644 --- a/rust/cube/cubesqlplanner/cubesqlplanner/src/logical_plan/multistage/time_series.rs +++ b/rust/cube/cubesqlplanner/cubesqlplanner/src/logical_plan/multistage/time_series.rs @@ -15,6 +15,15 @@ pub struct MultiStageTimeSeries { date_range: Option>, #[builder(default)] get_date_range_multistage_ref: Option, + /// Query over the calendar cube supplying the period each series point + /// belongs to, for `to_date` windows whose granularity defines its own SQL. + /// `None` when every window on this series bounds itself by interval math. + #[builder(default)] + calendar_source: Option>, + /// The time dimension at each granularity `calendar_source` projects a + /// period for. + #[builder(default)] + period_dimensions: Vec>, } impl MultiStageTimeSeries { @@ -29,6 +38,14 @@ impl MultiStageTimeSeries { pub fn get_date_range_multistage_ref(&self) -> &Option { &self.get_date_range_multistage_ref } + + pub fn calendar_source(&self) -> &Option> { + &self.calendar_source + } + + pub fn period_dimensions(&self) -> &Vec> { + &self.period_dimensions + } } impl PrettyPrint for MultiStageTimeSeries { @@ -45,6 +62,23 @@ impl PrettyPrint for MultiStageTimeSeries { &state, ); } + if !self.period_dimensions.is_empty() { + result.println( + &format!( + "period_dimensions: {}", + self.period_dimensions + .iter() + .map(|d| d.full_name()) + .collect::>() + .join(", ") + ), + &state, + ); + } + if let Some(calendar_source) = self.calendar_source() { + result.println("calendar_source:", &state); + calendar_source.pretty_print(result, &state.new_level()); + } if let Some(get_date_range_multistage_ref) = self.get_date_range_multistage_ref() { result.println( &format!( @@ -63,12 +97,26 @@ impl LogicalNode for MultiStageTimeSeries { } fn inputs(&self) -> Vec { - vec![] // MultiStageTimeSeries has no inputs + self.calendar_source + .iter() + .map(|source| source.as_plan_node()) + .collect() } fn with_inputs(self: Rc, inputs: Vec) -> Result, CubeError> { - check_inputs_len(&inputs, 0, self.node_name())?; - Ok(self) + let expected = if self.calendar_source.is_some() { 1 } else { 0 }; + check_inputs_len(&inputs, expected, self.node_name())?; + if let Some(source) = inputs.into_iter().next() { + Ok(Rc::new(Self { + time_dimension: self.time_dimension.clone(), + date_range: self.date_range.clone(), + get_date_range_multistage_ref: self.get_date_range_multistage_ref.clone(), + calendar_source: Some(source.into_logical_node()?), + period_dimensions: self.period_dimensions.clone(), + })) + } else { + Ok(self) + } } fn referenced_cte_names(&self) -> Vec { diff --git a/rust/cube/cubesqlplanner/cubesqlplanner/src/physical_plan/filter/operators/filter_sql_context.rs b/rust/cube/cubesqlplanner/cubesqlplanner/src/physical_plan/filter/operators/filter_sql_context.rs index 473a5f8db9804..6784f31b998dc 100644 --- a/rust/cube/cubesqlplanner/cubesqlplanner/src/physical_plan/filter/operators/filter_sql_context.rs +++ b/rust/cube/cubesqlplanner/cubesqlplanner/src/physical_plan/filter/operators/filter_sql_context.rs @@ -182,44 +182,33 @@ impl<'a> FilterSqlContext<'a> { } pub fn date_range_from_time_series(&self) -> Result<(String, String), CubeError> { - let from_expr = format!( - "min({})", - self.plan_templates.quote_identifier("date_from")? + Ok(( + self.time_series_bound("min", "date_from")?, + self.time_series_bound("max", "date_to")?, + )) + } + + /// Scalar sub-select of `aggregate(column)` over the time series driving + /// this rolling window. + pub fn time_series_bound(&self, aggregate: &str, column: &str) -> Result { + let expr = format!( + "{}({})", + aggregate, + self.plan_templates.quote_identifier(column)? ); - let to_expr = format!("max({})", self.plan_templates.quote_identifier("date_to")?); - let from_expr = self.plan_templates.series_bounds_cast(&from_expr)?; - let to_expr = self.plan_templates.series_bounds_cast(&to_expr)?; + let expr = self.plan_templates.series_bounds_cast(&expr)?; let alias = "value".to_string(); - let time_series_cte_name = "time_series".to_string(); - let from_column = TemplateProjectionColumn { - expr: from_expr.clone(), - alias: alias.clone(), - aliased: self.plan_templates.column_aliased(&from_expr, &alias)?, - }; - let to_column = TemplateProjectionColumn { - expr: to_expr.clone(), + let projection = TemplateProjectionColumn { + expr: expr.clone(), alias: alias.clone(), - aliased: self.plan_templates.column_aliased(&to_expr, &alias)?, + aliased: self.plan_templates.column_aliased(&expr, &alias)?, }; - let from = self.plan_templates.select( - vec![], - &time_series_cte_name, - vec![from_column], - None, - vec![], - None, - vec![], - None, - None, - false, - false, - )?; - let to = self.plan_templates.select( + let select = self.plan_templates.select( vec![], - &time_series_cte_name, - vec![to_column], + "time_series", + vec![projection], None, vec![], None, @@ -229,7 +218,7 @@ impl<'a> FilterSqlContext<'a> { false, false, )?; - Ok((format!("({})", from), format!("({})", to))) + Ok(format!("({})", select)) } pub fn extend_date_range_bound( diff --git a/rust/cube/cubesqlplanner/cubesqlplanner/src/physical_plan/filter/operators/to_date_rolling_window.rs b/rust/cube/cubesqlplanner/cubesqlplanner/src/physical_plan/filter/operators/to_date_rolling_window.rs index 69ea9a7bb1144..cd1502501d9dd 100644 --- a/rust/cube/cubesqlplanner/cubesqlplanner/src/physical_plan/filter/operators/to_date_rolling_window.rs +++ b/rust/cube/cubesqlplanner/cubesqlplanner/src/physical_plan/filter/operators/to_date_rolling_window.rs @@ -1,4 +1,5 @@ use super::{FilterOperationSql, FilterSqlContext}; +use crate::physical_plan::TimeSeries; use crate::planner::filter::operators::to_date_rolling_window::ToDateRollingWindowOp; use cubenativeutils::CubeError; @@ -6,9 +7,17 @@ impl FilterOperationSql for ToDateRollingWindowOp { fn to_sql(&self, ctx: &FilterSqlContext) -> Result { let (from, to) = ctx.date_range_from_time_series()?; - let from = self - .granularity - .apply_to_input_sql(ctx.plan_templates, from)?; + // A calendar period cannot be derived from a timestamp — the series + // carries the boundary it read off the calendar cube. + let from = if self.granularity.calendar_sql().is_some() { + ctx.time_series_bound( + "min", + &TimeSeries::period_start_column(self.granularity.granularity()), + )? + } else { + self.granularity + .apply_to_input_sql(ctx.plan_templates, from)? + }; let date_field = ctx.convert_tz(ctx.member_sql())?; ctx.plan_templates.time_range_filter(date_field, from, to) diff --git a/rust/cube/cubesqlplanner/cubesqlplanner/src/physical_plan/join.rs b/rust/cube/cubesqlplanner/cubesqlplanner/src/physical_plan/join.rs index b97fb8d68cfe3..62bf279a529d7 100644 --- a/rust/cube/cubesqlplanner/cubesqlplanner/src/physical_plan/join.rs +++ b/rust/cube/cubesqlplanner/cubesqlplanner/src/physical_plan/join.rs @@ -1,4 +1,4 @@ -use super::{Expr, SingleAliasedSource, VisitorContext}; +use super::{Expr, SingleAliasedSource, TimeSeries, VisitorContext}; use crate::planner::query_tools::QueryTools; use crate::planner::sql_templates::PlanSqlTemplates; use crate::planner::{BaseJoinCondition, Granularity}; @@ -127,7 +127,17 @@ impl ToDateRollingWindowJoinCondition { templates.column_reference(&Some(self.time_series_source.clone()), "date_to")?; let date_from = templates.rolling_window_expr_timestamp_cast(&date_from)?; let date_to = templates.rolling_window_expr_timestamp_cast(&date_to)?; - let grouped_from = self.granularity.apply_to_input_sql(templates, date_from)?; + // A calendar period cannot be derived from a timestamp — the series + // carries the boundary it read off the calendar cube. + let grouped_from = if self.granularity.calendar_sql().is_some() { + let period_start = templates.column_reference( + &Some(self.time_series_source.clone()), + &TimeSeries::period_start_column(self.granularity.granularity()), + )?; + templates.rolling_window_expr_timestamp_cast(&period_start)? + } else { + self.granularity.apply_to_input_sql(templates, date_from)? + }; let result = format!("{date_column} >= {grouped_from} and {date_column} <= {date_to}"); Ok(result) } diff --git a/rust/cube/cubesqlplanner/cubesqlplanner/src/physical_plan/mod.rs b/rust/cube/cubesqlplanner/cubesqlplanner/src/physical_plan/mod.rs index a08db407095c0..db94dc96cd6b5 100644 --- a/rust/cube/cubesqlplanner/cubesqlplanner/src/physical_plan/mod.rs +++ b/rust/cube/cubesqlplanner/cubesqlplanner/src/physical_plan/mod.rs @@ -33,6 +33,6 @@ pub use references_builder::ReferencesBuilder; pub use schema::{QualifiedColumnName, Schema, SchemaColumn}; pub use select::{AliasedExpr, Select}; pub use sql_visitor::SqlEvaluatorVisitor; -pub use time_series::{TimeSeries, TimeSeriesDateRange}; +pub use time_series::{CalendarPeriodSource, TimeSeries, TimeSeriesDateRange, TimeSeriesSource}; pub use union::Union; pub use visitor_context::{evaluate_sql_call_with_context, evaluate_with_context, VisitorContext}; diff --git a/rust/cube/cubesqlplanner/cubesqlplanner/src/physical_plan/time_series.rs b/rust/cube/cubesqlplanner/cubesqlplanner/src/physical_plan/time_series.rs index 5205e40a00d9e..ffd85a8808286 100644 --- a/rust/cube/cubesqlplanner/cubesqlplanner/src/physical_plan/time_series.rs +++ b/rust/cube/cubesqlplanner/cubesqlplanner/src/physical_plan/time_series.rs @@ -1,4 +1,5 @@ -use super::{Schema, SchemaColumn}; +use super::{QueryPlan, Schema, SchemaColumn}; +use crate::planner::sql_templates::TemplateProjectionColumn; use crate::planner::{sql_templates::PlanSqlTemplates, Granularity, MemberSymbol, QueryTimeSeries}; use cubenativeutils::CubeError; use std::rc::Rc; @@ -6,7 +7,7 @@ use std::rc::Rc; pub struct TimeSeries { #[allow(dead_code)] time_dimension_name: String, - date_range: TimeSeriesDateRange, + source: TimeSeriesSource, granularity: Granularity, schema: Rc, } @@ -16,10 +17,45 @@ pub enum TimeSeriesDateRange { Generated(String), // Name of cte with min/max dates } +/// Series points read off a calendar cube, each paired with the period it falls +/// into. Bounds a `to_date` window whose granularity defines its own SQL, which +/// no interval math can reproduce. +pub struct CalendarPeriodSource { + source: Rc, + date_from_alias: String, + /// Granularity name paired with the column `source` projects it as. + period_aliases: Vec<(String, String)>, + /// The range the series is restricted to. Applied outside the select that + /// derives the period bounds, so that select still sees the period + /// following the last one in range. + range: TimeSeriesDateRange, +} + +impl CalendarPeriodSource { + pub fn new( + source: Rc, + date_from_alias: String, + period_aliases: Vec<(String, String)>, + range: TimeSeriesDateRange, + ) -> Self { + Self { + source, + date_from_alias, + period_aliases, + range, + } + } +} + +pub enum TimeSeriesSource { + Range(TimeSeriesDateRange), + Calendar(CalendarPeriodSource), +} + impl TimeSeries { pub fn new( time_dimension: &Rc, - date_range: TimeSeriesDateRange, + source: TimeSeriesSource, granularity: Granularity, ) -> Self { let column = SchemaColumn::new(format!("date_from"), Some(time_dimension.clone())); @@ -27,7 +63,7 @@ impl TimeSeries { Self { time_dimension_name: time_dimension.full_name(), granularity, - date_range, + source, schema, } } @@ -36,7 +72,18 @@ impl TimeSeries { self.schema.clone() } + /// Column the series exposes the start of `granularity`'s period as. + pub fn period_start_column(granularity: &str) -> String { + format!("date_period_start_{}", granularity) + } + pub fn to_sql(&self, templates: &PlanSqlTemplates) -> Result { + let date_range = match &self.source { + TimeSeriesSource::Calendar(calendar) => { + return self.calendar_to_sql(calendar, templates) + } + TimeSeriesSource::Range(date_range) => date_range, + }; if templates.supports_generated_time_series(self.granularity.is_predefined_granularity())? { let interval_description = templates .interval_and_minimal_time_unit(self.granularity.granularity_interval().to_sql())?; @@ -47,7 +94,7 @@ impl TimeSeries { } let interval = interval_description[0].clone(); let minimal_time_unit = interval_description[1].clone(); - match &self.date_range { + match date_range { TimeSeriesDateRange::Filter(from_date, to_date) => { let start = templates.quote_string(from_date)?; let date_field = templates.quote_identifier("d")?; @@ -83,7 +130,7 @@ impl TimeSeries { } } } else { - let (from_date, to_date, raw_from_date, raw_to_date) = match &self.date_range { + let (from_date, to_date, raw_from_date, raw_to_date) = match date_range { TimeSeriesDateRange::Filter(from_date, to_date) => ( format!("'{}'", from_date), format!("'{}'", to_date), @@ -115,4 +162,149 @@ impl TimeSeries { templates.time_series_select(from_date.clone(), to_date.clone(), series) } } + + fn calendar_to_sql( + &self, + calendar: &CalendarPeriodSource, + templates: &PlanSqlTemplates, + ) -> Result { + let bounds_alias = "calendar_series".to_string(); + let bounds = self.calendar_period_bounds_to_sql(calendar, templates, &bounds_alias)?; + + let date_from = templates.column_reference(&Some(bounds_alias.clone()), "date_from")?; + let date_to = templates.column_reference(&Some(bounds_alias.clone()), "date_to")?; + let mut columns = vec![ + Self::projection_column(templates, &date_from, "date_from")?, + Self::projection_column(templates, &date_to, "date_to")?, + ]; + for (granularity, _) in calendar.period_aliases.iter() { + let name = Self::period_start_column(granularity); + let column = templates.column_reference(&Some(bounds_alias.clone()), &name)?; + columns.push(Self::projection_column(templates, &column, &name)?); + } + + let (range_from, range_to) = match &calendar.range { + TimeSeriesDateRange::Filter(from_date, to_date) => ( + templates.time_stamp_cast(templates.quote_string(from_date)?)?, + templates.time_stamp_cast(templates.quote_string(to_date)?)?, + ), + TimeSeriesDateRange::Generated(range_cte) => ( + Self::range_cte_bound(templates, range_cte, "min_date")?, + Self::range_cte_bound(templates, range_cte, "max_date")?, + ), + }; + + templates.select( + vec![], + &templates.query_aliased(&format!("({})", bounds), &bounds_alias)?, + columns, + // Kept by overlap rather than by where it starts: the period a range + // opens inside of opens before the range does. + Some(format!( + "{date_to} >= {range_from} AND {date_from} <= {range_to}" + )), + vec![], + None, + vec![], + None, + None, + false, + false, + ) + } + + /// Pairs every point of the calendar with the end of the period it opens. + /// Deliberately unrestricted by the query range: a period ends where the + /// next one starts, so the point past the range is what bounds the last one + /// inside it. + fn calendar_period_bounds_to_sql( + &self, + calendar: &CalendarPeriodSource, + templates: &PlanSqlTemplates, + outer_alias: &str, + ) -> Result { + let interval_description = templates + .interval_and_minimal_time_unit(self.granularity.granularity_interval().to_sql())?; + if interval_description.len() != 2 { + return Err(CubeError::internal( + "Interval description must have 2 elements".to_string(), + )); + } + let interval = interval_description[0].clone(); + + let source_alias = format!("{}_source", outer_alias); + let date_from = + templates.column_reference(&Some(source_alias.clone()), &calendar.date_from_alias)?; + let date_from = templates.time_stamp_cast(date_from)?; + + let nominal_end = format!("({})", templates.add_interval(date_from.clone(), interval)?); + // Only the genuine last point of the calendar has no next period to end + // on, and a nominal interval is all that is left to bound it by. + let period_end = if self.granularity.calendar_sql().is_some() { + let next_start = templates.window_function( + &format!("LEAD({})", date_from), + "", + &format!("{} ASC", date_from), + "", + )?; + format!("COALESCE({}, {})", next_start, nominal_end) + } else { + nominal_end + }; + let date_to = templates.subtract_interval(period_end, "1 millisecond".to_string())?; + + let mut columns = vec![ + Self::projection_column(templates, &date_from, "date_from")?, + Self::projection_column(templates, &date_to, "date_to")?, + ]; + for (granularity, alias) in calendar.period_aliases.iter() { + let column = templates.column_reference(&Some(source_alias.clone()), alias)?; + columns.push(Self::projection_column( + templates, + &column, + &Self::period_start_column(granularity), + )?); + } + + templates.select( + vec![], + &templates.query_aliased( + &format!("({})", calendar.source.to_sql(templates)?), + &source_alias, + )?, + columns, + None, + vec![], + None, + vec![], + None, + None, + false, + false, + ) + } + + fn projection_column( + templates: &PlanSqlTemplates, + expr: &str, + alias: &str, + ) -> Result { + Ok(TemplateProjectionColumn { + expr: expr.to_string(), + alias: alias.to_string(), + aliased: templates.column_aliased(expr, alias)?, + }) + } + + fn range_cte_bound( + templates: &PlanSqlTemplates, + range_cte: &str, + column: &str, + ) -> Result { + Ok(format!( + "(SELECT {} FROM {})", + templates.quote_identifier(column)?, + range_cte + )) + } } diff --git a/rust/cube/cubesqlplanner/cubesqlplanner/src/physical_plan_builder/processors/multi_stage_time_series.rs b/rust/cube/cubesqlplanner/cubesqlplanner/src/physical_plan_builder/processors/multi_stage_time_series.rs index d801d51e50170..8ed4b206b41ff 100644 --- a/rust/cube/cubesqlplanner/cubesqlplanner/src/physical_plan_builder/processors/multi_stage_time_series.rs +++ b/rust/cube/cubesqlplanner/cubesqlplanner/src/physical_plan_builder/processors/multi_stage_time_series.rs @@ -1,7 +1,9 @@ use super::super::context::PushDownBuilderContext; use super::super::{LogicalNodeProcessor, ProcessableNode}; use crate::logical_plan::MultiStageTimeSeries; -use crate::physical_plan::{QueryPlan, TimeSeries, TimeSeriesDateRange}; +use crate::physical_plan::{ + CalendarPeriodSource, QueryPlan, TimeSeries, TimeSeriesDateRange, TimeSeriesSource, +}; use crate::physical_plan_builder::PhysicalPlanBuilder; use cubenativeutils::CubeError; use std::rc::Rc; @@ -19,7 +21,7 @@ impl<'a> LogicalNodeProcessor<'a, MultiStageTimeSeries> for MultiStageTimeSeries fn process( &self, time_series: &MultiStageTimeSeries, - _context: &PushDownBuilderContext, + context: &PushDownBuilderContext, ) -> Result { let (query_tools, plan_sql_templates) = self.builder.qtools_and_templates(); let time_dimension = time_series.time_dimension().clone(); @@ -34,6 +36,59 @@ impl<'a> LogicalNodeProcessor<'a, MultiStageTimeSeries> for MultiStageTimeSeries )); }; + if let Some(calendar_source) = time_series.calendar_source() { + let source = self + .builder + .process_node(calendar_source.as_ref(), context)?; + let schema = source.schema(); + let date_from_alias = schema.resolve_member_alias(&time_dimension); + let period_aliases = time_series + .period_dimensions() + .iter() + .map(|dimension| { + let Some(granularity) = dimension.as_time_dimension()?.granularity().clone() + else { + return Err(CubeError::internal(format!( + "Calendar period dimension '{}' must have a granularity", + dimension.full_name() + ))); + }; + Ok((granularity, schema.resolve_member_alias(dimension))) + }) + .collect::, CubeError>>()?; + + // Taken raw: the aligned range snaps its start to the granularity's + // interval, which for a calendar period means an arbitrary point + // inside the period the range opens in. + let range = if let Some(date_range) = &date_range { + if date_range.len() != 2 { + return Err(CubeError::user(format!( + "Invalid date range: {:?}", + date_range + ))); + } + TimeSeriesDateRange::Filter(date_range[0].clone(), date_range[1].clone()) + } else if let Some(date_range_cte) = time_series.get_date_range_multistage_ref() { + TimeSeriesDateRange::Generated(date_range_cte.clone()) + } else { + return Err(CubeError::internal( + "Date range cte is required for time series without date range".to_string(), + )); + }; + + let time_series = TimeSeries::new( + &time_dimension, + TimeSeriesSource::Calendar(CalendarPeriodSource::new( + Rc::new(QueryPlan::Select(source)), + date_from_alias, + period_aliases, + range, + )), + granularity_obj, + ); + return Ok(QueryPlan::TimeSeries(Rc::new(time_series))); + } + let ts_date_range = if plan_sql_templates .supports_generated_time_series(granularity_obj.is_predefined_granularity())? { @@ -60,7 +115,11 @@ impl<'a> LogicalNodeProcessor<'a, MultiStageTimeSeries> for MultiStageTimeSeries } }; - let time_series = TimeSeries::new(&time_dimension, ts_date_range, granularity_obj); + let time_series = TimeSeries::new( + &time_dimension, + TimeSeriesSource::Range(ts_date_range), + granularity_obj, + ); let query_plan = QueryPlan::TimeSeries(Rc::new(time_series)); Ok(query_plan) } diff --git a/rust/cube/cubesqlplanner/cubesqlplanner/src/planner/planners/multi_stage/member.rs b/rust/cube/cubesqlplanner/cubesqlplanner/src/planner/planners/multi_stage/member.rs index 044a33a07d2f7..9479ab51f1e0a 100644 --- a/rust/cube/cubesqlplanner/cubesqlplanner/src/planner/planners/multi_stage/member.rs +++ b/rust/cube/cubesqlplanner/cubesqlplanner/src/planner/planners/multi_stage/member.rs @@ -1,4 +1,5 @@ use crate::planner::{MeasureTimeShifts, MemberSymbol, MultiStageGrain}; +use std::cell::RefCell; use std::rc::Rc; /// Description of the time-series CTE driving a rolling-window @@ -8,6 +9,16 @@ use std::rc::Rc; pub struct TimeSeriesDescription { pub time_dimension: Rc, pub date_range_cte: Option, + /// Granularities of the `to_date` rolling windows driven by this series + /// whose period boundary is a calendar column rather than interval math. + /// The series carries one boundary column per granularity, and the list + /// grows as further rolling windows attach to the same series. + /// + /// Load-bearing: every description is built before any is planned, so a + /// window registering here is always visible to the series. Planning a + /// description as soon as it is built would drop the boundary columns of + /// every window registered after it. + pub calendar_period_granularities: Rc>>, } /// Kind of leaf CTE in a multi-stage chain: a base measure query, diff --git a/rust/cube/cubesqlplanner/cubesqlplanner/src/planner/planners/multi_stage/member_query_planner.rs b/rust/cube/cubesqlplanner/cubesqlplanner/src/planner/planners/multi_stage/member_query_planner.rs index f5d4849cad38e..5afa41ddaacf3 100644 --- a/rust/cube/cubesqlplanner/cubesqlplanner/src/planner/planners/multi_stage/member_query_planner.rs +++ b/rust/cube/cubesqlplanner/cubesqlplanner/src/planner/planners/multi_stage/member_query_planner.rs @@ -9,6 +9,7 @@ use crate::planner::symbols::transforms; use crate::planner::GranularityHelper; use crate::planner::MemberSymbol; use crate::planner::MultiStageGrain; +use crate::planner::TimeDimensionSymbol; use crate::planner::{OrderByItem, QueryProperties}; use cubenativeutils::CubeError; @@ -60,7 +61,7 @@ impl MultiStageMemberQueryPlanner { MultiStageMemberType::Leaf(node) => match node { super::MultiStageLeafMemberType::Measure => self.plan_for_leaf_cte_query(scope), super::MultiStageLeafMemberType::TimeSeries(time_dimension) => { - self.plan_time_series_query(time_dimension.clone()) + self.plan_time_series_query(time_dimension.clone(), scope) } super::MultiStageLeafMemberType::TimeSeriesGetRange(time_dimension) => { self.plan_time_series_get_range_query(time_dimension.clone(), scope) @@ -112,12 +113,21 @@ impl MultiStageMemberQueryPlanner { fn plan_time_series_query( &self, time_series_description: Rc, + scope: &mut PlanningScope, ) -> Result, CubeError> { let time_dimension = time_series_description.time_dimension.clone(); + let period_dimensions = self.calendar_period_dimensions(&time_series_description)?; + let calendar_source = if period_dimensions.is_empty() { + None + } else { + Some(self.plan_calendar_period_source(&time_dimension, &period_dimensions, scope)?) + }; let result = MultiStageTimeSeries::builder() .time_dimension(time_dimension.clone()) .date_range(time_dimension.as_time_dimension()?.date_range_vec()) .get_date_range_multistage_ref(time_series_description.date_range_cte.clone()) + .calendar_source(calendar_source) + .period_dimensions(period_dimensions) .build(); Ok(Rc::new(LogicalMultiStageMember { name: self.description.alias().clone(), @@ -125,6 +135,77 @@ impl MultiStageMemberQueryPlanner { })) } + /// The series time dimension re-granularized to each calendar granularity + /// a `to_date` window on this series bounds itself by. + fn calendar_period_dimensions( + &self, + time_series_description: &Rc, + ) -> Result>, CubeError> { + let time_dimension = time_series_description.time_dimension.as_time_dimension()?; + let granularities = time_series_description + .calendar_period_granularities + .borrow(); + + let evaluator_compiler_cell = self.query_tools.compiler().clone(); + let mut evaluator_compiler = evaluator_compiler_cell.borrow_mut(); + + granularities + .iter() + .map(|granularity| { + let granularity_obj = GranularityHelper::make_granularity_obj( + self.query_tools.cube_evaluator().clone(), + &mut evaluator_compiler, + &time_dimension.cube_name(), + &time_dimension.name(), + Some(granularity.clone()), + )?; + Ok(MemberSymbol::new_time_dimension(TimeDimensionSymbol::new( + time_dimension.base_symbol().clone(), + Some(granularity.clone()), + granularity_obj, + time_dimension + .date_range_vec() + .map(|range| (range[0].clone(), range[1].clone())), + ))) + }) + .collect() + } + + /// A query over the calendar cube pairing every point of the series with + /// the period it falls into, so a `to_date` window can bound itself by the + /// calendar instead of by interval math. + fn plan_calendar_period_source( + &self, + time_dimension: &Rc, + period_dimensions: &[Rc], + scope: &mut PlanningScope, + ) -> Result, CubeError> { + // The series may already be granularized to the period a window bounds + // itself by; projecting it twice makes the column ambiguous. + let mut time_dimensions = vec![time_dimension.clone()]; + for period_dimension in period_dimensions { + if !time_dimensions + .iter() + .any(|dimension| dimension.full_name() == period_dimension.full_name()) + { + time_dimensions.push(period_dimension.clone()); + } + } + + // Left unfiltered on purpose: the series restricts itself to the query + // range only after it has read each period's end off the next point. + let cte_query_properties = QueryProperties::builder() + .query_tools(self.query_tools.clone()) + .time_dimensions(time_dimensions) + .ignore_cumulative(true) + .disable_external_pre_aggregations( + self.query_properties.disable_external_pre_aggregations(), + ) + .build()?; + + SimpleQueryPlanner::new(self.query_tools.clone(), cte_query_properties).plan(scope) + } + /// Builds the rolling-window CTE that combines a time-series /// input with a measure input, dispatching on /// `RollingWindowDescription` into the regular / to-date / diff --git a/rust/cube/cubesqlplanner/cubesqlplanner/src/planner/planners/multi_stage/multi_stage_query_planner.rs b/rust/cube/cubesqlplanner/cubesqlplanner/src/planner/planners/multi_stage/multi_stage_query_planner.rs index 817ea556ff402..c885e4f8ee52b 100644 --- a/rust/cube/cubesqlplanner/cubesqlplanner/src/planner/planners/multi_stage/multi_stage_query_planner.rs +++ b/rust/cube/cubesqlplanner/cubesqlplanner/src/planner/planners/multi_stage/multi_stage_query_planner.rs @@ -30,6 +30,7 @@ use crate::planner::QueryProperties; use cubenativeutils::CubeError; use indexmap::IndexMap; use itertools::Itertools; +use std::cell::RefCell; use std::collections::HashSet; use std::rc::Rc; @@ -135,6 +136,9 @@ impl MultiStageQueryPlanner { } } + // Planning only after every description exists is load-bearing: a + // description may still be collecting requirements from its siblings, + // as a time series does from the rolling windows it drives. for descr in descriptions.into_iter() { let planner = MultiStageMemberQueryPlanner::new( self.query_tools.clone(), @@ -1003,8 +1007,15 @@ impl MultiStageQueryPlanner { Rc::new(extended) }; - let time_series = - self.add_time_series(time_dimension.clone(), state.clone(), descriptions)?; + let calendar_period_granularity = + self.calendar_to_date_granularity(&rolling_window, &time_dimension)?; + + let time_series = self.add_time_series( + time_dimension.clone(), + calendar_period_granularity, + state.clone(), + descriptions, + )?; let rolling_base = if !measure.is_multi_stage() { self.add_rolling_window_base( @@ -1116,12 +1127,22 @@ impl MultiStageQueryPlanner { fn add_time_series( &self, time_dimension: Rc, + calendar_period_granularity: Option, state: Rc, descriptions: &mut Vec>, ) -> Result, CubeError> { let description = if let Some(description) = descriptions.iter().find(|d| d.alias() == "time_series") { + // Rolling windows share one series, so a window joining an existing + // one has to register its own boundary column on it. + if let Some(granularity) = &calendar_period_granularity { + let granularities = Self::time_series_calendar_granularities(description)?; + let mut granularities = granularities.borrow_mut(); + if !granularities.contains(granularity) { + granularities.push(granularity.clone()); + } + } description.clone() } else { let get_range_query_description = if time_dimension @@ -1143,6 +1164,9 @@ impl MultiStageQueryPlanner { TimeSeriesDescription { time_dimension: time_dimension.clone(), date_range_cte: get_range_query_description.map(|d| d.alias().clone()), + calendar_period_granularities: Rc::new(RefCell::new( + calendar_period_granularity.into_iter().collect(), + )), }, ))), time_dimension.clone(), @@ -1189,6 +1213,47 @@ impl MultiStageQueryPlanner { Ok(description) } + /// The granularity of a `to_date` rolling window whose period boundary is + /// defined by a calendar column. `None` for a boundary that interval math + /// can compute on its own. + fn calendar_to_date_granularity( + &self, + rolling_window: &RollingWindow, + time_dimension: &Rc, + ) -> Result, CubeError> { + let Some(granularity) = self.get_to_date_rolling_granularity(rolling_window)? else { + return Ok(None); + }; + let time_dimension = time_dimension.as_time_dimension()?; + + let compiler_cell = self.query_tools.compiler().clone(); + let mut compiler = compiler_cell.borrow_mut(); + let granularity_obj = GranularityHelper::make_granularity_obj( + self.query_tools.cube_evaluator().clone(), + &mut compiler, + &time_dimension.cube_name(), + &time_dimension.name(), + Some(granularity.clone()), + )?; + + Ok(granularity_obj + .filter(|obj| obj.calendar_sql().is_some()) + .map(|_| granularity)) + } + + fn time_series_calendar_granularities( + description: &Rc, + ) -> Result>>, CubeError> { + match description.member().member_type() { + MultiStageMemberType::Leaf(MultiStageLeafMemberType::TimeSeries(time_series)) => { + Ok(time_series.calendar_period_granularities.clone()) + } + _ => Err(CubeError::internal( + "Time series description expected for the `time_series` cte".to_string(), + )), + } + } + /// Returns the granularity of a `to_date` rolling window. Errors /// if the window is declared as `to_date` without a granularity, /// and returns `None` for window kinds that don't carry one. diff --git a/rust/cube/cubesqlplanner/cubesqlplanner/src/planner/sql_templates/plan.rs b/rust/cube/cubesqlplanner/cubesqlplanner/src/planner/sql_templates/plan.rs index c671d13f51af0..ada460f786f07 100644 --- a/rust/cube/cubesqlplanner/cubesqlplanner/src/planner/sql_templates/plan.rs +++ b/rust/cube/cubesqlplanner/cubesqlplanner/src/planner/sql_templates/plan.rs @@ -243,6 +243,24 @@ impl PlanSqlTemplates { ) } + pub fn window_function( + &self, + fun_call: &str, + partition_by_concat: &str, + order_by_concat: &str, + window_frame: &str, + ) -> Result { + self.render.render_template( + "expressions/window_function", + context! { + fun_call => fun_call, + partition_by_concat => partition_by_concat, + order_by_concat => order_by_concat, + window_frame => window_frame, + }, + ) + } + pub fn query_aliased(&self, query: &str, alias: &str) -> Result { let quoted_alias = self.quote_identifier(alias)?; self.render.render_template( diff --git a/rust/cube/cubesqlplanner/cubesqlplanner/src/test_fixtures/schemas/yaml_files/common/integration_calendar.yaml b/rust/cube/cubesqlplanner/cubesqlplanner/src/test_fixtures/schemas/yaml_files/common/integration_calendar.yaml index 5adfd111fa52c..de7661fb063fe 100644 --- a/rust/cube/cubesqlplanner/cubesqlplanner/src/test_fixtures/schemas/yaml_files/common/integration_calendar.yaml +++ b/rust/cube/cubesqlplanner/cubesqlplanner/src/test_fixtures/schemas/yaml_files/common/integration_calendar.yaml @@ -90,6 +90,10 @@ cubes: - name: year sql: "{CUBE.retail_year_begin_date}" + # 4 or 5 weeks long, so no interval can reproduce it + - name: month + sql: "{CUBE}.retail_month_begin_date" + - name: week sql: "{CUBE.retail_week_begin_date}" @@ -223,3 +227,15 @@ cubes: sql: "{count}" time_shift: - name: one_year_common_interval + + - name: count_week_to_date + type: count + rolling_window: + type: to_date + granularity: week + + - name: count_month_to_date + type: count + rolling_window: + type: to_date + granularity: month diff --git a/rust/cube/cubesqlplanner/cubesqlplanner/src/tests/integration/calendar.rs b/rust/cube/cubesqlplanner/cubesqlplanner/src/tests/integration/calendar.rs index 82058f6832ce8..30539c6eed199 100644 --- a/rust/cube/cubesqlplanner/cubesqlplanner/src/tests/integration/calendar.rs +++ b/rust/cube/cubesqlplanner/cubesqlplanner/src/tests/integration/calendar.rs @@ -327,3 +327,163 @@ async fn test_two_named_shifts() { insta::assert_snapshot!(result); } } + +// --- to_date windows bounded by the calendar --- +// +// The retail calendar starts 2024-02-04 with 7-day weeks and 4-5-4 months, so +// month 1 runs 2024-02-04..2024-03-02, month 2 2024-03-03..2024-04-06 (35 days) +// and month 3 2024-04-07..2024-05-04. None of those lengths is reachable from a +// nominal interval anchored anywhere. + +#[tokio::test(flavor = "multi_thread")] +async fn test_to_date_retail_week_by_day() { + let ctx = create_context(); + + let query = indoc! {r#" + measures: + - calendar_orders.count_week_to_date + time_dimensions: + - dimension: custom_calendar.date_val + granularity: day + dateRange: + - "2024-02-08" + - "2024-02-18" + order: + - id: custom_calendar.date_val + "#}; + + ctx.build_sql(query).unwrap(); + + if let Some(result) = ctx.try_execute_pg(query, SEED).await { + insta::assert_snapshot!(result); + } +} + +#[tokio::test(flavor = "multi_thread")] +async fn test_to_date_retail_month_by_day() { + let ctx = create_context(); + + let query = indoc! {r#" + measures: + - calendar_orders.count_month_to_date + time_dimensions: + - dimension: custom_calendar.date_val + granularity: day + dateRange: + - "2024-02-29" + - "2024-03-09" + order: + - id: custom_calendar.date_val + "#}; + + ctx.build_sql(query).unwrap(); + + if let Some(result) = ctx.try_execute_pg(query, SEED).await { + insta::assert_snapshot!(result); + } +} + +/// A 5-week retail month grouped by itself: a nominal `1 month` upper bound +/// reaches past its end and folds the next month in. +#[tokio::test(flavor = "multi_thread")] +async fn test_to_date_retail_month_by_retail_month() { + let ctx = create_context(); + + let query = indoc! {r#" + measures: + - calendar_orders.count_month_to_date + - calendar_orders.count + time_dimensions: + - dimension: custom_calendar.date_val + granularity: month + dateRange: + - "2024-02-04" + - "2024-05-04" + order: + - id: custom_calendar.date_val + "#}; + + ctx.build_sql(query).unwrap(); + + if let Some(result) = ctx.try_execute_pg(query, SEED).await { + insta::assert_snapshot!(result); + } +} + +/// The range ends exactly where the 5-week month does, so the point that bounds +/// it lies outside the range. +#[tokio::test(flavor = "multi_thread")] +async fn test_to_date_range_ending_on_a_period_end() { + let ctx = create_context(); + + let query = indoc! {r#" + measures: + - calendar_orders.count_month_to_date + - calendar_orders.count + time_dimensions: + - dimension: custom_calendar.date_val + granularity: month + dateRange: + - "2024-03-03" + - "2024-04-06" + "#}; + + ctx.build_sql(query).unwrap(); + + if let Some(result) = ctx.try_execute_pg(query, SEED).await { + insta::assert_snapshot!(result); + } +} + +/// A range opening mid-period still has to see the period it opens inside. +#[tokio::test(flavor = "multi_thread")] +async fn test_to_date_range_opening_mid_period() { + let ctx = create_context(); + + let query = indoc! {r#" + measures: + - calendar_orders.count_month_to_date + - calendar_orders.count + time_dimensions: + - dimension: custom_calendar.date_val + granularity: month + dateRange: + - "2024-04-01" + - "2024-04-20" + order: + - id: custom_calendar.date_val + "#}; + + ctx.build_sql(query).unwrap(); + + if let Some(result) = ctx.try_execute_pg(query, SEED).await { + insta::assert_snapshot!(result); + } +} + +/// Both windows are driven by the same series, each by its own period: the +/// weekly one restarts on 2024-03-10 while the monthly one keeps accumulating. +#[tokio::test(flavor = "multi_thread")] +async fn test_to_date_week_and_month_together() { + let ctx = create_context(); + + let query = indoc! {r#" + measures: + - calendar_orders.count_week_to_date + - calendar_orders.count_month_to_date + time_dimensions: + - dimension: custom_calendar.date_val + granularity: day + dateRange: + - "2024-03-08" + - "2024-03-16" + order: + - id: custom_calendar.date_val + "#}; + + ctx.build_sql(query).unwrap(); + + if let Some(result) = ctx.try_execute_pg(query, SEED).await { + insta::assert_snapshot!(result); + } +} diff --git a/rust/cube/cubesqlplanner/cubesqlplanner/src/tests/integration/snapshots/cubesqlplanner__tests__integration__calendar__to_date_range_ending_on_a_period_end.snap b/rust/cube/cubesqlplanner/cubesqlplanner/src/tests/integration/snapshots/cubesqlplanner__tests__integration__calendar__to_date_range_ending_on_a_period_end.snap new file mode 100644 index 0000000000000..3d052f017b67d --- /dev/null +++ b/rust/cube/cubesqlplanner/cubesqlplanner/src/tests/integration/snapshots/cubesqlplanner__tests__integration__calendar__to_date_range_ending_on_a_period_end.snap @@ -0,0 +1,8 @@ +--- +source: cubesqlplanner/cubesqlplanner/src/tests/integration/calendar.rs +assertion_line: 434 +expression: result +--- +custom_calendar__date_val_month | calendar_orders__count_month_to_date | calendar_orders__count +--------------------------------+--------------------------------------+----------------------- +2024-03-03 00:00:00+00 | 5 | 5 diff --git a/rust/cube/cubesqlplanner/cubesqlplanner/src/tests/integration/snapshots/cubesqlplanner__tests__integration__calendar__to_date_range_opening_mid_period.snap b/rust/cube/cubesqlplanner/cubesqlplanner/src/tests/integration/snapshots/cubesqlplanner__tests__integration__calendar__to_date_range_opening_mid_period.snap new file mode 100644 index 0000000000000..f1eef053d39a8 --- /dev/null +++ b/rust/cube/cubesqlplanner/cubesqlplanner/src/tests/integration/snapshots/cubesqlplanner__tests__integration__calendar__to_date_range_opening_mid_period.snap @@ -0,0 +1,9 @@ +--- +source: cubesqlplanner/cubesqlplanner/src/tests/integration/calendar.rs +assertion_line: 460 +expression: result +--- +custom_calendar__date_val_month | calendar_orders__count_month_to_date | calendar_orders__count +--------------------------------+--------------------------------------+----------------------- +2024-03-03 00:00:00+00 | 5 | 1 +2024-04-07 00:00:00+00 | 4 | 1 diff --git a/rust/cube/cubesqlplanner/cubesqlplanner/src/tests/integration/snapshots/cubesqlplanner__tests__integration__calendar__to_date_retail_month_by_day.snap b/rust/cube/cubesqlplanner/cubesqlplanner/src/tests/integration/snapshots/cubesqlplanner__tests__integration__calendar__to_date_retail_month_by_day.snap new file mode 100644 index 0000000000000..aff59181c8b4c --- /dev/null +++ b/rust/cube/cubesqlplanner/cubesqlplanner/src/tests/integration/snapshots/cubesqlplanner__tests__integration__calendar__to_date_retail_month_by_day.snap @@ -0,0 +1,17 @@ +--- +source: cubesqlplanner/cubesqlplanner/src/tests/integration/calendar.rs +assertion_line: 382 +expression: result +--- +custom_calendar__date_val_day | calendar_orders__count_month_to_date +------------------------------+------------------------------------- +2024-02-29 00:00:00+00 | 3 +2024-03-01 00:00:00+00 | 3 +2024-03-02 00:00:00+00 | 3 +2024-03-03 00:00:00+00 | NULL +2024-03-04 00:00:00+00 | NULL +2024-03-05 00:00:00+00 | NULL +2024-03-06 00:00:00+00 | NULL +2024-03-07 00:00:00+00 | NULL +2024-03-08 00:00:00+00 | 1 +2024-03-09 00:00:00+00 | 1 diff --git a/rust/cube/cubesqlplanner/cubesqlplanner/src/tests/integration/snapshots/cubesqlplanner__tests__integration__calendar__to_date_retail_month_by_retail_month.snap b/rust/cube/cubesqlplanner/cubesqlplanner/src/tests/integration/snapshots/cubesqlplanner__tests__integration__calendar__to_date_retail_month_by_retail_month.snap new file mode 100644 index 0000000000000..76863b408b13e --- /dev/null +++ b/rust/cube/cubesqlplanner/cubesqlplanner/src/tests/integration/snapshots/cubesqlplanner__tests__integration__calendar__to_date_retail_month_by_retail_month.snap @@ -0,0 +1,10 @@ +--- +source: cubesqlplanner/cubesqlplanner/src/tests/integration/calendar.rs +assertion_line: 409 +expression: result +--- +custom_calendar__date_val_month | calendar_orders__count_month_to_date | calendar_orders__count +--------------------------------+--------------------------------------+----------------------- +2024-02-04 00:00:00+00 | 3 | 3 +2024-03-03 00:00:00+00 | 5 | 5 +2024-04-07 00:00:00+00 | 4 | 4 diff --git a/rust/cube/cubesqlplanner/cubesqlplanner/src/tests/integration/snapshots/cubesqlplanner__tests__integration__calendar__to_date_retail_week_by_day.snap b/rust/cube/cubesqlplanner/cubesqlplanner/src/tests/integration/snapshots/cubesqlplanner__tests__integration__calendar__to_date_retail_week_by_day.snap new file mode 100644 index 0000000000000..a0f1209f3fe24 --- /dev/null +++ b/rust/cube/cubesqlplanner/cubesqlplanner/src/tests/integration/snapshots/cubesqlplanner__tests__integration__calendar__to_date_retail_week_by_day.snap @@ -0,0 +1,18 @@ +--- +source: cubesqlplanner/cubesqlplanner/src/tests/integration/calendar.rs +assertion_line: 358 +expression: result +--- +custom_calendar__date_val_day | calendar_orders__count_week_to_date +------------------------------+------------------------------------ +2024-02-08 00:00:00+00 | 1 +2024-02-09 00:00:00+00 | 1 +2024-02-10 00:00:00+00 | 2 +2024-02-11 00:00:00+00 | NULL +2024-02-12 00:00:00+00 | NULL +2024-02-13 00:00:00+00 | NULL +2024-02-14 00:00:00+00 | NULL +2024-02-15 00:00:00+00 | NULL +2024-02-16 00:00:00+00 | NULL +2024-02-17 00:00:00+00 | 1 +2024-02-18 00:00:00+00 | NULL diff --git a/rust/cube/cubesqlplanner/cubesqlplanner/src/tests/integration/snapshots/cubesqlplanner__tests__integration__calendar__to_date_week_and_month_together.snap b/rust/cube/cubesqlplanner/cubesqlplanner/src/tests/integration/snapshots/cubesqlplanner__tests__integration__calendar__to_date_week_and_month_together.snap new file mode 100644 index 0000000000000..d606cc952b28f --- /dev/null +++ b/rust/cube/cubesqlplanner/cubesqlplanner/src/tests/integration/snapshots/cubesqlplanner__tests__integration__calendar__to_date_week_and_month_together.snap @@ -0,0 +1,16 @@ +--- +source: cubesqlplanner/cubesqlplanner/src/tests/integration/calendar.rs +assertion_line: 461 +expression: result +--- +custom_calendar__date_val_day | calendar_orders__count_week_to_date | calendar_orders__count_month_to_date +------------------------------+-------------------------------------+------------------------------------- +2024-03-08 00:00:00+00 | 1 | 1 +2024-03-09 00:00:00+00 | 1 | 1 +2024-03-10 00:00:00+00 | NULL | 1 +2024-03-11 00:00:00+00 | NULL | 1 +2024-03-12 00:00:00+00 | NULL | 1 +2024-03-13 00:00:00+00 | NULL | 1 +2024-03-14 00:00:00+00 | NULL | 1 +2024-03-15 00:00:00+00 | 1 | 2 +2024-03-16 00:00:00+00 | 1 | 2 From 1ae6452a139d227935e3b68d9c8cc9283d982d3d Mon Sep 17 00:00:00 2001 From: waralexrom <108349432+waralexrom@users.noreply.github.com> Date: Tue, 1 Sep 2026 19:57:59 +0200 Subject: [PATCH 3/5] fix(tesseract): convert a view's raw time dimension timezone only once (#11712) * fix(tesseract): convert a view's raw time dimension timezone only once A `type: time` dimension requested without a granularity was converted into the query timezone twice when it was reached through a view: the view member applied the conversion and then rendered through the owning cube's dimension, which applied it again. On BigQuery this produced `TIMESTAMP(DATETIME(TIMESTAMP(DATETIME(col, tz)), tz))`, shifting the value by the offset twice and moving timestamps across day boundaries. Gate the conversion on `owned_by_cube()`: only the cube that owns the column reads it from the database, so only there is a conversion needed. Co-Authored-By: Claude Opus 5 (1M context) * test(tesseract): address review notes on the timezone conversion tests Move the plain-cube guard next to the other raw time dimension coverage in time_dimensions.rs, leaving views.rs to the cases that involve a view. Say in the date-bound table which reading of a bare date is the consistent one, so a later change to either planner is self-explanatory. Drop an eslint suppression the file does not need. Co-Authored-By: Claude Opus 5 (1M context) * test(tesseract): pin the converted values, not just how many conversions The count says how many timezone conversions a query applies, but not where they land: moving one onto the granularity wrapper, or applying it with the offset reversed, keeps the count intact. Run the two view queries against Postgres and snapshot the rows as well, so the column the conversion lands on and the direction of the shift are pinned too. Co-Authored-By: Claude Opus 5 (1M context) * test(tesseract): let the environment pick the planner for the tz tests The suite already runs under both planners through CUBEJS_TESSERACT_SQL_PLANNER, so selecting one inside the test duplicated that coverage and made the file carry a per-planner expectation table. Write each case once and let the environment decide. The date-bound cases are dropped with the table: their expected value differs per planner, so they cannot be stated once. The bound a single-date operator picks is covered on the Rust side. Co-Authored-By: Claude Opus 5 (1M context) --------- Co-authored-by: Claude Opus 5 (1M context) --- .../unit/raw-time-dimension-timezone.test.ts | 154 ++++++++++++++++++ .../physical_plan/sql_nodes/time_dimension.rs | 8 +- ...ar_time_dimension_converted_once_each.snap | 14 ++ ...iew_raw_time_dimension_converted_once.snap | 14 ++ .../src/tests/integration/time_dimensions.rs | 20 +++ .../src/tests/integration/views.rs | 63 +++++++ 6 files changed, 272 insertions(+), 1 deletion(-) create mode 100644 packages/cubejs-schema-compiler/test/unit/raw-time-dimension-timezone.test.ts create mode 100644 rust/cube/cubesqlplanner/cubesqlplanner/src/tests/integration/snapshots/cubesqlplanner__tests__integration__views__view_raw_and_granular_time_dimension_converted_once_each.snap create mode 100644 rust/cube/cubesqlplanner/cubesqlplanner/src/tests/integration/snapshots/cubesqlplanner__tests__integration__views__view_raw_time_dimension_converted_once.snap diff --git a/packages/cubejs-schema-compiler/test/unit/raw-time-dimension-timezone.test.ts b/packages/cubejs-schema-compiler/test/unit/raw-time-dimension-timezone.test.ts new file mode 100644 index 0000000000000..d4236d46c5da5 --- /dev/null +++ b/packages/cubejs-schema-compiler/test/unit/raw-time-dimension-timezone.test.ts @@ -0,0 +1,154 @@ +import { BigqueryQuery } from '../../src/adapter/BigqueryQuery'; +import { prepareJsCompiler } from './PrepareCompiler'; + +// A `type: time` dimension asked for without a granularity is converted into the +// query timezone once. A view re-exposing that dimension is not an extra +// conversion site: the value is read (and converted) on the owning cube. +const model = [ + 'cube(\'orders\', {', + ' sql: `SELECT * FROM orders`,', + ' measures: {', + ' count: {', + ' type: `count`', + ' }', + ' },', + ' dimensions: {', + ' id: {', + ' sql: `id`,', + ' type: `number`,', + ' primaryKey: true', + ' },', + ' createdAt: {', + ' sql: `created_at`,', + ' type: `time`', + ' },', + ' updatedAt: {', + ' sql: `updated_at`,', + ' type: `time`', + ' },', + ' epochSeconds: {', + ' sql: `epoch_seconds`,', + ' type: `number`', + ' },', + // Builds a timestamp out of a non-time member: the value is composed here, + // not read from a column of this cube. + ' fromEpoch: {', + // eslint-disable-next-line no-template-curly-in-string + ' sql: `TIMESTAMP_SECONDS(${CUBE.epochSeconds})`,', + ' type: `time`', + ' }', + ' }', + '});', + '', + 'view(\'ordersView\', {', + ' cubes: [{', + ' joinPath: orders,', + ' includes: [`count`, `createdAt`, `updatedAt`, `fromEpoch`]', + ' }]', + '});', +].join('\n'); + +const TIMEZONE = 'America/Chicago'; + +async function queryFor(options = {}) { + const { compiler, joinGraph, cubeEvaluator } = prepareJsCompiler(model); + await compiler.compile(); + + return new BigqueryQuery({ joinGraph, cubeEvaluator, compiler }, { + timezone: TIMEZONE, + convertTzForRawTimeDimension: true, + ...options, + }); +} + +// BigqueryQuery.convertTz wraps the field in `TIMESTAMP(DATETIME(field, ''))`, +// so the timezone literal appears once per conversion applied to the column. +// Counting the literal rather than matching the wrapper catches nested wrapping, +// where the outer call is no longer a flat `DATETIME(, '')`. +function conversionsCount(sql: string) { + return (sql.match(new RegExp(`'${TIMEZONE}'`, 'g')) || []).length; +} + +describe('raw time dimension timezone conversion', () => { + it('converts a cube time dimension once', async () => { + const query = await queryFor({ + measures: ['orders.count'], + dimensions: ['orders.createdAt'], + }); + const [sql] = query.buildSqlAndParams(); + + expect(conversionsCount(sql)).toEqual(1); + }); + + it('converts a view time dimension once', async () => { + const query = await queryFor({ + measures: ['ordersView.count'], + dimensions: ['ordersView.createdAt'], + }); + const [sql] = query.buildSqlAndParams(); + + expect(conversionsCount(sql)).toEqual(1); + }); + + it('converts a view time dimension with granularity once', async () => { + const query = await queryFor({ + measures: ['ordersView.count'], + timeDimensions: [{ + dimension: 'ordersView.createdAt', + granularity: 'day', + }], + }); + const [sql] = query.buildSqlAndParams(); + + expect(conversionsCount(sql)).toEqual(1); + }); + + it('converts each of two view time dimensions once', async () => { + const query = await queryFor({ + measures: ['ordersView.count'], + dimensions: ['ordersView.createdAt', 'ordersView.updatedAt'], + }); + const [sql] = query.buildSqlAndParams(); + + expect(conversionsCount(sql)).toEqual(2); + }); + + // A dimension composed out of another member is not read from a column of + // its own, so there is nothing to convert at this level. + it('does not convert a dimension composed from a non-time member', async () => { + const query = await queryFor({ + measures: ['ordersView.count'], + dimensions: ['ordersView.fromEpoch'], + }); + const [sql] = query.buildSqlAndParams(); + + expect(conversionsCount(sql)).toEqual(0); + }); + + // Filter bounds are normalized to the database timezone instead, so the + // filtered column is compared as it is stored. + it('does not convert a filtered column', async () => { + const query = await queryFor({ + measures: ['ordersView.count'], + filters: [{ + member: 'ordersView.createdAt', + operator: 'afterDate', + values: ['2026-08-04'], + }], + }); + const [sql] = query.buildSqlAndParams(); + + expect(conversionsCount(sql)).toEqual(0); + }); + + it('does not convert without a timezone conversion request', async () => { + const query = await queryFor({ + measures: ['ordersView.count'], + dimensions: ['ordersView.createdAt'], + convertTzForRawTimeDimension: false, + }); + const [sql] = query.buildSqlAndParams(); + + expect(conversionsCount(sql)).toEqual(0); + }); +}); diff --git a/rust/cube/cubesqlplanner/cubesqlplanner/src/physical_plan/sql_nodes/time_dimension.rs b/rust/cube/cubesqlplanner/cubesqlplanner/src/physical_plan/sql_nodes/time_dimension.rs index 9631e7c7c827c..f898f57cd1369 100644 --- a/rust/cube/cubesqlplanner/cubesqlplanner/src/physical_plan/sql_nodes/time_dimension.rs +++ b/rust/cube/cubesqlplanner/cubesqlplanner/src/physical_plan/sql_nodes/time_dimension.rs @@ -71,9 +71,15 @@ impl SqlNode for TimeDimensionNode { } } MemberSymbol::Dimension(ev) => { + // Only the cube owning the column reads it from the database, so + // only there is a conversion needed. A dimension that merely + // references another one renders through the owning symbol, + // which converts on its own; converting here as well would + // shift the value twice. let wraps_convert_tz = !visitor.ignore_tz_convert() && query_tools.convert_tz_for_raw_time_dimension() - && ev.dimension_type() == "time"; + && ev.dimension_type() == "time" + && ev.owned_by_cube(); if wraps_convert_tz { let inner_visitor = visitor.with_arg_needs_paren_safe(false); let input_sql = self.input.to_sql( diff --git a/rust/cube/cubesqlplanner/cubesqlplanner/src/tests/integration/snapshots/cubesqlplanner__tests__integration__views__view_raw_and_granular_time_dimension_converted_once_each.snap b/rust/cube/cubesqlplanner/cubesqlplanner/src/tests/integration/snapshots/cubesqlplanner__tests__integration__views__view_raw_and_granular_time_dimension_converted_once_each.snap new file mode 100644 index 0000000000000..6ad408b845347 --- /dev/null +++ b/rust/cube/cubesqlplanner/cubesqlplanner/src/tests/integration/snapshots/cubesqlplanner__tests__integration__views__view_raw_and_granular_time_dimension_converted_once_each.snap @@ -0,0 +1,14 @@ +--- +source: cubesqlplanner/cubesqlplanner/src/tests/integration/views.rs +expression: result +--- +orders_with_customers__created_at | orders_with_customers__created_at_day | orders_with_customers__count +----------------------------------+---------------------------------------+----------------------------- +2025-03-01 04:00:00 | 2025-03-01 00:00:00 | 1 +2025-03-02 05:00:00 | 2025-03-02 00:00:00 | 1 +2025-03-03 03:00:00 | 2025-03-03 00:00:00 | 1 +2025-03-04 08:00:00 | 2025-03-04 00:00:00 | 1 +2025-03-05 04:00:00 | 2025-03-05 00:00:00 | 1 +2025-03-06 02:00:00 | 2025-03-06 00:00:00 | 1 +2025-03-07 05:00:00 | 2025-03-07 00:00:00 | 1 +2025-03-08 03:00:00 | 2025-03-08 00:00:00 | 1 diff --git a/rust/cube/cubesqlplanner/cubesqlplanner/src/tests/integration/snapshots/cubesqlplanner__tests__integration__views__view_raw_time_dimension_converted_once.snap b/rust/cube/cubesqlplanner/cubesqlplanner/src/tests/integration/snapshots/cubesqlplanner__tests__integration__views__view_raw_time_dimension_converted_once.snap new file mode 100644 index 0000000000000..1d8d23f6e3838 --- /dev/null +++ b/rust/cube/cubesqlplanner/cubesqlplanner/src/tests/integration/snapshots/cubesqlplanner__tests__integration__views__view_raw_time_dimension_converted_once.snap @@ -0,0 +1,14 @@ +--- +source: cubesqlplanner/cubesqlplanner/src/tests/integration/views.rs +expression: result +--- +orders_with_customers__created_at | orders_with_customers__count +----------------------------------+----------------------------- +2025-03-01 04:00:00 | 1 +2025-03-02 05:00:00 | 1 +2025-03-03 03:00:00 | 1 +2025-03-04 08:00:00 | 1 +2025-03-05 04:00:00 | 1 +2025-03-06 02:00:00 | 1 +2025-03-07 05:00:00 | 1 +2025-03-08 03:00:00 | 1 diff --git a/rust/cube/cubesqlplanner/cubesqlplanner/src/tests/integration/time_dimensions.rs b/rust/cube/cubesqlplanner/cubesqlplanner/src/tests/integration/time_dimensions.rs index f6a51d3a1e2a4..26d0878a60671 100644 --- a/rust/cube/cubesqlplanner/cubesqlplanner/src/tests/integration/time_dimensions.rs +++ b/rust/cube/cubesqlplanner/cubesqlplanner/src/tests/integration/time_dimensions.rs @@ -388,3 +388,23 @@ async fn test_convert_tz_for_raw_time_dimensions() { insta::assert_snapshot!(result); } } + +// The conversion belongs to the cube that owns the column, and stays there when +// the dimension is asked for without a granularity. +#[test] +fn test_raw_time_dimension_converted_once() { + let ctx = create_context(); + + let sql = ctx + .build_sql(indoc! {" + measures: + - orders.count + dimensions: + - orders.created_at + timezone: \"America/Chicago\" + convert_tz_for_raw_time_dimension: true + "}) + .unwrap(); + + assert_eq!(sql.matches("AT TIME ZONE").count(), 1, "got: {sql}"); +} diff --git a/rust/cube/cubesqlplanner/cubesqlplanner/src/tests/integration/views.rs b/rust/cube/cubesqlplanner/cubesqlplanner/src/tests/integration/views.rs index 2f9e4d0e68a4b..cfabec9484f30 100644 --- a/rust/cube/cubesqlplanner/cubesqlplanner/src/tests/integration/views.rs +++ b/rust/cube/cubesqlplanner/cubesqlplanner/src/tests/integration/views.rs @@ -201,3 +201,66 @@ async fn test_view_ungrouped() { insta::assert_snapshot!(result); } } + +fn tz_conversions_count(sql: &str) -> usize { + sql.matches("AT TIME ZONE").count() +} + +fn raw_time_dimension_query(members_yaml: &str) -> String { + format!( + indoc! {" + {}timezone: \"America/Chicago\" + convert_tz_for_raw_time_dimension: true + "}, + members_yaml + ) +} + +// A `type: time` dimension asked for without a granularity is converted into the +// query timezone once. A view re-exposing such a dimension is not a second +// conversion site: the value is read, and converted, on the owning cube. +// +// The count pins how many conversions the query applies; the result pins that +// they land on the column, with the offset going the right way. +#[tokio::test(flavor = "multi_thread")] +async fn test_view_raw_time_dimension_converted_once() { + let ctx = create_context(); + let query = raw_time_dimension_query(indoc! {" + measures: + - orders_with_customers.count + dimensions: + - orders_with_customers.created_at + order: + - id: orders_with_customers.created_at + "}); + + let sql = ctx.build_sql(&query).unwrap(); + assert_eq!(tz_conversions_count(&sql), 1, "got: {sql}"); + + if let Some(result) = ctx.try_execute_pg(&query, SEED).await { + insta::assert_snapshot!(result); + } +} + +#[tokio::test(flavor = "multi_thread")] +async fn test_view_raw_and_granular_time_dimension_converted_once_each() { + let ctx = create_context(); + let query = raw_time_dimension_query(indoc! {" + measures: + - orders_with_customers.count + dimensions: + - orders_with_customers.created_at + time_dimensions: + - dimension: orders_with_customers.created_at + granularity: day + order: + - id: orders_with_customers.created_at + "}); + + let sql = ctx.build_sql(&query).unwrap(); + assert_eq!(tz_conversions_count(&sql), 2, "got: {sql}"); + + if let Some(result) = ctx.try_execute_pg(&query, SEED).await { + insta::assert_snapshot!(result); + } +} From 8f2ae29ebad5975a7cefeae4461ad08f68f1b859 Mon Sep 17 00:00:00 2001 From: Dmitry Patsura Date: Tue, 1 Sep 2026 20:02:05 +0200 Subject: [PATCH 4/5] v1.7.32 --- CHANGELOG.md | 9 +++ lerna.json | 2 +- packages/cubejs-api-gateway/CHANGELOG.md | 4 ++ packages/cubejs-api-gateway/package.json | 10 ++-- packages/cubejs-athena-driver/CHANGELOG.md | 4 ++ packages/cubejs-athena-driver/package.json | 10 ++-- packages/cubejs-backend-cloud/CHANGELOG.md | 4 ++ packages/cubejs-backend-cloud/package.json | 6 +- packages/cubejs-backend-maven/CHANGELOG.md | 4 ++ packages/cubejs-backend-maven/package.json | 6 +- packages/cubejs-backend-native/CHANGELOG.md | 4 ++ packages/cubejs-backend-native/package.json | 8 +-- packages/cubejs-backend-shared/CHANGELOG.md | 4 ++ packages/cubejs-backend-shared/package.json | 4 +- packages/cubejs-base-driver/CHANGELOG.md | 4 ++ packages/cubejs-base-driver/package.json | 6 +- packages/cubejs-bigquery-driver/CHANGELOG.md | 4 ++ packages/cubejs-bigquery-driver/package.json | 8 +-- packages/cubejs-cli/CHANGELOG.md | 4 ++ packages/cubejs-cli/package.json | 12 ++-- .../cubejs-clickhouse-driver/CHANGELOG.md | 4 ++ .../cubejs-clickhouse-driver/package.json | 10 ++-- packages/cubejs-client-core/CHANGELOG.md | 4 ++ packages/cubejs-client-core/package.json | 4 +- packages/cubejs-client-dx/CHANGELOG.md | 4 ++ packages/cubejs-client-dx/package.json | 2 +- packages/cubejs-client-ngx/CHANGELOG.md | 4 ++ packages/cubejs-client-ngx/package.json | 2 +- packages/cubejs-client-react/CHANGELOG.md | 4 ++ packages/cubejs-client-react/package.json | 4 +- packages/cubejs-client-vue3/CHANGELOG.md | 4 ++ packages/cubejs-client-vue3/package.json | 4 +- .../cubejs-client-ws-transport/CHANGELOG.md | 4 ++ .../cubejs-client-ws-transport/package.json | 6 +- packages/cubejs-crate-driver/CHANGELOG.md | 4 ++ packages/cubejs-crate-driver/package.json | 10 ++-- packages/cubejs-cubestore-driver/CHANGELOG.md | 4 ++ packages/cubejs-cubestore-driver/package.json | 12 ++-- .../CHANGELOG.md | 4 ++ .../package.json | 12 ++-- .../cubejs-dbt-schema-extension/CHANGELOG.md | 4 ++ .../cubejs-dbt-schema-extension/package.json | 8 +-- packages/cubejs-docker/CHANGELOG.md | 4 ++ packages/cubejs-docker/package.json | 58 +++++++++---------- packages/cubejs-dremio-driver/CHANGELOG.md | 4 ++ packages/cubejs-dremio-driver/package.json | 12 ++-- packages/cubejs-druid-driver/CHANGELOG.md | 4 ++ packages/cubejs-druid-driver/package.json | 10 ++-- packages/cubejs-duckdb-driver/CHANGELOG.md | 4 ++ packages/cubejs-duckdb-driver/package.json | 12 ++-- packages/cubejs-firebolt-driver/CHANGELOG.md | 4 ++ packages/cubejs-firebolt-driver/package.json | 12 ++-- packages/cubejs-hive-driver/CHANGELOG.md | 4 ++ packages/cubejs-hive-driver/package.json | 8 +-- packages/cubejs-jdbc-driver/CHANGELOG.md | 4 ++ packages/cubejs-jdbc-driver/package.json | 8 +-- packages/cubejs-ksql-driver/CHANGELOG.md | 4 ++ packages/cubejs-ksql-driver/package.json | 10 ++-- packages/cubejs-linter/CHANGELOG.md | 4 ++ packages/cubejs-linter/package.json | 2 +- .../cubejs-materialize-driver/CHANGELOG.md | 4 ++ .../cubejs-materialize-driver/package.json | 12 ++-- packages/cubejs-mongobi-driver/CHANGELOG.md | 4 ++ packages/cubejs-mongobi-driver/package.json | 8 +-- packages/cubejs-mssql-driver/CHANGELOG.md | 4 ++ packages/cubejs-mssql-driver/package.json | 6 +- .../CHANGELOG.md | 4 ++ .../package.json | 8 +-- packages/cubejs-mysql-driver/CHANGELOG.md | 4 ++ packages/cubejs-mysql-driver/package.json | 10 ++-- packages/cubejs-oracle-driver/CHANGELOG.md | 4 ++ packages/cubejs-oracle-driver/package.json | 6 +- packages/cubejs-pinot-driver/CHANGELOG.md | 4 ++ packages/cubejs-pinot-driver/package.json | 10 ++-- packages/cubejs-playground/CHANGELOG.md | 4 ++ packages/cubejs-playground/package.json | 6 +- packages/cubejs-postgres-driver/CHANGELOG.md | 4 ++ packages/cubejs-postgres-driver/package.json | 10 ++-- packages/cubejs-prestodb-driver/CHANGELOG.md | 4 ++ packages/cubejs-prestodb-driver/package.json | 8 +-- .../cubejs-query-orchestrator/CHANGELOG.md | 6 ++ .../cubejs-query-orchestrator/package.json | 10 ++-- packages/cubejs-questdb-driver/CHANGELOG.md | 4 ++ packages/cubejs-questdb-driver/package.json | 12 ++-- packages/cubejs-redshift-driver/CHANGELOG.md | 4 ++ packages/cubejs-redshift-driver/package.json | 10 ++-- packages/cubejs-schema-compiler/CHANGELOG.md | 8 +++ packages/cubejs-schema-compiler/package.json | 12 ++-- packages/cubejs-server-core/CHANGELOG.md | 4 ++ packages/cubejs-server-core/package.json | 24 ++++---- packages/cubejs-server/CHANGELOG.md | 4 ++ packages/cubejs-server/package.json | 14 ++--- packages/cubejs-snowflake-driver/CHANGELOG.md | 4 ++ packages/cubejs-snowflake-driver/package.json | 8 +-- packages/cubejs-sqlite-driver/CHANGELOG.md | 4 ++ packages/cubejs-sqlite-driver/package.json | 8 +-- packages/cubejs-templates/CHANGELOG.md | 4 ++ packages/cubejs-templates/package.json | 6 +- packages/cubejs-testing-drivers/CHANGELOG.md | 4 ++ packages/cubejs-testing-drivers/package.json | 46 +++++++-------- packages/cubejs-testing-shared/CHANGELOG.md | 4 ++ packages/cubejs-testing-shared/package.json | 10 ++-- packages/cubejs-testing/CHANGELOG.md | 4 ++ packages/cubejs-testing/package.json | 22 +++---- packages/cubejs-trino-driver/CHANGELOG.md | 4 ++ packages/cubejs-trino-driver/package.json | 12 ++-- packages/cubejs-vertica-driver/CHANGELOG.md | 4 ++ packages/cubejs-vertica-driver/package.json | 14 ++--- rust/cubesql/CHANGELOG.md | 4 ++ rust/cubesql/package.json | 2 +- rust/cubestore/CHANGELOG.md | 4 ++ rust/cubestore/Cargo.lock | 2 +- rust/cubestore/cubestore/Cargo.toml | 2 +- rust/cubestore/package.json | 6 +- 114 files changed, 526 insertions(+), 291 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c9d34b6ea6223..8c6d69999a331 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,15 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +### Bug Fixes + +- **query-orchestrator:** keep Interactive priority on user query paths ([#11715](https://github.com/cube-js/cube/issues/11715)) ([39d3b20](https://github.com/cube-js/cube/commit/39d3b20d114d6003562e0cdad0e98389056bb3a5)) +- **tesseract:** calendar sql granularities crash every query; to_date ignores the calendar ([#11709](https://github.com/cube-js/cube/issues/11709)) ([4029495](https://github.com/cube-js/cube/commit/4029495feb0cadfee20c56f565d94430852f5b27)) +- **tesseract:** compose grain.include with rolling_window ([#11639](https://github.com/cube-js/cube/issues/11639)) ([9d3dd45](https://github.com/cube-js/cube/commit/9d3dd45814a7fec41b6c4e23233f38bd7a1af1c2)) +- **tesseract:** convert a view's raw time dimension timezone only once ([#11712](https://github.com/cube-js/cube/issues/11712)) ([1ae6452](https://github.com/cube-js/cube/commit/1ae6452a139d227935e3b68d9c8cc9283d982d3d)) + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) ### Bug Fixes diff --git a/lerna.json b/lerna.json index c47c3b5eccfaa..7ddf6945bc0c2 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "1.7.31", + "version": "1.7.32", "npmClient": "yarn", "command": { "bootstrap": { diff --git a/packages/cubejs-api-gateway/CHANGELOG.md b/packages/cubejs-api-gateway/CHANGELOG.md index 2ced4fa35f090..903bf07b7fcfc 100644 --- a/packages/cubejs-api-gateway/CHANGELOG.md +++ b/packages/cubejs-api-gateway/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-backend/api-gateway + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) **Note:** Version bump only for package @cubejs-backend/api-gateway diff --git a/packages/cubejs-api-gateway/package.json b/packages/cubejs-api-gateway/package.json index 67e0d0ac3c65d..2d4f7578a2b2a 100644 --- a/packages/cubejs-api-gateway/package.json +++ b/packages/cubejs-api-gateway/package.json @@ -2,7 +2,7 @@ "name": "@cubejs-backend/api-gateway", "description": "Cube API Gateway", "author": "Cube Dev, Inc.", - "version": "1.7.31", + "version": "1.7.32", "repository": { "type": "git", "url": "https://github.com/cube-js/cube.git", @@ -27,9 +27,9 @@ "dist/src/*" ], "dependencies": { - "@cubejs-backend/native": "1.7.31", - "@cubejs-backend/query-orchestrator": "1.7.31", - "@cubejs-backend/shared": "1.7.31", + "@cubejs-backend/native": "1.7.32", + "@cubejs-backend/query-orchestrator": "1.7.32", + "@cubejs-backend/shared": "1.7.32", "@ungap/structured-clone": "^0.3.4", "assert-never": "^1.4.0", "body-parser": "^1.19.0", @@ -53,7 +53,7 @@ "zod": "^4.1.13" }, "devDependencies": { - "@cubejs-backend/linter": "1.7.31", + "@cubejs-backend/linter": "1.7.32", "@types/express": "^4.17.21", "@types/jest": "^29", "@types/jsonwebtoken": "^9.0.2", diff --git a/packages/cubejs-athena-driver/CHANGELOG.md b/packages/cubejs-athena-driver/CHANGELOG.md index 33bf14e29dd0b..e4731f0819c03 100644 --- a/packages/cubejs-athena-driver/CHANGELOG.md +++ b/packages/cubejs-athena-driver/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-backend/athena-driver + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) **Note:** Version bump only for package @cubejs-backend/athena-driver diff --git a/packages/cubejs-athena-driver/package.json b/packages/cubejs-athena-driver/package.json index 9625fed3494c2..9df08bb211a3b 100644 --- a/packages/cubejs-athena-driver/package.json +++ b/packages/cubejs-athena-driver/package.json @@ -2,7 +2,7 @@ "name": "@cubejs-backend/athena-driver", "description": "Cube.js Athena database driver", "author": "Cube Dev, Inc.", - "version": "1.7.31", + "version": "1.7.32", "repository": { "type": "git", "url": "https://github.com/cube-js/cube.git", @@ -31,12 +31,12 @@ "dependencies": { "@aws-sdk/client-athena": "^3.22.0", "@aws-sdk/credential-providers": "^3.22.0", - "@cubejs-backend/base-driver": "1.7.31", - "@cubejs-backend/shared": "1.7.31" + "@cubejs-backend/base-driver": "1.7.32", + "@cubejs-backend/shared": "1.7.32" }, "devDependencies": { - "@cubejs-backend/linter": "1.7.31", - "@cubejs-backend/testing-shared": "1.7.31", + "@cubejs-backend/linter": "1.7.32", + "@cubejs-backend/testing-shared": "1.7.32", "@types/ramda": "^0.27.40", "typescript": "~5.2.2" }, diff --git a/packages/cubejs-backend-cloud/CHANGELOG.md b/packages/cubejs-backend-cloud/CHANGELOG.md index 106dfe6c4bedc..6e264c687486c 100644 --- a/packages/cubejs-backend-cloud/CHANGELOG.md +++ b/packages/cubejs-backend-cloud/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-backend/cloud + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) **Note:** Version bump only for package @cubejs-backend/cloud diff --git a/packages/cubejs-backend-cloud/package.json b/packages/cubejs-backend-cloud/package.json index fcff9a30e3a15..f31a00b403263 100644 --- a/packages/cubejs-backend-cloud/package.json +++ b/packages/cubejs-backend-cloud/package.json @@ -1,6 +1,6 @@ { "name": "@cubejs-backend/cloud", - "version": "1.7.31", + "version": "1.7.32", "description": "Cube Cloud package", "main": "dist/src/index.js", "typings": "dist/src/index.d.ts", @@ -30,7 +30,7 @@ "devDependencies": { "@babel/core": "^7.24.5", "@babel/preset-env": "^7.24.5", - "@cubejs-backend/linter": "1.7.31", + "@cubejs-backend/linter": "1.7.32", "@types/fs-extra": "^9.0.8", "@types/jest": "^29", "jest": "^29", @@ -38,7 +38,7 @@ }, "dependencies": { "@cubejs-backend/dotenv": "^9.0.2", - "@cubejs-backend/shared": "1.7.31", + "@cubejs-backend/shared": "1.7.32", "chokidar": "^3.5.1", "env-var": "^6.3.0", "form-data": "^4.0.0", diff --git a/packages/cubejs-backend-maven/CHANGELOG.md b/packages/cubejs-backend-maven/CHANGELOG.md index 8e7599f08b22e..51784717a8e94 100644 --- a/packages/cubejs-backend-maven/CHANGELOG.md +++ b/packages/cubejs-backend-maven/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-backend/maven + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) **Note:** Version bump only for package @cubejs-backend/maven diff --git a/packages/cubejs-backend-maven/package.json b/packages/cubejs-backend-maven/package.json index 73af82480e1fe..cc1d516ed2c9f 100644 --- a/packages/cubejs-backend-maven/package.json +++ b/packages/cubejs-backend-maven/package.json @@ -2,7 +2,7 @@ "name": "@cubejs-backend/maven", "description": "Cube.js Maven Wrapper for java dependencies downloading", "author": "Cube Dev, Inc.", - "version": "1.7.31", + "version": "1.7.32", "license": "Apache-2.0", "repository": { "type": "git", @@ -31,12 +31,12 @@ "dist/src/*" ], "dependencies": { - "@cubejs-backend/shared": "1.7.31", + "@cubejs-backend/shared": "1.7.32", "source-map-support": "^0.5.19", "xmlbuilder2": "^2.4.0" }, "devDependencies": { - "@cubejs-backend/linter": "1.7.31", + "@cubejs-backend/linter": "1.7.32", "@types/jest": "^29", "@types/node": "^22", "jest": "^29", diff --git a/packages/cubejs-backend-native/CHANGELOG.md b/packages/cubejs-backend-native/CHANGELOG.md index 32cc71c63dfb6..1e1e5b9adda28 100644 --- a/packages/cubejs-backend-native/CHANGELOG.md +++ b/packages/cubejs-backend-native/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-backend/native + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) **Note:** Version bump only for package @cubejs-backend/native diff --git a/packages/cubejs-backend-native/package.json b/packages/cubejs-backend-native/package.json index b35df0ff223b4..4b5d97f45e240 100644 --- a/packages/cubejs-backend-native/package.json +++ b/packages/cubejs-backend-native/package.json @@ -1,6 +1,6 @@ { "name": "@cubejs-backend/native", - "version": "1.7.31", + "version": "1.7.32", "author": "Cube Dev, Inc.", "description": "Native module for Cube.js (binding to Rust codebase)", "main": "dist/js/index.js", @@ -39,7 +39,7 @@ "dist/js" ], "devDependencies": { - "@cubejs-backend/linter": "1.7.31", + "@cubejs-backend/linter": "1.7.32", "@types/jest": "^29", "@types/node": "^22", "cargo-cp-artifact": "^0.1.9", @@ -50,8 +50,8 @@ "uuid": "^11.1.1" }, "dependencies": { - "@cubejs-backend/cubesql": "1.7.31", - "@cubejs-backend/shared": "1.7.31", + "@cubejs-backend/cubesql": "1.7.32", + "@cubejs-backend/shared": "1.7.32", "@cubejs-infra/post-installer": "^0.1.2" }, "resources": { diff --git a/packages/cubejs-backend-shared/CHANGELOG.md b/packages/cubejs-backend-shared/CHANGELOG.md index 15c8089bc3bf9..1571ab31316c4 100644 --- a/packages/cubejs-backend-shared/CHANGELOG.md +++ b/packages/cubejs-backend-shared/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-backend/shared + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) ### Features diff --git a/packages/cubejs-backend-shared/package.json b/packages/cubejs-backend-shared/package.json index 139dc874ca9ae..93dfee5a3d519 100644 --- a/packages/cubejs-backend-shared/package.json +++ b/packages/cubejs-backend-shared/package.json @@ -1,6 +1,6 @@ { "name": "@cubejs-backend/shared", - "version": "1.7.31", + "version": "1.7.32", "description": "Shared code for Cube.js backend packages", "main": "dist/src/index.js", "typings": "dist/src/index.d.ts", @@ -27,7 +27,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@cubejs-backend/linter": "1.7.31", + "@cubejs-backend/linter": "1.7.32", "@types/bytes": "^3.1.5", "@types/cli-progress": "^3.9.1", "@types/jest": "^29", diff --git a/packages/cubejs-base-driver/CHANGELOG.md b/packages/cubejs-base-driver/CHANGELOG.md index 66c2dbbcc3cc8..0fe949a2c0d2a 100644 --- a/packages/cubejs-base-driver/CHANGELOG.md +++ b/packages/cubejs-base-driver/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-backend/base-driver + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) **Note:** Version bump only for package @cubejs-backend/base-driver diff --git a/packages/cubejs-base-driver/package.json b/packages/cubejs-base-driver/package.json index ff861a150058b..338ddaa4e4810 100644 --- a/packages/cubejs-base-driver/package.json +++ b/packages/cubejs-base-driver/package.json @@ -2,7 +2,7 @@ "name": "@cubejs-backend/base-driver", "description": "Cube.js Base Driver", "author": "Cube Dev, Inc.", - "version": "1.7.31", + "version": "1.7.32", "repository": { "type": "git", "url": "https://github.com/cube-js/cube.git", @@ -33,11 +33,11 @@ "@aws-sdk/s3-request-presigner": "^3.49.0", "@azure/identity": "^4.4.1", "@azure/storage-blob": "^12.9.0", - "@cubejs-backend/shared": "1.7.31", + "@cubejs-backend/shared": "1.7.32", "@google-cloud/storage": "^7.13.0" }, "devDependencies": { - "@cubejs-backend/linter": "1.7.31", + "@cubejs-backend/linter": "1.7.32", "@types/jest": "^29", "@types/node": "^22", "jest": "^29", diff --git a/packages/cubejs-bigquery-driver/CHANGELOG.md b/packages/cubejs-bigquery-driver/CHANGELOG.md index 139d01837c5a5..688d8347078fd 100644 --- a/packages/cubejs-bigquery-driver/CHANGELOG.md +++ b/packages/cubejs-bigquery-driver/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-backend/bigquery-driver + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) **Note:** Version bump only for package @cubejs-backend/bigquery-driver diff --git a/packages/cubejs-bigquery-driver/package.json b/packages/cubejs-bigquery-driver/package.json index 91e7e1470eef2..6169dd6ccc982 100644 --- a/packages/cubejs-bigquery-driver/package.json +++ b/packages/cubejs-bigquery-driver/package.json @@ -2,7 +2,7 @@ "name": "@cubejs-backend/bigquery-driver", "description": "Cube.js BigQuery database driver", "author": "Cube Dev, Inc.", - "version": "1.7.31", + "version": "1.7.32", "repository": { "type": "git", "url": "https://github.com/cube-js/cube.git", @@ -29,15 +29,15 @@ "main": "index.js", "types": "dist/src/index.d.ts", "dependencies": { - "@cubejs-backend/base-driver": "1.7.31", + "@cubejs-backend/base-driver": "1.7.32", "@cubejs-backend/dotenv": "^9.0.2", - "@cubejs-backend/shared": "1.7.31", + "@cubejs-backend/shared": "1.7.32", "@google-cloud/bigquery": "^7.7.0", "@google-cloud/storage": "^7.13.0", "ramda": "^0.27.2" }, "devDependencies": { - "@cubejs-backend/testing-shared": "1.7.31", + "@cubejs-backend/testing-shared": "1.7.32", "@types/big.js": "^6.2.2", "@types/dedent": "^0.7.0", "@types/jest": "^29", diff --git a/packages/cubejs-cli/CHANGELOG.md b/packages/cubejs-cli/CHANGELOG.md index d9b282f6e2354..4298e8dc205e4 100644 --- a/packages/cubejs-cli/CHANGELOG.md +++ b/packages/cubejs-cli/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package cubejs-cli + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) **Note:** Version bump only for package cubejs-cli diff --git a/packages/cubejs-cli/package.json b/packages/cubejs-cli/package.json index d4e5385c41874..90111ec05666f 100644 --- a/packages/cubejs-cli/package.json +++ b/packages/cubejs-cli/package.json @@ -2,7 +2,7 @@ "name": "cubejs-cli", "description": "Cube.js Command Line Interface", "author": "Cube Dev, Inc.", - "version": "1.7.31", + "version": "1.7.32", "repository": { "type": "git", "url": "https://github.com/cube-js/cube.git", @@ -30,10 +30,10 @@ "LICENSE" ], "dependencies": { - "@cubejs-backend/cloud": "1.7.31", + "@cubejs-backend/cloud": "1.7.32", "@cubejs-backend/dotenv": "^9.0.2", - "@cubejs-backend/schema-compiler": "1.7.31", - "@cubejs-backend/shared": "1.7.31", + "@cubejs-backend/schema-compiler": "1.7.32", + "@cubejs-backend/shared": "1.7.32", "chalk": "^2.4.2", "cli-progress": "^3.10", "commander": "^2.19.0", @@ -50,8 +50,8 @@ "colors": "1.4.0" }, "devDependencies": { - "@cubejs-backend/linter": "1.7.31", - "@cubejs-backend/server": "1.7.31", + "@cubejs-backend/linter": "1.7.32", + "@cubejs-backend/server": "1.7.32", "@oclif/command": "^1.8.0", "@types/cli-progress": "^3.8.0", "@types/cross-spawn": "^6.0.2", diff --git a/packages/cubejs-clickhouse-driver/CHANGELOG.md b/packages/cubejs-clickhouse-driver/CHANGELOG.md index 925759cf0a0b3..b2ed9502e2184 100644 --- a/packages/cubejs-clickhouse-driver/CHANGELOG.md +++ b/packages/cubejs-clickhouse-driver/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-backend/clickhouse-driver + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) **Note:** Version bump only for package @cubejs-backend/clickhouse-driver diff --git a/packages/cubejs-clickhouse-driver/package.json b/packages/cubejs-clickhouse-driver/package.json index 0dea34959f94f..bab6cee56d30e 100644 --- a/packages/cubejs-clickhouse-driver/package.json +++ b/packages/cubejs-clickhouse-driver/package.json @@ -2,7 +2,7 @@ "name": "@cubejs-backend/clickhouse-driver", "description": "Cube.js ClickHouse database driver", "author": "Cube Dev, Inc.", - "version": "1.7.31", + "version": "1.7.32", "repository": { "type": "git", "url": "https://github.com/cube-js/cube.git", @@ -29,16 +29,16 @@ }, "dependencies": { "@clickhouse/client": "^1.12.0", - "@cubejs-backend/base-driver": "1.7.31", - "@cubejs-backend/shared": "1.7.31", + "@cubejs-backend/base-driver": "1.7.32", + "@cubejs-backend/shared": "1.7.32", "moment": "^2.24.0", "sqlstring": "^2.3.1", "uuid": "^11.1.1" }, "license": "Apache-2.0", "devDependencies": { - "@cubejs-backend/linter": "1.7.31", - "@cubejs-backend/testing-shared": "1.7.31", + "@cubejs-backend/linter": "1.7.32", + "@cubejs-backend/testing-shared": "1.7.32", "@types/jest": "^29", "jest": "^29", "typescript": "~5.2.2" diff --git a/packages/cubejs-client-core/CHANGELOG.md b/packages/cubejs-client-core/CHANGELOG.md index a65cfdace21e7..c8679dbea86da 100644 --- a/packages/cubejs-client-core/CHANGELOG.md +++ b/packages/cubejs-client-core/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-client/core + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) **Note:** Version bump only for package @cubejs-client/core diff --git a/packages/cubejs-client-core/package.json b/packages/cubejs-client-core/package.json index b463365078b3d..879cc60d3ea99 100644 --- a/packages/cubejs-client-core/package.json +++ b/packages/cubejs-client-core/package.json @@ -1,6 +1,6 @@ { "name": "@cubejs-client/core", - "version": "1.7.31", + "version": "1.7.32", "engines": {}, "type": "module", "repository": { @@ -58,7 +58,7 @@ ], "license": "MIT", "devDependencies": { - "@cubejs-backend/linter": "1.7.31", + "@cubejs-backend/linter": "1.7.32", "@types/d3-format": "^3", "@types/d3-time-format": "^4", "@types/moment-range": "^4.0.0", diff --git a/packages/cubejs-client-dx/CHANGELOG.md b/packages/cubejs-client-dx/CHANGELOG.md index 9e0c2aa9b541d..f5e6be6de953e 100644 --- a/packages/cubejs-client-dx/CHANGELOG.md +++ b/packages/cubejs-client-dx/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-client/dx + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) **Note:** Version bump only for package @cubejs-client/dx diff --git a/packages/cubejs-client-dx/package.json b/packages/cubejs-client-dx/package.json index 67f3c4f3e5c29..e784dd94aabdd 100644 --- a/packages/cubejs-client-dx/package.json +++ b/packages/cubejs-client-dx/package.json @@ -1,6 +1,6 @@ { "name": "@cubejs-client/dx", - "version": "1.7.31", + "version": "1.7.32", "engines": {}, "repository": { "type": "git", diff --git a/packages/cubejs-client-ngx/CHANGELOG.md b/packages/cubejs-client-ngx/CHANGELOG.md index e0e880e5ba75e..87be39440a148 100644 --- a/packages/cubejs-client-ngx/CHANGELOG.md +++ b/packages/cubejs-client-ngx/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-client/ngx + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) **Note:** Version bump only for package @cubejs-client/ngx diff --git a/packages/cubejs-client-ngx/package.json b/packages/cubejs-client-ngx/package.json index 9d30fe40451d2..4e50b6a0592df 100644 --- a/packages/cubejs-client-ngx/package.json +++ b/packages/cubejs-client-ngx/package.json @@ -1,6 +1,6 @@ { "name": "@cubejs-client/ngx", - "version": "1.7.31", + "version": "1.7.32", "author": "Cube Dev, Inc.", "engines": {}, "repository": { diff --git a/packages/cubejs-client-react/CHANGELOG.md b/packages/cubejs-client-react/CHANGELOG.md index f8ffa5c5a3437..8ac4b985fd878 100644 --- a/packages/cubejs-client-react/CHANGELOG.md +++ b/packages/cubejs-client-react/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-client/react + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) **Note:** Version bump only for package @cubejs-client/react diff --git a/packages/cubejs-client-react/package.json b/packages/cubejs-client-react/package.json index b097d34e744d6..d081a7238cd61 100644 --- a/packages/cubejs-client-react/package.json +++ b/packages/cubejs-client-react/package.json @@ -1,6 +1,6 @@ { "name": "@cubejs-client/react", - "version": "1.7.31", + "version": "1.7.32", "author": "Cube Dev, Inc.", "license": "MIT", "engines": {}, @@ -26,7 +26,7 @@ ], "dependencies": { "@babel/runtime": "^7.1.2", - "@cubejs-client/core": "1.7.31", + "@cubejs-client/core": "1.7.32", "core-js": "^3.6.5", "ramda": "^0.27.2" }, diff --git a/packages/cubejs-client-vue3/CHANGELOG.md b/packages/cubejs-client-vue3/CHANGELOG.md index d20041878ee3d..7166ce797b8eb 100644 --- a/packages/cubejs-client-vue3/CHANGELOG.md +++ b/packages/cubejs-client-vue3/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-client/vue3 + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) **Note:** Version bump only for package @cubejs-client/vue3 diff --git a/packages/cubejs-client-vue3/package.json b/packages/cubejs-client-vue3/package.json index a56caac886f7b..9c3c35204911a 100644 --- a/packages/cubejs-client-vue3/package.json +++ b/packages/cubejs-client-vue3/package.json @@ -1,6 +1,6 @@ { "name": "@cubejs-client/vue3", - "version": "1.7.31", + "version": "1.7.32", "engines": {}, "repository": { "type": "git", @@ -27,7 +27,7 @@ "src" ], "dependencies": { - "@cubejs-client/core": "1.7.31", + "@cubejs-client/core": "1.7.32", "ramda": "^0.27.0" }, "devDependencies": { diff --git a/packages/cubejs-client-ws-transport/CHANGELOG.md b/packages/cubejs-client-ws-transport/CHANGELOG.md index c6f4ec82d7eed..08c8c2b1e82fe 100644 --- a/packages/cubejs-client-ws-transport/CHANGELOG.md +++ b/packages/cubejs-client-ws-transport/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-client/ws-transport + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) **Note:** Version bump only for package @cubejs-client/ws-transport diff --git a/packages/cubejs-client-ws-transport/package.json b/packages/cubejs-client-ws-transport/package.json index 5ee747f310f36..3babae69ad399 100644 --- a/packages/cubejs-client-ws-transport/package.json +++ b/packages/cubejs-client-ws-transport/package.json @@ -1,6 +1,6 @@ { "name": "@cubejs-client/ws-transport", - "version": "1.7.31", + "version": "1.7.32", "engines": {}, "repository": { "type": "git", @@ -20,7 +20,7 @@ }, "dependencies": { "@babel/runtime": "^7.1.2", - "@cubejs-client/core": "1.7.31", + "@cubejs-client/core": "1.7.32", "core-js": "^3.6.5", "isomorphic-ws": "^4.0.1", "ws": "^7.3.1" @@ -33,7 +33,7 @@ "@babel/core": "^7.3.3", "@babel/preset-env": "^7.3.1", "@babel/preset-typescript": "^7.12.1", - "@cubejs-backend/linter": "1.7.31", + "@cubejs-backend/linter": "1.7.32", "@types/ws": "^7.2.9", "typescript": "~5.2.2" }, diff --git a/packages/cubejs-crate-driver/CHANGELOG.md b/packages/cubejs-crate-driver/CHANGELOG.md index 455ca2ef7d784..12a6e83fdce77 100644 --- a/packages/cubejs-crate-driver/CHANGELOG.md +++ b/packages/cubejs-crate-driver/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-backend/crate-driver + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) **Note:** Version bump only for package @cubejs-backend/crate-driver diff --git a/packages/cubejs-crate-driver/package.json b/packages/cubejs-crate-driver/package.json index 07f7d8bddf822..7cee885a9f4ab 100644 --- a/packages/cubejs-crate-driver/package.json +++ b/packages/cubejs-crate-driver/package.json @@ -2,7 +2,7 @@ "name": "@cubejs-backend/crate-driver", "description": "Cube.js Crate database driver", "author": "Cube Dev, Inc.", - "version": "1.7.31", + "version": "1.7.32", "repository": { "type": "git", "url": "https://github.com/cube-js/cube.git", @@ -29,13 +29,13 @@ "lint:fix": "eslint --fix src/* --ext .ts" }, "dependencies": { - "@cubejs-backend/postgres-driver": "1.7.31", - "@cubejs-backend/shared": "1.7.31" + "@cubejs-backend/postgres-driver": "1.7.32", + "@cubejs-backend/shared": "1.7.32" }, "license": "Apache-2.0", "devDependencies": { - "@cubejs-backend/linter": "1.7.31", - "@cubejs-backend/testing-shared": "1.7.31", + "@cubejs-backend/linter": "1.7.32", + "@cubejs-backend/testing-shared": "1.7.32", "testcontainers": "^10.28.0", "typescript": "~5.2.2" }, diff --git a/packages/cubejs-cubestore-driver/CHANGELOG.md b/packages/cubejs-cubestore-driver/CHANGELOG.md index c912263b784cc..a7caab2a014f7 100644 --- a/packages/cubejs-cubestore-driver/CHANGELOG.md +++ b/packages/cubejs-cubestore-driver/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-backend/cubestore-driver + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) **Note:** Version bump only for package @cubejs-backend/cubestore-driver diff --git a/packages/cubejs-cubestore-driver/package.json b/packages/cubejs-cubestore-driver/package.json index 6e4c0e8270a3c..197e0dc5655cd 100644 --- a/packages/cubejs-cubestore-driver/package.json +++ b/packages/cubejs-cubestore-driver/package.json @@ -2,7 +2,7 @@ "name": "@cubejs-backend/cubestore-driver", "description": "Cube Store driver", "author": "Cube Dev, Inc.", - "version": "1.7.31", + "version": "1.7.32", "repository": { "type": "git", "url": "https://github.com/cube-js/cube.git", @@ -27,10 +27,10 @@ "unit": "jest --coverage" }, "dependencies": { - "@cubejs-backend/base-driver": "1.7.31", - "@cubejs-backend/cubestore": "1.7.31", - "@cubejs-backend/native": "1.7.31", - "@cubejs-backend/shared": "1.7.31", + "@cubejs-backend/base-driver": "1.7.32", + "@cubejs-backend/cubestore": "1.7.32", + "@cubejs-backend/native": "1.7.32", + "@cubejs-backend/shared": "1.7.32", "csv-write-stream": "^2.0.0", "flatbuffers": "25.9.23", "fs-extra": "^9.1.0", @@ -41,7 +41,7 @@ "ws": "^7.4.3" }, "devDependencies": { - "@cubejs-backend/linter": "1.7.31", + "@cubejs-backend/linter": "1.7.32", "@types/csv-write-stream": "^2.0.0", "@types/jest": "^29", "@types/node": "^22", diff --git a/packages/cubejs-databricks-jdbc-driver/CHANGELOG.md b/packages/cubejs-databricks-jdbc-driver/CHANGELOG.md index d017227bb1901..0c8c6d8fc3af4 100644 --- a/packages/cubejs-databricks-jdbc-driver/CHANGELOG.md +++ b/packages/cubejs-databricks-jdbc-driver/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-backend/databricks-jdbc-driver + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) **Note:** Version bump only for package @cubejs-backend/databricks-jdbc-driver diff --git a/packages/cubejs-databricks-jdbc-driver/package.json b/packages/cubejs-databricks-jdbc-driver/package.json index 43ba30a838826..56e11b43c4dd9 100644 --- a/packages/cubejs-databricks-jdbc-driver/package.json +++ b/packages/cubejs-databricks-jdbc-driver/package.json @@ -2,7 +2,7 @@ "name": "@cubejs-backend/databricks-jdbc-driver", "description": "Cube.js Databricks database driver", "author": "Cube Dev, Inc.", - "version": "1.7.31", + "version": "1.7.32", "license": "Apache-2.0", "repository": { "type": "git", @@ -30,17 +30,17 @@ "bin" ], "dependencies": { - "@cubejs-backend/base-driver": "1.7.31", - "@cubejs-backend/jdbc-driver": "1.7.31", - "@cubejs-backend/schema-compiler": "1.7.31", - "@cubejs-backend/shared": "1.7.31", + "@cubejs-backend/base-driver": "1.7.32", + "@cubejs-backend/jdbc-driver": "1.7.32", + "@cubejs-backend/schema-compiler": "1.7.32", + "@cubejs-backend/shared": "1.7.32", "node-fetch": "^2.6.1", "ramda": "^0.27.2", "source-map-support": "^0.5.19", "uuid": "^11.1.1" }, "devDependencies": { - "@cubejs-backend/linter": "1.7.31", + "@cubejs-backend/linter": "1.7.32", "@types/jest": "^29", "@types/node": "^22", "@types/ramda": "^0.27.34", diff --git a/packages/cubejs-dbt-schema-extension/CHANGELOG.md b/packages/cubejs-dbt-schema-extension/CHANGELOG.md index e6ec7c74b61a9..0f879e2ba5a1f 100644 --- a/packages/cubejs-dbt-schema-extension/CHANGELOG.md +++ b/packages/cubejs-dbt-schema-extension/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-backend/dbt-schema-extension + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) **Note:** Version bump only for package @cubejs-backend/dbt-schema-extension diff --git a/packages/cubejs-dbt-schema-extension/package.json b/packages/cubejs-dbt-schema-extension/package.json index 9b5e08b991ad7..f117e76984be6 100644 --- a/packages/cubejs-dbt-schema-extension/package.json +++ b/packages/cubejs-dbt-schema-extension/package.json @@ -2,7 +2,7 @@ "name": "@cubejs-backend/dbt-schema-extension", "description": "Cube.js dbt Schema Extension", "author": "Cube Dev, Inc.", - "version": "1.7.31", + "version": "1.7.32", "repository": { "type": "git", "url": "https://github.com/cube-js/cube.git", @@ -25,14 +25,14 @@ "lint:fix": "eslint --fix src/* --ext .ts,.js" }, "dependencies": { - "@cubejs-backend/schema-compiler": "1.7.31", + "@cubejs-backend/schema-compiler": "1.7.32", "fs-extra": "^9.1.0", "inflection": "^1.12.0", "node-fetch": "^2.6.1" }, "devDependencies": { - "@cubejs-backend/linter": "1.7.31", - "@cubejs-backend/testing": "1.7.31", + "@cubejs-backend/linter": "1.7.32", + "@cubejs-backend/testing": "1.7.32", "@types/jest": "^29", "jest": "^29", "stream-to-array": "^2.3.0", diff --git a/packages/cubejs-docker/CHANGELOG.md b/packages/cubejs-docker/CHANGELOG.md index 5432c52af3f24..95a231621c95b 100644 --- a/packages/cubejs-docker/CHANGELOG.md +++ b/packages/cubejs-docker/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-backend/docker + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) **Note:** Version bump only for package @cubejs-backend/docker diff --git a/packages/cubejs-docker/package.json b/packages/cubejs-docker/package.json index 3c1f447de511b..f257a6fd5aa12 100644 --- a/packages/cubejs-docker/package.json +++ b/packages/cubejs-docker/package.json @@ -1,6 +1,6 @@ { "name": "@cubejs-backend/docker", - "version": "1.7.31", + "version": "1.7.32", "description": "Cube.js In Docker (virtual package)", "author": "Cube Dev, Inc.", "license": "Apache-2.0", @@ -9,34 +9,34 @@ "node": ">=20.0.0" }, "dependencies": { - "@cubejs-backend/athena-driver": "1.7.31", - "@cubejs-backend/bigquery-driver": "1.7.31", - "@cubejs-backend/clickhouse-driver": "1.7.31", - "@cubejs-backend/crate-driver": "1.7.31", - "@cubejs-backend/databricks-jdbc-driver": "1.7.31", - "@cubejs-backend/dbt-schema-extension": "1.7.31", - "@cubejs-backend/dremio-driver": "1.7.31", - "@cubejs-backend/druid-driver": "1.7.31", - "@cubejs-backend/duckdb-driver": "1.7.31", - "@cubejs-backend/firebolt-driver": "1.7.31", - "@cubejs-backend/hive-driver": "1.7.31", - "@cubejs-backend/ksql-driver": "1.7.31", - "@cubejs-backend/materialize-driver": "1.7.31", - "@cubejs-backend/mongobi-driver": "1.7.31", - "@cubejs-backend/mssql-driver": "1.7.31", - "@cubejs-backend/mysql-driver": "1.7.31", - "@cubejs-backend/oracle-driver": "1.7.31", - "@cubejs-backend/pinot-driver": "1.7.31", - "@cubejs-backend/postgres-driver": "1.7.31", - "@cubejs-backend/prestodb-driver": "1.7.31", - "@cubejs-backend/questdb-driver": "1.7.31", - "@cubejs-backend/redshift-driver": "1.7.31", - "@cubejs-backend/server": "1.7.31", - "@cubejs-backend/snowflake-driver": "1.7.31", - "@cubejs-backend/sqlite-driver": "1.7.31", - "@cubejs-backend/trino-driver": "1.7.31", - "@cubejs-backend/vertica-driver": "1.7.31", - "cubejs-cli": "1.7.31", + "@cubejs-backend/athena-driver": "1.7.32", + "@cubejs-backend/bigquery-driver": "1.7.32", + "@cubejs-backend/clickhouse-driver": "1.7.32", + "@cubejs-backend/crate-driver": "1.7.32", + "@cubejs-backend/databricks-jdbc-driver": "1.7.32", + "@cubejs-backend/dbt-schema-extension": "1.7.32", + "@cubejs-backend/dremio-driver": "1.7.32", + "@cubejs-backend/druid-driver": "1.7.32", + "@cubejs-backend/duckdb-driver": "1.7.32", + "@cubejs-backend/firebolt-driver": "1.7.32", + "@cubejs-backend/hive-driver": "1.7.32", + "@cubejs-backend/ksql-driver": "1.7.32", + "@cubejs-backend/materialize-driver": "1.7.32", + "@cubejs-backend/mongobi-driver": "1.7.32", + "@cubejs-backend/mssql-driver": "1.7.32", + "@cubejs-backend/mysql-driver": "1.7.32", + "@cubejs-backend/oracle-driver": "1.7.32", + "@cubejs-backend/pinot-driver": "1.7.32", + "@cubejs-backend/postgres-driver": "1.7.32", + "@cubejs-backend/prestodb-driver": "1.7.32", + "@cubejs-backend/questdb-driver": "1.7.32", + "@cubejs-backend/redshift-driver": "1.7.32", + "@cubejs-backend/server": "1.7.32", + "@cubejs-backend/snowflake-driver": "1.7.32", + "@cubejs-backend/sqlite-driver": "1.7.32", + "@cubejs-backend/trino-driver": "1.7.32", + "@cubejs-backend/vertica-driver": "1.7.32", + "cubejs-cli": "1.7.32", "typescript": "~5.2.2" }, "resolutions": { diff --git a/packages/cubejs-dremio-driver/CHANGELOG.md b/packages/cubejs-dremio-driver/CHANGELOG.md index 53130e6163187..1403b096ada41 100644 --- a/packages/cubejs-dremio-driver/CHANGELOG.md +++ b/packages/cubejs-dremio-driver/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-backend/dremio-driver + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) **Note:** Version bump only for package @cubejs-backend/dremio-driver diff --git a/packages/cubejs-dremio-driver/package.json b/packages/cubejs-dremio-driver/package.json index deb04aed67b8b..f69653e67b2a8 100644 --- a/packages/cubejs-dremio-driver/package.json +++ b/packages/cubejs-dremio-driver/package.json @@ -2,7 +2,7 @@ "name": "@cubejs-backend/dremio-driver", "description": "Cube.js Dremio driver", "author": "Cube Dev, Inc.", - "version": "1.7.31", + "version": "1.7.32", "repository": { "type": "git", "url": "https://github.com/cube-js/cube.git", @@ -23,14 +23,14 @@ "lint:fix": "eslint driver/*.js" }, "dependencies": { - "@cubejs-backend/base-driver": "1.7.31", - "@cubejs-backend/schema-compiler": "1.7.31", - "@cubejs-backend/shared": "1.7.31", + "@cubejs-backend/base-driver": "1.7.32", + "@cubejs-backend/schema-compiler": "1.7.32", + "@cubejs-backend/shared": "1.7.32", "axios": "^1.8.3" }, "devDependencies": { - "@cubejs-backend/linter": "1.7.31", - "@cubejs-backend/testing-shared": "1.7.31", + "@cubejs-backend/linter": "1.7.32", + "@cubejs-backend/testing-shared": "1.7.32", "jest": "^29" }, "license": "Apache-2.0", diff --git a/packages/cubejs-druid-driver/CHANGELOG.md b/packages/cubejs-druid-driver/CHANGELOG.md index 7d51d93d20972..8fed29ddb1c0c 100644 --- a/packages/cubejs-druid-driver/CHANGELOG.md +++ b/packages/cubejs-druid-driver/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-backend/druid-driver + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) **Note:** Version bump only for package @cubejs-backend/druid-driver diff --git a/packages/cubejs-druid-driver/package.json b/packages/cubejs-druid-driver/package.json index bbbb5102de26a..c89d4e3f7e95b 100644 --- a/packages/cubejs-druid-driver/package.json +++ b/packages/cubejs-druid-driver/package.json @@ -2,7 +2,7 @@ "name": "@cubejs-backend/druid-driver", "description": "Cube.js Druid database driver", "author": "Cube Dev, Inc.", - "version": "1.7.31", + "version": "1.7.32", "license": "Apache-2.0", "repository": { "type": "git", @@ -28,13 +28,13 @@ "dist/src/*" ], "dependencies": { - "@cubejs-backend/base-driver": "1.7.31", - "@cubejs-backend/schema-compiler": "1.7.31", - "@cubejs-backend/shared": "1.7.31", + "@cubejs-backend/base-driver": "1.7.32", + "@cubejs-backend/schema-compiler": "1.7.32", + "@cubejs-backend/shared": "1.7.32", "axios": "^1.8.3" }, "devDependencies": { - "@cubejs-backend/linter": "1.7.31", + "@cubejs-backend/linter": "1.7.32", "@types/jest": "^29", "@types/node": "^22", "jest": "^29", diff --git a/packages/cubejs-duckdb-driver/CHANGELOG.md b/packages/cubejs-duckdb-driver/CHANGELOG.md index bcca4273319ca..adf8fcc42d417 100644 --- a/packages/cubejs-duckdb-driver/CHANGELOG.md +++ b/packages/cubejs-duckdb-driver/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-backend/duckdb-driver + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) **Note:** Version bump only for package @cubejs-backend/duckdb-driver diff --git a/packages/cubejs-duckdb-driver/package.json b/packages/cubejs-duckdb-driver/package.json index 1b4ba37d1805f..05a1df4e35981 100644 --- a/packages/cubejs-duckdb-driver/package.json +++ b/packages/cubejs-duckdb-driver/package.json @@ -2,7 +2,7 @@ "name": "@cubejs-backend/duckdb-driver", "description": "Cube DuckDB database driver", "author": "Cube Dev, Inc.", - "version": "1.7.31", + "version": "1.7.32", "repository": { "type": "git", "url": "https://github.com/cube-js/cube.git", @@ -28,15 +28,15 @@ "lint:fix": "eslint --fix src/* --ext .ts" }, "dependencies": { - "@cubejs-backend/base-driver": "1.7.31", - "@cubejs-backend/schema-compiler": "1.7.31", - "@cubejs-backend/shared": "1.7.31", + "@cubejs-backend/base-driver": "1.7.32", + "@cubejs-backend/schema-compiler": "1.7.32", + "@cubejs-backend/shared": "1.7.32", "duckdb": "^1.4.1" }, "license": "Apache-2.0", "devDependencies": { - "@cubejs-backend/linter": "1.7.31", - "@cubejs-backend/testing-shared": "1.7.31", + "@cubejs-backend/linter": "1.7.32", + "@cubejs-backend/testing-shared": "1.7.32", "@types/jest": "^29", "@types/node": "^22", "jest": "^29", diff --git a/packages/cubejs-firebolt-driver/CHANGELOG.md b/packages/cubejs-firebolt-driver/CHANGELOG.md index ee8dc7a54c262..67ae8a552a79c 100644 --- a/packages/cubejs-firebolt-driver/CHANGELOG.md +++ b/packages/cubejs-firebolt-driver/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-backend/firebolt-driver + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) **Note:** Version bump only for package @cubejs-backend/firebolt-driver diff --git a/packages/cubejs-firebolt-driver/package.json b/packages/cubejs-firebolt-driver/package.json index 5c951d1773f50..d3ee6d501c5ef 100644 --- a/packages/cubejs-firebolt-driver/package.json +++ b/packages/cubejs-firebolt-driver/package.json @@ -2,7 +2,7 @@ "name": "@cubejs-backend/firebolt-driver", "description": "Cube.js Firebolt database driver", "author": "Cube Dev, Inc.", - "version": "1.7.31", + "version": "1.7.32", "repository": { "type": "git", "url": "https://github.com/cube-js/cube.git", @@ -28,15 +28,15 @@ "lint:fix": "eslint --fix src/* --ext .ts" }, "dependencies": { - "@cubejs-backend/base-driver": "1.7.31", - "@cubejs-backend/schema-compiler": "1.7.31", - "@cubejs-backend/shared": "1.7.31", + "@cubejs-backend/base-driver": "1.7.32", + "@cubejs-backend/schema-compiler": "1.7.32", + "@cubejs-backend/shared": "1.7.32", "firebolt-sdk": "1.10.0" }, "license": "Apache-2.0", "devDependencies": { - "@cubejs-backend/linter": "1.7.31", - "@cubejs-backend/testing-shared": "1.7.31", + "@cubejs-backend/linter": "1.7.32", + "@cubejs-backend/testing-shared": "1.7.32", "typescript": "~5.2.2" }, "publishConfig": { diff --git a/packages/cubejs-hive-driver/CHANGELOG.md b/packages/cubejs-hive-driver/CHANGELOG.md index 1307ba987e863..3e83304fdd41a 100644 --- a/packages/cubejs-hive-driver/CHANGELOG.md +++ b/packages/cubejs-hive-driver/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-backend/hive-driver + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) **Note:** Version bump only for package @cubejs-backend/hive-driver diff --git a/packages/cubejs-hive-driver/package.json b/packages/cubejs-hive-driver/package.json index 3b1427d5009ef..e84374787d63a 100644 --- a/packages/cubejs-hive-driver/package.json +++ b/packages/cubejs-hive-driver/package.json @@ -2,7 +2,7 @@ "name": "@cubejs-backend/hive-driver", "description": "Cube.js Hive database driver", "author": "Cube Dev, Inc.", - "version": "1.7.31", + "version": "1.7.32", "repository": { "type": "git", "url": "https://github.com/cube-js/cube.git", @@ -17,8 +17,8 @@ "lint:fix": "eslint --fix src/* --ext .ts" }, "dependencies": { - "@cubejs-backend/base-driver": "1.7.31", - "@cubejs-backend/shared": "1.7.31", + "@cubejs-backend/base-driver": "1.7.32", + "@cubejs-backend/shared": "1.7.32", "jshs2": "^0.4.4", "sasl-plain": "^0.1.0", "saslmechanisms": "^0.1.1", @@ -27,7 +27,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@cubejs-backend/linter": "1.7.31" + "@cubejs-backend/linter": "1.7.32" }, "publishConfig": { "access": "public" diff --git a/packages/cubejs-jdbc-driver/CHANGELOG.md b/packages/cubejs-jdbc-driver/CHANGELOG.md index 35632e8b27775..bf0fe781418bc 100644 --- a/packages/cubejs-jdbc-driver/CHANGELOG.md +++ b/packages/cubejs-jdbc-driver/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-backend/jdbc-driver + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) **Note:** Version bump only for package @cubejs-backend/jdbc-driver diff --git a/packages/cubejs-jdbc-driver/package.json b/packages/cubejs-jdbc-driver/package.json index e8215f27f1314..c56117219b56d 100644 --- a/packages/cubejs-jdbc-driver/package.json +++ b/packages/cubejs-jdbc-driver/package.json @@ -2,7 +2,7 @@ "name": "@cubejs-backend/jdbc-driver", "description": "Cube.js JDBC database driver", "author": "Cube Dev, Inc.", - "version": "1.7.31", + "version": "1.7.32", "repository": { "type": "git", "url": "https://github.com/cube-js/cube.git", @@ -26,9 +26,9 @@ "index.js" ], "dependencies": { - "@cubejs-backend/base-driver": "1.7.31", + "@cubejs-backend/base-driver": "1.7.32", "@cubejs-backend/node-java-maven": "^0.1.3", - "@cubejs-backend/shared": "1.7.31" + "@cubejs-backend/shared": "1.7.32" }, "optionalDependencies": { "@cubejs-backend/jdbc": "^0.9.0", @@ -42,7 +42,7 @@ "testEnvironment": "node" }, "devDependencies": { - "@cubejs-backend/linter": "1.7.31", + "@cubejs-backend/linter": "1.7.32", "@types/node": "^22", "typescript": "~5.2.2" } diff --git a/packages/cubejs-ksql-driver/CHANGELOG.md b/packages/cubejs-ksql-driver/CHANGELOG.md index dfcd969cb1c0c..b6784c7324b9e 100644 --- a/packages/cubejs-ksql-driver/CHANGELOG.md +++ b/packages/cubejs-ksql-driver/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-backend/ksql-driver + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) **Note:** Version bump only for package @cubejs-backend/ksql-driver diff --git a/packages/cubejs-ksql-driver/package.json b/packages/cubejs-ksql-driver/package.json index 7b1271d0a177c..395eafc5f5873 100644 --- a/packages/cubejs-ksql-driver/package.json +++ b/packages/cubejs-ksql-driver/package.json @@ -2,7 +2,7 @@ "name": "@cubejs-backend/ksql-driver", "description": "Cube.js ksql database driver", "author": "Cube Dev, Inc.", - "version": "1.7.31", + "version": "1.7.32", "repository": { "type": "git", "url": "https://github.com/cube-js/cube.git", @@ -26,9 +26,9 @@ "lint:fix": "eslint --fix src/* --ext .ts" }, "dependencies": { - "@cubejs-backend/base-driver": "1.7.31", - "@cubejs-backend/schema-compiler": "1.7.31", - "@cubejs-backend/shared": "1.7.31", + "@cubejs-backend/base-driver": "1.7.32", + "@cubejs-backend/schema-compiler": "1.7.32", + "@cubejs-backend/shared": "1.7.32", "async-mutex": "0.3.2", "axios": "^1.8.3", "kafkajs": "^2.2.3" @@ -41,7 +41,7 @@ "extends": "../cubejs-linter" }, "devDependencies": { - "@cubejs-backend/linter": "1.7.31", + "@cubejs-backend/linter": "1.7.32", "typescript": "~5.2.2" } } diff --git a/packages/cubejs-linter/CHANGELOG.md b/packages/cubejs-linter/CHANGELOG.md index 16ab6611ab9ae..293ec107135eb 100644 --- a/packages/cubejs-linter/CHANGELOG.md +++ b/packages/cubejs-linter/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-backend/linter + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) **Note:** Version bump only for package @cubejs-backend/linter diff --git a/packages/cubejs-linter/package.json b/packages/cubejs-linter/package.json index 179331188571f..661e839fc151b 100644 --- a/packages/cubejs-linter/package.json +++ b/packages/cubejs-linter/package.json @@ -2,7 +2,7 @@ "name": "@cubejs-backend/linter", "description": "Cube.js ESLint (virtual package) for linting code", "author": "Cube Dev, Inc.", - "version": "1.7.31", + "version": "1.7.32", "repository": { "type": "git", "url": "https://github.com/cube-js/cube.git", diff --git a/packages/cubejs-materialize-driver/CHANGELOG.md b/packages/cubejs-materialize-driver/CHANGELOG.md index 5e8a70d6685fa..94cb1ee2fbaca 100644 --- a/packages/cubejs-materialize-driver/CHANGELOG.md +++ b/packages/cubejs-materialize-driver/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-backend/materialize-driver + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) **Note:** Version bump only for package @cubejs-backend/materialize-driver diff --git a/packages/cubejs-materialize-driver/package.json b/packages/cubejs-materialize-driver/package.json index ccbcc7024e685..69d123b93e04a 100644 --- a/packages/cubejs-materialize-driver/package.json +++ b/packages/cubejs-materialize-driver/package.json @@ -2,7 +2,7 @@ "name": "@cubejs-backend/materialize-driver", "description": "Cube.js Materialize database driver", "author": "Cube Dev, Inc.", - "version": "1.7.31", + "version": "1.7.32", "repository": { "type": "git", "url": "https://github.com/cube-js/cube.git", @@ -27,15 +27,15 @@ "lint:fix": "eslint --fix src/* --ext .ts" }, "dependencies": { - "@cubejs-backend/base-driver": "1.7.31", - "@cubejs-backend/postgres-driver": "1.7.31", - "@cubejs-backend/shared": "1.7.31", + "@cubejs-backend/base-driver": "1.7.32", + "@cubejs-backend/postgres-driver": "1.7.32", + "@cubejs-backend/shared": "1.7.32", "semver": "^7.6.3" }, "license": "Apache-2.0", "devDependencies": { - "@cubejs-backend/linter": "1.7.31", - "@cubejs-backend/testing": "1.7.31", + "@cubejs-backend/linter": "1.7.32", + "@cubejs-backend/testing": "1.7.32", "typescript": "~5.2.2" }, "publishConfig": { diff --git a/packages/cubejs-mongobi-driver/CHANGELOG.md b/packages/cubejs-mongobi-driver/CHANGELOG.md index ac8b5e647e220..054351d937b3f 100644 --- a/packages/cubejs-mongobi-driver/CHANGELOG.md +++ b/packages/cubejs-mongobi-driver/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-backend/mongobi-driver + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) **Note:** Version bump only for package @cubejs-backend/mongobi-driver diff --git a/packages/cubejs-mongobi-driver/package.json b/packages/cubejs-mongobi-driver/package.json index 5f40fdf163ba1..b2a8470a1db37 100644 --- a/packages/cubejs-mongobi-driver/package.json +++ b/packages/cubejs-mongobi-driver/package.json @@ -2,7 +2,7 @@ "name": "@cubejs-backend/mongobi-driver", "description": "Cube.js MongoBI driver", "author": "krunalsabnis@gmail.com", - "version": "1.7.31", + "version": "1.7.32", "repository": { "type": "git", "url": "https://github.com/cube-js/cube.git", @@ -27,8 +27,8 @@ "integration:mongobi": "jest dist/test" }, "dependencies": { - "@cubejs-backend/base-driver": "1.7.31", - "@cubejs-backend/shared": "1.7.31", + "@cubejs-backend/base-driver": "1.7.32", + "@cubejs-backend/shared": "1.7.32", "@types/node": "^22", "moment": "^2.29.1", "mysql2": "^3.11.5" @@ -38,7 +38,7 @@ "access": "public" }, "devDependencies": { - "@cubejs-backend/linter": "1.7.31", + "@cubejs-backend/linter": "1.7.32", "testcontainers": "^10.28.0", "typescript": "~5.2.2" }, diff --git a/packages/cubejs-mssql-driver/CHANGELOG.md b/packages/cubejs-mssql-driver/CHANGELOG.md index 41304f729ef6d..8437599606d61 100644 --- a/packages/cubejs-mssql-driver/CHANGELOG.md +++ b/packages/cubejs-mssql-driver/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-backend/mssql-driver + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) **Note:** Version bump only for package @cubejs-backend/mssql-driver diff --git a/packages/cubejs-mssql-driver/package.json b/packages/cubejs-mssql-driver/package.json index 89b554c2935ec..01717fe23b9e9 100644 --- a/packages/cubejs-mssql-driver/package.json +++ b/packages/cubejs-mssql-driver/package.json @@ -2,7 +2,7 @@ "name": "@cubejs-backend/mssql-driver", "description": "Cube.js MS SQL database driver", "author": "Cube Dev, Inc.", - "version": "1.7.31", + "version": "1.7.32", "repository": { "type": "git", "url": "https://github.com/cube-js/cube.git", @@ -25,8 +25,8 @@ "lint:fix": "eslint --fix src/* --ext .ts,.js" }, "dependencies": { - "@cubejs-backend/base-driver": "1.7.31", - "@cubejs-backend/shared": "1.7.31", + "@cubejs-backend/base-driver": "1.7.32", + "@cubejs-backend/shared": "1.7.32", "mssql": "^11.0.1" }, "devDependencies": { diff --git a/packages/cubejs-mysql-aurora-serverless-driver/CHANGELOG.md b/packages/cubejs-mysql-aurora-serverless-driver/CHANGELOG.md index 9c74a1df3351d..c494c672d73d3 100644 --- a/packages/cubejs-mysql-aurora-serverless-driver/CHANGELOG.md +++ b/packages/cubejs-mysql-aurora-serverless-driver/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-backend/mysql-aurora-serverless-driver + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) **Note:** Version bump only for package @cubejs-backend/mysql-aurora-serverless-driver diff --git a/packages/cubejs-mysql-aurora-serverless-driver/package.json b/packages/cubejs-mysql-aurora-serverless-driver/package.json index 5432b76bb31d5..c3bc7bf31e16c 100644 --- a/packages/cubejs-mysql-aurora-serverless-driver/package.json +++ b/packages/cubejs-mysql-aurora-serverless-driver/package.json @@ -2,7 +2,7 @@ "name": "@cubejs-backend/mysql-aurora-serverless-driver", "description": "Cube.js Aurora Serverless Mysql database driver", "author": "Cube Dev, Inc.", - "version": "1.7.31", + "version": "1.7.32", "repository": { "type": "git", "url": "https://github.com/cube-js/cube.git", @@ -21,14 +21,14 @@ "lint": "eslint driver/*.js test/*.js" }, "dependencies": { - "@cubejs-backend/base-driver": "1.7.31", - "@cubejs-backend/shared": "1.7.31", + "@cubejs-backend/base-driver": "1.7.32", + "@cubejs-backend/shared": "1.7.32", "@types/mysql": "^2.15.15", "aws-sdk": "^2.787.0", "data-api-client": "^1.1.0" }, "devDependencies": { - "@cubejs-backend/linter": "1.7.31", + "@cubejs-backend/linter": "1.7.32", "@types/data-api-client": "^1.2.1", "@types/jest": "^29", "jest": "^29", diff --git a/packages/cubejs-mysql-driver/CHANGELOG.md b/packages/cubejs-mysql-driver/CHANGELOG.md index a0eb094bd71db..7d86b46ac13ef 100644 --- a/packages/cubejs-mysql-driver/CHANGELOG.md +++ b/packages/cubejs-mysql-driver/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-backend/mysql-driver + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) **Note:** Version bump only for package @cubejs-backend/mysql-driver diff --git a/packages/cubejs-mysql-driver/package.json b/packages/cubejs-mysql-driver/package.json index 9b5a3d6c6b4af..e3df4e6595780 100644 --- a/packages/cubejs-mysql-driver/package.json +++ b/packages/cubejs-mysql-driver/package.json @@ -2,7 +2,7 @@ "name": "@cubejs-backend/mysql-driver", "description": "Cube.js Mysql database driver", "author": "Cube Dev, Inc.", - "version": "1.7.31", + "version": "1.7.32", "repository": { "type": "git", "url": "https://github.com/cube-js/cube.git", @@ -27,13 +27,13 @@ "lint:fix": "eslint --fix src/* test/* --ext .ts,.js" }, "dependencies": { - "@cubejs-backend/base-driver": "1.7.31", - "@cubejs-backend/shared": "1.7.31", + "@cubejs-backend/base-driver": "1.7.32", + "@cubejs-backend/shared": "1.7.32", "mysql2": "^3.16.1" }, "devDependencies": { - "@cubejs-backend/linter": "1.7.31", - "@cubejs-backend/testing-shared": "1.7.31", + "@cubejs-backend/linter": "1.7.32", + "@cubejs-backend/testing-shared": "1.7.32", "@types/jest": "^29", "jest": "^29", "stream-to-array": "^2.3.0", diff --git a/packages/cubejs-oracle-driver/CHANGELOG.md b/packages/cubejs-oracle-driver/CHANGELOG.md index 3f123d52a9caa..6ba4f8f2970a0 100644 --- a/packages/cubejs-oracle-driver/CHANGELOG.md +++ b/packages/cubejs-oracle-driver/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-backend/oracle-driver + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) **Note:** Version bump only for package @cubejs-backend/oracle-driver diff --git a/packages/cubejs-oracle-driver/package.json b/packages/cubejs-oracle-driver/package.json index 28e17085cc236..f03ddb377c358 100644 --- a/packages/cubejs-oracle-driver/package.json +++ b/packages/cubejs-oracle-driver/package.json @@ -2,7 +2,7 @@ "name": "@cubejs-backend/oracle-driver", "description": "Cube.js oracle database driver", "author": "Cube Dev, Inc.", - "version": "1.7.31", + "version": "1.7.32", "repository": { "type": "git", "url": "https://github.com/cube-js/cube.git", @@ -13,8 +13,8 @@ }, "main": "driver/OracleDriver.js", "dependencies": { - "@cubejs-backend/base-driver": "1.7.31", - "@cubejs-backend/shared": "1.7.31", + "@cubejs-backend/base-driver": "1.7.32", + "@cubejs-backend/shared": "1.7.32", "ramda": "^0.27.0" }, "devDependencies": { diff --git a/packages/cubejs-pinot-driver/CHANGELOG.md b/packages/cubejs-pinot-driver/CHANGELOG.md index e6b58888f5a23..9de614e746761 100644 --- a/packages/cubejs-pinot-driver/CHANGELOG.md +++ b/packages/cubejs-pinot-driver/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-backend/pinot-driver + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) **Note:** Version bump only for package @cubejs-backend/pinot-driver diff --git a/packages/cubejs-pinot-driver/package.json b/packages/cubejs-pinot-driver/package.json index e07bae208368f..6fd7de42a124b 100644 --- a/packages/cubejs-pinot-driver/package.json +++ b/packages/cubejs-pinot-driver/package.json @@ -2,7 +2,7 @@ "name": "@cubejs-backend/pinot-driver", "description": "Cube.js Pinot database driver", "author": "Julian Ronsse, InTheMemory, Cube Dev, Inc.", - "version": "1.7.31", + "version": "1.7.32", "repository": { "type": "git", "url": "https://github.com/cube-js/cube.git", @@ -28,9 +28,9 @@ "lint:fix": "eslint --fix src/* --ext .ts" }, "dependencies": { - "@cubejs-backend/base-driver": "1.7.31", - "@cubejs-backend/schema-compiler": "1.7.31", - "@cubejs-backend/shared": "1.7.31", + "@cubejs-backend/base-driver": "1.7.32", + "@cubejs-backend/schema-compiler": "1.7.32", + "@cubejs-backend/shared": "1.7.32", "node-fetch": "^2.6.1", "ramda": "^0.27.2" }, @@ -39,7 +39,7 @@ "access": "public" }, "devDependencies": { - "@cubejs-backend/linter": "1.7.31", + "@cubejs-backend/linter": "1.7.32", "@types/jest": "^29", "jest": "^29", "should": "^13.2.3", diff --git a/packages/cubejs-playground/CHANGELOG.md b/packages/cubejs-playground/CHANGELOG.md index e77044c92eb3c..89be0859cb8ee 100644 --- a/packages/cubejs-playground/CHANGELOG.md +++ b/packages/cubejs-playground/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-client/playground + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) **Note:** Version bump only for package @cubejs-client/playground diff --git a/packages/cubejs-playground/package.json b/packages/cubejs-playground/package.json index 1a07bf5a56b5a..7d7db8bacfbb3 100644 --- a/packages/cubejs-playground/package.json +++ b/packages/cubejs-playground/package.json @@ -1,7 +1,7 @@ { "name": "@cubejs-client/playground", "author": "Cube Dev, Inc.", - "version": "1.7.31", + "version": "1.7.32", "engines": {}, "repository": { "type": "git", @@ -68,8 +68,8 @@ "@ant-design/compatible": "^1.0.1", "@ant-design/icons": "^5.3.5", "@cube-dev/ui-kit": "0.52.3", - "@cubejs-client/core": "1.7.31", - "@cubejs-client/react": "1.7.31", + "@cubejs-client/core": "1.7.32", + "@cubejs-client/react": "1.7.32", "@types/flexsearch": "^0.7.3", "@types/node": "^22", "@types/react": "^18.3.4", diff --git a/packages/cubejs-postgres-driver/CHANGELOG.md b/packages/cubejs-postgres-driver/CHANGELOG.md index 0c17972f03f3e..7794f4a2eb158 100644 --- a/packages/cubejs-postgres-driver/CHANGELOG.md +++ b/packages/cubejs-postgres-driver/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-backend/postgres-driver + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) **Note:** Version bump only for package @cubejs-backend/postgres-driver diff --git a/packages/cubejs-postgres-driver/package.json b/packages/cubejs-postgres-driver/package.json index 04dca7c34c292..8994d295895fc 100644 --- a/packages/cubejs-postgres-driver/package.json +++ b/packages/cubejs-postgres-driver/package.json @@ -2,7 +2,7 @@ "name": "@cubejs-backend/postgres-driver", "description": "Cube.js Postgres database driver", "author": "Cube Dev, Inc.", - "version": "1.7.31", + "version": "1.7.32", "repository": { "type": "git", "url": "https://github.com/cube-js/cube.git", @@ -27,8 +27,8 @@ "lint:fix": "eslint --fix src/* --ext .ts" }, "dependencies": { - "@cubejs-backend/base-driver": "1.7.31", - "@cubejs-backend/shared": "1.7.31", + "@cubejs-backend/base-driver": "1.7.32", + "@cubejs-backend/shared": "1.7.32", "@types/pg": "^8.16.0", "@types/pg-query-stream": "^1.0.3", "pg": "^8.18.0", @@ -36,8 +36,8 @@ }, "license": "Apache-2.0", "devDependencies": { - "@cubejs-backend/linter": "1.7.31", - "@cubejs-backend/testing-shared": "1.7.31", + "@cubejs-backend/linter": "1.7.32", + "@cubejs-backend/testing-shared": "1.7.32", "testcontainers": "^10.28.0", "typescript": "~5.2.2" }, diff --git a/packages/cubejs-prestodb-driver/CHANGELOG.md b/packages/cubejs-prestodb-driver/CHANGELOG.md index cf00ac153c875..a60cef1a77f60 100644 --- a/packages/cubejs-prestodb-driver/CHANGELOG.md +++ b/packages/cubejs-prestodb-driver/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-backend/prestodb-driver + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) **Note:** Version bump only for package @cubejs-backend/prestodb-driver diff --git a/packages/cubejs-prestodb-driver/package.json b/packages/cubejs-prestodb-driver/package.json index d65fb71cc1e81..df0e296c9ec42 100644 --- a/packages/cubejs-prestodb-driver/package.json +++ b/packages/cubejs-prestodb-driver/package.json @@ -2,7 +2,7 @@ "name": "@cubejs-backend/prestodb-driver", "description": "Cube.js Presto database driver", "author": "Cube Dev, Inc.", - "version": "1.7.31", + "version": "1.7.32", "repository": { "type": "git", "url": "https://github.com/cube-js/cube.git", @@ -28,8 +28,8 @@ "lint:fix": "eslint --fix src/* --ext .ts" }, "dependencies": { - "@cubejs-backend/base-driver": "1.7.31", - "@cubejs-backend/shared": "1.7.31", + "@cubejs-backend/base-driver": "1.7.32", + "@cubejs-backend/shared": "1.7.32", "presto-client": "1.2.0", "ramda": "^0.27.0" }, @@ -38,7 +38,7 @@ "access": "public" }, "devDependencies": { - "@cubejs-backend/linter": "1.7.31", + "@cubejs-backend/linter": "1.7.32", "@types/jest": "^29", "jest": "^29", "should": "^13.2.3", diff --git a/packages/cubejs-query-orchestrator/CHANGELOG.md b/packages/cubejs-query-orchestrator/CHANGELOG.md index fd3148d697652..2bd577f239d49 100644 --- a/packages/cubejs-query-orchestrator/CHANGELOG.md +++ b/packages/cubejs-query-orchestrator/CHANGELOG.md @@ -3,6 +3,12 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +### Bug Fixes + +- **query-orchestrator:** keep Interactive priority on user query paths ([#11715](https://github.com/cube-js/cube/issues/11715)) ([39d3b20](https://github.com/cube-js/cube/commit/39d3b20d114d6003562e0cdad0e98389056bb3a5)) + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) ### Bug Fixes diff --git a/packages/cubejs-query-orchestrator/package.json b/packages/cubejs-query-orchestrator/package.json index 801d6ab50fbef..d37bcacaa2e2d 100644 --- a/packages/cubejs-query-orchestrator/package.json +++ b/packages/cubejs-query-orchestrator/package.json @@ -2,7 +2,7 @@ "name": "@cubejs-backend/query-orchestrator", "description": "Cube.js Query Orchestrator and Cache", "author": "Cube Dev, Inc.", - "version": "1.7.31", + "version": "1.7.32", "repository": { "type": "git", "url": "https://github.com/cube-js/cube.git", @@ -30,15 +30,15 @@ "dist/src/*" ], "dependencies": { - "@cubejs-backend/base-driver": "1.7.31", - "@cubejs-backend/cubestore-driver": "1.7.31", - "@cubejs-backend/shared": "1.7.31", + "@cubejs-backend/base-driver": "1.7.32", + "@cubejs-backend/cubestore-driver": "1.7.32", + "@cubejs-backend/shared": "1.7.32", "csv-write-stream": "^2.0.0", "lru-cache": "^11.1.0", "ramda": "^0.27.2" }, "devDependencies": { - "@cubejs-backend/linter": "1.7.31", + "@cubejs-backend/linter": "1.7.32", "@types/jest": "^29", "@types/node": "^22", "@types/ramda": "^0.27.32", diff --git a/packages/cubejs-questdb-driver/CHANGELOG.md b/packages/cubejs-questdb-driver/CHANGELOG.md index b80ef909d9c8b..a9cff656c2615 100644 --- a/packages/cubejs-questdb-driver/CHANGELOG.md +++ b/packages/cubejs-questdb-driver/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-backend/questdb-driver + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) **Note:** Version bump only for package @cubejs-backend/questdb-driver diff --git a/packages/cubejs-questdb-driver/package.json b/packages/cubejs-questdb-driver/package.json index 10aa65c14cafa..99761209cb379 100644 --- a/packages/cubejs-questdb-driver/package.json +++ b/packages/cubejs-questdb-driver/package.json @@ -2,7 +2,7 @@ "name": "@cubejs-backend/questdb-driver", "description": "Cube.js QuestDB database driver", "author": "Cube Dev, Inc.", - "version": "1.7.31", + "version": "1.7.32", "repository": { "type": "git", "url": "https://github.com/cube-js/cube.git", @@ -27,9 +27,9 @@ "lint:fix": "eslint --fix src/* --ext .ts" }, "dependencies": { - "@cubejs-backend/base-driver": "1.7.31", - "@cubejs-backend/schema-compiler": "1.7.31", - "@cubejs-backend/shared": "1.7.31", + "@cubejs-backend/base-driver": "1.7.32", + "@cubejs-backend/schema-compiler": "1.7.32", + "@cubejs-backend/shared": "1.7.32", "@types/pg": "^8.6.0", "moment": "^2.24.0", "pg": "^8.7.0", @@ -37,8 +37,8 @@ }, "license": "Apache-2.0", "devDependencies": { - "@cubejs-backend/linter": "1.7.31", - "@cubejs-backend/testing-shared": "1.7.31", + "@cubejs-backend/linter": "1.7.32", + "@cubejs-backend/testing-shared": "1.7.32", "testcontainers": "^10.28.0", "typescript": "~5.2.2" }, diff --git a/packages/cubejs-redshift-driver/CHANGELOG.md b/packages/cubejs-redshift-driver/CHANGELOG.md index 137099af75d9f..d7e0ed5d183e9 100644 --- a/packages/cubejs-redshift-driver/CHANGELOG.md +++ b/packages/cubejs-redshift-driver/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-backend/redshift-driver + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) **Note:** Version bump only for package @cubejs-backend/redshift-driver diff --git a/packages/cubejs-redshift-driver/package.json b/packages/cubejs-redshift-driver/package.json index 4af1d9ce2069c..abe459f4bb94c 100644 --- a/packages/cubejs-redshift-driver/package.json +++ b/packages/cubejs-redshift-driver/package.json @@ -2,7 +2,7 @@ "name": "@cubejs-backend/redshift-driver", "description": "Cube.js Redshift database driver", "author": "Cube Dev, Inc.", - "version": "1.7.31", + "version": "1.7.32", "repository": { "type": "git", "url": "https://github.com/cube-js/cube.git", @@ -27,13 +27,13 @@ "dependencies": { "@aws-sdk/client-redshift": "^3.22.0", "@aws-sdk/credential-providers": "^3.22.0", - "@cubejs-backend/base-driver": "1.7.31", - "@cubejs-backend/postgres-driver": "1.7.31", - "@cubejs-backend/shared": "1.7.31" + "@cubejs-backend/base-driver": "1.7.32", + "@cubejs-backend/postgres-driver": "1.7.32", + "@cubejs-backend/shared": "1.7.32" }, "license": "Apache-2.0", "devDependencies": { - "@cubejs-backend/linter": "1.7.31", + "@cubejs-backend/linter": "1.7.32", "typescript": "~5.2.2" }, "publishConfig": { diff --git a/packages/cubejs-schema-compiler/CHANGELOG.md b/packages/cubejs-schema-compiler/CHANGELOG.md index 9184e9c967a2c..78f099e7de2b3 100644 --- a/packages/cubejs-schema-compiler/CHANGELOG.md +++ b/packages/cubejs-schema-compiler/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +### Bug Fixes + +- **tesseract:** calendar sql granularities crash every query; to_date ignores the calendar ([#11709](https://github.com/cube-js/cube/issues/11709)) ([4029495](https://github.com/cube-js/cube/commit/4029495feb0cadfee20c56f565d94430852f5b27)) +- **tesseract:** compose grain.include with rolling_window ([#11639](https://github.com/cube-js/cube/issues/11639)) ([9d3dd45](https://github.com/cube-js/cube/commit/9d3dd45814a7fec41b6c4e23233f38bd7a1af1c2)) +- **tesseract:** convert a view's raw time dimension timezone only once ([#11712](https://github.com/cube-js/cube/issues/11712)) ([1ae6452](https://github.com/cube-js/cube/commit/1ae6452a139d227935e3b68d9c8cc9283d982d3d)) + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) ### Bug Fixes diff --git a/packages/cubejs-schema-compiler/package.json b/packages/cubejs-schema-compiler/package.json index 9044322bad769..8cb20eeb6dffa 100644 --- a/packages/cubejs-schema-compiler/package.json +++ b/packages/cubejs-schema-compiler/package.json @@ -2,7 +2,7 @@ "name": "@cubejs-backend/schema-compiler", "description": "Cube schema compiler", "author": "Cube Dev, Inc.", - "version": "1.7.31", + "version": "1.7.32", "repository": { "type": "git", "url": "https://github.com/cube-js/cube.git", @@ -40,8 +40,8 @@ "@babel/standalone": "^7.24", "@babel/traverse": "^7.24", "@babel/types": "^7.24", - "@cubejs-backend/native": "1.7.31", - "@cubejs-backend/shared": "1.7.31", + "@cubejs-backend/native": "1.7.32", + "@cubejs-backend/shared": "1.7.32", "antlr4": "^4.13.2", "camelcase": "^6.2.0", "cron-parser": "^4.9.0", @@ -60,9 +60,9 @@ }, "devDependencies": { "@clickhouse/client": "^1.12.0", - "@cubejs-backend/linter": "1.7.31", - "@cubejs-backend/mssql-driver": "1.7.31", - "@cubejs-backend/query-orchestrator": "1.7.31", + "@cubejs-backend/linter": "1.7.32", + "@cubejs-backend/mssql-driver": "1.7.32", + "@cubejs-backend/query-orchestrator": "1.7.32", "@types/babel__code-frame": "^7.0.6", "@types/babel__generator": "^7.6.8", "@types/babel__traverse": "^7.20.5", diff --git a/packages/cubejs-server-core/CHANGELOG.md b/packages/cubejs-server-core/CHANGELOG.md index 6e93921974177..8c9658481bc06 100644 --- a/packages/cubejs-server-core/CHANGELOG.md +++ b/packages/cubejs-server-core/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-backend/server-core + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) ### Features diff --git a/packages/cubejs-server-core/package.json b/packages/cubejs-server-core/package.json index 76fc9a0161ce3..23de6199bb457 100644 --- a/packages/cubejs-server-core/package.json +++ b/packages/cubejs-server-core/package.json @@ -2,7 +2,7 @@ "name": "@cubejs-backend/server-core", "description": "Cube.js base component to wire all backend components together", "author": "Cube Dev, Inc.", - "version": "1.7.31", + "version": "1.7.32", "repository": { "type": "git", "url": "https://github.com/cube-js/cube.git", @@ -29,16 +29,16 @@ "unit": "jest --runInBand --forceExit --coverage dist/test" }, "dependencies": { - "@cubejs-backend/api-gateway": "1.7.31", - "@cubejs-backend/base-driver": "1.7.31", - "@cubejs-backend/cloud": "1.7.31", - "@cubejs-backend/cubestore-driver": "1.7.31", + "@cubejs-backend/api-gateway": "1.7.32", + "@cubejs-backend/base-driver": "1.7.32", + "@cubejs-backend/cloud": "1.7.32", + "@cubejs-backend/cubestore-driver": "1.7.32", "@cubejs-backend/dotenv": "^9.0.2", - "@cubejs-backend/native": "1.7.31", - "@cubejs-backend/query-orchestrator": "1.7.31", - "@cubejs-backend/schema-compiler": "1.7.31", - "@cubejs-backend/shared": "1.7.31", - "@cubejs-backend/templates": "1.7.31", + "@cubejs-backend/native": "1.7.32", + "@cubejs-backend/query-orchestrator": "1.7.32", + "@cubejs-backend/schema-compiler": "1.7.32", + "@cubejs-backend/shared": "1.7.32", + "@cubejs-backend/templates": "1.7.32", "codesandbox-import-utils": "^2.1.12", "cross-spawn": "^7.0.1", "fs-extra": "^8.1.0", @@ -62,8 +62,8 @@ "ws": "^7.5.3" }, "devDependencies": { - "@cubejs-backend/linter": "1.7.31", - "@cubejs-client/playground": "1.7.31", + "@cubejs-backend/linter": "1.7.32", + "@cubejs-client/playground": "1.7.32", "@types/cross-spawn": "^6.0.2", "@types/express": "^4.17.21", "@types/fs-extra": "^9.0.8", diff --git a/packages/cubejs-server/CHANGELOG.md b/packages/cubejs-server/CHANGELOG.md index b80c84a4c8bc9..faa8b54557740 100644 --- a/packages/cubejs-server/CHANGELOG.md +++ b/packages/cubejs-server/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-backend/server + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) **Note:** Version bump only for package @cubejs-backend/server diff --git a/packages/cubejs-server/package.json b/packages/cubejs-server/package.json index d643b0edf2754..0226b3dc24d7a 100644 --- a/packages/cubejs-server/package.json +++ b/packages/cubejs-server/package.json @@ -2,7 +2,7 @@ "name": "@cubejs-backend/server", "description": "Cube.js all-in-one server", "author": "Cube Dev, Inc.", - "version": "1.7.31", + "version": "1.7.32", "types": "index.d.ts", "repository": { "type": "git", @@ -40,11 +40,11 @@ "jest:shapshot": "jest --updateSnapshot test" }, "dependencies": { - "@cubejs-backend/cubestore-driver": "1.7.31", + "@cubejs-backend/cubestore-driver": "1.7.32", "@cubejs-backend/dotenv": "^9.0.2", - "@cubejs-backend/native": "1.7.31", - "@cubejs-backend/server-core": "1.7.31", - "@cubejs-backend/shared": "1.7.31", + "@cubejs-backend/native": "1.7.32", + "@cubejs-backend/server-core": "1.7.32", + "@cubejs-backend/shared": "1.7.32", "@oclif/color": "^1.0.0", "@oclif/command": "^1.8.13", "@oclif/config": "^1.18.2", @@ -61,8 +61,8 @@ "ws": "^7.1.2" }, "devDependencies": { - "@cubejs-backend/linter": "1.7.31", - "@cubejs-backend/query-orchestrator": "1.7.31", + "@cubejs-backend/linter": "1.7.32", + "@cubejs-backend/query-orchestrator": "1.7.32", "@oclif/dev-cli": "^1.23.1", "@types/body-parser": "^1.19.0", "@types/cors": "^2.8.8", diff --git a/packages/cubejs-snowflake-driver/CHANGELOG.md b/packages/cubejs-snowflake-driver/CHANGELOG.md index a967dc36dfcc6..7c71539e60760 100644 --- a/packages/cubejs-snowflake-driver/CHANGELOG.md +++ b/packages/cubejs-snowflake-driver/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-backend/snowflake-driver + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) **Note:** Version bump only for package @cubejs-backend/snowflake-driver diff --git a/packages/cubejs-snowflake-driver/package.json b/packages/cubejs-snowflake-driver/package.json index 676c6695abf63..402dda221eb30 100644 --- a/packages/cubejs-snowflake-driver/package.json +++ b/packages/cubejs-snowflake-driver/package.json @@ -2,7 +2,7 @@ "name": "@cubejs-backend/snowflake-driver", "description": "Cube.js Snowflake database driver", "author": "Cube Dev, Inc.", - "version": "1.7.31", + "version": "1.7.32", "repository": { "type": "git", "url": "https://github.com/cube-js/cube.git", @@ -29,8 +29,8 @@ }, "dependencies": { "@aws-sdk/client-s3": "^3.726.0", - "@cubejs-backend/base-driver": "1.7.31", - "@cubejs-backend/shared": "1.7.31", + "@cubejs-backend/base-driver": "1.7.32", + "@cubejs-backend/shared": "1.7.32", "snowflake-sdk": "^2.4.0" }, "license": "Apache-2.0", @@ -41,7 +41,7 @@ "extends": "../cubejs-linter" }, "devDependencies": { - "@cubejs-backend/linter": "1.7.31", + "@cubejs-backend/linter": "1.7.32", "typescript": "~5.2.2", "vitest": "^4" } diff --git a/packages/cubejs-sqlite-driver/CHANGELOG.md b/packages/cubejs-sqlite-driver/CHANGELOG.md index bd33db79ae477..99b8ffb1996a3 100644 --- a/packages/cubejs-sqlite-driver/CHANGELOG.md +++ b/packages/cubejs-sqlite-driver/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-backend/sqlite-driver + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) **Note:** Version bump only for package @cubejs-backend/sqlite-driver diff --git a/packages/cubejs-sqlite-driver/package.json b/packages/cubejs-sqlite-driver/package.json index 3d536acd9a176..eb2d6318093e1 100644 --- a/packages/cubejs-sqlite-driver/package.json +++ b/packages/cubejs-sqlite-driver/package.json @@ -2,7 +2,7 @@ "name": "@cubejs-backend/sqlite-driver", "description": "Cube.js Sqlite database driver", "author": "Cube Dev, Inc.", - "version": "1.7.31", + "version": "1.7.32", "repository": { "type": "git", "url": "https://github.com/cube-js/cube.git", @@ -18,13 +18,13 @@ "unit": "jest" }, "dependencies": { - "@cubejs-backend/base-driver": "1.7.31", - "@cubejs-backend/shared": "1.7.31", + "@cubejs-backend/base-driver": "1.7.32", + "@cubejs-backend/shared": "1.7.32", "sqlite3": "^5.1.7" }, "license": "Apache-2.0", "devDependencies": { - "@cubejs-backend/linter": "1.7.31", + "@cubejs-backend/linter": "1.7.32", "jest": "^29" }, "publishConfig": { diff --git a/packages/cubejs-templates/CHANGELOG.md b/packages/cubejs-templates/CHANGELOG.md index 5473e5f3bec07..1780f6d89eddb 100644 --- a/packages/cubejs-templates/CHANGELOG.md +++ b/packages/cubejs-templates/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-backend/templates + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) **Note:** Version bump only for package @cubejs-backend/templates diff --git a/packages/cubejs-templates/package.json b/packages/cubejs-templates/package.json index 02a949c3f2466..21dccfbfe6dad 100644 --- a/packages/cubejs-templates/package.json +++ b/packages/cubejs-templates/package.json @@ -1,6 +1,6 @@ { "name": "@cubejs-backend/templates", - "version": "1.7.31", + "version": "1.7.32", "description": "Cube.js Templates helpers", "author": "Cube Dev, Inc.", "repository": { @@ -31,7 +31,7 @@ "extends": "../cubejs-linter" }, "dependencies": { - "@cubejs-backend/shared": "1.7.31", + "@cubejs-backend/shared": "1.7.32", "cross-spawn": "^7.0.3", "fs-extra": "^9.1.0", "node-fetch": "^2.6.1", @@ -40,7 +40,7 @@ "tar": "^7.5.22" }, "devDependencies": { - "@cubejs-backend/linter": "1.7.31", + "@cubejs-backend/linter": "1.7.32", "typescript": "~5.2.2" } } diff --git a/packages/cubejs-testing-drivers/CHANGELOG.md b/packages/cubejs-testing-drivers/CHANGELOG.md index afebdfb4b995d..6a0ef8df433d5 100644 --- a/packages/cubejs-testing-drivers/CHANGELOG.md +++ b/packages/cubejs-testing-drivers/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-backend/testing-drivers + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) **Note:** Version bump only for package @cubejs-backend/testing-drivers diff --git a/packages/cubejs-testing-drivers/package.json b/packages/cubejs-testing-drivers/package.json index 99d1bb776d5d7..44b27057dc174 100644 --- a/packages/cubejs-testing-drivers/package.json +++ b/packages/cubejs-testing-drivers/package.json @@ -1,6 +1,6 @@ { "name": "@cubejs-backend/testing-drivers", - "version": "1.7.31", + "version": "1.7.32", "description": "Cube.js drivers test suite", "author": "Cube Dev, Inc.", "repository": { @@ -87,29 +87,29 @@ "dist/src" ], "dependencies": { - "@cubejs-backend/athena-driver": "1.7.31", - "@cubejs-backend/base-driver": "1.7.31", - "@cubejs-backend/bigquery-driver": "1.7.31", - "@cubejs-backend/clickhouse-driver": "1.7.31", - "@cubejs-backend/crate-driver": "1.7.31", - "@cubejs-backend/cubestore-driver": "1.7.31", - "@cubejs-backend/databricks-jdbc-driver": "1.7.31", + "@cubejs-backend/athena-driver": "1.7.32", + "@cubejs-backend/base-driver": "1.7.32", + "@cubejs-backend/bigquery-driver": "1.7.32", + "@cubejs-backend/clickhouse-driver": "1.7.32", + "@cubejs-backend/crate-driver": "1.7.32", + "@cubejs-backend/cubestore-driver": "1.7.32", + "@cubejs-backend/databricks-jdbc-driver": "1.7.32", "@cubejs-backend/dotenv": "^9.0.2", - "@cubejs-backend/linter": "1.7.31", - "@cubejs-backend/mssql-driver": "1.7.31", - "@cubejs-backend/mysql-driver": "1.7.31", - "@cubejs-backend/oracle-driver": "1.7.31", - "@cubejs-backend/pinot-driver": "1.7.31", - "@cubejs-backend/postgres-driver": "1.7.31", - "@cubejs-backend/query-orchestrator": "1.7.31", - "@cubejs-backend/questdb-driver": "1.7.31", - "@cubejs-backend/server-core": "1.7.31", - "@cubejs-backend/shared": "1.7.31", - "@cubejs-backend/snowflake-driver": "1.7.31", - "@cubejs-backend/testing-shared": "1.7.31", - "@cubejs-backend/trino-driver": "1.7.31", - "@cubejs-client/core": "1.7.31", - "@cubejs-client/ws-transport": "1.7.31", + "@cubejs-backend/linter": "1.7.32", + "@cubejs-backend/mssql-driver": "1.7.32", + "@cubejs-backend/mysql-driver": "1.7.32", + "@cubejs-backend/oracle-driver": "1.7.32", + "@cubejs-backend/pinot-driver": "1.7.32", + "@cubejs-backend/postgres-driver": "1.7.32", + "@cubejs-backend/query-orchestrator": "1.7.32", + "@cubejs-backend/questdb-driver": "1.7.32", + "@cubejs-backend/server-core": "1.7.32", + "@cubejs-backend/shared": "1.7.32", + "@cubejs-backend/snowflake-driver": "1.7.32", + "@cubejs-backend/testing-shared": "1.7.32", + "@cubejs-backend/trino-driver": "1.7.32", + "@cubejs-client/core": "1.7.32", + "@cubejs-client/ws-transport": "1.7.32", "@jest/globals": "^29", "@types/jest": "^29", "@types/node": "^22", diff --git a/packages/cubejs-testing-shared/CHANGELOG.md b/packages/cubejs-testing-shared/CHANGELOG.md index 44c565adf37d8..525dd9da71d0c 100644 --- a/packages/cubejs-testing-shared/CHANGELOG.md +++ b/packages/cubejs-testing-shared/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-backend/testing-shared + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) ### Bug Fixes diff --git a/packages/cubejs-testing-shared/package.json b/packages/cubejs-testing-shared/package.json index 2ce65227996fa..aab62e81b0874 100644 --- a/packages/cubejs-testing-shared/package.json +++ b/packages/cubejs-testing-shared/package.json @@ -1,6 +1,6 @@ { "name": "@cubejs-backend/testing-shared", - "version": "1.7.31", + "version": "1.7.32", "description": "Cube.js Testing Helpers", "author": "Cube Dev, Inc.", "repository": { @@ -26,16 +26,16 @@ ], "dependencies": { "@cubejs-backend/dotenv": "^9.0.2", - "@cubejs-backend/query-orchestrator": "1.7.31", - "@cubejs-backend/schema-compiler": "1.7.31", - "@cubejs-backend/shared": "1.7.31", + "@cubejs-backend/query-orchestrator": "1.7.32", + "@cubejs-backend/schema-compiler": "1.7.32", + "@cubejs-backend/shared": "1.7.32", "@testcontainers/kafka": "~10.28.0", "dedent": "^0.7.0", "node-fetch": "^2.6.7", "testcontainers": "^10.28.0" }, "devDependencies": { - "@cubejs-backend/linter": "1.7.31", + "@cubejs-backend/linter": "1.7.32", "@jest/globals": "^29", "@types/dedent": "^0.7.0", "@types/jest": "^29", diff --git a/packages/cubejs-testing/CHANGELOG.md b/packages/cubejs-testing/CHANGELOG.md index bb9d27eb309a2..3759f78cc385b 100644 --- a/packages/cubejs-testing/CHANGELOG.md +++ b/packages/cubejs-testing/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-backend/testing + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) **Note:** Version bump only for package @cubejs-backend/testing diff --git a/packages/cubejs-testing/package.json b/packages/cubejs-testing/package.json index eb759b5c53074..b9b692c931fd9 100644 --- a/packages/cubejs-testing/package.json +++ b/packages/cubejs-testing/package.json @@ -1,6 +1,6 @@ { "name": "@cubejs-backend/testing", - "version": "1.7.31", + "version": "1.7.32", "description": "Cube.js e2e tests", "author": "Cube Dev, Inc.", "repository": { @@ -92,15 +92,15 @@ "birdbox-fixtures" ], "dependencies": { - "@cubejs-backend/cubestore-driver": "1.7.31", + "@cubejs-backend/cubestore-driver": "1.7.32", "@cubejs-backend/dotenv": "^9.0.2", - "@cubejs-backend/ksql-driver": "1.7.31", - "@cubejs-backend/postgres-driver": "1.7.31", - "@cubejs-backend/query-orchestrator": "1.7.31", - "@cubejs-backend/schema-compiler": "1.7.31", - "@cubejs-backend/shared": "1.7.31", - "@cubejs-backend/testing-shared": "1.7.31", - "@cubejs-client/ws-transport": "1.7.31", + "@cubejs-backend/ksql-driver": "1.7.32", + "@cubejs-backend/postgres-driver": "1.7.32", + "@cubejs-backend/query-orchestrator": "1.7.32", + "@cubejs-backend/schema-compiler": "1.7.32", + "@cubejs-backend/shared": "1.7.32", + "@cubejs-backend/testing-shared": "1.7.32", + "@cubejs-client/ws-transport": "1.7.32", "dedent": "^0.7.0", "fs-extra": "^8.1.0", "http-proxy": "^1.18.1", @@ -111,8 +111,8 @@ }, "devDependencies": { "@4tw/cypress-drag-drop": "^1.6.0", - "@cubejs-backend/linter": "1.7.31", - "@cubejs-client/core": "1.7.31", + "@cubejs-backend/linter": "1.7.32", + "@cubejs-client/core": "1.7.32", "@jest/globals": "^29", "@types/dedent": "^0.7.0", "@types/http-proxy": "^1.17.5", diff --git a/packages/cubejs-trino-driver/CHANGELOG.md b/packages/cubejs-trino-driver/CHANGELOG.md index f04447edc4794..d5f517fa9bfb3 100644 --- a/packages/cubejs-trino-driver/CHANGELOG.md +++ b/packages/cubejs-trino-driver/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-backend/trino-driver + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) **Note:** Version bump only for package @cubejs-backend/trino-driver diff --git a/packages/cubejs-trino-driver/package.json b/packages/cubejs-trino-driver/package.json index c742f72c1377a..df9bf85893aa1 100644 --- a/packages/cubejs-trino-driver/package.json +++ b/packages/cubejs-trino-driver/package.json @@ -2,7 +2,7 @@ "name": "@cubejs-backend/trino-driver", "description": "Cube.js Trino database driver", "author": "Cube Dev, Inc.", - "version": "1.7.31", + "version": "1.7.32", "repository": { "type": "git", "url": "https://github.com/cube-js/cube.git", @@ -28,10 +28,10 @@ "lint:fix": "eslint --fix src/* --ext .ts" }, "dependencies": { - "@cubejs-backend/base-driver": "1.7.31", - "@cubejs-backend/prestodb-driver": "1.7.31", - "@cubejs-backend/schema-compiler": "1.7.31", - "@cubejs-backend/shared": "1.7.31", + "@cubejs-backend/base-driver": "1.7.32", + "@cubejs-backend/prestodb-driver": "1.7.32", + "@cubejs-backend/schema-compiler": "1.7.32", + "@cubejs-backend/shared": "1.7.32", "node-fetch": "^2.6.1", "presto-client": "^1.2.0" }, @@ -40,7 +40,7 @@ "access": "public" }, "devDependencies": { - "@cubejs-backend/linter": "1.7.31", + "@cubejs-backend/linter": "1.7.32", "@types/jest": "^29", "jest": "^29", "testcontainers": "^10.28.0", diff --git a/packages/cubejs-vertica-driver/CHANGELOG.md b/packages/cubejs-vertica-driver/CHANGELOG.md index 23da6e1dd563b..689d69b3fe203 100644 --- a/packages/cubejs-vertica-driver/CHANGELOG.md +++ b/packages/cubejs-vertica-driver/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-backend/vertica-driver + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) **Note:** Version bump only for package @cubejs-backend/vertica-driver diff --git a/packages/cubejs-vertica-driver/package.json b/packages/cubejs-vertica-driver/package.json index e611a3a235699..6cc8f53e31546 100644 --- a/packages/cubejs-vertica-driver/package.json +++ b/packages/cubejs-vertica-driver/package.json @@ -2,7 +2,7 @@ "name": "@cubejs-backend/vertica-driver", "description": "Cube.js Vertica database driver", "author": "Eduard Karacharov, Tim Brown, Cube Dev, Inc.", - "version": "1.7.31", + "version": "1.7.32", "repository": { "type": "git", "url": "https://github.com/cube-js/cube.git", @@ -19,16 +19,16 @@ "lint:fix": "eslint --fix **/*.js" }, "dependencies": { - "@cubejs-backend/base-driver": "1.7.31", - "@cubejs-backend/query-orchestrator": "1.7.31", - "@cubejs-backend/schema-compiler": "1.7.31", - "@cubejs-backend/shared": "1.7.31", + "@cubejs-backend/base-driver": "1.7.32", + "@cubejs-backend/query-orchestrator": "1.7.32", + "@cubejs-backend/schema-compiler": "1.7.32", + "@cubejs-backend/shared": "1.7.32", "vertica-nodejs": "^1.0.3" }, "license": "Apache-2.0", "devDependencies": { - "@cubejs-backend/linter": "1.7.31", - "@cubejs-backend/testing-shared": "1.7.31", + "@cubejs-backend/linter": "1.7.32", + "@cubejs-backend/testing-shared": "1.7.32", "@types/jest": "^29", "jest": "^29", "testcontainers": "^10.28.0" diff --git a/rust/cubesql/CHANGELOG.md b/rust/cubesql/CHANGELOG.md index 0a32e521ebdd0..18a9af836353c 100644 --- a/rust/cubesql/CHANGELOG.md +++ b/rust/cubesql/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-backend/cubesql + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) ### Bug Fixes diff --git a/rust/cubesql/package.json b/rust/cubesql/package.json index e1b4b4f05289f..290a1668be595 100644 --- a/rust/cubesql/package.json +++ b/rust/cubesql/package.json @@ -1,6 +1,6 @@ { "name": "@cubejs-backend/cubesql", - "version": "1.7.31", + "version": "1.7.32", "description": "SQL API for Cube as proxy over MySQL protocol.", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" diff --git a/rust/cubestore/CHANGELOG.md b/rust/cubestore/CHANGELOG.md index 82b2af3fd13d1..c89ba2330c397 100644 --- a/rust/cubestore/CHANGELOG.md +++ b/rust/cubestore/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.32](https://github.com/cube-js/cube/compare/v1.7.31...v1.7.32) (2026-09-01) + +**Note:** Version bump only for package @cubejs-backend/cubestore + ## [1.7.31](https://github.com/cube-js/cube/compare/v1.7.30...v1.7.31) (2026-08-31) ### Performance Improvements diff --git a/rust/cubestore/Cargo.lock b/rust/cubestore/Cargo.lock index d0784092ea70d..15c9effe2fdb0 100644 --- a/rust/cubestore/Cargo.lock +++ b/rust/cubestore/Cargo.lock @@ -1445,7 +1445,7 @@ dependencies = [ [[package]] name = "cubestore" -version = "1.7.31" +version = "1.7.32" dependencies = [ "actix-rt", "anyhow", diff --git a/rust/cubestore/cubestore/Cargo.toml b/rust/cubestore/cubestore/Cargo.toml index 6fcc2e830e757..5b9a2fbfe5f9b 100644 --- a/rust/cubestore/cubestore/Cargo.toml +++ b/rust/cubestore/cubestore/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cubestore" -version = "1.7.31" +version = "1.7.32" authors = ["Cube Dev, Inc."] edition = "2021" license = "Apache-2.0" diff --git a/rust/cubestore/package.json b/rust/cubestore/package.json index b77034ae0cc9a..a8bdaebfb1a69 100644 --- a/rust/cubestore/package.json +++ b/rust/cubestore/package.json @@ -1,6 +1,6 @@ { "name": "@cubejs-backend/cubestore", - "version": "1.7.31", + "version": "1.7.32", "description": "Cube.js pre-aggregation storage layer.", "main": "dist/src/index.js", "typings": "dist/src/index.d.ts", @@ -33,7 +33,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@cubejs-backend/linter": "1.7.31", + "@cubejs-backend/linter": "1.7.32", "@types/jest": "^29", "@types/node": "^18", "jest": "^29", @@ -43,7 +43,7 @@ "access": "public" }, "dependencies": { - "@cubejs-backend/shared": "1.7.31", + "@cubejs-backend/shared": "1.7.32", "@octokit/core": "^3.2.5", "source-map-support": "^0.5.19" }, From f923b0ec998d0e8413b3fd33cbea0d5ef65c1651 Mon Sep 17 00:00:00 2001 From: Alex Qyoun-ae <4062971+MazterQyou@users.noreply.github.com> Date: Tue, 1 Sep 2026 22:54:08 +0400 Subject: [PATCH 5/5] fix(cubesql): Push `LIMIT 0` down to CubeScan (#11589) Signed-off-by: Alex Qyoun-ae <4062971+MazterQyou@users.noreply.github.com> --- .../test/normalize-query.test.ts | 12 ++ .../src/adapter/BaseQuery.js | 39 +++- .../src/adapter/MssqlQuery.ts | 42 +++- .../src/adapter/OracleQuery.ts | 6 +- .../src/adapter/PreAggregations.ts | 4 +- .../test/unit/mssql-query.test.ts | 188 ++++++++++++++++++ .../test/unit/oracle-query.test.ts | 33 +++ .../test/unit/postgres-query.test.ts | 18 ++ rust/cubesql/cubesql/src/compile/mod.rs | 58 ++++++ .../src/compile/rewrite/rules/members.rs | 5 - .../src/compile/test/test_cube_scan.rs | 67 +++++++ 11 files changed, 457 insertions(+), 15 deletions(-) diff --git a/packages/cubejs-api-gateway/test/normalize-query.test.ts b/packages/cubejs-api-gateway/test/normalize-query.test.ts index 75229aaa49d62..1899bd3811f84 100644 --- a/packages/cubejs-api-gateway/test/normalize-query.test.ts +++ b/packages/cubejs-api-gateway/test/normalize-query.test.ts @@ -161,3 +161,15 @@ describe('cubeSqlRequestSchema', () => { expect(cubeSqlRequestSchema.validate({ ...baseBody, timezone: tz }).error).toBeDefined(); }); }); + +describe('limit normalization', () => { + test('keeps an explicit limit of 0 instead of applying the default limit', () => { + const result = normalizeQuery({ ...baseQuery, limit: 0 }, false); + expect(result.limit).toBe(0); + }); + + test('applies the default limit when no limit is given', () => { + const result = normalizeQuery({ ...baseQuery }, false); + expect(result.limit).toBeGreaterThan(0); + }); +}); diff --git a/packages/cubejs-schema-compiler/src/adapter/BaseQuery.js b/packages/cubejs-schema-compiler/src/adapter/BaseQuery.js index 2536bc655f061..171e30f3457f2 100644 --- a/packages/cubejs-schema-compiler/src/adapter/BaseQuery.js +++ b/packages/cubejs-schema-compiler/src/adapter/BaseQuery.js @@ -962,8 +962,10 @@ export class BaseQuery { securityContext: this.contextSymbols.securityContext, order, filters: this.options.filters, - limit: this.options.limit ? this.options.limit.toString() : null, - rowLimit: this.options.rowLimit ? this.options.rowLimit.toString() : null, + limit: this.options.limit != null ? this.options.limit.toString() : null, + // `rowLimit: 0` is a valid limit (BI tools use `LIMIT 0` as a schema probe), + // so it must not be collapsed into `null` (no limit) here + rowLimit: this.options.rowLimit != null ? this.options.rowLimit.toString() : null, offset: this.options.offset ? this.options.offset.toString() : null, baseTools: this, ungrouped: this.options.ungrouped, @@ -1019,8 +1021,10 @@ export class BaseQuery { cubeEvaluator: this.cubeEvaluator, order, filters: this.options.filters, - limit: this.options.limit ? this.options.limit.toString() : null, - rowLimit: this.options.rowLimit ? this.options.rowLimit.toString() : null, + limit: this.options.limit != null ? this.options.limit.toString() : null, + // `rowLimit: 0` is a valid limit (BI tools use `LIMIT 0` as a schema probe), + // so it must not be collapsed into `null` (no limit) here + rowLimit: this.options.rowLimit != null ? this.options.rowLimit.toString() : null, offset: this.options.offset ? this.options.offset.toString() : null, baseTools: this, ungrouped: this.options.ungrouped, @@ -3226,6 +3230,33 @@ export class BaseQuery { return ''; } + /** + * Row limit as a number, or `null` when it is not set at all. Unlike a truthy check + * this keeps `0` (a valid limit that returns no rows) distinct from "no limit", and + * unlike a bare `parseInt` it keeps a non-numeric `rowLimit` out of the rendered SQL. + * @protected + * @returns {number|null} + */ + parsedRowLimit() { + if (this.rowLimit == null) { + return null; + } + const parsed = parseInt(this.rowLimit, 10); + return Number.isNaN(parsed) ? null : parsed; + } + + /** + * Leading row-limit clause for statements that do not render `topLimit()` -- the legacy + * rollup query in `PreAggregations` is the one such statement. Only dialects that cannot + * express a zero row limit as a trailing clause (T-SQL, where FETCH NEXT must be >= 1) + * return anything here; every other dialect renders `LIMIT 0` and gets `''`. + * @public + * @returns {string} + */ + zeroRowLimitTopClause() { + return ''; + } + baseSelect() { return R.flatten(this.forSelect().map(s => s.selectColumns())).filter(s => !!s).join(', '); } diff --git a/packages/cubejs-schema-compiler/src/adapter/MssqlQuery.ts b/packages/cubejs-schema-compiler/src/adapter/MssqlQuery.ts index fb3481b23c80c..0f9503df9d391 100644 --- a/packages/cubejs-schema-compiler/src/adapter/MssqlQuery.ts +++ b/packages/cubejs-schema-compiler/src/adapter/MssqlQuery.ts @@ -152,6 +152,11 @@ export class MssqlQuery extends BaseQuery { // TODO replace with limitOffsetClause override public groupByDimensionLimit() { + // T-SQL requires FETCH NEXT to be greater than zero, so a zero row limit is + // rendered as `TOP 0` by topLimit() instead, and OFFSET is redundant for it + if (this.parsedRowLimit() === 0) { + return ''; + } if (this.rowLimit) { return this.offset ? ` OFFSET ${parseInt(this.offset, 10)} ROWS FETCH NEXT ${parseInt(this.rowLimit, 10)} ROWS ONLY` : ''; } else { @@ -160,10 +165,32 @@ export class MssqlQuery extends BaseQuery { } public topLimit() { + // Deliberately a strict null check: an explicit `rowLimit: null` means "no limit", + // while an absent one keeps the historical TOP 10000 default below, since T-SQL has + // no LIMIT clause to fall back on + if (this.rowLimit === null) { + return ''; + } + const rowLimit = this.parsedRowLimit(); + // `TOP 0` is the only way to express an empty result in T-SQL, and it takes + // precedence over the offset branch below: OFFSET without FETCH would return rows + if (rowLimit === 0) { + return ' TOP 0'; + } if (this.offset) { return ''; } - return this.rowLimit === null ? '' : ` TOP ${this.rowLimit && parseInt(this.rowLimit, 10) || 10000}`; + return ` TOP ${rowLimit ?? 10000}`; + } + + /** + * The legacy rollup query in `PreAggregations` renders no `topLimit()`, so a zero row + * limit would otherwise emit no row-limiting clause there at all (groupByDimensionLimit() + * cannot express it: FETCH NEXT must be >= 1 in T-SQL) and scan the whole rollup. + * @override + */ + public zeroRowLimitTopClause() { + return this.parsedRowLimit() === 0 ? ' TOP 0' : ''; } /** @@ -348,7 +375,9 @@ export class MssqlQuery extends BaseQuery { templates.statements.select = '{% if ctes %} WITH \n' + '{{ ctes | join(\',\n\') }}\n' + '{% endif %}' + - 'SELECT {% if limit is not none and not order_by %}TOP {{ limit }} {% endif %}{% if distinct %}DISTINCT {% endif %}' + + // T-SQL clause order is SELECT [ALL | DISTINCT] [TOP (expr)], so DISTINCT has to come + // first: `SELECT TOP 0 DISTINCT ...` is a syntax error + 'SELECT {% if distinct %}DISTINCT {% endif %}{% if limit is not none and (not order_by or limit == 0) %}TOP {{ limit }} {% endif %}' + '{{ select_concat | map(attribute=\'aliased\') | join(\', \') }} {% if from %}\n' + 'FROM (\n' + '{{ from | indent(2, true) }}\n' + @@ -358,8 +387,13 @@ export class MssqlQuery extends BaseQuery { '{% if filter %}\nWHERE {{ filter }}{% endif %}' + '{% if group_by %}\nGROUP BY {{ group_by }}{% endif %}' + '{% if having %}\nHAVING {{ having }}{% endif %}' + - '{% if order_by %}\nORDER BY {{ order_by | map(attribute=\'expr\') | join(\', \') }}\nOFFSET {% if offset is not none %}{{ offset }}{% else %}0{% endif %} ROWS' + - '\nFETCH NEXT {% if limit is not none %}{{ limit }}{% else %}2147483647{% endif %} ROWS ONLY{% endif %}' + + '{% if order_by %}\nORDER BY {{ order_by | map(attribute=\'expr\') | join(\', \') }}' + + // FETCH NEXT must be greater than zero in T-SQL, so `LIMIT 0` is rendered as + // `TOP 0` above and the OFFSET/FETCH tail is dropped entirely. `limit` is always a + // number here (both renderers pass Option); `limit | int` would not work as a + // guard, since `none | int` is 0 and that would drop the 2147483647 fallback below + '{% if limit != 0 %}\nOFFSET {% if offset is not none %}{{ offset }}{% else %}0{% endif %} ROWS' + + '\nFETCH NEXT {% if limit is not none %}{{ limit }}{% else %}2147483647{% endif %} ROWS ONLY{% endif %}{% endif %}' + '{% if ctes %}\nOPTION (MAXRECURSION 0){% endif %}'; // T-SQL has no LIMIT, and neither TOP nor OFFSET/FETCH can be attached to a set // operation directly (OFFSET/FETCH also requires an ORDER BY), so a bounded set diff --git a/packages/cubejs-schema-compiler/src/adapter/OracleQuery.ts b/packages/cubejs-schema-compiler/src/adapter/OracleQuery.ts index 2f8dd5dde8e97..f21ab49bf8583 100644 --- a/packages/cubejs-schema-compiler/src/adapter/OracleQuery.ts +++ b/packages/cubejs-schema-compiler/src/adapter/OracleQuery.ts @@ -36,7 +36,11 @@ export class OracleQuery extends BaseQuery { * TODO replace with limitOffsetClause override */ public groupByDimensionLimit() { - const limitClause = this.rowLimit === null ? '' : ` FETCH NEXT ${this.rowLimit && parseInt(this.rowLimit, 10) || 10000} ROWS ONLY`; + // `rowLimit: 0` is a valid limit that returns no rows, so it must not fall back to the + // default below the way a truthy check would. Same null policy as MssqlQuery#topLimit: + // an explicit `rowLimit: null` means "no limit", an absent one keeps the 10000 default + const rowLimit = this.parsedRowLimit() ?? 10000; + const limitClause = this.rowLimit === null ? '' : ` FETCH NEXT ${rowLimit} ROWS ONLY`; const offsetClause = this.offset ? ` OFFSET ${parseInt(this.offset, 10)} ROWS` : ''; return `${offsetClause}${limitClause}`; } diff --git a/packages/cubejs-schema-compiler/src/adapter/PreAggregations.ts b/packages/cubejs-schema-compiler/src/adapter/PreAggregations.ts index 5fa4174ebbb44..212032f98b1df 100644 --- a/packages/cubejs-schema-compiler/src/adapter/PreAggregations.ts +++ b/packages/cubejs-schema-compiler/src/adapter/PreAggregations.ts @@ -1624,8 +1624,10 @@ export class PreAggregations { return this.query.evaluateSymbolSqlWithContext( () => { + // zeroRowLimitTopClause() is empty for every dialect that can express a zero row + // limit as a trailing clause; T-SQL can not, and this statement has no topLimit() // eslint-disable-next-line prefer-template - const query = `SELECT ${this.query.selectAllDimensionsAndMeasures(measures)} FROM ${from} ${this.query.baseWhere(replacedFilters)}` + + const query = `SELECT${this.query.zeroRowLimitTopClause()} ${this.query.selectAllDimensionsAndMeasures(measures)} FROM ${from} ${this.query.baseWhere(replacedFilters)}` + this.query.groupByClause(); return isFullSimpleQuery ? this.query.baseHaving(query, this.query.measureFilters) + diff --git a/packages/cubejs-schema-compiler/test/unit/mssql-query.test.ts b/packages/cubejs-schema-compiler/test/unit/mssql-query.test.ts index 4d13071990f3b..8dd435f19f506 100644 --- a/packages/cubejs-schema-compiler/test/unit/mssql-query.test.ts +++ b/packages/cubejs-schema-compiler/test/unit/mssql-query.test.ts @@ -196,6 +196,194 @@ describe('MssqlQuery', () => { expect(/GROUP BY/.test(queryString)).toEqual(false); })); + it('renders rowLimit: 0 as TOP 0 without an invalid FETCH NEXT 0', async () => { + await compiler.compile(); + + // With an ORDER BY the template would normally emit OFFSET/FETCH NEXT, but T-SQL + // rejects `FETCH NEXT 0 ROWS ONLY`, so a zero limit has to go through TOP + const query = new MssqlQuery({ joinGraph, cubeEvaluator, compiler }, { + measures: ['visitors.count'], + dimensions: ['visitors.source'], + order: [{ id: 'visitors.source', desc: false }], + timezone: 'UTC', + rowLimit: 0, + }); + + const sql = query.buildSqlAndParams()[0]; + + expect(sql).toContain('TOP 0'); + expect(sql).not.toContain('FETCH NEXT'); + }); + + it('renders rowLimit: 0 with an offset as TOP 0 and no OFFSET tail', async () => { + await compiler.compile(); + + // T-SQL forbids TOP together with OFFSET/FETCH, and a zero limit yields no rows + // whatever the offset is, so the whole OFFSET/FETCH tail has to go + const query = new MssqlQuery({ joinGraph, cubeEvaluator, compiler }, { + measures: ['visitors.count'], + dimensions: ['visitors.source'], + order: [{ id: 'visitors.source', desc: false }], + timezone: 'UTC', + rowLimit: 0, + offset: 10, + }); + + const sql = query.buildSqlAndParams()[0]; + + expect(sql).toContain('TOP 0'); + expect(sql).not.toContain('FETCH NEXT'); + expect(sql).not.toContain('OFFSET'); + }); + + it('still renders OFFSET/FETCH NEXT for a non-zero rowLimit with an offset', async () => { + await compiler.compile(); + + const query = new MssqlQuery({ joinGraph, cubeEvaluator, compiler }, { + measures: ['visitors.count'], + dimensions: ['visitors.source'], + order: [{ id: 'visitors.source', desc: false }], + timezone: 'UTC', + rowLimit: 5, + offset: 10, + }); + + const sql = query.buildSqlAndParams()[0]; + + expect(sql).toContain('OFFSET 10 ROWS'); + expect(sql).toContain('FETCH NEXT 5 ROWS ONLY'); + expect(sql).not.toContain('TOP'); + }); + + it('renders DISTINCT before TOP in the select template', async () => { + await compiler.compile(); + + const query = new MssqlQuery({ joinGraph, cubeEvaluator, compiler }, { + measures: ['visitors.count'], + timezone: 'UTC', + rowLimit: 0, + }); + + // T-SQL clause order is SELECT [ALL | DISTINCT] [TOP (expr)], so `SELECT TOP 0 DISTINCT` + // is a syntax error. A single select carrying both is reachable through the cubesql + // wrapper (`SELECT DISTINCT ... LIMIT 0`), which can't be built from here, so the + // template itself is what gets pinned + const { select } = query.sqlTemplates().statements; + + expect(select).toContain('DISTINCT'); + expect(select).toContain('TOP'); + expect(select.indexOf('DISTINCT')).toBeLessThan(select.indexOf('TOP')); + }); + + it('keeps rowLimit: 0 out of the legacy limit clauses', async () => { + await compiler.compile(); + + const query = new MssqlQuery({ joinGraph, cubeEvaluator, compiler }, { + measures: ['visitors.count'], + timezone: 'UTC', + rowLimit: 0, + offset: 10, + }); + + expect(query.topLimit()).toEqual(' TOP 0'); + expect(query.groupByDimensionLimit()).toEqual(''); + // The legacy rollup query in PreAggregations renders no topLimit(), so the zero limit + // has to come from this hook or that statement would scan the whole rollup + expect(query.zeroRowLimitTopClause()).toEqual(' TOP 0'); + }); + + it('renders no leading zero-limit clause for a non-zero rowLimit', async () => { + await compiler.compile(); + + const query = new MssqlQuery({ joinGraph, cubeEvaluator, compiler }, { + measures: ['visitors.count'], + timezone: 'UTC', + rowLimit: 5, + }); + + expect(query.zeroRowLimitTopClause()).toEqual(''); + }); + + it('renders TOP 0 in the legacy-planner pre-aggregation rollup query', async () => { + // The rollup statement in PreAggregations renders no topLimit(), and T-SQL cannot put a + // zero limit in a trailing clause, so without zeroRowLimitTopClause() a `rowLimit: 0` + // query served from a pre-aggregation would scan the whole rollup + const preAggCompilers = prepareJsCompiler(` + cube('visits', { + sql: 'SELECT * FROM visits', + + preAggregations: { + bySource: { + measures: [CUBE.count], + dimensions: [CUBE.source], + }, + }, + + measures: { + count: { type: 'count' }, + }, + + dimensions: { + id: { sql: 'id', type: 'number', primaryKey: true }, + source: { sql: 'source', type: 'string' }, + }, + }); + `); + await preAggCompilers.compiler.compile(); + + const queryOptions = { + measures: ['visits.count'], + dimensions: ['visits.source'], + timezone: 'UTC', + useNativeSqlPlanner: false, + preAggregationsSchema: '', + }; + + const zeroLimit = new MssqlQuery({ + joinGraph: preAggCompilers.joinGraph, + cubeEvaluator: preAggCompilers.cubeEvaluator, + compiler: preAggCompilers.compiler, + }, { ...queryOptions, rowLimit: 0 }); + + const zeroLimitSql = zeroLimit.buildSqlAndParams()[0]; + + expect(zeroLimit.preAggregations.findPreAggregationForQuery()).toBeDefined(); + expect(zeroLimitSql).toContain('TOP 0'); + + const nonZeroLimit = new MssqlQuery({ + joinGraph: preAggCompilers.joinGraph, + cubeEvaluator: preAggCompilers.cubeEvaluator, + compiler: preAggCompilers.compiler, + }, { ...queryOptions, rowLimit: 5 }); + + // Non-zero limits keep their existing rendering on this path + expect(nonZeroLimit.buildSqlAndParams()[0]).not.toContain('TOP 0'); + }); + + it('keeps DISTINCT and TOP 0 in a valid order for a multiplied-measure query', async () => { + await joinedSchemaCompilers.compiler.compile(); + + // Multiplied measures make the full-key-aggregate path emit DISTINCT keys sub-selects + // alongside the TOP 0 outer select + const query = new MssqlQuery({ + joinGraph: joinedSchemaCompilers.joinGraph, + cubeEvaluator: joinedSchemaCompilers.cubeEvaluator, + compiler: joinedSchemaCompilers.compiler, + }, { + measures: ['B.bval_sum', 'C.count'], + dimensions: ['B.bid'], + order: [{ id: 'B.bid', desc: false }], + timezone: 'UTC', + rowLimit: 0, + }); + + const sql = query.buildSqlAndParams()[0]; + + expect(sql).toContain('TOP 0'); + expect(sql).toContain('DISTINCT'); + expect(sql).not.toMatch(/TOP\s+0\s+DISTINCT/); + }); + it('aggregating on top of sub-queries', async () => { await joinedSchemaCompilers.compiler.compile(); const query = new MssqlQuery({ diff --git a/packages/cubejs-schema-compiler/test/unit/oracle-query.test.ts b/packages/cubejs-schema-compiler/test/unit/oracle-query.test.ts index 58bf4f2696d70..78c1921dfb427 100644 --- a/packages/cubejs-schema-compiler/test/unit/oracle-query.test.ts +++ b/packages/cubejs-schema-compiler/test/unit/oracle-query.test.ts @@ -236,6 +236,39 @@ describe('OracleQuery', () => { expect(sql).not.toContain('LIMIT'); }); + it('renders rowLimit: 0 as FETCH NEXT 0 ROWS ONLY', async () => { + await compiler.compile(); + + const query = new OracleQuery({ joinGraph, cubeEvaluator, compiler }, { + measures: [ + 'visitors.count' + ], + timezone: 'UTC', + rowLimit: 0 + }); + + const sql = query.buildSqlAndParams()[0]; + + expect(sql).toContain('FETCH NEXT 0 ROWS ONLY'); + // A truthy check on rowLimit used to fall back to the default limit here + expect(sql).not.toContain('10000'); + expect(query.groupByDimensionLimit()).toEqual(' FETCH NEXT 0 ROWS ONLY'); + }); + + it('keeps the documented null policy for rowLimit', async () => { + await compiler.compile(); + + const newQuery = (rowLimit?: number | null) => new OracleQuery( + { joinGraph, cubeEvaluator, compiler }, + { measures: ['visitors.count'], timezone: 'UTC', ...(rowLimit === undefined ? {} : { rowLimit }) } + ); + + // An absent rowLimit keeps the historical default, an explicit null means no limit + expect(newQuery().groupByDimensionLimit()).toEqual(' FETCH NEXT 10000 ROWS ONLY'); + expect(newQuery(null).groupByDimensionLimit()).toEqual(''); + expect(newQuery(0).groupByDimensionLimit()).toEqual(' FETCH NEXT 0 ROWS ONLY'); + }); + it('uses FETCH NEXT syntax with subqueries and rolling windows', async () => { await compiler.compile(); diff --git a/packages/cubejs-schema-compiler/test/unit/postgres-query.test.ts b/packages/cubejs-schema-compiler/test/unit/postgres-query.test.ts index cf59f4c39eab3..40591351629e5 100644 --- a/packages/cubejs-schema-compiler/test/unit/postgres-query.test.ts +++ b/packages/cubejs-schema-compiler/test/unit/postgres-query.test.ts @@ -384,6 +384,24 @@ describe('PostgresQuery', () => { expect(sql).toMatch(/WHERE/i); }); + it('pushes down rowLimit: 0 as LIMIT 0', async () => { + await compiler.compile(); + + const query = new PostgresQuery({ joinGraph, cubeEvaluator, compiler }, { + measures: [ + 'visitors.count' + ], + dimensions: [ + 'visitors.name' + ], + timezone: 'UTC', + rowLimit: 0, + }); + + const queryAndParams = query.buildSqlAndParams(); + expect(queryAndParams[0]).toContain('LIMIT 0'); + }); + it('uses AS keyword in subquery aliases (regression test)', async () => { await compiler.compile(); diff --git a/rust/cubesql/cubesql/src/compile/mod.rs b/rust/cubesql/cubesql/src/compile/mod.rs index a66370f23d007..bda2ae3768937 100644 --- a/rust/cubesql/cubesql/src/compile/mod.rs +++ b/rust/cubesql/cubesql/src/compile/mod.rs @@ -13922,6 +13922,64 @@ ORDER BY "source"."str0" ASC insta::assert_snapshot!(context.execute_query(query).await.unwrap()); } + /// `LIMIT 0` should reach the transport as `limit: 0` (and not as the default row + /// limit), and execute into an empty result + #[tokio::test] + async fn test_cube_scan_exec_limit_zero() { + init_testing_logger(); + + let context = TestContext::new(DatabaseProtocol::PostgreSQL).await; + + // language=PostgreSQL + let query = r#" + SELECT dim_str0 + FROM MultiTypeCube + GROUP BY 1 + LIMIT 0 + "#; + + let expected_cube_scan = V1LoadRequestQuery { + measures: Some(vec![]), + segments: Some(vec![]), + dimensions: Some(vec!["MultiTypeCube.dim_str0".to_string()]), + order: Some(vec![]), + limit: Some(0), + ..Default::default() + }; + + assert_eq!( + context + .convert_sql_to_cube_query(query) + .await + .unwrap() + .as_logical_plan() + .find_cube_scan() + .request, + expected_cube_scan, + ); + + // Mock is matched by the exact request, so execution would fail here if anything + // downstream replaced `limit: 0` with a default limit + context + .add_cube_load_mock( + expected_cube_scan, + simple_load_response(vec!["MultiTypeCube.dim_str0"], vec![vec![]]), + ) + .await; + + let result = context.execute_query(query).await.unwrap(); + assert_eq!( + result.trim(), + [ + "+----------+", + "| dim_str0 |", + "+----------+", + "+----------+", + ] + .join("\n") + ); + } + #[tokio::test] async fn test_wrapper_tableau_week_number() { if !Rewriter::sql_push_down_enabled() { diff --git a/rust/cubesql/cubesql/src/compile/rewrite/rules/members.rs b/rust/cubesql/cubesql/src/compile/rewrite/rules/members.rs index ebccb095aec62..3ad1983571cbc 100644 --- a/rust/cubesql/cubesql/src/compile/rewrite/rules/members.rs +++ b/rust/cubesql/cubesql/src/compile/rewrite/rules/members.rs @@ -2140,11 +2140,6 @@ impl MemberRules { fetch_value = *fetch; break; } - // TODO support this case - if fetch_value == Some(0) { - // Broken and unsupported case for now - return false; - } let mut inner_skip_value = None; for inner_skip in var_iter!(egraph[subst[inner_skip_var]], CubeScanOffset) { diff --git a/rust/cubesql/cubesql/src/compile/test/test_cube_scan.rs b/rust/cubesql/cubesql/src/compile/test/test_cube_scan.rs index c8686e4da883f..7052f35e2a570 100644 --- a/rust/cubesql/cubesql/src/compile/test/test_cube_scan.rs +++ b/rust/cubesql/cubesql/src/compile/test/test_cube_scan.rs @@ -100,6 +100,73 @@ async fn cubescan_limit_limit() { } } +/// LIMIT 0 should be pushed to CubeScan as limit=0, and not replaced with a default limit +#[tokio::test] +async fn cubescan_limit_zero() { + init_testing_logger(); + + let variants = vec![ + // language=PostgreSQL + r#" + SELECT + customer_gender + FROM + KibanaSampleDataEcommerce + GROUP BY + 1 + LIMIT 0 + "#, + // language=PostgreSQL + r#" + SELECT + customer_gender + FROM ( + SELECT + customer_gender + FROM + KibanaSampleDataEcommerce + GROUP BY + 1 + LIMIT 3 + ) scan + LIMIT 0 + "#, + // language=PostgreSQL + r#" + SELECT + customer_gender + FROM ( + SELECT + customer_gender + FROM + KibanaSampleDataEcommerce + GROUP BY + 1 + LIMIT 0 + ) scan + LIMIT 3 + "#, + ]; + + for variant in variants { + let query_plan = + convert_select_to_query_plan(variant.to_string(), DatabaseProtocol::PostgreSQL).await; + + let logical_plan = query_plan.as_logical_plan(); + assert_eq!( + logical_plan.find_cube_scan().request, + V1LoadRequestQuery { + measures: Some(vec![]), + dimensions: Some(vec!["KibanaSampleDataEcommerce.customer_gender".to_string()]), + segments: Some(vec![]), + order: Some(vec![]), + limit: Some(0), + ..Default::default() + } + ); + } +} + /// OFFSET over OFFSET should be pushed to single CubeScan #[tokio::test] async fn cubescan_offset_offset() {