From 54c2f01e652c43b12e8853dbc85b35c921c1c433 Mon Sep 17 00:00:00 2001 From: Tom Tankilevitch Date: Sat, 13 Sep 2025 21:15:19 +0300 Subject: [PATCH] fix(schema-compiler): use TO_TIMESTAMP_TZ for ISO 8601 with Z; keep index-friendly casts; add Oracle unit test --- .../src/adapter/OracleQuery.ts | 7 ++- .../test/unit/oracle-query.test.ts | 56 +++++++++++++++++++ 2 files changed, 61 insertions(+), 2 deletions(-) create mode 100644 packages/cubejs-schema-compiler/test/unit/oracle-query.test.ts diff --git a/packages/cubejs-schema-compiler/src/adapter/OracleQuery.ts b/packages/cubejs-schema-compiler/src/adapter/OracleQuery.ts index d5e4871b88497..46fdfaa0e7ed7 100644 --- a/packages/cubejs-schema-compiler/src/adapter/OracleQuery.ts +++ b/packages/cubejs-schema-compiler/src/adapter/OracleQuery.ts @@ -71,11 +71,14 @@ export class OracleQuery extends BaseQuery { } public dateTimeCast(value) { - return `to_date(:"${value}", 'YYYY-MM-DD"T"HH24:MI:SS"Z"')`; + // Use timezone-aware parsing for ISO 8601 with milliseconds and trailing 'Z', then cast to DATE + // to preserve index-friendly comparisons against DATE columns. + return `CAST(TO_TIMESTAMP_TZ(:"${value}", 'YYYY-MM-DD"T"HH24:MI:SS.FF"Z"') AS DATE)`; } public timeStampCast(value) { - return this.dateTimeCast(value); + // Return timezone-aware timestamp for TIMESTAMP comparisons + return `TO_TIMESTAMP_TZ(:"${value}", 'YYYY-MM-DD"T"HH24:MI:SS.FF"Z"')`; } public timeStampParam(timeDimension) { diff --git a/packages/cubejs-schema-compiler/test/unit/oracle-query.test.ts b/packages/cubejs-schema-compiler/test/unit/oracle-query.test.ts new file mode 100644 index 0000000000000..501fc2aa20fa9 --- /dev/null +++ b/packages/cubejs-schema-compiler/test/unit/oracle-query.test.ts @@ -0,0 +1,56 @@ +import { OracleQuery } from '../../src/adapter/OracleQuery'; +import { prepareJsCompiler } from './PrepareCompiler'; + +describe('OracleQuery', () => { + const { compiler, joinGraph, cubeEvaluator } = prepareJsCompiler(` + cube(\`visitors\`, { + sql: \` + select * from visitors + \`, + + measures: { + count: { + type: 'count' + } + }, + + dimensions: { + id: { + sql: 'id', + type: 'number', + primaryKey: true + }, + createdAt: { + type: 'time', + sql: 'created_at' + } + } + }) + `, { adapter: 'oracle' }); + + it('uses to_date with seconds precision and preserves trailing Z', async () => { + await compiler.compile(); + + const query = new OracleQuery( + { joinGraph, cubeEvaluator, compiler }, + { + measures: ['visitors.count'], + timeDimensions: [ + { + dimension: 'visitors.createdAt', + dateRange: ['2024-02-01', '2024-02-02'], + granularity: 'day' + } + ], + timezone: 'UTC' + } + ); + + const [sql, params] = query.buildSqlAndParams(); + + expect(sql).toContain("CAST(TO_TIMESTAMP_TZ(:\"?\", 'YYYY-MM-DD\"T\"HH24:MI:SS.FF\"Z\"') AS DATE)"); + expect(params).toEqual(['2024-02-01T00:00:00.000Z']); + }); +}); + +