Skip to content

Commit 515eeae

Browse files
authored
fix(tesseract): Tesseract should respect convertTzForRawTimeDimension (#10585)
1 parent 3bfe812 commit 515eeae

16 files changed

Lines changed: 162 additions & 12 deletions

File tree

packages/cubejs-schema-compiler/src/adapter/BaseQuery.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -951,6 +951,7 @@ export class BaseQuery {
951951
joinHints: this.options.joinHints,
952952
cubestoreSupportMultistage: this.options.cubestoreSupportMultistage ?? getEnv('cubeStoreRollingWindowJoin'),
953953
disableExternalPreAggregations: !!this.options.disableExternalPreAggregations,
954+
convertTzForRawTimeDimension: !!this.options.convertTzForRawTimeDimension,
954955
maskedMembers: this.options.maskedMembers,
955956
memberToAlias: this.options.memberToAlias,
956957
};

packages/cubejs-schema-compiler/test/integration/postgres/sql-generation.test.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5067,6 +5067,47 @@ SELECT 1 AS revenue, cast('2024-01-01' AS timestamp) as time UNION ALL
50675067
}]
50685068
));
50695069

5070+
it('raw time dimension with timezone', async () => runQueryTest(
5071+
{
5072+
measures: [
5073+
'visitors.visitor_revenue',
5074+
],
5075+
dimensions: ['visitors.created_at'],
5076+
timeDimensions: [{
5077+
dimension: 'visitors.created_at',
5078+
granularity: 'day',
5079+
dateRange: ['2017-01-01', '2017-01-30']
5080+
}],
5081+
timezone: 'America/Los_Angeles',
5082+
convertTzForRawTimeDimension: true,
5083+
order: [{
5084+
id: 'visitors.created_at'
5085+
}]
5086+
},
5087+
[
5088+
{
5089+
visitors__created_at: '2017-01-02T16:00:00.000Z',
5090+
visitors__created_at_day: '2017-01-02T00:00:00.000Z',
5091+
visitors__visitor_revenue: '100'
5092+
},
5093+
{
5094+
visitors__created_at: '2017-01-04T16:00:00.000Z',
5095+
visitors__created_at_day: '2017-01-04T00:00:00.000Z',
5096+
visitors__visitor_revenue: '200'
5097+
},
5098+
{
5099+
visitors__created_at: '2017-01-05T16:00:00.000Z',
5100+
visitors__created_at_day: '2017-01-05T00:00:00.000Z',
5101+
visitors__visitor_revenue: null
5102+
},
5103+
{
5104+
visitors__created_at: '2017-01-06T16:00:00.000Z',
5105+
visitors__created_at_day: '2017-01-06T00:00:00.000Z',
5106+
visitors__visitor_revenue: null
5107+
}
5108+
]
5109+
));
5110+
50705111
it('simple join with segment', async () => runQueryTest(
50715112
{
50725113
measures: [

rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/base_query_options.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ pub struct BaseQueryOptionsStatic {
7474
pub disable_external_pre_aggregations: bool,
7575
#[serde(rename = "preAggregationId")]
7676
pub pre_aggregation_id: Option<String>,
77+
#[serde(rename = "convertTzForRawTimeDimension")]
78+
pub convert_tz_for_raw_time_dimension: Option<bool>,
7779
#[serde(rename = "maskedMembers")]
7880
pub masked_members: Option<Vec<String>>,
7981
#[serde(rename = "memberToAlias", default)]

rust/cubesqlplanner/cubesqlplanner/src/planner/base_query.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ impl<IT: InnerTypes> BaseQuery<IT> {
3434
options.join_graph()?,
3535
options.static_data().timezone.clone(),
3636
options.static_data().export_annotated_sql,
37+
options
38+
.static_data()
39+
.convert_tz_for_raw_time_dimension
40+
.unwrap_or(false),
3741
options.static_data().masked_members.clone(),
3842
options.static_data().member_to_alias.clone(),
3943
)?;

rust/cubesqlplanner/cubesqlplanner/src/planner/filter/typed_filter.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ use crate::cube_bridge::member_sql::FilterParamsColumn;
22
use crate::planner::query_tools::QueryTools;
33
use crate::planner::sql_evaluator::MemberSymbol;
44
use crate::planner::sql_templates::PlanSqlTemplates;
5-
use crate::planner::{evaluate_with_context, FiltersContext, VisitorContext};
5+
use crate::planner::visitor_context::evaluate_filter_with_context;
6+
use crate::planner::{FiltersContext, VisitorContext};
67
use cubenativeutils::CubeError;
78
use std::rc::Rc;
89

@@ -109,7 +110,7 @@ impl TypedFilter {
109110
}
110111

111112
let resolved = resolve_base_symbol(&self.member_evaluator);
112-
let member_sql = evaluate_with_context(&resolved, context.clone(), plan_templates)?;
113+
let member_sql = evaluate_filter_with_context(&resolved, context.clone(), plan_templates)?;
113114

114115
let filters_context = context.filters_context();
115116
let ctx = FilterSqlContext {

rust/cubesqlplanner/cubesqlplanner/src/planner/query_tools.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ pub struct QueryTools {
3030
params_allocator: Rc<RefCell<ParamsAllocator>>,
3131
evaluator_compiler: Rc<RefCell<Compiler>>,
3232
timezone: Tz,
33+
convert_tz_for_raw_time_dimension: bool,
3334
masked_members: HashSet<String>,
3435
}
3536

@@ -41,6 +42,7 @@ impl QueryTools {
4142
join_graph: Rc<dyn JoinGraph>,
4243
timezone_name: Option<String>,
4344
export_annotated_sql: bool,
45+
convert_tz_for_raw_time_dimension: bool,
4446
masked_members: Option<Vec<String>>,
4547
member_to_alias: Option<HashMap<String, String>>,
4648
) -> Result<Rc<Self>, CubeError> {
@@ -67,6 +69,7 @@ impl QueryTools {
6769
params_allocator: Rc::new(RefCell::new(ParamsAllocator::new(export_annotated_sql))),
6870
evaluator_compiler,
6971
timezone,
72+
convert_tz_for_raw_time_dimension,
7073
masked_members: masked_members.unwrap_or_default().into_iter().collect(),
7174
}))
7275
}
@@ -96,6 +99,10 @@ impl QueryTools {
9699
self.timezone
97100
}
98101

102+
pub fn convert_tz_for_raw_time_dimension(&self) -> bool {
103+
self.convert_tz_for_raw_time_dimension
104+
}
105+
99106
pub fn join_for_hints(
100107
&self,
101108
hints: &JoinHints,

rust/cubesqlplanner/cubesqlplanner/src/planner/sql_evaluator/sql_nodes/evaluate_sql.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ impl SqlNode for EvaluateSqlNode {
3535
Ok(res)
3636
}
3737
MemberSymbol::TimeDimension(ev) => {
38+
let visitor = visitor.with_ignore_tz_convert();
3839
let res = visitor.apply(&ev.base_symbol(), node_processor.clone(), templates)?;
3940
Ok(res)
4041
}

rust/cubesqlplanner/cubesqlplanner/src/planner/sql_evaluator/sql_nodes/factory.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -257,12 +257,13 @@ impl SqlNodesFactory {
257257
let input: Rc<dyn SqlNode> = CaseSqlNode::new(input);
258258
input
259259
};
260-
let input: Rc<dyn SqlNode> =
261-
TimeDimensionNode::new(self.dimensions_with_ignored_timezone.clone(), input);
262260

263261
let input: Rc<dyn SqlNode> =
264262
AutoPrefixSqlNode::new(input, self.cube_name_references.clone());
265263

264+
let input: Rc<dyn SqlNode> =
265+
TimeDimensionNode::new(self.dimensions_with_ignored_timezone.clone(), input);
266+
266267
let input = if !self.calendar_time_shifts.is_empty() {
267268
CalendarTimeShiftSqlNode::new(self.calendar_time_shifts.clone(), input)
268269
} else {

rust/cubesqlplanner/cubesqlplanner/src/planner/sql_evaluator/sql_nodes/time_dimension.rs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,11 @@ impl SqlNode for TimeDimensionNode {
5353
);
5454
}
5555

56-
let converted_tz = if self
56+
let skip_convert_tz = self
5757
.dimensions_with_ignored_timezone
58-
.contains(&ev.full_name())
59-
{
58+
.contains(&ev.full_name());
59+
60+
let converted_tz = if skip_convert_tz {
6061
input_sql
6162
} else {
6263
templates.convert_tz(input_sql)?
@@ -68,6 +69,16 @@ impl SqlNode for TimeDimensionNode {
6869
};
6970
Ok(res)
7071
}
72+
MemberSymbol::Dimension(ev) => {
73+
if !visitor.ignore_tz_convert()
74+
&& query_tools.convert_tz_for_raw_time_dimension()
75+
&& ev.dimension_type() == "time"
76+
{
77+
Ok(templates.convert_tz(input_sql)?)
78+
} else {
79+
Ok(input_sql)
80+
}
81+
}
7182
_ => Ok(input_sql),
7283
}
7384
}

rust/cubesqlplanner/cubesqlplanner/src/planner/sql_evaluator/sql_visitor.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ pub struct SqlEvaluatorVisitor {
1313
query_tools: Rc<QueryTools>,
1414
cube_ref_evaluator: Rc<CubeRefEvaluator>,
1515
all_filters: Option<Filter>, //To pass to FILTER_PARAMS and FILTER_GROUP
16+
ignore_tz_convert: bool,
1617
}
1718

1819
impl SqlEvaluatorVisitor {
@@ -25,9 +26,16 @@ impl SqlEvaluatorVisitor {
2526
query_tools,
2627
cube_ref_evaluator,
2728
all_filters,
29+
ignore_tz_convert: false,
2830
}
2931
}
3032

33+
pub fn with_ignore_tz_convert(&self) -> Self {
34+
let mut self_copy = self.clone();
35+
self_copy.ignore_tz_convert = true;
36+
self_copy
37+
}
38+
3139
pub fn all_filters(&self) -> Option<Filter> {
3240
self.all_filters.clone()
3341
}
@@ -48,6 +56,10 @@ impl SqlEvaluatorVisitor {
4856
Ok(result)
4957
}
5058

59+
pub fn ignore_tz_convert(&self) -> bool {
60+
self.ignore_tz_convert
61+
}
62+
5163
pub fn evaluate_cube_ref(
5264
&self,
5365
cube_ref: &CubeRef,

0 commit comments

Comments
 (0)