diff --git a/.github/workflows/drivers-tests.yml b/.github/workflows/drivers-tests.yml index c9df773f44cb5..263a61fbc8045 100644 --- a/.github/workflows/drivers-tests.yml +++ b/.github/workflows/drivers-tests.yml @@ -271,6 +271,8 @@ jobs: use_tesseract_sql_planner: true - database: bigquery-export-bucket-gcs use_tesseract_sql_planner: true + - database: athena-export-bucket-s3 + use_tesseract_sql_planner: true fail-fast: false steps: diff --git a/.github/workflows/rust-cubesql.yml b/.github/workflows/rust-cubesql.yml index cac2512a62473..a759162ae3d32 100644 --- a/.github/workflows/rust-cubesql.yml +++ b/.github/workflows/rust-cubesql.yml @@ -325,7 +325,7 @@ jobs: matrix: # We do not need to test under all versions, we do it under linux node-version: [22.x] - os-version: [windows-2019] + os-version: [windows-2022] python-version: ["fallback"] fail-fast: false diff --git a/packages/cubejs-schema-compiler/src/adapter/BaseQuery.js b/packages/cubejs-schema-compiler/src/adapter/BaseQuery.js index afb9f78704659..5dd34176028ce 100644 --- a/packages/cubejs-schema-compiler/src/adapter/BaseQuery.js +++ b/packages/cubejs-schema-compiler/src/adapter/BaseQuery.js @@ -1078,7 +1078,8 @@ export class BaseQuery { * @returns {string} */ subtractInterval(date, interval) { - return `${date} - interval '${interval}'`; + const intervalStr = this.intervalString(interval); + return `${date} - interval ${intervalStr}`; } /** @@ -1087,7 +1088,16 @@ export class BaseQuery { * @returns {string} */ addInterval(date, interval) { - return `${date} + interval '${interval}'`; + const intervalStr = this.intervalString(interval); + return `${date} + interval ${intervalStr}`; + } + + /** + * @param {string} interval + * @returns {string} + */ + intervalString(interval) { + return `'${interval}'`; } /** @@ -4111,6 +4121,7 @@ export class BaseQuery { }, tesseract: { ilike: '{{ expr }} {% if negated %}NOT {% endif %}ILIKE {{ pattern }}', // May require different overloads in Tesseract than the ilike from expressions used in SQLAPI. + series_bounds_cast: '{{ expr }}' }, filters: { equals: '{{ column }} = {{ value }}{{ is_null_check }}', diff --git a/packages/cubejs-schema-compiler/src/adapter/BigqueryQuery.ts b/packages/cubejs-schema-compiler/src/adapter/BigqueryQuery.ts index e231bbca93bbe..1b62e8da30024 100644 --- a/packages/cubejs-schema-compiler/src/adapter/BigqueryQuery.ts +++ b/packages/cubejs-schema-compiler/src/adapter/BigqueryQuery.ts @@ -203,6 +203,10 @@ export class BigqueryQuery extends BaseQuery { return this.subtractInterval(timestamp, interval); } + public intervalString(interval: string): string { + return `${interval}`; + } + public addTimestampInterval(timestamp, interval) { return this.addInterval(timestamp, interval); } @@ -353,6 +357,7 @@ export class BigqueryQuery extends BaseQuery { delete templates.expressions.like_escape; templates.filters.like_pattern = 'CONCAT({% if start_wild %}\'%\'{% else %}\'\'{% endif %}, LOWER({{ value }}), {% if end_wild %}\'%\'{% else %}\'\'{% endif %})'; templates.tesseract.ilike = 'LOWER({{ expr }}) {% if negated %}NOT {% endif %} LIKE {{ pattern }}'; + templates.tesseract.series_bounds_cast = 'TIMESTAMP({{ expr }})'; templates.types.boolean = 'BOOL'; templates.types.float = 'FLOAT64'; templates.types.double = 'FLOAT64'; diff --git a/packages/cubejs-schema-compiler/src/adapter/PostgresQuery.ts b/packages/cubejs-schema-compiler/src/adapter/PostgresQuery.ts index fdcec50062f9d..58cf3c240b440 100644 --- a/packages/cubejs-schema-compiler/src/adapter/PostgresQuery.ts +++ b/packages/cubejs-schema-compiler/src/adapter/PostgresQuery.ts @@ -83,11 +83,11 @@ export class PostgresQuery extends BaseQuery { templates.types.binary = 'BYTEA'; templates.operators.is_not_distinct_from = 'IS NOT DISTINCT FROM'; templates.statements.generated_time_series_select = 'SELECT d AS "date_from",\n' + - 'd + interval \'{{ granularity }}\' - interval \'1 millisecond\' AS "date_to" \n' + - 'FROM generate_series({{ start }}::timestamp, {{ end }}:: timestamp, \'{{ granularity }}\'::interval) d '; + 'd + interval {{ granularity }} - interval \'1 millisecond\' AS "date_to" \n' + + 'FROM generate_series({{ start }}::timestamp, {{ end }}:: timestamp, {{ granularity }}::interval) d '; templates.statements.generated_time_series_with_cte_range_source = 'SELECT d AS "date_from",\n' + - 'd + interval \'{{ granularity }}\' - interval \'1 millisecond\' AS "date_to" \n' + - 'FROM {{ range_source }}, LATERAL generate_series({{ range_source }}.{{ min_name }}, {{ range_source }}.{{ max_name }}, \'{{ granularity }}\'::interval) d '; + 'd + interval {{ granularity }} - interval \'1 millisecond\' AS "date_to" \n' + + 'FROM {{ range_source }}, LATERAL generate_series({{ range_source }}.{{ min_name }}, {{ range_source }}.{{ max_name }}, {{ granularity }}::interval) d '; return templates; } diff --git a/packages/cubejs-schema-compiler/src/adapter/PrestodbQuery.ts b/packages/cubejs-schema-compiler/src/adapter/PrestodbQuery.ts index 81b5d34aa1743..b04e5e55cb783 100644 --- a/packages/cubejs-schema-compiler/src/adapter/PrestodbQuery.ts +++ b/packages/cubejs-schema-compiler/src/adapter/PrestodbQuery.ts @@ -84,14 +84,9 @@ export class PrestodbQuery extends BaseQuery { return `date_trunc('${GRANULARITY_TO_INTERVAL[granularity]}', ${dimension})`; } - public subtractInterval(date, interval) { + public intervalString(interval: string): string { const [intervalValue, intervalUnit] = interval.split(' '); - return `${date} - interval '${intervalValue}' ${intervalUnit}`; - } - - public addInterval(date, interval) { - const [intervalValue, intervalUnit] = interval.split(' '); - return `${date} + interval '${intervalValue}' ${intervalUnit}`; + return `'${intervalValue}' ${intervalUnit}`; } public seriesSql(timeDimension) { @@ -138,9 +133,16 @@ export class PrestodbQuery extends BaseQuery { templates.functions.DATETRUNC = 'DATE_TRUNC({{ args_concat }})'; templates.functions.DATEPART = 'DATE_PART({{ args_concat }})'; delete templates.functions.PERCENTILECONT; - templates.statements.select = 'SELECT {{ select_concat | map(attribute=\'aliased\') | join(\', \') }} \n' + - 'FROM (\n {{ from }}\n) AS {{ from_alias }} \n' + + templates.statements.select = '{% if ctes %} WITH \n' + + '{{ ctes | join(\',\n\') }}\n' + + '{% endif %}' + + 'SELECT {{ select_concat | map(attribute=\'aliased\') | join(\', \') }} {% if from %}\n' + + 'FROM (\n {{ from }}\n) AS {{ from_alias }} {% elif from_prepared %}\n' + + 'FROM {{ from_prepared }}' + + '{% endif %}' + + '{% if filter %}\nWHERE {{ filter }}{% endif %}' + '{% if group_by %} GROUP BY {{ group_by }}{% endif %}' + + '{% if having %}\nHAVING {{ having }}{% endif %}' + '{% if order_by %} ORDER BY {{ order_by | map(attribute=\'expr\') | join(\', \') }}{% endif %}' + '{% if offset is not none %}\nOFFSET {{ offset }}{% endif %}' + '{% if limit is not none %}\nLIMIT {{ limit }}{% endif %}'; @@ -153,6 +155,25 @@ export class PrestodbQuery extends BaseQuery { // Presto intervals have a YearMonth or DayTime type variants, but no universal type delete templates.types.interval; templates.types.binary = 'VARBINARY'; + templates.tesseract.ilike = 'LOWER({{ expr }}) {% if negated %}NOT {% endif %} LIKE {{ pattern }}'; + templates.filters.like_pattern = 'CONCAT({% if start_wild %}\'%\'{% else %}\'\'{% endif %}, LOWER({{ value }}), {% if end_wild %}\'%\'{% else %}\'\'{% endif %}) ESCAPE \'\\\''; + templates.statements.time_series_select = 'SELECT from_iso8601_timestamp(dates.f) date_from, from_iso8601_timestamp(dates.t) date_to \n' + + 'FROM (\n' + + '{% for time_item in seria %}' + + ' select \'{{ time_item[0] }}\' f, \'{{ time_item[1] }}\' t \n' + + '{% if not loop.last %} UNION ALL\n{% endif %}' + + '{% endfor %}' + + ') AS dates'; + templates.statements.generated_time_series_select = 'SELECT d AS date_from,\n' + + 'date_add(\'MILLISECOND\', -1, d + interval {{ granularity }}) AS date_to\n' + + 'FROM UNNEST(\n' + + 'SEQUENCE(CAST(from_iso8601_timestamp({{ start }}) AS TIMESTAMP), CAST(from_iso8601_timestamp({{ end }}) AS TIMESTAMP), INTERVAL {{ granularity }})\n' + + ') AS dates(d)'; + templates.statements.generated_time_series_with_cte_range_source = 'SELECT d AS date_from,\n' + + 'date_add(\'MILLISECOND\', -1, d + interval {{ granularity }}) AS date_to\n' + + 'FROM {{ range_source }} CROSS JOIN UNNEST(\n' + + 'SEQUENCE(CAST({{ range_source }}.{{ min_name }} AS TIMESTAMP), CAST({{ range_source }}.{{ max_name }} AS TIMESTAMP), INTERVAL {{ granularity }})\n' + + ') AS dates(d)'; return templates; } diff --git a/packages/cubejs-testing-drivers/fixtures/athena.json b/packages/cubejs-testing-drivers/fixtures/athena.json index a429d22fe442c..2edc2b683144d 100644 --- a/packages/cubejs-testing-drivers/fixtures/athena.json +++ b/packages/cubejs-testing-drivers/fixtures/athena.json @@ -174,5 +174,41 @@ "SQL API: Nested Rollup with aliases", "SQL API: Nested Rollup over asterisk", "SQL API: Extended nested Rollup over asterisk" + ], + "tesseractSkip": [ + "for the ECommerce.TimeAnalysisExternal", + "for the ECommerce.TimeAnalysisInternal", + + "querying Products: dimensions -- doesn't work wo ordering", + "querying ECommerce: total quantity, avg discount, total sales, total profit by product + order + total -- rounding in athena", + "querying ECommerce: total sales, total profit by month + order (date) + total -- doesn't work with the BigQuery", + "querying ECommerce: total quantity, avg discount, total sales, total profit by product + order + total -- noisy test", + "querying BigECommerce: partitioned pre-agg", + "querying BigECommerce: null sum", + "querying BigECommerce: null boolean", + "--------------------", + + + "querying BigECommerce: rolling window by 2 week", + "querying custom granularities ECommerce: count by three_months_by_march + no dimension", + "querying custom granularities ECommerce: count by three_months_by_march + dimension", + "querying custom granularities (with preaggregation) ECommerce: totalQuantity by half_year + no dimension", + "querying custom granularities (with preaggregation) ECommerce: totalQuantity by half_year + dimension", + "querying custom granularities ECommerce: count by two_mo_by_feb + no dimension + rollingCountByUnbounded", + "querying custom granularities ECommerce: count by two_mo_by_feb + no dimension + rollingCountByTrailing", + "querying custom granularities ECommerce: count by two_mo_by_feb + no dimension + rollingCountByLeading", + "pre-aggregations Customers: running total without time dimension", + "querying BigECommerce: totalProfitYearAgo", + "SQL API: post-aggregate percentage of total", + "SQL API: Simple Rollup", + "SQL API: Complex Rollup", + "SQL API: Nested Rollup", + "SQL API: Rollup with aliases", + "SQL API: Rollup over exprs", + "SQL API: Nested Rollup with aliases", + "SQL API: Nested Rollup over asterisk", + "SQL API: Extended nested Rollup over asterisk", + "SQL API: Timeshift measure from cube", + "SQL API: SQL push down push to cube quoted alias" ] } 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 4f9bdb9eacb98..b67bcb7477c12 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 @@ -1,5 +1,21 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +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", + }, +] +`; + exports[`Queries with the @cubejs-backend/athena-driver SQL API: NULLS FIRST/LAST SQL push down: nulls_first_last_sql_push_down 1`] = ` Array [ Object { @@ -2846,6 +2862,136 @@ Array [ ] `; +exports[`Queries with the @cubejs-backend/athena-driver querying BigECommerce: rolling window YTD 1`] = ` +Array [ + Object { + "BigECommerce.orderDate": "2020-01-01T00:00:00.000", + "BigECommerce.orderDate.month": "2020-01-01T00:00:00.000", + "BigECommerce.rollingCountYTD": "2", + }, + Object { + "BigECommerce.orderDate": "2020-02-01T00:00:00.000", + "BigECommerce.orderDate.month": "2020-02-01T00:00:00.000", + "BigECommerce.rollingCountYTD": "3", + }, + Object { + "BigECommerce.orderDate": "2020-03-01T00:00:00.000", + "BigECommerce.orderDate.month": "2020-03-01T00:00:00.000", + "BigECommerce.rollingCountYTD": "5", + }, + Object { + "BigECommerce.orderDate": "2020-04-01T00:00:00.000", + "BigECommerce.orderDate.month": "2020-04-01T00:00:00.000", + "BigECommerce.rollingCountYTD": "6", + }, + Object { + "BigECommerce.orderDate": "2020-05-01T00:00:00.000", + "BigECommerce.orderDate.month": "2020-05-01T00:00:00.000", + "BigECommerce.rollingCountYTD": "11", + }, + Object { + "BigECommerce.orderDate": "2020-06-01T00:00:00.000", + "BigECommerce.orderDate.month": "2020-06-01T00:00:00.000", + "BigECommerce.rollingCountYTD": "18", + }, + Object { + "BigECommerce.orderDate": "2020-07-01T00:00:00.000", + "BigECommerce.orderDate.month": "2020-07-01T00:00:00.000", + "BigECommerce.rollingCountYTD": "18", + }, + Object { + "BigECommerce.orderDate": "2020-08-01T00:00:00.000", + "BigECommerce.orderDate.month": "2020-08-01T00:00:00.000", + "BigECommerce.rollingCountYTD": "18", + }, + Object { + "BigECommerce.orderDate": "2020-09-01T00:00:00.000", + "BigECommerce.orderDate.month": "2020-09-01T00:00:00.000", + "BigECommerce.rollingCountYTD": "24", + }, + Object { + "BigECommerce.orderDate": "2020-10-01T00:00:00.000", + "BigECommerce.orderDate.month": "2020-10-01T00:00:00.000", + "BigECommerce.rollingCountYTD": "28", + }, + Object { + "BigECommerce.orderDate": "2020-11-01T00:00:00.000", + "BigECommerce.orderDate.month": "2020-11-01T00:00:00.000", + "BigECommerce.rollingCountYTD": "37", + }, + Object { + "BigECommerce.orderDate": "2020-12-01T00:00:00.000", + "BigECommerce.orderDate.month": "2020-12-01T00:00:00.000", + "BigECommerce.rollingCountYTD": "44", + }, +] +`; + +exports[`Queries with the @cubejs-backend/athena-driver querying BigECommerce: rolling window YTD without date range 1`] = ` +Array [ + Object { + "BigECommerce.orderDate": "2020-01-01T00:00:00.000", + "BigECommerce.orderDate.month": "2020-01-01T00:00:00.000", + "BigECommerce.rollingCountYTD": "2", + }, + Object { + "BigECommerce.orderDate": "2020-02-01T00:00:00.000", + "BigECommerce.orderDate.month": "2020-02-01T00:00:00.000", + "BigECommerce.rollingCountYTD": "3", + }, + Object { + "BigECommerce.orderDate": "2020-03-01T00:00:00.000", + "BigECommerce.orderDate.month": "2020-03-01T00:00:00.000", + "BigECommerce.rollingCountYTD": "5", + }, + Object { + "BigECommerce.orderDate": "2020-04-01T00:00:00.000", + "BigECommerce.orderDate.month": "2020-04-01T00:00:00.000", + "BigECommerce.rollingCountYTD": "6", + }, + Object { + "BigECommerce.orderDate": "2020-05-01T00:00:00.000", + "BigECommerce.orderDate.month": "2020-05-01T00:00:00.000", + "BigECommerce.rollingCountYTD": "11", + }, + Object { + "BigECommerce.orderDate": "2020-06-01T00:00:00.000", + "BigECommerce.orderDate.month": "2020-06-01T00:00:00.000", + "BigECommerce.rollingCountYTD": "18", + }, + Object { + "BigECommerce.orderDate": "2020-07-01T00:00:00.000", + "BigECommerce.orderDate.month": "2020-07-01T00:00:00.000", + "BigECommerce.rollingCountYTD": "18", + }, + Object { + "BigECommerce.orderDate": "2020-08-01T00:00:00.000", + "BigECommerce.orderDate.month": "2020-08-01T00:00:00.000", + "BigECommerce.rollingCountYTD": "18", + }, + Object { + "BigECommerce.orderDate": "2020-09-01T00:00:00.000", + "BigECommerce.orderDate.month": "2020-09-01T00:00:00.000", + "BigECommerce.rollingCountYTD": "24", + }, + Object { + "BigECommerce.orderDate": "2020-10-01T00:00:00.000", + "BigECommerce.orderDate.month": "2020-10-01T00:00:00.000", + "BigECommerce.rollingCountYTD": "28", + }, + Object { + "BigECommerce.orderDate": "2020-11-01T00:00:00.000", + "BigECommerce.orderDate.month": "2020-11-01T00:00:00.000", + "BigECommerce.rollingCountYTD": "37", + }, + Object { + "BigECommerce.orderDate": "2020-12-01T00:00:00.000", + "BigECommerce.orderDate.month": "2020-12-01T00:00:00.000", + "BigECommerce.rollingCountYTD": "44", + }, +] +`; + exports[`Queries with the @cubejs-backend/athena-driver querying BigECommerce: rolling window by 2 day 1`] = ` Array [ Object { @@ -2911,6 +3057,71 @@ Array [ ] `; +exports[`Queries with the @cubejs-backend/athena-driver querying BigECommerce: rolling window by 2 day without date range 1`] = ` +Array [ + Object { + "BigECommerce.orderDate": "2020-01-01T00:00:00.000", + "BigECommerce.orderDate.month": "2020-01-01T00:00:00.000", + "BigECommerce.rollingCountBy2Day": null, + }, + Object { + "BigECommerce.orderDate": "2020-02-01T00:00:00.000", + "BigECommerce.orderDate.month": "2020-02-01T00:00:00.000", + "BigECommerce.rollingCountBy2Day": null, + }, + Object { + "BigECommerce.orderDate": "2020-03-01T00:00:00.000", + "BigECommerce.orderDate.month": "2020-03-01T00:00:00.000", + "BigECommerce.rollingCountBy2Day": null, + }, + Object { + "BigECommerce.orderDate": "2020-04-01T00:00:00.000", + "BigECommerce.orderDate.month": "2020-04-01T00:00:00.000", + "BigECommerce.rollingCountBy2Day": null, + }, + Object { + "BigECommerce.orderDate": "2020-05-01T00:00:00.000", + "BigECommerce.orderDate.month": "2020-05-01T00:00:00.000", + "BigECommerce.rollingCountBy2Day": null, + }, + Object { + "BigECommerce.orderDate": "2020-06-01T00:00:00.000", + "BigECommerce.orderDate.month": "2020-06-01T00:00:00.000", + "BigECommerce.rollingCountBy2Day": null, + }, + Object { + "BigECommerce.orderDate": "2020-07-01T00:00:00.000", + "BigECommerce.orderDate.month": "2020-07-01T00:00:00.000", + "BigECommerce.rollingCountBy2Day": null, + }, + Object { + "BigECommerce.orderDate": "2020-08-01T00:00:00.000", + "BigECommerce.orderDate.month": "2020-08-01T00:00:00.000", + "BigECommerce.rollingCountBy2Day": null, + }, + Object { + "BigECommerce.orderDate": "2020-09-01T00:00:00.000", + "BigECommerce.orderDate.month": "2020-09-01T00:00:00.000", + "BigECommerce.rollingCountBy2Day": null, + }, + Object { + "BigECommerce.orderDate": "2020-10-01T00:00:00.000", + "BigECommerce.orderDate.month": "2020-10-01T00:00:00.000", + "BigECommerce.rollingCountBy2Day": "1", + }, + Object { + "BigECommerce.orderDate": "2020-11-01T00:00:00.000", + "BigECommerce.orderDate.month": "2020-11-01T00:00:00.000", + "BigECommerce.rollingCountBy2Day": null, + }, + Object { + "BigECommerce.orderDate": "2020-12-01T00:00:00.000", + "BigECommerce.orderDate.month": "2020-12-01T00:00:00.000", + "BigECommerce.rollingCountBy2Day": null, + }, +] +`; + exports[`Queries with the @cubejs-backend/athena-driver querying BigECommerce: rolling window by 2 month 1`] = ` Array [ Object { @@ -2976,6 +3187,71 @@ Array [ ] `; +exports[`Queries with the @cubejs-backend/athena-driver querying BigECommerce: rolling window by 2 month without date range 1`] = ` +Array [ + Object { + "BigECommerce.orderDate": "2020-01-01T00:00:00.000", + "BigECommerce.orderDate.month": "2020-01-01T00:00:00.000", + "BigECommerce.rollingCountBy2Month": "2", + }, + Object { + "BigECommerce.orderDate": "2020-02-01T00:00:00.000", + "BigECommerce.orderDate.month": "2020-02-01T00:00:00.000", + "BigECommerce.rollingCountBy2Month": "3", + }, + Object { + "BigECommerce.orderDate": "2020-03-01T00:00:00.000", + "BigECommerce.orderDate.month": "2020-03-01T00:00:00.000", + "BigECommerce.rollingCountBy2Month": "3", + }, + Object { + "BigECommerce.orderDate": "2020-04-01T00:00:00.000", + "BigECommerce.orderDate.month": "2020-04-01T00:00:00.000", + "BigECommerce.rollingCountBy2Month": "3", + }, + Object { + "BigECommerce.orderDate": "2020-05-01T00:00:00.000", + "BigECommerce.orderDate.month": "2020-05-01T00:00:00.000", + "BigECommerce.rollingCountBy2Month": "6", + }, + Object { + "BigECommerce.orderDate": "2020-06-01T00:00:00.000", + "BigECommerce.orderDate.month": "2020-06-01T00:00:00.000", + "BigECommerce.rollingCountBy2Month": "12", + }, + Object { + "BigECommerce.orderDate": "2020-07-01T00:00:00.000", + "BigECommerce.orderDate.month": "2020-07-01T00:00:00.000", + "BigECommerce.rollingCountBy2Month": "7", + }, + Object { + "BigECommerce.orderDate": "2020-08-01T00:00:00.000", + "BigECommerce.orderDate.month": "2020-08-01T00:00:00.000", + "BigECommerce.rollingCountBy2Month": null, + }, + Object { + "BigECommerce.orderDate": "2020-09-01T00:00:00.000", + "BigECommerce.orderDate.month": "2020-09-01T00:00:00.000", + "BigECommerce.rollingCountBy2Month": "6", + }, + Object { + "BigECommerce.orderDate": "2020-10-01T00:00:00.000", + "BigECommerce.orderDate.month": "2020-10-01T00:00:00.000", + "BigECommerce.rollingCountBy2Month": "10", + }, + Object { + "BigECommerce.orderDate": "2020-11-01T00:00:00.000", + "BigECommerce.orderDate.month": "2020-11-01T00:00:00.000", + "BigECommerce.rollingCountBy2Month": "13", + }, + Object { + "BigECommerce.orderDate": "2020-12-01T00:00:00.000", + "BigECommerce.orderDate.month": "2020-12-01T00:00:00.000", + "BigECommerce.rollingCountBy2Month": "16", + }, +] +`; + exports[`Queries with the @cubejs-backend/athena-driver querying BigECommerce: totalProfitYearAgo 1`] = `Array []`; exports[`Queries with the @cubejs-backend/athena-driver querying Customers: dimensions + limit 1`] = ` @@ -8007,19 +8283,3 @@ 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/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/driver_tools.rs b/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/driver_tools.rs index 31efcb3e94ee4..47bb919030e0c 100644 --- a/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/driver_tools.rs +++ b/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/driver_tools.rs @@ -24,6 +24,7 @@ pub trait DriverTools { fn get_allocated_params(&self) -> Result, CubeError>; fn subtract_interval(&self, date: String, interval: String) -> Result; fn add_interval(&self, date: String, interval: String) -> Result; + fn interval_string(&self, interval: String) -> Result; fn add_timestamp_interval(&self, date: String, interval: String) -> Result; fn interval_and_minimal_time_unit(&self, interval: String) -> Result, CubeError>; fn hll_init(&self, sql: String) -> Result; diff --git a/rust/cubesqlplanner/cubesqlplanner/src/plan/time_series.rs b/rust/cubesqlplanner/cubesqlplanner/src/plan/time_series.rs index cdad6a3c9e20b..7129f6fb718e0 100644 --- a/rust/cubesqlplanner/cubesqlplanner/src/plan/time_series.rs +++ b/rust/cubesqlplanner/cubesqlplanner/src/plan/time_series.rs @@ -51,6 +51,7 @@ impl TimeSeries { )); } let interval = interval_description[0].clone(); + let interval = templates.interval_string(interval)?; let minimal_time_unit = interval_description[1].clone(); match &self.date_range { TimeSeriesDateRange::Filter(from_date, to_date) => { diff --git a/rust/cubesqlplanner/cubesqlplanner/src/planner/filter/base_filter.rs b/rust/cubesqlplanner/cubesqlplanner/src/planner/filter/base_filter.rs index e0738d93b3fc5..cebdc6dd86631 100644 --- a/rust/cubesqlplanner/cubesqlplanner/src/planner/filter/base_filter.rs +++ b/rust/cubesqlplanner/cubesqlplanner/src/planner/filter/base_filter.rs @@ -397,8 +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 from_expr = plan_templates.series_bounds_cast(&from_expr)?; + let to_expr = plan_templates.series_bounds_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 3cdb0957e33d8..3b4a8fca00e6c 100644 --- a/rust/cubesqlplanner/cubesqlplanner/src/planner/sql_templates/plan.rs +++ b/rust/cubesqlplanner/cubesqlplanner/src/planner/sql_templates/plan.rs @@ -86,6 +86,10 @@ impl PlanSqlTemplates { self.driver_tools.add_interval(date, interval) } + pub fn interval_string(&self, interval: String) -> Result { + self.driver_tools.interval_string(interval) + } + pub fn add_timestamp_interval( &self, date: String, @@ -669,6 +673,11 @@ impl PlanSqlTemplates { ) } + pub fn series_bounds_cast(&self, expr: &str) -> Result { + self.render + .render_template(&"tesseract/series_bounds_cast", context! { expr => expr }) + } + pub fn additional_null_check(&self, need: bool, column: &String) -> Result { if need { self.or_is_null_check(column.clone())