Skip to content

Commit d22c327

Browse files
committed
fix(cubeplanner): Fixes to pass the tests
1 parent 1d4f34f commit d22c327

File tree

11 files changed

+210
-64
lines changed

11 files changed

+210
-64
lines changed

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1036,8 +1036,10 @@ export class BaseQuery {
10361036
R.uniq,
10371037
R.map(m => this.newMeasure(m))
10381038
);
1039+
console.log("!!!! meas hierarchy", measureToHierarchy);
10391040

10401041
const multipliedMeasures = measuresToRender(true, false)(measureToHierarchy);
1042+
console.log("!!! mul meas", multipliedMeasures);
10411043
const regularMeasures = measuresToRender(false, false)(measureToHierarchy);
10421044

10431045
const cumulativeMeasures =
@@ -1775,6 +1777,7 @@ export class BaseQuery {
17751777
return measures.map(measure => {
17761778
const cubes = this.collectFrom([measure], this.collectCubeNamesFor.bind(this), 'collectCubeNamesFor');
17771779
const joinHints = this.collectFrom([measure], this.collectJoinHintsFor.bind(this), 'collectJoinHintsFor');
1780+
console.log("!!! cubes: ", cubes, " ", joinHints);
17781781
if (R.any(cubeName => keyCubeName !== cubeName, cubes)) {
17791782
const measuresJoin = this.joinGraph.buildJoin(joinHints);
17801783
if (measuresJoin.multiplicationFactor[keyCubeName]) {
@@ -2481,6 +2484,7 @@ export class BaseQuery {
24812484
fn,
24822485
renderContext
24832486
);
2487+
console.log("!!!!! renderContext.measuresToRender.length ", renderContext.measuresToRender.length);
24842488
return renderContext.measuresToRender.length ?
24852489
R.uniq(renderContext.measuresToRender) :
24862490
[renderContext.rootMeasure.value];
@@ -3288,6 +3292,7 @@ export class BaseQuery {
32883292
gte: '{{ column }} >= {{ param }}',
32893293
lt: '{{ column }} < {{ param }}',
32903294
lte: '{{ column }} <= {{ param }}',
3295+
like_pattern: '{% if start_wild %}\'%\' || {% endif %}{{ value }}{% if end_wild %}|| \'%\'{% endif %}',
32913296
always_true: '1 == 1'
32923297

32933298
},

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -976,7 +976,7 @@ describe('SQL Generation', () => {
976976

977977
console.log(query.buildSqlAndParams());
978978

979-
return dbRunner.testQuery(query.buildSqlAndParams()).then(res => {
979+
return dbRunner.testQuery(query.buildSqlAndParamsTest()).then(res => {
980980
console.log(JSON.stringify(res));
981981
expect(res).toEqual(
982982
[{ visitor_checkins__revenue_per_checkin: '50' }]
@@ -1721,7 +1721,7 @@ describe('SQL Generation', () => {
17211721
]));
17221722

17231723
it(
1724-
'contains filter',
1724+
'contains filter 1',
17251725
() => runQueryTest({
17261726
measures: [],
17271727
dimensions: [

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ impl<IT: InnerTypes> BaseQuery<IT> {
6060

6161
fn build_sql_and_params_impl(&self) -> Result<Select, CubeError> {
6262
if self.request.is_simple_query()? {
63+
println!("!!!! IS SIMPLE");
6364
let planner = SimpleQueryPlanner::new(
6465
self.query_tools.clone(),
6566
self.request.clone(),

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

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,12 @@ impl BaseFilter {
116116
FilterOperator::Gte => self.gte_where(&member_sql)?,
117117
FilterOperator::Lt => self.lt_where(&member_sql)?,
118118
FilterOperator::Lte => self.lte_where(&member_sql)?,
119+
FilterOperator::Contains => self.contains_where(&member_sql)?,
120+
FilterOperator::NotContains => self.not_contains_where(&member_sql)?,
121+
FilterOperator::StartsWith => self.starts_with_where(&member_sql)?,
122+
FilterOperator::NotStartsWith => self.not_starts_with_where(&member_sql)?,
123+
FilterOperator::EndsWith => self.ends_with_where(&member_sql)?,
124+
FilterOperator::NotEndsWith => self.not_ends_with_where(&member_sql)?,
119125
};
120126
Ok(res)
121127
}
@@ -243,6 +249,58 @@ impl BaseFilter {
243249
.lte(member_sql.to_string(), self.first_param()?)
244250
}
245251

252+
fn contains_where(&self, member_sql: &str) -> Result<String, CubeError> {
253+
self.like_or_where(member_sql, false, true, true)
254+
}
255+
256+
fn not_contains_where(&self, member_sql: &str) -> Result<String, CubeError> {
257+
self.like_or_where(member_sql, true, true, true)
258+
}
259+
260+
fn starts_with_where(&self, member_sql: &str) -> Result<String, CubeError> {
261+
self.like_or_where(member_sql, false, false, true)
262+
}
263+
264+
fn not_starts_with_where(&self, member_sql: &str) -> Result<String, CubeError> {
265+
self.like_or_where(member_sql, true, false, true)
266+
}
267+
268+
fn ends_with_where(&self, member_sql: &str) -> Result<String, CubeError> {
269+
self.like_or_where(member_sql, false, true, false)
270+
}
271+
272+
fn not_ends_with_where(&self, member_sql: &str) -> Result<String, CubeError> {
273+
self.like_or_where(member_sql, true, true, false)
274+
}
275+
276+
fn like_or_where(
277+
&self,
278+
member_sql: &str,
279+
not: bool,
280+
start_wild: bool,
281+
end_wild: bool,
282+
) -> Result<String, CubeError> {
283+
let values = self.filter_and_allocate_values();
284+
let like_parts = values
285+
.into_iter()
286+
.map(|v| {
287+
self.templates
288+
.ilike(member_sql, &v, start_wild, end_wild, not)
289+
})
290+
.collect::<Result<Vec<_>, _>>()?;
291+
let logical_symbol = if not { " AND " } else { " OR " };
292+
let null_check = if self.is_need_null_chek(not) {
293+
self.templates.or_is_null_check(member_sql.to_string())?
294+
} else {
295+
"".to_string()
296+
};
297+
Ok(format!(
298+
"({}){}",
299+
like_parts.join(logical_symbol),
300+
null_check
301+
))
302+
}
303+
246304
fn allocate_date_params(&self) -> Result<(String, String), CubeError> {
247305
if self.values.len() >= 2 {
248306
let from = if let Some(from_str) = &self.values[0] {

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ pub enum FilterOperator {
1515
Gte,
1616
Lt,
1717
Lte,
18+
Contains,
19+
NotContains,
20+
StartsWith,
21+
NotStartsWith,
22+
NotEndsWith,
23+
EndsWith,
1824
}
1925

2026
impl FromStr for FilterOperator {
@@ -32,6 +38,12 @@ impl FromStr for FilterOperator {
3238
"gte" => Ok(Self::Gte),
3339
"lt" => Ok(Self::Lt),
3440
"lte" => Ok(Self::Lte),
41+
"contains" => Ok(Self::Contains),
42+
"notcontains" => Ok(Self::NotContains),
43+
"startswith" => Ok(Self::StartsWith),
44+
"notstartswith" => Ok(Self::NotStartsWith),
45+
"endswith" => Ok(Self::EndsWith),
46+
"notendswith" => Ok(Self::NotEndsWith),
3547

3648
_ => Err(CubeError::user(format!("Unknown filter operator {}", s))),
3749
}

rust/cubesqlplanner/cubesqlplanner/src/planner/planners/full_key_query_aggregate_planner.rs

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -33,21 +33,8 @@ impl FullKeyAggregateQueryPlanner {
3333
)));
3434
}
3535

36-
let measures = self.query_properties.full_key_aggregate_measures()?;
37-
38-
let inner_measures = measures
39-
.multiplied_measures
40-
.iter()
41-
.chain(measures.multi_stage_measures.iter())
42-
.chain(measures.regular_measures.iter())
43-
.cloned()
44-
.collect_vec();
45-
46-
let mut aggregate = self.outer_measures_join_full_key_aggregate(
47-
&inner_measures,
48-
&self.query_properties.measures(),
49-
joins,
50-
)?;
36+
let mut aggregate =
37+
self.outer_measures_join_full_key_aggregate(&self.query_properties.measures(), joins)?;
5138
if !ctes.is_empty() {
5239
aggregate.set_ctes(ctes.clone());
5340
}
@@ -57,7 +44,6 @@ impl FullKeyAggregateQueryPlanner {
5744

5845
fn outer_measures_join_full_key_aggregate(
5946
&self,
60-
_inner_measures: &Vec<Rc<BaseMeasure>>,
6147
outer_measures: &Vec<Rc<BaseMeasure>>,
6248
joins: Vec<Rc<Select>>,
6349
) -> Result<SelectBuilder, CubeError> {

rust/cubesqlplanner/cubesqlplanner/src/planner/query_properties.rs

Lines changed: 21 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -381,13 +381,14 @@ impl QueryProperties {
381381
}
382382

383383
pub fn is_simple_query(&self) -> Result<bool, CubeError> {
384-
for member in self.all_members(false) {
385-
match self.get_symbol_aggregate_type(&member.member_evaluator())? {
386-
SymbolAggregateType::Regular => {}
387-
_ => return Ok(false),
388-
}
384+
let full_aggregate_measure = self.full_key_aggregate_measures()?;
385+
if full_aggregate_measure.multiplied_measures.is_empty()
386+
&& full_aggregate_measure.multi_stage_measures.is_empty()
387+
{
388+
Ok(true)
389+
} else {
390+
Ok(false)
389391
}
390-
Ok(true)
391392
}
392393

393394
pub fn should_use_time_series(&self) -> Result<bool, CubeError> {
@@ -403,33 +404,23 @@ impl QueryProperties {
403404
let mut result = FullKeyAggregateMeasures::default();
404405
let measures = self.measures();
405406
for m in measures.iter() {
406-
match self.get_symbol_aggregate_type(m.member_evaluator())? {
407-
SymbolAggregateType::Regular => result.regular_measures.push(m.clone()),
408-
SymbolAggregateType::Multiplied => result.multiplied_measures.push(m.clone()),
409-
SymbolAggregateType::MultiStage => result.multi_stage_measures.push(m.clone()),
407+
if has_multi_stage_members(m.member_evaluator(), self.ignore_cumulative)? {
408+
result.multi_stage_measures.push(m.clone())
409+
} else {
410+
for item in
411+
collect_multiplied_measures(self.query_tools.clone(), m.member_evaluator())?
412+
{
413+
if item.multiplied {
414+
println!("!!!! multiplied measure: {:?}", item.measure.full_name());
415+
result.multiplied_measures.push(item.measure.clone());
416+
} else {
417+
println!("!!!! regular measure: {:?}", item.measure.full_name());
418+
result.regular_measures.push(item.measure.clone());
419+
}
420+
}
410421
}
411422
}
412423

413424
Ok(result)
414425
}
415-
416-
fn get_symbol_aggregate_type(
417-
&self,
418-
symbol: &Rc<EvaluationNode>,
419-
) -> Result<SymbolAggregateType, CubeError> {
420-
let symbol_type = if has_multi_stage_members(symbol, self.ignore_cumulative)? {
421-
SymbolAggregateType::MultiStage
422-
} else if let Some(multiple) =
423-
collect_multiplied_measures(self.query_tools.clone(), symbol)?
424-
{
425-
if multiple.multiplied {
426-
SymbolAggregateType::Multiplied
427-
} else {
428-
SymbolAggregateType::Regular
429-
}
430-
} else {
431-
SymbolAggregateType::Regular
432-
};
433-
Ok(symbol_type)
434-
}
435426
}

rust/cubesqlplanner/cubesqlplanner/src/planner/sql_evaluator/collectors/multiplied_measures_collector.rs

Lines changed: 67 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,75 @@ use crate::planner::query_tools::QueryTools;
22
use crate::planner::sql_evaluator::{
33
EvaluationNode, MemberSymbol, MemberSymbolType, TraversalVisitor,
44
};
5+
use crate::planner::BaseMeasure;
56
use cubenativeutils::CubeError;
7+
use std::collections::HashSet;
68
use std::rc::Rc;
79

8-
pub struct RootMeasureResult {
10+
struct CompositeMeasuresCollector {
11+
parent_measure: Option<Rc<EvaluationNode>>,
12+
composite_measures: HashSet<String>,
13+
}
14+
15+
impl CompositeMeasuresCollector {
16+
pub fn new() -> Self {
17+
Self {
18+
parent_measure: None,
19+
composite_measures: HashSet::new(),
20+
}
21+
}
22+
23+
pub fn extract_result(self) -> HashSet<String> {
24+
self.composite_measures
25+
}
26+
}
27+
28+
impl TraversalVisitor for CompositeMeasuresCollector {
29+
fn on_node_traverse(&mut self, node: &Rc<EvaluationNode>) -> Result<bool, CubeError> {
30+
let res = match node.symbol() {
31+
MemberSymbolType::Measure(e) => {
32+
if let Some(parent) = &self.parent_measure {
33+
if parent.cube_name() != node.cube_name() {
34+
self.composite_measures.insert(parent.full_name());
35+
}
36+
}
37+
38+
self.parent_measure = Some(node.clone());
39+
true
40+
}
41+
MemberSymbolType::Dimension(_) => false,
42+
_ => false,
43+
};
44+
Ok(res)
45+
}
46+
}
47+
48+
pub struct MeasureResult {
949
pub multiplied: bool,
10-
pub measure: String,
50+
pub measure: Rc<BaseMeasure>,
1151
}
1252

1353
pub struct MultipliedMeasuresCollector {
1454
query_tools: Rc<QueryTools>,
55+
composite_measures: HashSet<String>,
1556
parent_measure: Option<String>,
16-
root_measure: Option<RootMeasureResult>,
57+
root_measure: Option<MeasureResult>,
58+
colllected_measures: Vec<MeasureResult>,
1759
}
1860

1961
impl MultipliedMeasuresCollector {
20-
pub fn new(query_tools: Rc<QueryTools>) -> Self {
62+
pub fn new(query_tools: Rc<QueryTools>, composite_measures: HashSet<String>) -> Self {
2163
Self {
2264
query_tools,
65+
composite_measures,
2366
parent_measure: None,
2467
root_measure: None,
68+
colllected_measures: vec![],
2569
}
2670
}
2771

28-
pub fn extract_result(self) -> Option<RootMeasureResult> {
29-
self.root_measure
72+
pub fn extract_result(self) -> Vec<MeasureResult> {
73+
self.colllected_measures
3074
}
3175
}
3276

@@ -43,16 +87,22 @@ impl TraversalVisitor for MultipliedMeasuresCollector {
4387
.unwrap_or(&false)
4488
.clone();
4589

46-
if self.parent_measure.is_none() {
47-
self.root_measure = Some(RootMeasureResult {
90+
if !self.composite_measures.contains(&full_name) {
91+
self.colllected_measures.push(MeasureResult {
4892
multiplied,
49-
measure: full_name.clone(),
93+
measure: BaseMeasure::try_new(node.clone(), self.query_tools.clone())?
94+
.unwrap(),
5095
})
5196
}
52-
self.parent_measure = Some(full_name);
53-
true
97+
98+
self.parent_measure = Some(full_name.clone());
99+
if self.composite_measures.contains(&full_name) {
100+
true
101+
} else {
102+
false
103+
}
54104
}
55-
MemberSymbolType::Dimension(_) => true,
105+
MemberSymbolType::Dimension(_) => false,
56106
_ => false,
57107
};
58108
Ok(res)
@@ -62,8 +112,11 @@ impl TraversalVisitor for MultipliedMeasuresCollector {
62112
pub fn collect_multiplied_measures(
63113
query_tools: Rc<QueryTools>,
64114
node: &Rc<EvaluationNode>,
65-
) -> Result<Option<RootMeasureResult>, CubeError> {
66-
let mut visitor = MultipliedMeasuresCollector::new(query_tools);
115+
) -> Result<Vec<MeasureResult>, CubeError> {
116+
let mut composite_collector = CompositeMeasuresCollector::new();
117+
composite_collector.apply(node)?;
118+
let composite_measures = composite_collector.extract_result();
119+
let mut visitor = MultipliedMeasuresCollector::new(query_tools, composite_measures);
67120
visitor.apply(node)?;
68121
Ok(visitor.extract_result())
69122
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ impl EvaluationNode {
6666
self.symbol.name()
6767
}
6868

69+
pub fn cube_name(&self) -> String {
70+
self.symbol.cube_name()
71+
}
72+
6973
pub fn is_measure(&self) -> bool {
7074
self.symbol.is_measure()
7175
}

0 commit comments

Comments
 (0)