Skip to content

Commit 16e6a9e

Browse files
fix(@cubejs-schema-compilter): MSSQL rollingWindow with granularity (#1169) Thanks to @JoshMentzer!
Co-authored-by: Joshua D. Mentzer <mentzerj@trinity-health.org>
1 parent f82b84d commit 16e6a9e

File tree

2 files changed

+91
-0
lines changed

2 files changed

+91
-0
lines changed

packages/cubejs-schema-compiler/adapter/MssqlQuery.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,21 @@ class MssqlQuery extends BaseQuery {
9595
return dimensionColumns.length ? ` GROUP BY ${dimensionColumns.join(', ')}` : '';
9696
}
9797

98+
overTimeSeriesSelect(cumulativeMeasures, dateSeriesSql, baseQuery, dateJoinConditionSql, baseQueryAlias) {
99+
const forGroupBy = this.timeDimensions.map(
100+
(t) => `${t.dateSeriesAliasName() + '.' + this.escapeColumnName('date_from')}`
101+
);
102+
const forSelect = this.dateSeriesSelect()
103+
.concat(this.dimensions.concat(cumulativeMeasures).map((s) => s.cumulativeSelectColumns()))
104+
.filter((c) => !!c)
105+
.join(', ');
106+
return (
107+
`SELECT ${forSelect} FROM ${dateSeriesSql}` +
108+
` LEFT JOIN (${baseQuery}) ${this.asSyntaxJoin} ${baseQueryAlias} ON ${dateJoinConditionSql}` +
109+
` GROUP BY ${forGroupBy}`
110+
);
111+
}
112+
98113
nowTimestampSql() {
99114
return `CURRENT_TIMESTAMP`;
100115
}
@@ -111,6 +126,13 @@ class MssqlQuery extends BaseQuery {
111126
wrapSegmentForDimensionSelect(sql) {
112127
return `CAST((CASE WHEN ${sql} THEN 1 ELSE 0 END) AS BIT)`;
113128
}
129+
130+
seriesSql(timeDimension) {
131+
const values = timeDimension.timeSeries().map(([from, to]) => `('${from}', '${to}')`);
132+
return `SELECT ${this.dateTimeCast('date_from')} date_from, ${this.dateTimeCast(
133+
'date_to'
134+
)} date_to FROM (VALUES ${values}) ${this.asSyntaxTable} dates (date_from, date_to)`;
135+
}
114136
}
115137

116138
module.exports = MssqlQuery;
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/* globals it, describe, after */
2+
/* eslint-disable quote-props */
3+
const MssqlQuery = require('../../adapter/MssqlQuery');
4+
const PrepareCompiler = require('./PrepareCompiler');
5+
require('should');
6+
7+
const { prepareCompiler } = PrepareCompiler;
8+
9+
describe('MssqlQuery', () => {
10+
const { compiler, joinGraph, cubeEvaluator } = prepareCompiler(`
11+
cube(\`visitors\`, {
12+
sql: \`
13+
select * from visitors
14+
\`,
15+
16+
measures: {
17+
count: {
18+
type: 'count'
19+
},
20+
21+
unboundedCount: {
22+
type: 'count',
23+
rollingWindow: {
24+
trailing: 'unbounded'
25+
}
26+
}
27+
},
28+
29+
dimensions: {
30+
createdAt: {
31+
type: 'time',
32+
sql: 'created_at'
33+
}
34+
}
35+
});
36+
`);
37+
38+
it('group by the date_from field on unbounded trailing windows', () =>
39+
compiler.compile().then(() => {
40+
const query = new MssqlQuery(
41+
{ joinGraph, cubeEvaluator, compiler },
42+
{
43+
measures: ['visitors.count', 'visitors.unboundedCount'],
44+
timeDimensions: [
45+
{
46+
dimension: 'visitors.createdAt',
47+
granularity: 'week',
48+
dateRange: ['2017-01-01', '2017-01-30'],
49+
},
50+
],
51+
timezone: 'America/Los_Angeles',
52+
order: [
53+
{
54+
id: 'visitors.createdAt',
55+
},
56+
],
57+
}
58+
);
59+
60+
const queryAndParams = query.buildSqlAndParams();
61+
62+
const queryString = queryAndParams[0];
63+
const lastGroupByIdx = queryString.lastIndexOf('GROUP BY');
64+
const queryCloseIdx = queryString.indexOf(')', lastGroupByIdx + 1);
65+
const finalGroupBy = queryString.substring(lastGroupByIdx, queryCloseIdx);
66+
67+
finalGroupBy.should.equal('GROUP BY "visitors.createdAt_series"."date_from"');
68+
}));
69+
});

0 commit comments

Comments
 (0)