Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ export class MssqlQuery extends BaseQuery {
// MSSQL uses + for string concatenation instead of ||
templates.expressions.concat_strings = '{{ strings | join(\' + \' ) }}';
// NOTE: this template contains a comma; two order expressions are being generated
templates.expressions.sort = '{{ expr }} IS NULL {% if nulls_first %}DESC{% else %}ASC{% endif %}, {{ expr }} {% if asc %}ASC{% else %}DESC{% endif %}';
templates.expressions.sort = 'CASE WHEN {{ expr }} IS NULL THEN 1 ELSE 0 END {% if nulls_first %}DESC{% else %}ASC{% endif %}, {{ expr }} {% if asc %}ASC{% else %}DESC{% endif %}';
// Timestamp constants arrive as ISO-8601 UTC strings ('2021-01-01T00:00:00.000Z');
// CONVERT style 127 is defined as exactly this format (yyyy-mm-ddThh:mi:ss.mmmZ,
// "ISO8601 with time zone Z"). The base template renders the value bare, which is
Expand Down
19 changes: 19 additions & 0 deletions packages/cubejs-schema-compiler/test/unit/mssql-query.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,25 @@ describe('MssqlQuery', () => {

const joinedSchemaCompilers = prepareJsCompiler(createJoinedCubesSchema());

it('renders a scalar null discriminator for SQL API pushdown sorting', async () => {
await compiler.compile();

const query = new MssqlQuery({ joinGraph, cubeEvaluator, compiler }, {
measures: ['visitors.count'],
dimensions: ['visitors.source'],
});

// SQL API pushdown uses expressions.sort, rather than the regular query's
// order_by template. T-SQL rejects a bare IS NULL predicate in ORDER BY and
// can report the subsequent FETCH NEXT clause as the failing syntax.
const { sort } = query.sqlTemplates().expressions;
expect(sort).toContain('CASE WHEN {{ expr }} IS NULL THEN 1 ELSE 0 END');
// The discriminator's direction depends on null placement, independently
// of the value's direction. NULL maps to 1, so DESC puts NULLs first.
expect(sort).toContain('END {% if nulls_first %}DESC{% else %}ASC{% endif %},');
expect(sort).toContain('{{ expr }} {% if asc %}ASC{% else %}DESC{% endif %}');
});

it('should group by the created_at field on the calculated granularity for unbounded trailing windows',
() => compiler.compile().then(() => {
const query = new MssqlQuery(
Expand Down
Loading