Skip to content

Commit 304de6e

Browse files
committed
feat(tesseract): Subqueries support
1 parent 8f0758e commit 304de6e

34 files changed

+721
-185
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,7 @@ describe('SQL Generation', () => {
453453
}
454454
});
455455

456-
it('having filter with operator OR 1', async () => {
456+
it('having filter with operator OR', async () => {
457457
await compiler.compile();
458458

459459
const query = new PostgresQuery({ joinGraph, cubeEvaluator, compiler }, {
@@ -648,7 +648,7 @@ describe('SQL Generation', () => {
648648
});
649649
});
650650

651-
it('where filter with operators OR & AND 1', async () => {
651+
it('where filter with operators OR & AND', async () => {
652652
await compiler.compile();
653653

654654
const query = new PostgresQuery({ joinGraph, cubeEvaluator, compiler }, {

rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/dimension_definition.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ pub struct DimenstionDefinitionStatic {
1717
pub owned_by_cube: Option<bool>,
1818
#[serde(rename = "multiStage")]
1919
pub multi_stage: Option<bool>,
20+
#[serde(rename = "subQuery")]
21+
pub sub_query: Option<bool>,
22+
#[serde(rename = "propagateFiltersToSubQuery")]
23+
pub propagate_filters_to_sub_query: Option<bool>,
2024
}
2125

2226
#[nativebridge::native_bridge(DimenstionDefinitionStatic)]

rust/cubesqlplanner/cubesqlplanner/src/plan/builder/select.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,22 @@ impl SelectBuilder {
4040
}
4141
}
4242

43+
pub fn new_from_select(select: Rc<Select>) -> Self {
44+
Self {
45+
projection_columns: select.projection_columns.clone(),
46+
from: select.from.clone(),
47+
filter: select.filter.clone(),
48+
group_by: select.group_by.clone(),
49+
having: select.having.clone(),
50+
order_by: select.order_by.clone(),
51+
ctes: select.ctes.clone(),
52+
is_distinct: select.is_distinct,
53+
limit: select.limit,
54+
offset: select.offset,
55+
result_schema: Schema::clone(&select.schema),
56+
}
57+
}
58+
4359
pub fn add_projection_member(&mut self, member: &Rc<dyn BaseMember>, alias: Option<String>) {
4460
let alias = if let Some(alias) = alias {
4561
alias

rust/cubesqlplanner/cubesqlplanner/src/plan/filter.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ pub enum FilterItem {
3636
Item(Rc<BaseFilter>),
3737
}
3838

39+
#[derive(Clone)]
3940
pub struct Filter {
4041
pub items: Vec<FilterItem>,
4142
}

rust/cubesqlplanner/cubesqlplanner/src/plan/order.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use super::Expr;
22

3+
#[derive(Clone)]
34
pub struct OrderBy {
45
pub expr: Expr,
56
pub pos: usize,

rust/cubesqlplanner/cubesqlplanner/src/plan/schema/schema.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::planner::BaseMember;
33
use itertools::Itertools;
44
use std::rc::Rc;
55

6-
#[derive(Debug)]
6+
#[derive(Debug, Clone)]
77
pub struct Schema {
88
columns: Vec<SchemaColumn>,
99
}

rust/cubesqlplanner/cubesqlplanner/src/plan/select.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use crate::planner::VisitorContext;
77
use cubenativeutils::CubeError;
88
use std::rc::Rc;
99

10+
#[derive(Clone)]
1011
pub struct AliasedExpr {
1112
pub expr: Expr,
1213
pub alias: String,
@@ -32,6 +33,7 @@ impl AliasedExpr {
3233
}
3334
}
3435

36+
#[derive(Clone)]
3537
pub struct Select {
3638
pub(super) projection_columns: Vec<AliasedExpr>,
3739
pub(super) from: Rc<From>,

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

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
use super::query_tools::QueryTools;
2-
use super::sql_evaluator::MemberSymbol;
2+
use super::sql_evaluator::{MemberSymbol, SqlCall};
33
use super::{evaluate_with_context, BaseMember, BaseMemberHelper, VisitorContext};
4+
use crate::cube_bridge::dimension_definition::DimensionDefinition;
45
use cubenativeutils::CubeError;
56
use std::rc::Rc;
67

78
pub struct BaseDimension {
89
dimension: String,
910
query_tools: Rc<QueryTools>,
1011
member_evaluator: Rc<MemberSymbol>,
12+
definition: Rc<dyn DimensionDefinition>,
1113
cube_name: String,
1214
name: String,
1315
default_alias: String,
@@ -58,6 +60,7 @@ impl BaseDimension {
5860
member_evaluator: evaluation_node.clone(),
5961
cube_name: s.cube_name().clone(),
6062
name: s.name().clone(),
63+
definition: s.definition().clone(),
6164
default_alias,
6265
}))
6366
}
@@ -83,7 +86,27 @@ impl BaseDimension {
8386
self.member_evaluator.clone()
8487
}
8588

89+
pub fn sql_call(&self) -> Result<Rc<SqlCall>, CubeError> {
90+
match self.member_evaluator.as_ref() {
91+
MemberSymbol::Dimension(d) => Ok(d.member_sql().clone()),
92+
_ => Err(CubeError::internal(format!(
93+
"MemberSymbol::Dimension expected"
94+
))),
95+
}
96+
}
97+
8698
pub fn dimension(&self) -> &String {
8799
&self.dimension
88100
}
101+
102+
pub fn is_sub_query(&self) -> bool {
103+
self.definition.static_data().sub_query.unwrap_or(false)
104+
}
105+
106+
pub fn propagate_filters_to_sub_query(&self) -> bool {
107+
self.definition
108+
.static_data()
109+
.propagate_filters_to_sub_query
110+
.unwrap_or(false)
111+
}
89112
}

rust/cubesqlplanner/cubesqlplanner/src/planner/base_measure.rs

Lines changed: 58 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use super::query_tools::QueryTools;
2-
use super::sql_evaluator::MemberSymbol;
2+
use super::sql_evaluator::{MemberSymbol, SqlCall};
33
use super::{evaluate_with_context, BaseMember, BaseMemberHelper, VisitorContext};
44
use crate::cube_bridge::measure_definition::{
55
MeasureDefinition, RollingWindow, TimeShiftReference,
@@ -66,7 +66,7 @@ pub struct BaseMeasure {
6666
measure: String,
6767
query_tools: Rc<QueryTools>,
6868
member_evaluator: Rc<MemberSymbol>,
69-
definition: Rc<dyn MeasureDefinition>,
69+
definition: Option<Rc<dyn MeasureDefinition>>,
7070
time_shifts: Vec<MeasureTimeShift>,
7171
cube_name: String,
7272
name: String,
@@ -100,6 +100,10 @@ impl BaseMember for BaseMeasure {
100100
self.clone()
101101
}
102102

103+
fn full_name(&self) -> String {
104+
format!("{}.{}", self.cube_name, self.name)
105+
}
106+
103107
fn cube_name(&self) -> &String {
104108
&self.cube_name
105109
}
@@ -127,7 +131,7 @@ impl BaseMeasure {
127131
measure: s.full_name(),
128132
query_tools: query_tools.clone(),
129133
member_evaluator: evaluation_node.clone(),
130-
definition: s.definition().clone(),
134+
definition: Some(s.definition().clone()),
131135
cube_name: s.cube_name().clone(),
132136
name: s.name().clone(),
133137
time_shifts,
@@ -152,6 +156,28 @@ impl BaseMeasure {
152156
}
153157
}
154158

159+
pub fn try_new_from_expression(
160+
expression: Rc<SqlCall>,
161+
cube_name: String,
162+
name: String,
163+
query_tools: Rc<QueryTools>,
164+
) -> Result<Self, CubeError> {
165+
let full_name = format!("{}.{}", cube_name, name);
166+
let member_evaluator = Rc::new(MemberSymbol::SqlCall(expression));
167+
let default_alias =
168+
BaseMemberHelper::default_alias(&cube_name, &name, &None, query_tools.clone())?;
169+
Ok(Self {
170+
measure: full_name,
171+
query_tools,
172+
member_evaluator,
173+
definition: None,
174+
cube_name,
175+
name,
176+
default_alias,
177+
time_shifts: vec![],
178+
})
179+
}
180+
155181
fn parse_time_shifts(
156182
definition: &Rc<dyn MeasureDefinition>,
157183
) -> Result<Vec<MeasureTimeShift>, CubeError> {
@@ -177,40 +203,52 @@ impl BaseMeasure {
177203
&self.cube_name
178204
}
179205

180-
pub fn reduce_by(&self) -> &Option<Vec<String>> {
181-
&self.definition.static_data().reduce_by_references
206+
pub fn reduce_by(&self) -> Option<Vec<String>> {
207+
self.definition
208+
.as_ref()
209+
.map_or(None, |d| d.static_data().reduce_by_references.clone())
182210
}
183211

184-
pub fn add_group_by(&self) -> &Option<Vec<String>> {
185-
&self.definition.static_data().add_group_by_references
212+
pub fn add_group_by(&self) -> Option<Vec<String>> {
213+
self.definition
214+
.as_ref()
215+
.map_or(None, |d| d.static_data().add_group_by_references.clone())
186216
}
187217

188-
pub fn group_by(&self) -> &Option<Vec<String>> {
189-
&self.definition.static_data().group_by_references
218+
pub fn group_by(&self) -> Option<Vec<String>> {
219+
self.definition
220+
.as_ref()
221+
.map_or(None, |d| d.static_data().group_by_references.clone())
190222
}
191223

192224
//FIXME dublicate with symbol
193225
pub fn is_calculated(&self) -> bool {
194-
match self.definition.static_data().measure_type.as_str() {
226+
match self.measure_type() {
195227
"number" | "string" | "time" | "boolean" => true,
196228
_ => false,
197229
}
198230
}
199231

200-
pub fn time_shift_references(&self) -> &Option<Vec<TimeShiftReference>> {
201-
&self.definition.static_data().time_shift_references
232+
pub fn time_shift_references(&self) -> Option<Vec<TimeShiftReference>> {
233+
self.definition
234+
.as_ref()
235+
.map_or(None, |d| d.static_data().time_shift_references.clone())
202236
}
203237

204238
pub fn time_shifts(&self) -> &Vec<MeasureTimeShift> {
205239
&self.time_shifts
206240
}
207241

208242
pub fn is_multi_stage(&self) -> bool {
209-
self.definition.static_data().multi_stage.unwrap_or(false)
243+
self.definition
244+
.as_ref()
245+
.map_or(false, |d| d.static_data().multi_stage.unwrap_or(false))
210246
}
211247

212-
pub fn rolling_window(&self) -> &Option<RollingWindow> {
213-
&self.definition.static_data().rolling_window
248+
pub fn rolling_window(&self) -> Option<RollingWindow> {
249+
self.definition
250+
.as_ref()
251+
.map_or(None, |d| d.static_data().rolling_window.clone())
214252
}
215253

216254
pub fn is_rolling_window(&self) -> bool {
@@ -226,11 +264,13 @@ impl BaseMeasure {
226264
}
227265

228266
//FIXME dublicate with symbol
229-
pub fn measure_type(&self) -> &String {
230-
&self.definition.static_data().measure_type
267+
pub fn measure_type(&self) -> &str {
268+
self.definition
269+
.as_ref()
270+
.map_or("number", |d| &d.static_data().measure_type)
231271
}
232272

233273
pub fn is_multi_stage_ungroupped(&self) -> bool {
234-
self.is_calculated() || self.definition.static_data().measure_type == "rank"
274+
self.is_calculated() || self.measure_type() == "rank"
235275
}
236276
}
Lines changed: 3 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,7 @@
1-
use super::planners::{
2-
FullKeyAggregateQueryPlanner, MultiStageQueryPlanner, MultipliedMeasuresQueryPlanner,
3-
SimpleQueryPlanner,
4-
};
1+
use super::planners::QueryPlanner;
52
use super::query_tools::QueryTools;
63
use super::QueryProperties;
74
use crate::cube_bridge::base_query_options::BaseQueryOptions;
8-
use crate::plan::Select;
9-
use crate::planner::sql_evaluator::sql_nodes::SqlNodesFactory;
105
use crate::planner::sql_templates::PlanSqlTemplates;
116
use cubenativeutils::wrappers::inner_types::InnerTypes;
127
use cubenativeutils::wrappers::object::NativeArray;
@@ -45,7 +40,8 @@ impl<IT: InnerTypes> BaseQuery<IT> {
4540

4641
pub fn build_sql_and_params(&self) -> Result<NativeObjectHandle<IT>, CubeError> {
4742
let templates = PlanSqlTemplates::new(self.query_tools.templates_render());
48-
let plan = self.build_sql_and_params_impl(templates.clone())?;
43+
let query_planner = QueryPlanner::new(self.request.clone(), self.query_tools.clone());
44+
let plan = query_planner.build_sql()?;
4945

5046
let sql = plan.to_sql(&templates)?;
5147
let (result_sql, params) = self.query_tools.build_sql_and_params(&sql, true)?;
@@ -57,41 +53,4 @@ impl<IT: InnerTypes> BaseQuery<IT> {
5753

5854
Ok(result)
5955
}
60-
61-
fn build_sql_and_params_impl(&self, templates: PlanSqlTemplates) -> Result<Select, CubeError> {
62-
let mut nodes_factory = SqlNodesFactory::new();
63-
64-
if self.request.ungrouped() {
65-
nodes_factory.set_ungrouped(true)
66-
}
67-
68-
if self.request.is_simple_query()? {
69-
let planner = SimpleQueryPlanner::new(
70-
self.query_tools.clone(),
71-
self.request.clone(),
72-
nodes_factory.clone(),
73-
);
74-
planner.plan()
75-
} else {
76-
let request = self.request.clone();
77-
let multiplied_measures_query_planner = MultipliedMeasuresQueryPlanner::new(
78-
self.query_tools.clone(),
79-
request.clone(),
80-
nodes_factory.clone(),
81-
);
82-
let multi_stage_query_planner =
83-
MultiStageQueryPlanner::new(self.query_tools.clone(), request.clone());
84-
let full_key_aggregate_planner = FullKeyAggregateQueryPlanner::new(
85-
request.clone(),
86-
nodes_factory.clone(),
87-
templates,
88-
);
89-
let mut subqueries = multiplied_measures_query_planner.plan_queries()?;
90-
let (multi_stage_ctes, multi_stage_subqueries) =
91-
multi_stage_query_planner.plan_queries()?;
92-
subqueries.extend(multi_stage_subqueries.into_iter());
93-
let result = full_key_aggregate_planner.plan(subqueries, multi_stage_ctes)?;
94-
Ok(result)
95-
}
96-
}
9756
}

0 commit comments

Comments
 (0)