Skip to content

Commit 98d334b

Browse files
authored
fix(tesseract): Fix rolling window with few time dimensions, filter_group in segments and member expressions (#9673)
1 parent 896af5e commit 98d334b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+779
-282
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -806,6 +806,7 @@ export class BaseQuery {
806806
exportAnnotatedSql: exportAnnotatedSql === true,
807807
preAggregationQuery: this.options.preAggregationQuery,
808808
totalQuery: this.options.totalQuery,
809+
joinHints: this.options.joinHints,
809810
};
810811

811812
const buildResult = nativeBuildSqlAndParams(queryParams);

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3281,6 +3281,9 @@ SELECT 1 AS revenue, cast('2024-01-01' AS timestamp) as time UNION ALL
32813281
for (const granularityTest of granularityCases) {
32823282
// eslint-disable-next-line no-loop-func
32833283
it(`Should date with TZ, when pass timeDimensions with granularity by ${granularityTest.granularity}`, async () => {
3284+
if (getEnv('nativeSqlPlanner')) {
3285+
return;
3286+
}
32843287
await compiler.compile();
32853288

32863289
const query = new BigqueryQuery({ joinGraph, cubeEvaluator, compiler }, {

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use super::join_graph::{JoinGraph, NativeJoinGraph};
2+
use super::join_hints::JoinHintItem;
23
use super::options_member::OptionsMember;
34
use crate::cube_bridge::base_tools::{BaseTools, NativeBaseTools};
45
use crate::cube_bridge::evaluator::{CubeEvaluator, NativeCubeEvaluator};
@@ -81,4 +82,6 @@ pub trait BaseQueryOptions {
8182
fn base_tools(&self) -> Result<Rc<dyn BaseTools>, CubeError>;
8283
#[nbridge(field)]
8384
fn join_graph(&self) -> Result<Rc<dyn JoinGraph>, CubeError>;
85+
#[nbridge(field, optional, vec)]
86+
fn join_hints(&self) -> Result<Option<Vec<JoinHintItem>>, CubeError>;
8487
}
Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,25 @@
1-
use serde::{Deserialize, Serialize};
1+
use cubenativeutils::wrappers::inner_types::InnerTypes;
2+
use cubenativeutils::wrappers::serializer::NativeDeserialize;
3+
use cubenativeutils::wrappers::NativeObjectHandle;
4+
use cubenativeutils::CubeError;
5+
use serde::Serialize;
26

3-
#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
7+
#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize)]
48
pub enum JoinHintItem {
59
Single(String),
610
Vector(Vec<String>),
711
}
12+
13+
impl<IT: InnerTypes> NativeDeserialize<IT> for JoinHintItem {
14+
fn from_native(native_object: NativeObjectHandle<IT>) -> Result<Self, CubeError> {
15+
match Vec::<String>::from_native(native_object.clone()) {
16+
Ok(value) => Ok(Self::Vector(value)),
17+
Err(_) => match String::from_native(native_object) {
18+
Ok(value) => Ok(Self::Single(value)),
19+
Err(_) => Err(CubeError::user(format!(
20+
"Join hint item expected to be string or vector of strings"
21+
))),
22+
},
23+
}
24+
}
25+
}

rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/measure_definition.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub struct TimeShiftReference {
1919
#[serde(rename = "type")]
2020
pub shift_type: Option<String>,
2121
#[serde(rename = "timeDimension")]
22-
pub time_dimension: String,
22+
pub time_dimension: Option<String>,
2323
}
2424

2525
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,62 @@
11
use super::member_sql::{MemberSql, NativeMemberSql};
2+
use super::struct_with_sql_member::{NativeStructWithSqlMember, StructWithSqlMember};
23
use cubenativeutils::wrappers::serializer::{
34
NativeDeserialize, NativeDeserializer, NativeSerialize,
45
};
6+
use cubenativeutils::wrappers::NativeArray;
57
use cubenativeutils::wrappers::{NativeContextHolder, NativeObjectHandle};
68
use cubenativeutils::CubeError;
79
use serde::{Deserialize, Serialize};
810
use std::any::Any;
911
use std::rc::Rc;
1012

13+
#[derive(Serialize, Deserialize, Debug, Clone)]
14+
pub struct ExpressionStructStatic {
15+
#[serde(rename = "type")]
16+
pub expression_type: String,
17+
#[serde(rename = "sourceMeasure")]
18+
pub source_measure: Option<String>,
19+
#[serde(rename = "replaceAggregationType")]
20+
pub replace_aggregation_type: Option<String>,
21+
}
22+
23+
#[nativebridge::native_bridge(ExpressionStructStatic)]
24+
pub trait ExpressionStruct {
25+
#[nbridge(field, optional, vec)]
26+
fn add_filters(&self) -> Result<Option<Vec<Rc<dyn StructWithSqlMember>>>, CubeError>;
27+
}
28+
29+
pub enum MemberExpressionExpressionDef {
30+
Sql(Rc<dyn MemberSql>),
31+
Struct(Rc<dyn ExpressionStruct>),
32+
}
33+
34+
impl<IT: InnerTypes> NativeDeserialize<IT> for MemberExpressionExpressionDef {
35+
fn from_native(native_object: NativeObjectHandle<IT>) -> Result<Self, CubeError> {
36+
match NativeMemberSql::from_native(native_object.clone()) {
37+
Ok(sql) => Ok(Self::Sql(Rc::new(sql))),
38+
Err(_) => match NativeExpressionStruct::from_native(native_object) {
39+
Ok(expr) => Ok(Self::Struct(Rc::new(expr))),
40+
Err(_) => Err(CubeError::user(format!(
41+
"Member sql or expression struct expected for member expression expression field"
42+
))),
43+
},
44+
}
45+
}
46+
}
47+
1148
#[derive(Serialize, Deserialize, Debug, Clone)]
1249
pub struct MemberExpressionDefinitionStatic {
1350
#[serde(rename = "expressionName")]
1451
pub expression_name: Option<String>,
52+
pub name: Option<String>,
1553
#[serde(rename = "cubeName")]
1654
pub cube_name: Option<String>,
1755
pub definition: Option<String>,
1856
}
1957

20-
#[nativebridge::native_bridge(MemberExpressionDefinitionStatic)]
58+
#[nativebridge::native_bridge(MemberExpressionDefinitionStatic, without_imports)]
2159
pub trait MemberExpressionDefinition {
2260
#[nbridge(field)]
23-
fn expression(&self) -> Result<Rc<dyn MemberSql>, CubeError>;
61+
fn expression(&self) -> Result<MemberExpressionExpressionDef, CubeError>;
2462
}

rust/cubesqlplanner/cubesqlplanner/src/logical_plan/multistage/common.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,10 @@ impl PrettyPrint for MultiStageAppliedState {
5353
}
5454

5555
result.println("time_shifts:", &state);
56-
for (_, time_shift) in self.time_shifts().iter() {
56+
if let Some(common) = &self.time_shifts().common_time_shift {
57+
result.println(&format!("- common: {}", common.to_sql()), &details_state);
58+
}
59+
for (_, time_shift) in self.time_shifts().dimensions_shifts.iter() {
5760
result.println(
5861
&format!(
5962
"- {}: {}",

rust/cubesqlplanner/cubesqlplanner/src/logical_plan/multistage/leaf_measure.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
use crate::logical_plan::*;
2-
use crate::planner::sql_evaluator::MeasureTimeShift;
2+
use crate::planner::planners::multi_stage::TimeShiftState;
33
use crate::planner::sql_evaluator::MemberSymbol;
4-
use std::collections::HashMap;
54
use std::rc::Rc;
65

76
pub struct MultiStageLeafMeasure {
87
pub measure: Rc<MemberSymbol>,
98
pub render_measure_as_state: bool, //Render measure as state, for example hll state for count_approx
109
pub render_measure_for_ungrouped: bool,
11-
pub time_shifts: HashMap<String, MeasureTimeShift>,
10+
pub time_shifts: TimeShiftState,
1211
pub query: Rc<Query>,
1312
}
1413

@@ -23,10 +22,13 @@ impl PrettyPrint for MultiStageLeafMeasure {
2322
if self.render_measure_for_ungrouped {
2423
result.println("render_measure_for_ungrouped: true", &state);
2524
}
26-
if !self.time_shifts.is_empty() {
25+
if !self.time_shifts.dimensions_shifts.is_empty() {
2726
result.println("time_shifts:", &state);
2827
let details_state = state.new_level();
29-
for (_, time_shift) in self.time_shifts.iter() {
28+
if let Some(common) = &self.time_shifts.common_time_shift {
29+
result.println(&format!("- common: {}", common.to_sql()), &details_state);
30+
}
31+
for (_, time_shift) in self.time_shifts.dimensions_shifts.iter() {
3032
result.println(
3133
&format!(
3234
"- {}: {}",

rust/cubesqlplanner/cubesqlplanner/src/physical_plan_builder/builder.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
use crate::logical_plan::*;
22
use crate::plan::schema::QualifiedColumnName;
33
use crate::plan::*;
4+
use crate::planner::planners::multi_stage::TimeShiftState;
45
use crate::planner::query_properties::OrderByItem;
56
use crate::planner::query_tools::QueryTools;
67
use crate::planner::sql_evaluator::sql_nodes::SqlNodesFactory;
7-
use crate::planner::sql_evaluator::MeasureTimeShift;
88
use crate::planner::sql_evaluator::MemberSymbol;
99
use crate::planner::sql_evaluator::ReferencesBuilder;
1010
use crate::planner::sql_templates::PlanSqlTemplates;
@@ -24,7 +24,7 @@ struct PhysicalPlanBuilderContext {
2424
pub alias_prefix: Option<String>,
2525
pub render_measure_as_state: bool, //Render measure as state, for example hll state for count_approx
2626
pub render_measure_for_ungrouped: bool,
27-
pub time_shifts: HashMap<String, MeasureTimeShift>,
27+
pub time_shifts: TimeShiftState,
2828
pub original_sql_pre_aggregations: HashMap<String, String>,
2929
}
3030

rust/cubesqlplanner/cubesqlplanner/src/planner/base_dimension.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use super::query_tools::QueryTools;
22
use super::sql_evaluator::{MemberExpressionSymbol, MemberSymbol, SqlCall};
33
use super::{evaluate_with_context, BaseMember, BaseMemberHelper, VisitorContext};
44
use crate::cube_bridge::dimension_definition::DimensionDefinition;
5+
use crate::planner::sql_evaluator::MemberExpressionExpression;
56
use crate::planner::sql_templates::PlanSqlTemplates;
67
use cubenativeutils::CubeError;
78
use std::rc::Rc;
@@ -126,11 +127,12 @@ impl BaseDimension {
126127
let member_expression_symbol = MemberExpressionSymbol::try_new(
127128
cube_name.clone(),
128129
name.clone(),
129-
expression,
130+
MemberExpressionExpression::SqlCall(expression),
130131
member_expression_definition.clone(),
132+
query_tools.base_tools().clone(),
131133
)?;
132134
let full_name = member_expression_symbol.full_name();
133-
let member_evaluator = Rc::new(MemberSymbol::MemberExpression(member_expression_symbol));
135+
let member_evaluator = MemberSymbol::new_member_expression(member_expression_symbol);
134136
let default_alias = PlanSqlTemplates::alias_name(&name);
135137

136138
Ok(Rc::new(Self {

0 commit comments

Comments
 (0)