Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion docs/pages/reference/data-model/dimensions.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,14 @@ examples.

</ReferenceBox>

<WarningBox>

Custom granularities are supported for the following [data sources][ref-data-sources]:
Amazon Athena, Amazon Redshift, DuckDB, Databricks, Google BigQuery, ClickHouse, Microsoft SQL Server, MySQL, Postgres, and Snowflake.
Please [file an issue](https://github.com/cube-js/cube/issues) if you need support for another data source.

</WarningBox>

For each custom granularity, the `interval` parameter is required. It specifies
the duration of the time interval and has the following format:
`quantity unit [quantity unit...]`, e.g., `5 days` or `1 year 6 months`.
Expand Down Expand Up @@ -713,4 +721,5 @@ cube(`orders`, {
[ref-time-dimensions]: /reference/data-model/types-and-formats#time-1
[link-date-time-string]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#date_time_string_format
[ref-custom-granularity-recipe]: /guides/recipes/data-modeling/custom-granularity
[ref-ref-hierarchies]: /reference/data-model/hierarchies
[ref-ref-hierarchies]: /reference/data-model/hierarchies
[ref-data-sources]: /product/configuration/data-sources
2 changes: 1 addition & 1 deletion packages/cubejs-schema-compiler/src/adapter/BaseQuery.js
Original file line number Diff line number Diff line change
Expand Up @@ -3110,7 +3110,7 @@ export class BaseQuery {
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
dateBin(interval, source, origin) {
throw new Error('Date bin function is not implemented');
throw new Error('Date bin function, required for custom time dimension granularities, is not implemented for this data source');
// Different syntax possible in different DBs
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ export class PreAggregations {
const tableName = this.preAggregationTableName(cube, preAggregationName, preAggregation);
const invalidateKeyQueries = this.query.preAggregationInvalidateKeyQueries(cube, preAggregation, preAggregationName);
const queryForSqlEvaluation = this.query.preAggregationQueryForSqlEvaluation(cube, preAggregation);
const partitionInvalidateKeyQueries = queryForSqlEvaluation.partitionInvalidateKeyQueries && queryForSqlEvaluation.partitionInvalidateKeyQueries(cube, preAggregation);
const partitionInvalidateKeyQueries = queryForSqlEvaluation.partitionInvalidateKeyQueries?.(cube, preAggregation);

const allBackAliasMembers = this.query.allBackAliasMembers();

Expand Down
25 changes: 25 additions & 0 deletions packages/cubejs-schema-compiler/src/adapter/PrestodbQuery.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { parseSqlInterval } from '@cubejs-backend/shared';
import { BaseQuery } from './BaseQuery';
import { BaseFilter } from './BaseFilter';

Expand Down Expand Up @@ -55,6 +56,30 @@ export class PrestodbQuery extends BaseQuery {
field;
}

/**
* Returns sql for source expression floored to timestamps aligned with
* intervals relative to origin timestamp point.
* Athena doesn't support INTERVALs directly — using date_diff/date_add
*/
public dateBin(interval: string, source: string, origin: string): string {
const intervalParsed = parseSqlInterval(interval);
const intervalParts = Object.entries(intervalParsed);

if (intervalParts.length > 1) {
throw new Error('Athena/Presto supports only simple intervals with one date part');
}

const [unit, count] = intervalParts[0];
const originExpr = this.timeStampCast(`'${origin}'`);

return `date_add('${unit}',
floor(
date_diff('${unit}', ${originExpr}, ${source}) / ${count}
) * ${count},
${originExpr}
)`;
}

public timeGroupedColumn(granularity, dimension) {
return `date_trunc('${GRANULARITY_TO_INTERVAL[granularity]}', ${dimension})`;
}
Expand Down
8 changes: 4 additions & 4 deletions packages/cubejs-server-core/src/core/DriverResolvers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,13 @@ export const lookupDriverClass = (dbType): Constructor<BaseDriver> & {
*/
export const isDriver = (val: any): boolean => {
let isDriverInstance = val instanceof BaseDriver;
if (!isDriverInstance && val && val.constructor) {
if (!isDriverInstance && val?.constructor) {
let end = false;
let obj = val.constructor;
while (!isDriverInstance && !end) {
obj = Object.getPrototypeOf(obj);
end = !obj;
isDriverInstance = obj && obj.name ? obj.name === 'BaseDriver' : false;
isDriverInstance = obj?.name ? obj.name === 'BaseDriver' : false;
}
}
return isDriverInstance;
Expand All @@ -82,11 +82,11 @@ export const getDriverMaxPool = async (
const queryQueueOptions = await options
.queryCacheOptions
.queueOptions(context.dataSource);

const preAggregationsQueueOptions = await options
.preAggregationsOptions
.queueOptions(context.dataSource);

return 2 * (
queryQueueOptions.concurrency +
preAggregationsQueueOptions.concurrency
Expand Down
7 changes: 0 additions & 7 deletions packages/cubejs-testing-drivers/fixtures/athena.json
Original file line number Diff line number Diff line change
Expand Up @@ -151,15 +151,8 @@
"---------------------------------------",
"Custom Granularities ",
"---------------------------------------",
"querying custom granularities ECommerce: count by half_year + no dimension",
"querying custom granularities ECommerce: count by half_year_by_1st_april + no dimension",
"querying custom granularities ECommerce: count by three_months_by_march + no dimension",
"querying custom granularities ECommerce: count by half_year + dimension",
"querying custom granularities ECommerce: count by half_year_by_1st_april + dimension",
"querying custom granularities ECommerce: count by three_months_by_march + 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",

"SKIPPED SQL API (Need work)",
"---------------------------------------",
Expand Down
Loading