From ce59d69bc8ab320dc36406de222c7e089f461ff1 Mon Sep 17 00:00:00 2001 From: Konstantin Burkalev Date: Tue, 17 Jun 2025 15:31:25 +0300 Subject: [PATCH 01/10] ConvertTZ and date_trunc should not change the data type as time dims should be timestamps --- .../cubejs-schema-compiler/src/adapter/BigqueryQuery.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/cubejs-schema-compiler/src/adapter/BigqueryQuery.ts b/packages/cubejs-schema-compiler/src/adapter/BigqueryQuery.ts index c13e26d224f37..163d5bcce400b 100644 --- a/packages/cubejs-schema-compiler/src/adapter/BigqueryQuery.ts +++ b/packages/cubejs-schema-compiler/src/adapter/BigqueryQuery.ts @@ -42,7 +42,7 @@ export class BigqueryQuery extends BaseQuery { } public convertTz(field) { - return `DATETIME(${this.timeStampCast(field)}, '${this.timezone}')`; + return `TIMESTAMP(DATETIME(${field}), '${this.timezone}')`; } public timeStampCast(value) { @@ -58,7 +58,7 @@ export class BigqueryQuery extends BaseQuery { } public timeGroupedColumn(granularity, dimension) { - return `DATETIME_TRUNC(${dimension}, ${GRANULARITY_TO_INTERVAL[granularity]})`; + return this.timeStampCast(`DATETIME_TRUNC(${dimension}, ${GRANULARITY_TO_INTERVAL[granularity]})`); } /** @@ -72,7 +72,7 @@ export class BigqueryQuery extends BaseQuery { return `(${this.dateTimeCast(`'${origin}'`)} + INTERVAL ${intervalFormatted} * CAST(FLOOR( - DATETIME_DIFF(${source}, ${this.dateTimeCast(`'${origin}'`)}, ${timeUnit}) / + DATETIME_DIFF(${this.dateTimeCast(source)}, ${this.dateTimeCast(`'${origin}'`)}, ${timeUnit}) / DATETIME_DIFF(${beginOfTime} + INTERVAL ${intervalFormatted}, ${beginOfTime}, ${timeUnit}) ) AS INT64))`; } From 0493052027dbedb78f9c4c2f8102d9325a6b3120 Mon Sep 17 00:00:00 2001 From: Konstantin Burkalev Date: Tue, 17 Jun 2025 15:35:33 +0300 Subject: [PATCH 02/10] fix intervals math in bq --- .../src/adapter/BigqueryQuery.ts | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/cubejs-schema-compiler/src/adapter/BigqueryQuery.ts b/packages/cubejs-schema-compiler/src/adapter/BigqueryQuery.ts index 163d5bcce400b..cdb943ee38ce6 100644 --- a/packages/cubejs-schema-compiler/src/adapter/BigqueryQuery.ts +++ b/packages/cubejs-schema-compiler/src/adapter/BigqueryQuery.ts @@ -182,31 +182,31 @@ export class BigqueryQuery extends BaseQuery { } public subtractInterval(date, interval) { - return `DATETIME_SUB(${date}, INTERVAL ${this.formatInterval(interval)[0]})`; - } - - public addInterval(date, interval) { - return `DATETIME_ADD(${date}, INTERVAL ${this.formatInterval(interval)[0]})`; - } - - public subtractTimestampInterval(date, interval) { const [intervalFormatted, timeUnit] = this.formatInterval(interval); - if (['YEAR', 'MONTH', 'QUARTER'].includes(timeUnit)) { + if (['YEAR', 'MONTH', 'QUARTER'].includes(timeUnit) || intervalFormatted.includes('WEEK')) { return this.timeStampCast(`DATETIME_SUB(DATETIME(${date}), INTERVAL ${intervalFormatted})`); } return `TIMESTAMP_SUB(${date}, INTERVAL ${intervalFormatted})`; } - public addTimestampInterval(date, interval) { + public addInterval(date, interval) { const [intervalFormatted, timeUnit] = this.formatInterval(interval); - if (['YEAR', 'MONTH', 'QUARTER'].includes(timeUnit)) { + if (['YEAR', 'MONTH', 'QUARTER'].includes(timeUnit) || intervalFormatted.includes('WEEK')) { return this.timeStampCast(`DATETIME_ADD(DATETIME(${date}), INTERVAL ${intervalFormatted})`); } return `TIMESTAMP_ADD(${date}, INTERVAL ${intervalFormatted})`; } + public subtractTimestampInterval(timestamp, interval) { + return this.subtractInterval(timestamp, interval); + } + + public addTimestampInterval(timestamp, interval) { + return this.addInterval(timestamp, interval); + } + public nowTimestampSql() { return 'CURRENT_TIMESTAMP()'; } From 9c51dfb8571463744c3ad267bc84b355d1c2cb95 Mon Sep 17 00:00:00 2001 From: Konstantin Burkalev Date: Tue, 17 Jun 2025 15:36:20 +0300 Subject: [PATCH 03/10] fix join conditions date time datatypes comparisons for BQ --- .../src/adapter/BaseQuery.js | 11 +++++--- .../src/adapter/BigqueryQuery.ts | 27 +++++++++++++++++-- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/packages/cubejs-schema-compiler/src/adapter/BaseQuery.js b/packages/cubejs-schema-compiler/src/adapter/BaseQuery.js index 61392c094b3a4..b1f8665d36a0a 100644 --- a/packages/cubejs-schema-compiler/src/adapter/BaseQuery.js +++ b/packages/cubejs-schema-compiler/src/adapter/BaseQuery.js @@ -1788,8 +1788,12 @@ export class BaseQuery { const dateJoinConditionSql = dateJoinCondition.map( ([d, f]) => f( - `${d.dateSeriesAliasName()}.${this.escapeColumnName('date_from')}`, - `${d.dateSeriesAliasName()}.${this.escapeColumnName('date_to')}`, + // Time-series table is generated differently in different dialects, + // but some dialects (like BigQuery) require strict date types and can not automatically convert + // between date and timestamp for comparisons, at the same time, time dimensions are expected to be + // timestamps, so we need to align types for join conditions/comparisons. + this.timeStampCast(`${d.dateSeriesAliasName()}.${this.escapeColumnName('date_from')}`), + this.timeStampCast(`${d.dateSeriesAliasName()}.${this.escapeColumnName('date_to')}`), `${baseQueryAlias}.${d.aliasName()}`, `'${d.dateFromFormatted()}'`, `'${d.dateToFormatted()}'` @@ -1822,9 +1826,10 @@ export class BaseQuery { .join(', '); } + // BigQuery has strict date type and can not automatically convert between date + // and timestamp, so we override dateFromStartToEndConditionSql() in BigQuery Dialect dateFromStartToEndConditionSql(dateJoinCondition, fromRollup, isFromStartToEnd) { return dateJoinCondition.map( - // TODO these weird conversions to be strict typed for big query. // TODO Consider adding strict definitions of local and UTC time type ([d, f]) => ({ filterToWhere: () => { diff --git a/packages/cubejs-schema-compiler/src/adapter/BigqueryQuery.ts b/packages/cubejs-schema-compiler/src/adapter/BigqueryQuery.ts index cdb943ee38ce6..9b6abcb95ab43 100644 --- a/packages/cubejs-schema-compiler/src/adapter/BigqueryQuery.ts +++ b/packages/cubejs-schema-compiler/src/adapter/BigqueryQuery.ts @@ -215,6 +215,29 @@ export class BigqueryQuery extends BaseQuery { return `UNIX_SECONDS(${this.nowTimestampSql()})`; } + // Should be protected, but BaseQuery is in js + public override dateFromStartToEndConditionSql(dateJoinCondition, fromRollup, isFromStartToEnd) { + return dateJoinCondition.map( + ([d, f]) => ({ + filterToWhere: () => { + const timeSeries = d.timeSeries(); + return f( + isFromStartToEnd ? + this.timeStampCast(this.paramAllocator.allocateParam(timeSeries[0][0])) : + `${this.timeStampInClientTz(d.dateFromParam())}`, + isFromStartToEnd ? + this.timeStampCast(this.paramAllocator.allocateParam(timeSeries[timeSeries.length - 1][1])) : + `${this.timeStampInClientTz(d.dateToParam())}`, + `${fromRollup ? this.dimensionSql(d) : d.convertedToTz()}`, + `${this.timeStampInClientTz(d.dateFromParam())}`, + `${this.timeStampInClientTz(d.dateToParam())}`, + isFromStartToEnd + ); + } + }) + ); + } + // eslint-disable-next-line no-unused-vars public preAggregationLoadSql(cube, preAggregation, tableName) { return this.preAggregationSql(cube, preAggregation); @@ -250,7 +273,7 @@ export class BigqueryQuery extends BaseQuery { const templates = super.sqlTemplates(); templates.quotes.identifiers = '`'; templates.quotes.escape = '\\`'; - templates.functions.DATETRUNC = 'DATETIME_TRUNC(CAST({{ args[1] }} AS DATETIME), {% if date_part|upper == \'WEEK\' %}{{ \'WEEK(MONDAY)\' }}{% else %}{{ date_part }}{% endif %})'; + templates.functions.DATETRUNC = 'TIMESTAMP(DATETIME_TRUNC(CAST({{ args[1] }} AS DATETIME), {% if date_part|upper == \'WEEK\' %}{{ \'WEEK(MONDAY)\' }}{% else %}{{ date_part }}{% endif %}))'; templates.functions.LOG = 'LOG({{ args_concat }}{% if args[1] is undefined %}, 10{% endif %})'; templates.functions.BTRIM = 'TRIM({{ args_concat }})'; templates.functions.STRPOS = 'STRPOS({{ args_concat }})'; @@ -263,7 +286,7 @@ export class BigqueryQuery extends BaseQuery { templates.expressions.binary = '{% if op == \'%\' %}MOD({{ left }}, {{ right }}){% else %}({{ left }} {{ op }} {{ right }}){% endif %}'; templates.expressions.interval = 'INTERVAL {{ interval }}'; templates.expressions.extract = 'EXTRACT({% if date_part == \'DOW\' %}DAYOFWEEK{% elif date_part == \'DOY\' %}DAYOFYEAR{% else %}{{ date_part }}{% endif %} FROM {{ expr }})'; - templates.expressions.timestamp_literal = 'DATETIME(TIMESTAMP(\'{{ value }}\'))'; + templates.expressions.timestamp_literal = 'TIMESTAMP(\'{{ value }}\')'; delete templates.expressions.ilike; delete templates.expressions.like_escape; templates.filters.like_pattern = 'CONCAT({% if start_wild %}\'%\'{% else %}\'\'{% endif %}, LOWER({{ value }}), {% if end_wild %}\'%\'{% else %}\'\'{% endif %})'; From d5b6d692068c70f8bea5ef4e33c025f6afc49b0e Mon Sep 17 00:00:00 2001 From: Konstantin Burkalev Date: Tue, 17 Jun 2025 15:36:29 +0300 Subject: [PATCH 04/10] Add tests --- .../src/tests/testQueries.ts | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/packages/cubejs-testing-drivers/src/tests/testQueries.ts b/packages/cubejs-testing-drivers/src/tests/testQueries.ts index 7b90cb0680cd2..e4d52b55f04ab 100644 --- a/packages/cubejs-testing-drivers/src/tests/testQueries.ts +++ b/packages/cubejs-testing-drivers/src/tests/testQueries.ts @@ -2118,5 +2118,25 @@ from `); expect(res.rows).toMatchSnapshot(); }); + + executePg('SQL API: Date/time comparison with SQL push down', async (connection) => { + const res = await connection.query(` + SELECT MEASURE(BigECommerce.rollingCountBy2Day) + FROM BigECommerce + WHERE BigECommerce.orderDate < CAST('2021-01-01' AS TIMESTAMP) AND + LOWER("city") = 'columbus' + `); + expect(res.rows).toMatchSnapshot(); + }); + + executePg('SQL API: Date/time comparison with date_trunc with SQL push down', async (connection) => { + const res = await connection.query(` + SELECT MEASURE(BigECommerce.rollingCountBy2Week) + FROM BigECommerce + WHERE date_trunc('day', BigECommerce.orderDate) < CAST('2021-01-01' AS TIMESTAMP) AND + LOWER("city") = 'columbus' + `); + expect(res.rows).toMatchSnapshot(); + }); }); } From f1e8612ce50038830adb7285ef4e9dbee8cfe5da Mon Sep 17 00:00:00 2001 From: Konstantin Burkalev Date: Tue, 17 Jun 2025 15:47:32 +0300 Subject: [PATCH 05/10] update test snapshots --- .../athena-export-bucket-s3-full.test.ts.snap | 16 ++++++++++++++++ .../bigquery-export-bucket-gcs-full.test.ts.snap | 16 ++++++++++++++++ ...clickhouse-export-bucket-s3-full.test.ts.snap | 16 ++++++++++++++++ ...use-export-bucket-s3-prefix-full.test.ts.snap | 16 ++++++++++++++++ .../__snapshots__/clickhouse-full.test.ts.snap | 16 ++++++++++++++++ ...ks-jdbc-export-bucket-azure-full.test.ts.snap | 16 ++++++++++++++++ ...-export-bucket-azure-prefix-full.test.ts.snap | 16 ++++++++++++++++ ...icks-jdbc-export-bucket-gcs-full.test.ts.snap | 16 ++++++++++++++++ ...bc-export-bucket-gcs-prefix-full.test.ts.snap | 16 ++++++++++++++++ ...ricks-jdbc-export-bucket-s3-full.test.ts.snap | 16 ++++++++++++++++ ...dbc-export-bucket-s3-prefix-full.test.ts.snap | 16 ++++++++++++++++ .../databricks-jdbc-full.test.ts.snap | 16 ++++++++++++++++ .../test/__snapshots__/mssql-full.test.ts.snap | 16 ++++++++++++++++ .../test/__snapshots__/mysql-full.test.ts.snap | 16 ++++++++++++++++ .../__snapshots__/postgres-full.test.ts.snap | 16 ++++++++++++++++ .../redshift-export-bucket-s3-full.test.ts.snap | 16 ++++++++++++++++ .../__snapshots__/redshift-full.test.ts.snap | 16 ++++++++++++++++ .../snowflake-encrypted-pk-full.test.ts.snap | 16 ++++++++++++++++ ...owflake-export-bucket-azure-full.test.ts.snap | 16 ++++++++++++++++ ...-export-bucket-azure-prefix-full.test.ts.snap | 16 ++++++++++++++++ ...ure-via-storage-integration-full.test.ts.snap | 16 ++++++++++++++++ ...snowflake-export-bucket-gcs-full.test.ts.snap | 16 ++++++++++++++++ ...ke-export-bucket-gcs-prefix-full.test.ts.snap | 16 ++++++++++++++++ .../snowflake-export-bucket-s3-full.test.ts.snap | 16 ++++++++++++++++ ...ake-export-bucket-s3-prefix-full.test.ts.snap | 16 ++++++++++++++++ .../__snapshots__/snowflake-full.test.ts.snap | 16 ++++++++++++++++ 26 files changed, 416 insertions(+) diff --git a/packages/cubejs-testing-drivers/test/__snapshots__/athena-export-bucket-s3-full.test.ts.snap b/packages/cubejs-testing-drivers/test/__snapshots__/athena-export-bucket-s3-full.test.ts.snap index 0a5ec1590374a..c4185cbc02b0d 100644 --- a/packages/cubejs-testing-drivers/test/__snapshots__/athena-export-bucket-s3-full.test.ts.snap +++ b/packages/cubejs-testing-drivers/test/__snapshots__/athena-export-bucket-s3-full.test.ts.snap @@ -8007,3 +8007,19 @@ Array [ }, ] `; + +exports[`Queries with the @cubejs-backend/athena-driver SQL API: Date/time comparison with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Day)": "12", + }, +] +`; + +exports[`Queries with the @cubejs-backend/athena-driver SQL API: Date/time comparison with date_trunc with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Week)": "12", + }, +] +`; diff --git a/packages/cubejs-testing-drivers/test/__snapshots__/bigquery-export-bucket-gcs-full.test.ts.snap b/packages/cubejs-testing-drivers/test/__snapshots__/bigquery-export-bucket-gcs-full.test.ts.snap index 4ede85c023a74..696d5864d11ee 100644 --- a/packages/cubejs-testing-drivers/test/__snapshots__/bigquery-export-bucket-gcs-full.test.ts.snap +++ b/packages/cubejs-testing-drivers/test/__snapshots__/bigquery-export-bucket-gcs-full.test.ts.snap @@ -1,5 +1,21 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`Queries with the @cubejs-backend/bigquery-driver SQL API: Date/time comparison with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Day)": "12", + }, +] +`; + +exports[`Queries with the @cubejs-backend/bigquery-driver SQL API: Date/time comparison with date_trunc with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Week)": "12", + }, +] +`; + exports[`Queries with the @cubejs-backend/bigquery-driver SQL API: NULLS FIRST/LAST SQL push down: nulls_first_last_sql_push_down 1`] = ` Array [ Object { diff --git a/packages/cubejs-testing-drivers/test/__snapshots__/clickhouse-export-bucket-s3-full.test.ts.snap b/packages/cubejs-testing-drivers/test/__snapshots__/clickhouse-export-bucket-s3-full.test.ts.snap index f1275b929ff23..5408ba73216ca 100644 --- a/packages/cubejs-testing-drivers/test/__snapshots__/clickhouse-export-bucket-s3-full.test.ts.snap +++ b/packages/cubejs-testing-drivers/test/__snapshots__/clickhouse-export-bucket-s3-full.test.ts.snap @@ -8952,3 +8952,19 @@ Array [ }, ] `; + +exports[`Queries with the @cubejs-backend/clickhouse-driver export-bucket-s3 SQL API: Date/time comparison with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Day)": "12", + }, +] +`; + +exports[`Queries with the @cubejs-backend/clickhouse-driver export-bucket-s3 SQL API: Date/time comparison with date_trunc with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Week)": "12", + }, +] +`; diff --git a/packages/cubejs-testing-drivers/test/__snapshots__/clickhouse-export-bucket-s3-prefix-full.test.ts.snap b/packages/cubejs-testing-drivers/test/__snapshots__/clickhouse-export-bucket-s3-prefix-full.test.ts.snap index 343055c8a4b3a..81ae022e92d68 100644 --- a/packages/cubejs-testing-drivers/test/__snapshots__/clickhouse-export-bucket-s3-prefix-full.test.ts.snap +++ b/packages/cubejs-testing-drivers/test/__snapshots__/clickhouse-export-bucket-s3-prefix-full.test.ts.snap @@ -8952,3 +8952,19 @@ Array [ }, ] `; + +exports[`Queries with the @cubejs-backend/clickhouse-driver export-bucket-s3-prefix SQL API: Date/time comparison with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Day)": "12", + }, +] +`; + +exports[`Queries with the @cubejs-backend/clickhouse-driver export-bucket-s3-prefix SQL API: Date/time comparison with date_trunc with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Week)": "12", + }, +] +`; diff --git a/packages/cubejs-testing-drivers/test/__snapshots__/clickhouse-full.test.ts.snap b/packages/cubejs-testing-drivers/test/__snapshots__/clickhouse-full.test.ts.snap index 2221fdc128706..876500d525120 100644 --- a/packages/cubejs-testing-drivers/test/__snapshots__/clickhouse-full.test.ts.snap +++ b/packages/cubejs-testing-drivers/test/__snapshots__/clickhouse-full.test.ts.snap @@ -8952,3 +8952,19 @@ Array [ }, ] `; + +exports[`Queries with the @cubejs-backend/clickhouse-driver SQL API: Date/time comparison with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Day)": "12", + }, +] +`; + +exports[`Queries with the @cubejs-backend/clickhouse-driver SQL API: Date/time comparison with date_trunc with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Week)": "12", + }, +] +`; diff --git a/packages/cubejs-testing-drivers/test/__snapshots__/databricks-jdbc-export-bucket-azure-full.test.ts.snap b/packages/cubejs-testing-drivers/test/__snapshots__/databricks-jdbc-export-bucket-azure-full.test.ts.snap index 05ff7008ee367..5536ac59ddb91 100644 --- a/packages/cubejs-testing-drivers/test/__snapshots__/databricks-jdbc-export-bucket-azure-full.test.ts.snap +++ b/packages/cubejs-testing-drivers/test/__snapshots__/databricks-jdbc-export-bucket-azure-full.test.ts.snap @@ -14342,3 +14342,19 @@ Array [ }, ] `; + +exports[`Queries with the @cubejs-backend/databricks-jdbc-driver export-bucket-azure SQL API: Date/time comparison with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Day)": "12", + }, +] +`; + +exports[`Queries with the @cubejs-backend/databricks-jdbc-driver export-bucket-azure SQL API: Date/time comparison with date_trunc with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Week)": "12", + }, +] +`; diff --git a/packages/cubejs-testing-drivers/test/__snapshots__/databricks-jdbc-export-bucket-azure-prefix-full.test.ts.snap b/packages/cubejs-testing-drivers/test/__snapshots__/databricks-jdbc-export-bucket-azure-prefix-full.test.ts.snap index 050e772bc9269..96c4f6fe6042d 100644 --- a/packages/cubejs-testing-drivers/test/__snapshots__/databricks-jdbc-export-bucket-azure-prefix-full.test.ts.snap +++ b/packages/cubejs-testing-drivers/test/__snapshots__/databricks-jdbc-export-bucket-azure-prefix-full.test.ts.snap @@ -14147,3 +14147,19 @@ Array [ }, ] `; + +exports[`Queries with the @cubejs-backend/databricks-jdbc-driver export-bucket-azure-prefix SQL API: Date/time comparison with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Day)": "12", + }, +] +`; + +exports[`Queries with the @cubejs-backend/databricks-jdbc-driver export-bucket-azure-prefix SQL API: Date/time comparison with date_trunc with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Week)": "12", + }, +] +`; diff --git a/packages/cubejs-testing-drivers/test/__snapshots__/databricks-jdbc-export-bucket-gcs-full.test.ts.snap b/packages/cubejs-testing-drivers/test/__snapshots__/databricks-jdbc-export-bucket-gcs-full.test.ts.snap index 6d89ef63971ab..ccb26104fefcc 100644 --- a/packages/cubejs-testing-drivers/test/__snapshots__/databricks-jdbc-export-bucket-gcs-full.test.ts.snap +++ b/packages/cubejs-testing-drivers/test/__snapshots__/databricks-jdbc-export-bucket-gcs-full.test.ts.snap @@ -14342,3 +14342,19 @@ Array [ }, ] `; + +exports[`Queries with the @cubejs-backend/databricks-jdbc-driver export-bucket-gcs SQL API: Date/time comparison with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Day)": "12", + }, +] +`; + +exports[`Queries with the @cubejs-backend/databricks-jdbc-driver export-bucket-gcs SQL API: Date/time comparison with date_trunc with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Week)": "12", + }, +] +`; diff --git a/packages/cubejs-testing-drivers/test/__snapshots__/databricks-jdbc-export-bucket-gcs-prefix-full.test.ts.snap b/packages/cubejs-testing-drivers/test/__snapshots__/databricks-jdbc-export-bucket-gcs-prefix-full.test.ts.snap index 28fbad50da184..129ff15bd53b2 100644 --- a/packages/cubejs-testing-drivers/test/__snapshots__/databricks-jdbc-export-bucket-gcs-prefix-full.test.ts.snap +++ b/packages/cubejs-testing-drivers/test/__snapshots__/databricks-jdbc-export-bucket-gcs-prefix-full.test.ts.snap @@ -14147,3 +14147,19 @@ Array [ }, ] `; + +exports[`Queries with the @cubejs-backend/databricks-jdbc-driver export-bucket-gcs-prefix SQL API: Date/time comparison with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Day)": "12", + }, +] +`; + +exports[`Queries with the @cubejs-backend/databricks-jdbc-driver export-bucket-gcs-prefix SQL API: Date/time comparison with date_trunc with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Week)": "12", + }, +] +`; diff --git a/packages/cubejs-testing-drivers/test/__snapshots__/databricks-jdbc-export-bucket-s3-full.test.ts.snap b/packages/cubejs-testing-drivers/test/__snapshots__/databricks-jdbc-export-bucket-s3-full.test.ts.snap index f759420e12bc3..9ee352932017c 100644 --- a/packages/cubejs-testing-drivers/test/__snapshots__/databricks-jdbc-export-bucket-s3-full.test.ts.snap +++ b/packages/cubejs-testing-drivers/test/__snapshots__/databricks-jdbc-export-bucket-s3-full.test.ts.snap @@ -14342,3 +14342,19 @@ Array [ }, ] `; + +exports[`Queries with the @cubejs-backend/databricks-jdbc-driver export-bucket-s3 SQL API: Date/time comparison with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Day)": "12", + }, +] +`; + +exports[`Queries with the @cubejs-backend/databricks-jdbc-driver export-bucket-s3 SQL API: Date/time comparison with date_trunc with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Week)": "12", + }, +] +`; diff --git a/packages/cubejs-testing-drivers/test/__snapshots__/databricks-jdbc-export-bucket-s3-prefix-full.test.ts.snap b/packages/cubejs-testing-drivers/test/__snapshots__/databricks-jdbc-export-bucket-s3-prefix-full.test.ts.snap index 24c2cc871b852..663b8108366cf 100644 --- a/packages/cubejs-testing-drivers/test/__snapshots__/databricks-jdbc-export-bucket-s3-prefix-full.test.ts.snap +++ b/packages/cubejs-testing-drivers/test/__snapshots__/databricks-jdbc-export-bucket-s3-prefix-full.test.ts.snap @@ -14147,3 +14147,19 @@ Array [ }, ] `; + +exports[`Queries with the @cubejs-backend/databricks-jdbc-driver export-bucket-s3-prefix SQL API: Date/time comparison with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Day)": "12", + }, +] +`; + +exports[`Queries with the @cubejs-backend/databricks-jdbc-driver export-bucket-s3-prefix SQL API: Date/time comparison with date_trunc with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Week)": "12", + }, +] +`; diff --git a/packages/cubejs-testing-drivers/test/__snapshots__/databricks-jdbc-full.test.ts.snap b/packages/cubejs-testing-drivers/test/__snapshots__/databricks-jdbc-full.test.ts.snap index a54b78fd4398d..3f9d95646da5f 100644 --- a/packages/cubejs-testing-drivers/test/__snapshots__/databricks-jdbc-full.test.ts.snap +++ b/packages/cubejs-testing-drivers/test/__snapshots__/databricks-jdbc-full.test.ts.snap @@ -14342,3 +14342,19 @@ Array [ }, ] `; + +exports[`Queries with the @cubejs-backend/databricks-jdbc-driver SQL API: Date/time comparison with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Day)": "12", + }, +] +`; + +exports[`Queries with the @cubejs-backend/databricks-jdbc-driver SQL API: Date/time comparison with date_trunc with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Week)": "12", + }, +] +`; diff --git a/packages/cubejs-testing-drivers/test/__snapshots__/mssql-full.test.ts.snap b/packages/cubejs-testing-drivers/test/__snapshots__/mssql-full.test.ts.snap index 8d9558a3d6c72..9fd4bccf44874 100644 --- a/packages/cubejs-testing-drivers/test/__snapshots__/mssql-full.test.ts.snap +++ b/packages/cubejs-testing-drivers/test/__snapshots__/mssql-full.test.ts.snap @@ -6654,3 +6654,19 @@ Array [ }, ] `; + +exports[`Queries with the @cubejs-backend/mssql-driver SQL API: Date/time comparison with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Day)": "12", + }, +] +`; + +exports[`Queries with the @cubejs-backend/mssql-driver SQL API: Date/time comparison with date_trunc with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Week)": "12", + }, +] +`; diff --git a/packages/cubejs-testing-drivers/test/__snapshots__/mysql-full.test.ts.snap b/packages/cubejs-testing-drivers/test/__snapshots__/mysql-full.test.ts.snap index 052a00c0734b3..6152c29960239 100644 --- a/packages/cubejs-testing-drivers/test/__snapshots__/mysql-full.test.ts.snap +++ b/packages/cubejs-testing-drivers/test/__snapshots__/mysql-full.test.ts.snap @@ -7395,3 +7395,19 @@ Array [ }, ] `; + +exports[`Queries with the @cubejs-backend/mysql-driver SQL API: Date/time comparison with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Day)": 12, + }, +] +`; + +exports[`Queries with the @cubejs-backend/mysql-driver SQL API: Date/time comparison with date_trunc with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Week)": 12, + }, +] +`; diff --git a/packages/cubejs-testing-drivers/test/__snapshots__/postgres-full.test.ts.snap b/packages/cubejs-testing-drivers/test/__snapshots__/postgres-full.test.ts.snap index c432883af4846..7bfe549bb279d 100644 --- a/packages/cubejs-testing-drivers/test/__snapshots__/postgres-full.test.ts.snap +++ b/packages/cubejs-testing-drivers/test/__snapshots__/postgres-full.test.ts.snap @@ -1797,6 +1797,22 @@ Array [ ] `; +exports[`Queries with the @cubejs-backend/postgres-driver SQL API: Date/time comparison with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Day)": "12", + }, +] +`; + +exports[`Queries with the @cubejs-backend/postgres-driver SQL API: Date/time comparison with date_trunc with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Week)": "12", + }, +] +`; + exports[`Queries with the @cubejs-backend/postgres-driver SQL API: Extended nested Rollup over asterisk: extended_nested_rollup_over_asterisk 1`] = ` Array [ Object { diff --git a/packages/cubejs-testing-drivers/test/__snapshots__/redshift-export-bucket-s3-full.test.ts.snap b/packages/cubejs-testing-drivers/test/__snapshots__/redshift-export-bucket-s3-full.test.ts.snap index e463bcb330a7d..5c9df8f069749 100644 --- a/packages/cubejs-testing-drivers/test/__snapshots__/redshift-export-bucket-s3-full.test.ts.snap +++ b/packages/cubejs-testing-drivers/test/__snapshots__/redshift-export-bucket-s3-full.test.ts.snap @@ -16260,3 +16260,19 @@ Array [ }, ] `; + +exports[`Queries with the @cubejs-backend/redshift-driver export-bucket-s3 SQL API: Date/time comparison with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Day)": "12", + }, +] +`; + +exports[`Queries with the @cubejs-backend/redshift-driver export-bucket-s3 SQL API: Date/time comparison with date_trunc with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Week)": "12", + }, +] +`; diff --git a/packages/cubejs-testing-drivers/test/__snapshots__/redshift-full.test.ts.snap b/packages/cubejs-testing-drivers/test/__snapshots__/redshift-full.test.ts.snap index feb96785b15b6..c7004a6977685 100644 --- a/packages/cubejs-testing-drivers/test/__snapshots__/redshift-full.test.ts.snap +++ b/packages/cubejs-testing-drivers/test/__snapshots__/redshift-full.test.ts.snap @@ -16260,3 +16260,19 @@ Array [ }, ] `; + +exports[`Queries with the @cubejs-backend/redshift-driver SQL API: Date/time comparison with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Day)": "12", + }, +] +`; + +exports[`Queries with the @cubejs-backend/redshift-driver SQL API: Date/time comparison with date_trunc with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Week)": "12", + }, +] +`; diff --git a/packages/cubejs-testing-drivers/test/__snapshots__/snowflake-encrypted-pk-full.test.ts.snap b/packages/cubejs-testing-drivers/test/__snapshots__/snowflake-encrypted-pk-full.test.ts.snap index fc4da49bdd500..fe3816af0ca56 100644 --- a/packages/cubejs-testing-drivers/test/__snapshots__/snowflake-encrypted-pk-full.test.ts.snap +++ b/packages/cubejs-testing-drivers/test/__snapshots__/snowflake-encrypted-pk-full.test.ts.snap @@ -16415,3 +16415,19 @@ Array [ }, ] `; + +exports[`Queries with the @cubejs-backend/snowflake-driver encrypted-pk SQL API: Date/time comparison with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Day)": "12", + }, +] +`; + +exports[`Queries with the @cubejs-backend/snowflake-driver encrypted-pk SQL API: Date/time comparison with date_trunc with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Week)": "12", + }, +] +`; diff --git a/packages/cubejs-testing-drivers/test/__snapshots__/snowflake-export-bucket-azure-full.test.ts.snap b/packages/cubejs-testing-drivers/test/__snapshots__/snowflake-export-bucket-azure-full.test.ts.snap index bd40134111d76..d48b3808d3e60 100644 --- a/packages/cubejs-testing-drivers/test/__snapshots__/snowflake-export-bucket-azure-full.test.ts.snap +++ b/packages/cubejs-testing-drivers/test/__snapshots__/snowflake-export-bucket-azure-full.test.ts.snap @@ -16610,3 +16610,19 @@ Array [ }, ] `; + +exports[`Queries with the @cubejs-backend/snowflake-driver export-bucket-azure SQL API: Date/time comparison with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Day)": "12", + }, +] +`; + +exports[`Queries with the @cubejs-backend/snowflake-driver export-bucket-azure SQL API: Date/time comparison with date_trunc with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Week)": "12", + }, +] +`; diff --git a/packages/cubejs-testing-drivers/test/__snapshots__/snowflake-export-bucket-azure-prefix-full.test.ts.snap b/packages/cubejs-testing-drivers/test/__snapshots__/snowflake-export-bucket-azure-prefix-full.test.ts.snap index 31f905f778f3f..1a06bccf846c2 100644 --- a/packages/cubejs-testing-drivers/test/__snapshots__/snowflake-export-bucket-azure-prefix-full.test.ts.snap +++ b/packages/cubejs-testing-drivers/test/__snapshots__/snowflake-export-bucket-azure-prefix-full.test.ts.snap @@ -16415,3 +16415,19 @@ Array [ }, ] `; + +exports[`Queries with the @cubejs-backend/snowflake-driver export-bucket-azure-prefix SQL API: Date/time comparison with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Day)": "12", + }, +] +`; + +exports[`Queries with the @cubejs-backend/snowflake-driver export-bucket-azure-prefix SQL API: Date/time comparison with date_trunc with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Week)": "12", + }, +] +`; diff --git a/packages/cubejs-testing-drivers/test/__snapshots__/snowflake-export-bucket-azure-via-storage-integration-full.test.ts.snap b/packages/cubejs-testing-drivers/test/__snapshots__/snowflake-export-bucket-azure-via-storage-integration-full.test.ts.snap index 876ca6d72c6e7..6d51f51c70165 100644 --- a/packages/cubejs-testing-drivers/test/__snapshots__/snowflake-export-bucket-azure-via-storage-integration-full.test.ts.snap +++ b/packages/cubejs-testing-drivers/test/__snapshots__/snowflake-export-bucket-azure-via-storage-integration-full.test.ts.snap @@ -16610,3 +16610,19 @@ Array [ }, ] `; + +exports[`Queries with the @cubejs-backend/snowflake-driver export-bucket-azure-via-storage-integration SQL API: Date/time comparison with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Day)": "12", + }, +] +`; + +exports[`Queries with the @cubejs-backend/snowflake-driver export-bucket-azure-via-storage-integration SQL API: Date/time comparison with date_trunc with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Week)": "12", + }, +] +`; diff --git a/packages/cubejs-testing-drivers/test/__snapshots__/snowflake-export-bucket-gcs-full.test.ts.snap b/packages/cubejs-testing-drivers/test/__snapshots__/snowflake-export-bucket-gcs-full.test.ts.snap index f271de780bbdb..9f447578479df 100644 --- a/packages/cubejs-testing-drivers/test/__snapshots__/snowflake-export-bucket-gcs-full.test.ts.snap +++ b/packages/cubejs-testing-drivers/test/__snapshots__/snowflake-export-bucket-gcs-full.test.ts.snap @@ -16610,3 +16610,19 @@ Array [ }, ] `; + +exports[`Queries with the @cubejs-backend/snowflake-driver export-bucket-gcs SQL API: Date/time comparison with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Day)": "12", + }, +] +`; + +exports[`Queries with the @cubejs-backend/snowflake-driver export-bucket-gcs SQL API: Date/time comparison with date_trunc with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Week)": "12", + }, +] +`; diff --git a/packages/cubejs-testing-drivers/test/__snapshots__/snowflake-export-bucket-gcs-prefix-full.test.ts.snap b/packages/cubejs-testing-drivers/test/__snapshots__/snowflake-export-bucket-gcs-prefix-full.test.ts.snap index f19a5725b3af5..331a2f89b84cd 100644 --- a/packages/cubejs-testing-drivers/test/__snapshots__/snowflake-export-bucket-gcs-prefix-full.test.ts.snap +++ b/packages/cubejs-testing-drivers/test/__snapshots__/snowflake-export-bucket-gcs-prefix-full.test.ts.snap @@ -16415,3 +16415,19 @@ Array [ }, ] `; + +exports[`Queries with the @cubejs-backend/snowflake-driver export-bucket-gcs-prefix SQL API: Date/time comparison with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Day)": "12", + }, +] +`; + +exports[`Queries with the @cubejs-backend/snowflake-driver export-bucket-gcs-prefix SQL API: Date/time comparison with date_trunc with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Week)": "12", + }, +] +`; diff --git a/packages/cubejs-testing-drivers/test/__snapshots__/snowflake-export-bucket-s3-full.test.ts.snap b/packages/cubejs-testing-drivers/test/__snapshots__/snowflake-export-bucket-s3-full.test.ts.snap index 218ba02038682..08cd267a3e464 100644 --- a/packages/cubejs-testing-drivers/test/__snapshots__/snowflake-export-bucket-s3-full.test.ts.snap +++ b/packages/cubejs-testing-drivers/test/__snapshots__/snowflake-export-bucket-s3-full.test.ts.snap @@ -16610,3 +16610,19 @@ Array [ }, ] `; + +exports[`Queries with the @cubejs-backend/snowflake-driver export-bucket-s3 SQL API: Date/time comparison with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Day)": "12", + }, +] +`; + +exports[`Queries with the @cubejs-backend/snowflake-driver export-bucket-s3 SQL API: Date/time comparison with date_trunc with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Week)": "12", + }, +] +`; diff --git a/packages/cubejs-testing-drivers/test/__snapshots__/snowflake-export-bucket-s3-prefix-full.test.ts.snap b/packages/cubejs-testing-drivers/test/__snapshots__/snowflake-export-bucket-s3-prefix-full.test.ts.snap index 0d99dace33347..2100fbb39607f 100644 --- a/packages/cubejs-testing-drivers/test/__snapshots__/snowflake-export-bucket-s3-prefix-full.test.ts.snap +++ b/packages/cubejs-testing-drivers/test/__snapshots__/snowflake-export-bucket-s3-prefix-full.test.ts.snap @@ -16415,3 +16415,19 @@ Array [ }, ] `; + +exports[`Queries with the @cubejs-backend/snowflake-driver export-bucket-s3-prefix SQL API: Date/time comparison with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Day)": "12", + }, +] +`; + +exports[`Queries with the @cubejs-backend/snowflake-driver export-bucket-s3-prefix SQL API: Date/time comparison with date_trunc with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Week)": "12", + }, +] +`; diff --git a/packages/cubejs-testing-drivers/test/__snapshots__/snowflake-full.test.ts.snap b/packages/cubejs-testing-drivers/test/__snapshots__/snowflake-full.test.ts.snap index e22c2af7604a0..91e49a4e34b03 100644 --- a/packages/cubejs-testing-drivers/test/__snapshots__/snowflake-full.test.ts.snap +++ b/packages/cubejs-testing-drivers/test/__snapshots__/snowflake-full.test.ts.snap @@ -16610,3 +16610,19 @@ Array [ }, ] `; + +exports[`Queries with the @cubejs-backend/snowflake-driver SQL API: Date/time comparison with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Day)": "12", + }, +] +`; + +exports[`Queries with the @cubejs-backend/snowflake-driver SQL API: Date/time comparison with date_trunc with SQL push down 1`] = ` +Array [ + Object { + "measure(BigECommerce.rollingCountBy2Week)": "12", + }, +] +`; From 219d4a8d1fb041f9927240f3ad6b078035ba6bd9 Mon Sep 17 00:00:00 2001 From: Konstantin Burkalev Date: Tue, 17 Jun 2025 16:27:37 +0300 Subject: [PATCH 06/10] fix mssql tests --- .../cubejs-testing-drivers/fixtures/mssql.json | 4 +++- .../test/__snapshots__/mssql-full.test.ts.snap | 16 ---------------- 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/packages/cubejs-testing-drivers/fixtures/mssql.json b/packages/cubejs-testing-drivers/fixtures/mssql.json index 76d595fc385be..5cad09cc45838 100644 --- a/packages/cubejs-testing-drivers/fixtures/mssql.json +++ b/packages/cubejs-testing-drivers/fixtures/mssql.json @@ -161,6 +161,8 @@ "SQL API: Extended nested Rollup over asterisk", "SQL API: ungrouped pre-agg", "SQL API: NULLS FIRST/LAST SQL push down", - "SQL API: SQL push down push to cube quoted alias" + "SQL API: SQL push down push to cube quoted alias", + "SQL API: Date/time comparison with SQL push down", + "SQL API: Date/time comparison with date_trunc with SQL push down" ] } diff --git a/packages/cubejs-testing-drivers/test/__snapshots__/mssql-full.test.ts.snap b/packages/cubejs-testing-drivers/test/__snapshots__/mssql-full.test.ts.snap index 9fd4bccf44874..8d9558a3d6c72 100644 --- a/packages/cubejs-testing-drivers/test/__snapshots__/mssql-full.test.ts.snap +++ b/packages/cubejs-testing-drivers/test/__snapshots__/mssql-full.test.ts.snap @@ -6654,19 +6654,3 @@ Array [ }, ] `; - -exports[`Queries with the @cubejs-backend/mssql-driver SQL API: Date/time comparison with SQL push down 1`] = ` -Array [ - Object { - "measure(BigECommerce.rollingCountBy2Day)": "12", - }, -] -`; - -exports[`Queries with the @cubejs-backend/mssql-driver SQL API: Date/time comparison with date_trunc with SQL push down 1`] = ` -Array [ - Object { - "measure(BigECommerce.rollingCountBy2Week)": "12", - }, -] -`; From 376d0d75669b3d748816af98c155a549a2a6dfbf Mon Sep 17 00:00:00 2001 From: Konstantin Burkalev Date: Tue, 17 Jun 2025 16:29:12 +0300 Subject: [PATCH 07/10] fix mysql tests --- packages/cubejs-testing-drivers/fixtures/mysql.json | 3 ++- .../test/__snapshots__/mysql-full.test.ts.snap | 10 +--------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/packages/cubejs-testing-drivers/fixtures/mysql.json b/packages/cubejs-testing-drivers/fixtures/mysql.json index 56167c862c4e8..6631bb00918c2 100644 --- a/packages/cubejs-testing-drivers/fixtures/mysql.json +++ b/packages/cubejs-testing-drivers/fixtures/mysql.json @@ -157,6 +157,7 @@ "SQL API: Nested Rollup with aliases", "SQL API: Nested Rollup over asterisk", "SQL API: Extended nested Rollup over asterisk", - "SQL API: SQL push down push to cube quoted alias" + "SQL API: SQL push down push to cube quoted alias", + "SQL API: Date/time comparison with date_trunc with SQL push down" ] } diff --git a/packages/cubejs-testing-drivers/test/__snapshots__/mysql-full.test.ts.snap b/packages/cubejs-testing-drivers/test/__snapshots__/mysql-full.test.ts.snap index 6152c29960239..c4380197bf3bc 100644 --- a/packages/cubejs-testing-drivers/test/__snapshots__/mysql-full.test.ts.snap +++ b/packages/cubejs-testing-drivers/test/__snapshots__/mysql-full.test.ts.snap @@ -7399,15 +7399,7 @@ Array [ exports[`Queries with the @cubejs-backend/mysql-driver SQL API: Date/time comparison with SQL push down 1`] = ` Array [ Object { - "measure(BigECommerce.rollingCountBy2Day)": 12, - }, -] -`; - -exports[`Queries with the @cubejs-backend/mysql-driver SQL API: Date/time comparison with date_trunc with SQL push down 1`] = ` -Array [ - Object { - "measure(BigECommerce.rollingCountBy2Week)": 12, + "measure(BigECommerce.rollingCountBy2Day)": "12", }, ] `; From 444c95d39efd61ecf5ac25fb424c0a946d87286e Mon Sep 17 00:00:00 2001 From: Konstantin Burkalev Date: Tue, 17 Jun 2025 17:19:56 +0300 Subject: [PATCH 08/10] fix for redshift --- .../src/adapter/BaseQuery.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/cubejs-schema-compiler/src/adapter/BaseQuery.js b/packages/cubejs-schema-compiler/src/adapter/BaseQuery.js index b1f8665d36a0a..3f84607156e73 100644 --- a/packages/cubejs-schema-compiler/src/adapter/BaseQuery.js +++ b/packages/cubejs-schema-compiler/src/adapter/BaseQuery.js @@ -958,8 +958,7 @@ export class BaseQuery { .map( d => [ d, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - (dateFrom, dateTo, dateField, dimensionDateFrom, dimensionDateTo) => `${dateField} >= ${dimensionDateFrom} AND ${dateField} <= ${dateTo}` + (_dateFrom, dateTo, dateField, dimensionDateFrom, _dimensionDateTo) => `${dateField} >= ${dimensionDateFrom} AND ${dateField} <= ${this.timeStampCast(dateTo)}` ] ); } @@ -970,7 +969,7 @@ export class BaseQuery { .map( d => [ d, - (dateFrom, dateTo, dateField, dimensionDateFrom, dimensionDateTo, isFromStartToEnd) => `${dateField} >= ${this.timeGroupedColumn(granularity, dateFrom)} AND ${dateField} <= ${dateTo}` + (dateFrom, dateTo, dateField, _dimensionDateFrom, _dimensionDateTo, _isFromStartToEnd) => `${dateField} >= ${this.timeGroupedColumn(granularity, dateFrom)} AND ${dateField} <= ${this.timeStampCast(dateTo)}` ] ); } @@ -987,13 +986,13 @@ export class BaseQuery { const startDate = isFromStartToEnd || offset === 'start' ? dateFrom : dateTo; const trailingStart = trailingInterval ? this.subtractInterval(startDate, trailingInterval) : startDate; const sign = offset === 'start' ? '>=' : '>'; - conditions.push(`${dateField} ${sign} ${trailingStart}`); + conditions.push(`${dateField} ${sign} ${this.timeStampCast(trailingStart)}`); } if (leadingInterval !== 'unbounded') { const endDate = isFromStartToEnd || offset === 'end' ? dateTo : dateFrom; const leadingEnd = leadingInterval ? this.addInterval(endDate, leadingInterval) : endDate; const sign = offset === 'end' ? '<=' : '<'; - conditions.push(`${dateField} ${sign} ${leadingEnd}`); + conditions.push(`${dateField} ${sign} ${this.timeStampCast(leadingEnd)}`); } return conditions.length ? conditions.join(' AND ') : '1 = 1'; }] @@ -1792,8 +1791,11 @@ export class BaseQuery { // but some dialects (like BigQuery) require strict date types and can not automatically convert // between date and timestamp for comparisons, at the same time, time dimensions are expected to be // timestamps, so we need to align types for join conditions/comparisons. - this.timeStampCast(`${d.dateSeriesAliasName()}.${this.escapeColumnName('date_from')}`), - this.timeStampCast(`${d.dateSeriesAliasName()}.${this.escapeColumnName('date_to')}`), + // But we can't do it here, as it would break interval maths used in some types of + // rolling window join conditions in some dialects (like Redshift), so we need to + // do casts granularly in rolling window join conditions functions. + `${d.dateSeriesAliasName()}.${this.escapeColumnName('date_from')}`, + `${d.dateSeriesAliasName()}.${this.escapeColumnName('date_to')}`, `${baseQueryAlias}.${d.aliasName()}`, `'${d.dateFromFormatted()}'`, `'${d.dateToFormatted()}'` From e5acc277646343a0a36a1df87eb656e7a28d040b Mon Sep 17 00:00:00 2001 From: Konstantin Burkalev Date: Tue, 17 Jun 2025 18:47:53 +0300 Subject: [PATCH 09/10] override runningTotals funcs for BQ. --- .../src/adapter/BaseQuery.js | 17 +++--- .../src/adapter/BigqueryQuery.ts | 61 +++++++++++++++++++ 2 files changed, 71 insertions(+), 7 deletions(-) diff --git a/packages/cubejs-schema-compiler/src/adapter/BaseQuery.js b/packages/cubejs-schema-compiler/src/adapter/BaseQuery.js index 3f84607156e73..179426c43ce96 100644 --- a/packages/cubejs-schema-compiler/src/adapter/BaseQuery.js +++ b/packages/cubejs-schema-compiler/src/adapter/BaseQuery.js @@ -958,7 +958,7 @@ export class BaseQuery { .map( d => [ d, - (_dateFrom, dateTo, dateField, dimensionDateFrom, _dimensionDateTo) => `${dateField} >= ${dimensionDateFrom} AND ${dateField} <= ${this.timeStampCast(dateTo)}` + (_dateFrom, dateTo, dateField, dimensionDateFrom, _dimensionDateTo) => `${dateField} >= ${dimensionDateFrom} AND ${dateField} <= ${dateTo}` ] ); } @@ -969,7 +969,7 @@ export class BaseQuery { .map( d => [ d, - (dateFrom, dateTo, dateField, _dimensionDateFrom, _dimensionDateTo, _isFromStartToEnd) => `${dateField} >= ${this.timeGroupedColumn(granularity, dateFrom)} AND ${dateField} <= ${this.timeStampCast(dateTo)}` + (dateFrom, dateTo, dateField, _dimensionDateFrom, _dimensionDateTo, _isFromStartToEnd) => `${dateField} >= ${this.timeGroupedColumn(granularity, dateFrom)} AND ${dateField} <= ${dateTo}` ] ); } @@ -979,20 +979,20 @@ export class BaseQuery { return this.timeDimensions .filter(td => td.granularity) .map( - d => [d, (dateFrom, dateTo, dateField, dimensionDateFrom, dimensionDateTo, isFromStartToEnd) => { + d => [d, (dateFrom, dateTo, dateField, _dimensionDateFrom, _dimensionDateTo, isFromStartToEnd) => { // dateFrom based window const conditions = []; if (trailingInterval !== 'unbounded') { const startDate = isFromStartToEnd || offset === 'start' ? dateFrom : dateTo; const trailingStart = trailingInterval ? this.subtractInterval(startDate, trailingInterval) : startDate; const sign = offset === 'start' ? '>=' : '>'; - conditions.push(`${dateField} ${sign} ${this.timeStampCast(trailingStart)}`); + conditions.push(`${dateField} ${sign} ${trailingStart}`); } if (leadingInterval !== 'unbounded') { const endDate = isFromStartToEnd || offset === 'end' ? dateTo : dateFrom; const leadingEnd = leadingInterval ? this.addInterval(endDate, leadingInterval) : endDate; const sign = offset === 'end' ? '<=' : '<'; - conditions.push(`${dateField} ${sign} ${this.timeStampCast(leadingEnd)}`); + conditions.push(`${dateField} ${sign} ${leadingEnd}`); } return conditions.length ? conditions.join(' AND ') : '1 = 1'; }] @@ -1828,8 +1828,11 @@ export class BaseQuery { .join(', '); } - // BigQuery has strict date type and can not automatically convert between date - // and timestamp, so we override dateFromStartToEndConditionSql() in BigQuery Dialect + /** + * BigQuery has strict date type and can not automatically convert between date + * and timestamp, so we override dateFromStartToEndConditionSql() in BigQuery Dialect + * @protected + */ dateFromStartToEndConditionSql(dateJoinCondition, fromRollup, isFromStartToEnd) { return dateJoinCondition.map( // TODO Consider adding strict definitions of local and UTC time type diff --git a/packages/cubejs-schema-compiler/src/adapter/BigqueryQuery.ts b/packages/cubejs-schema-compiler/src/adapter/BigqueryQuery.ts index 9b6abcb95ab43..312ef4851264f 100644 --- a/packages/cubejs-schema-compiler/src/adapter/BigqueryQuery.ts +++ b/packages/cubejs-schema-compiler/src/adapter/BigqueryQuery.ts @@ -215,6 +215,67 @@ export class BigqueryQuery extends BaseQuery { return `UNIX_SECONDS(${this.nowTimestampSql()})`; } + /** + * Should be protected, but BaseQuery is in js + * Overridden from BaseQuery to support BigQuery strict data types for + * joining conditions (note timeStampCast) + */ + public override runningTotalDateJoinCondition() { + return this.timeDimensions + .map( + d => [ + d, + (_dateFrom: string, dateTo: string, dateField: string, dimensionDateFrom: string, _dimensionDateTo: string) => `${dateField} >= ${dimensionDateFrom} AND ${dateField} <= ${this.timeStampCast(dateTo)}` + ] + ); + } + + /** + * Should be protected, but BaseQuery is in js + * Overridden from BaseQuery to support BigQuery strict data types for + * joining conditions (note timeStampCast) + */ + public override rollingWindowToDateJoinCondition(granularity) { + return this.timeDimensions + .filter(td => td.granularity) + .map( + d => [ + d, + (dateFrom: string, dateTo: string, dateField: string, _dimensionDateFrom: string, _dimensionDateTo: string, _isFromStartToEnd: boolean) => `${dateField} >= ${this.timeGroupedColumn(granularity, dateFrom)} AND ${dateField} <= ${this.timeStampCast(dateTo)}` + ] + ); + } + + /** + * Should be protected, but BaseQuery is in js + * Overridden from BaseQuery to support BigQuery strict data types for + * joining conditions (note timeStampCast) + */ + public override rollingWindowDateJoinCondition(trailingInterval, leadingInterval, offset) { + offset = offset || 'end'; + return this.timeDimensions + .filter(td => td.granularity) + .map( + d => [d, (dateFrom: string, dateTo: string, dateField: string, _dimensionDateFrom: string, _dimensionDateTo: string, isFromStartToEnd: boolean) => { + // dateFrom based window + const conditions: string[] = []; + if (trailingInterval !== 'unbounded') { + const startDate = isFromStartToEnd || offset === 'start' ? dateFrom : dateTo; + const trailingStart = trailingInterval ? this.subtractInterval(startDate, trailingInterval) : startDate; + const sign = offset === 'start' ? '>=' : '>'; + conditions.push(`${dateField} ${sign} ${this.timeStampCast(trailingStart)}`); + } + if (leadingInterval !== 'unbounded') { + const endDate = isFromStartToEnd || offset === 'end' ? dateTo : dateFrom; + const leadingEnd = leadingInterval ? this.addInterval(endDate, leadingInterval) : endDate; + const sign = offset === 'end' ? '<=' : '<'; + conditions.push(`${dateField} ${sign} ${this.timeStampCast(leadingEnd)}`); + } + return conditions.length ? conditions.join(' AND ') : '1 = 1'; + }] + ); + } + // Should be protected, but BaseQuery is in js public override dateFromStartToEndConditionSql(dateJoinCondition, fromRollup, isFromStartToEnd) { return dateJoinCondition.map( From c0972cd1fc1db9822522909dd6d3caefc9753d84 Mon Sep 17 00:00:00 2001 From: Alexandr Romanenko Date: Thu, 19 Jun 2025 12:20:45 +0200 Subject: [PATCH 10/10] tesseract implementation --- packages/cubejs-schema-compiler/src/adapter/BaseQuery.js | 1 + .../cubejs-schema-compiler/src/adapter/BigqueryQuery.ts | 1 + rust/cubesqlplanner/cubesqlplanner/src/plan/join.rs | 5 +++++ .../cubesqlplanner/src/planner/filter/base_filter.rs | 2 ++ .../cubesqlplanner/src/planner/sql_templates/plan.rs | 9 +++++++++ 5 files changed, 18 insertions(+) diff --git a/packages/cubejs-schema-compiler/src/adapter/BaseQuery.js b/packages/cubejs-schema-compiler/src/adapter/BaseQuery.js index 179426c43ce96..be70314f75855 100644 --- a/packages/cubejs-schema-compiler/src/adapter/BaseQuery.js +++ b/packages/cubejs-schema-compiler/src/adapter/BaseQuery.js @@ -3916,6 +3916,7 @@ export class BaseQuery { like_escape: '{{ like_expr }} ESCAPE {{ escape_char }}', within_group: '{{ fun_sql }} WITHIN GROUP (ORDER BY {{ within_group_concat }})', concat_strings: '{{ strings | join(\' || \' ) }}', + rolling_window_expr_timestamp_cast: '{{ value }}' }, tesseract: { ilike: '{{ expr }} {% if negated %}NOT {% endif %}ILIKE {{ pattern }}', // May require different overloads in Tesseract than the ilike from expressions used in SQLAPI. diff --git a/packages/cubejs-schema-compiler/src/adapter/BigqueryQuery.ts b/packages/cubejs-schema-compiler/src/adapter/BigqueryQuery.ts index 312ef4851264f..e231bbca93bbe 100644 --- a/packages/cubejs-schema-compiler/src/adapter/BigqueryQuery.ts +++ b/packages/cubejs-schema-compiler/src/adapter/BigqueryQuery.ts @@ -348,6 +348,7 @@ export class BigqueryQuery extends BaseQuery { templates.expressions.interval = 'INTERVAL {{ interval }}'; templates.expressions.extract = 'EXTRACT({% if date_part == \'DOW\' %}DAYOFWEEK{% elif date_part == \'DOY\' %}DAYOFYEAR{% else %}{{ date_part }}{% endif %} FROM {{ expr }})'; templates.expressions.timestamp_literal = 'TIMESTAMP(\'{{ value }}\')'; + templates.expressions.rolling_window_expr_timestamp_cast = 'TIMESTAMP({{ value }})'; delete templates.expressions.ilike; delete templates.expressions.like_escape; templates.filters.like_pattern = 'CONCAT({% if start_wild %}\'%\'{% else %}\'\'{% endif %}, LOWER({{ value }}), {% if end_wild %}\'%\'{% else %}\'\'{% endif %})'; diff --git a/rust/cubesqlplanner/cubesqlplanner/src/plan/join.rs b/rust/cubesqlplanner/cubesqlplanner/src/plan/join.rs index d7d7b896f191c..93c3bfa3a458c 100644 --- a/rust/cubesqlplanner/cubesqlplanner/src/plan/join.rs +++ b/rust/cubesqlplanner/cubesqlplanner/src/plan/join.rs @@ -57,6 +57,7 @@ impl RegularRollingWindowJoinCondition { start_date }; + let trailing_start = templates.rolling_window_expr_timestamp_cast(&trailing_start)?; let sign = if self.offset == "start" { ">=" } else { ">" }; conditions.push(format!("{date_column} {sign} {trailing_start}")); @@ -75,6 +76,7 @@ impl RegularRollingWindowJoinCondition { end_date }; + let leading_end = templates.rolling_window_expr_timestamp_cast(&leading_end)?; let sign = if self.offset == "end" { "<=" } else { "<" }; conditions.push(format!("{date_column} {sign} {leading_end}")); @@ -109,6 +111,7 @@ impl RollingTotalJoinCondition { let date_column = self.time_dimension.to_sql(templates, context)?; let date_to = templates.column_reference(&Some(self.time_series_source.clone()), "date_to")?; + let date_to = templates.rolling_window_expr_timestamp_cast(&date_to)?; let result = format!("{date_column} <= {date_to}"); Ok(result) } @@ -146,6 +149,8 @@ impl ToDateRollingWindowJoinCondition { templates.column_reference(&Some(self.time_series_source.clone()), "date_to")?; let date_to = templates.column_reference(&Some(self.time_series_source.clone()), "date_from")?; + 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 = templates.time_grouped_column(self.granularity.clone(), date_from)?; let result = format!("{date_column} >= {grouped_from} and {date_column} <= {date_to}"); Ok(result) diff --git a/rust/cubesqlplanner/cubesqlplanner/src/planner/filter/base_filter.rs b/rust/cubesqlplanner/cubesqlplanner/src/planner/filter/base_filter.rs index a54dae7dc1f64..e0738d93b3fc5 100644 --- a/rust/cubesqlplanner/cubesqlplanner/src/planner/filter/base_filter.rs +++ b/rust/cubesqlplanner/cubesqlplanner/src/planner/filter/base_filter.rs @@ -397,6 +397,8 @@ impl BaseFilter { ) -> Result<(String, String), CubeError> { let from_expr = format!("min({})", plan_templates.quote_identifier("date_from")?); let to_expr = format!("max({})", plan_templates.quote_identifier("date_to")?); + let from_expr = plan_templates.time_stamp_cast(from_expr)?; + let to_expr = plan_templates.time_stamp_cast(to_expr)?; let alias = format!("value"); let time_series_cte_name = format!("time_series"); // FIXME May be should be passed as parameter diff --git a/rust/cubesqlplanner/cubesqlplanner/src/planner/sql_templates/plan.rs b/rust/cubesqlplanner/cubesqlplanner/src/planner/sql_templates/plan.rs index a5931f5f708f4..3cdb0957e33d8 100644 --- a/rust/cubesqlplanner/cubesqlplanner/src/planner/sql_templates/plan.rs +++ b/rust/cubesqlplanner/cubesqlplanner/src/planner/sql_templates/plan.rs @@ -702,4 +702,13 @@ impl PlanSqlTemplates { }, ) } + pub fn rolling_window_expr_timestamp_cast(&self, value: &str) -> Result { + self.render.render_template( + &"expressions/rolling_window_expr_timestamp_cast", + context! { + value => value + + }, + ) + } }