From 53e85acec964b63a11b1414c0b2788353a7a8d8d Mon Sep 17 00:00:00 2001 From: Sean McQueen Date: Mon, 1 Jun 2026 17:01:55 -0700 Subject: [PATCH 1/2] fix(pinot): support tesseract select template sources Committed-By-Agent: codex Co-authored-by: codex --- .../cubejs-pinot-driver/src/PinotQuery.ts | 23 ++++++++++++++----- .../test/PinotQueryTemplates.test.ts | 16 +++++++++++++ 2 files changed, 33 insertions(+), 6 deletions(-) create mode 100644 packages/cubejs-pinot-driver/test/PinotQueryTemplates.test.ts diff --git a/packages/cubejs-pinot-driver/src/PinotQuery.ts b/packages/cubejs-pinot-driver/src/PinotQuery.ts index 204bce55d46b4..565f852152a56 100644 --- a/packages/cubejs-pinot-driver/src/PinotQuery.ts +++ b/packages/cubejs-pinot-driver/src/PinotQuery.ts @@ -142,12 +142,23 @@ export class PinotQuery extends BaseQuery { const templates = super.sqlTemplates(); templates.functions.DATETRUNC = 'DATE_TRUNC({{ args_concat }})'; templates.functions.STRING_AGG = 'LISTAGG({% if distinct %}DISTINCT {% endif %}{{ args_concat }})'; - templates.statements.select = 'SELECT {{ select_concat | map(attribute=\'aliased\') | join(\', \') }} \n' + - 'FROM (\n {{ from }}\n) AS {{ from_alias }} \n' + - '{% if group_by %} GROUP BY {{ group_by }}{% endif %}' + - '{% if order_by %} ORDER BY {{ order_by | map(attribute=\'expr\') | join(\', \') }}{% endif %}' + - '{% if offset %}\nOFFSET {{ offset }}{% endif %}' + - '{% if limit %}\nLIMIT {{ limit }}{% endif %}'; + templates.statements.select = '{% if ctes %} WITH \n' + + '{{ ctes | join(\',\n\') }}\n' + + '{% endif %}' + + 'SELECT {% if distinct %}DISTINCT {% endif %}' + + '{{ select_concat | map(attribute=\'aliased\') | join(\', \') }} {% if from %}\n' + + 'FROM (\n' + + '{{ from | indent(2, true) }}\n' + + ') AS {{ from_alias }}{% elif from_prepared %}\n' + + 'FROM {{ from_prepared }}' + + '{% endif %}' + + '{% for join in joins %}\n{{ join }}{% endfor %}' + + '{% if filter %}\nWHERE {{ filter }}{% endif %}' + + '{% if group_by %}\nGROUP BY {{ group_by }}{% endif %}' + + '{% if having %}\nHAVING {{ having }}{% endif %}' + + '{% if order_by %}\nORDER BY {{ order_by | map(attribute=\'expr\') | join(\', \') }}{% endif %}' + + '{% if offset is not none %}\nOFFSET {{ offset }}{% endif %}' + + '{% if limit is not none %}\nLIMIT {{ limit }}{% endif %}'; templates.expressions.extract = 'EXTRACT({{ date_part }} FROM {{ expr }})'; templates.expressions.timestamp_literal = `fromDateTime('{{ value }}', ${DATE_TIME_FORMAT})`; // NOTE: this template contains a comma; two order expressions are being generated diff --git a/packages/cubejs-pinot-driver/test/PinotQueryTemplates.test.ts b/packages/cubejs-pinot-driver/test/PinotQueryTemplates.test.ts new file mode 100644 index 0000000000000..816ec5af092cb --- /dev/null +++ b/packages/cubejs-pinot-driver/test/PinotQueryTemplates.test.ts @@ -0,0 +1,16 @@ +import { PinotQuery } from '../src/PinotQuery'; + +describe('PinotQuery SQL templates', () => { + it('supports Tesseract select template variables', () => { + const templates = PinotQuery.prototype.sqlTemplates.call({} as PinotQuery); + const selectTemplate = templates.statements.select; + + expect(selectTemplate).toContain('from_prepared'); + expect(selectTemplate).toContain('ctes'); + expect(selectTemplate).toContain('distinct'); + expect(selectTemplate).toContain('joins'); + expect(selectTemplate).toContain('filter'); + expect(selectTemplate).toContain('having'); + expect(selectTemplate.indexOf('OFFSET')).toBeLessThan(selectTemplate.indexOf('LIMIT')); + }); +}); From 570c9b5e87b415f00760310fa2c90326b35f4dd4 Mon Sep 17 00:00:00 2001 From: Sean McQueen Date: Mon, 1 Jun 2026 17:11:03 -0700 Subject: [PATCH 2/2] test(pinot): cover tesseract sql table rendering Committed-By-Agent: codex Co-authored-by: codex --- .../test/PinotQueryTemplates.test.ts | 57 +++++++++++++++---- 1 file changed, 46 insertions(+), 11 deletions(-) diff --git a/packages/cubejs-pinot-driver/test/PinotQueryTemplates.test.ts b/packages/cubejs-pinot-driver/test/PinotQueryTemplates.test.ts index 816ec5af092cb..cac48e48af350 100644 --- a/packages/cubejs-pinot-driver/test/PinotQueryTemplates.test.ts +++ b/packages/cubejs-pinot-driver/test/PinotQueryTemplates.test.ts @@ -1,16 +1,51 @@ +import { prepareCompiler as originalPrepareCompiler } from '@cubejs-backend/schema-compiler'; import { PinotQuery } from '../src/PinotQuery'; +const prepareCompiler = (content: string) => originalPrepareCompiler({ + localPath: () => __dirname, + dataSchemaFiles: () => Promise.resolve([ + { fileName: 'main.js', content } + ]) +}, { adapter: 'postgres' }); + describe('PinotQuery SQL templates', () => { - it('supports Tesseract select template variables', () => { - const templates = PinotQuery.prototype.sqlTemplates.call({} as PinotQuery); - const selectTemplate = templates.statements.select; - - expect(selectTemplate).toContain('from_prepared'); - expect(selectTemplate).toContain('ctes'); - expect(selectTemplate).toContain('distinct'); - expect(selectTemplate).toContain('joins'); - expect(selectTemplate).toContain('filter'); - expect(selectTemplate).toContain('having'); - expect(selectTemplate.indexOf('OFFSET')).toBeLessThan(selectTemplate.indexOf('LIMIT')); + it('renders Tesseract sql_table queries with a prepared FROM source', async () => { + const { compiler, joinGraph, cubeEvaluator } = prepareCompiler(` + cube('orders', { + sql_table: 'orders', + + measures: { + count: { + type: 'count', + }, + }, + + dimensions: { + id: { + sql: 'id', + type: 'number', + primary_key: true, + }, + }, + }); + `); + + await compiler.compile(); + + const query = new PinotQuery({ joinGraph, cubeEvaluator, compiler }, { + measures: ['orders.count'], + timeDimensions: [], + filters: [], + limit: 10, + offset: 5, + useNativeSqlPlanner: true, + }); + + const [sql] = query.buildSqlAndParams(); + + expect(sql).toMatch(/FROM\s+orders\b/); + expect(sql).not.toMatch(/FROM\s*\(\s*\)\s+AS\b/); + expect(sql.indexOf('OFFSET 5')).toBeGreaterThan(-1); + expect(sql.indexOf('OFFSET 5')).toBeLessThan(sql.indexOf('LIMIT 10')); }); });