Skip to content

Commit 2cd7934

Browse files
committed
Implement dimensionTimeGroupedColumn for Snowflake
1 parent 63156b8 commit 2cd7934

File tree

1 file changed

+49
-0
lines changed

1 file changed

+49
-0
lines changed

packages/cubejs-schema-compiler/src/adapter/SnowflakeQuery.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,55 @@ export class SnowflakeQuery extends BaseQuery {
4242
return `date_trunc('${GRANULARITY_TO_INTERVAL[granularity]}', ${dimension})`;
4343
}
4444

45+
public dimensionTimeGroupedColumn(dimension: string, interval: string, offset: string): string {
46+
if (offset) {
47+
offset = this.formatInterval(offset);
48+
}
49+
50+
if (this.isGranularityNaturalAligned(interval)) {
51+
return super.dimensionTimeGroupedColumn(dimension, interval, offset);
52+
}
53+
54+
// Formula:
55+
// SELECT DATEADD(second,
56+
// FLOOR(
57+
// DATEDIFF(seconds, DATE_TRUNC('year', dimension) + offset?, dimension) /
58+
// DATE_PART(epoch_seconds FROM (TIMESTAMP_FROM_PARTS(1970, 1, 1, 0, 0, 0) + interval))
59+
// ) * DATE_PART(epoch_seconds FROM (TIMESTAMP_FROM_PARTS(1970, 1, 1, 0, 0, 0) + interval)),
60+
// DATE_TRUNC('year', dimension) + offset?)
61+
//
62+
// The formula operates with seconds so it won't produce dates aligned with offset date parts, like:
63+
// if offset is "6 months 3 days" - the result won't always be the 3rd of July. It will add
64+
// exact number of seconds in the "6 months 3 days" without aligning with natural calendar.
65+
66+
let dtDate = this.timeGroupedColumn('year', dimension);
67+
if (offset) {
68+
dtDate = this.addInterval(dtDate, offset);
69+
}
70+
71+
interval = this.formatInterval(interval);
72+
73+
return `DATEADD(second,
74+
FLOOR(
75+
DATEDIFF(seconds, ${dtDate}, CURRENT_TIMESTAMP) /
76+
DATE_PART(epoch_seconds FROM (TIMESTAMP_FROM_PARTS(1970, 1, 1, 0, 0, 0) + interval '${interval}'))
77+
) * DATE_PART(epoch_seconds FROM (TIMESTAMP_FROM_PARTS(1970, 1, 1, 0, 0, 0) + interval '${interval}')),
78+
${dtDate})`;
79+
}
80+
81+
/**
82+
* The input interval in format "2 years 3 months 4 weeks 5 days...."
83+
* will be converted to Snowflake dialect "2 years, 3 months, 4 weeks, 5 days...."
84+
*/
85+
private formatInterval(interval: string): string {
86+
return interval.split(' ').map((word, index, arr) => {
87+
if (index % 2 !== 0 && index < arr.length - 1) {
88+
return `${word},`;
89+
}
90+
return word;
91+
}).join(' ');
92+
}
93+
4594
public timeStampCast(value) {
4695
return `${value}::timestamp_tz`;
4796
}

0 commit comments

Comments
 (0)