Skip to content

Commit d1b07f1

Browse files
authored
feat(sqlplanner): Extract alias logic from the symbols (#8919)
1 parent fe62933 commit d1b07f1

Some content is hidden

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

69 files changed

+2397
-1233
lines changed

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

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3214,24 +3214,35 @@ export class BaseQuery {
32143214
DATE: 'DATE({{ args_concat }})',
32153215
},
32163216
statements: {
3217-
select: 'SELECT {% if distinct %}DISTINCT {% endif %}' +
3217+
select: '{% if ctes %} WITH \n' +
3218+
'{{ ctes | join(\',\n\') }}\n' +
3219+
'{% endif %}' +
3220+
'SELECT {% if distinct %}DISTINCT {% endif %}' +
32183221
'{{ select_concat | map(attribute=\'aliased\') | join(\', \') }} {% if from %}\n' +
32193222
'FROM (\n' +
32203223
'{{ from | indent(2, true) }}\n' +
3221-
') AS {{ from_alias }}{% endif %}' +
3224+
') AS {{ from_alias }}{% elif from_prepared %}\n' +
3225+
'FROM {{ from_prepared }}' +
3226+
'{% endif %}' +
32223227
'{% if filter %}\nWHERE {{ filter }}{% endif %}' +
32233228
'{% if group_by %}\nGROUP BY {{ group_by }}{% endif %}' +
3229+
'{% if having %}\nHAVING {{ having }}{% endif %}' +
32243230
'{% if order_by %}\nORDER BY {{ order_by | map(attribute=\'expr\') | join(\', \') }}{% endif %}' +
32253231
'{% if limit is not none %}\nLIMIT {{ limit }}{% endif %}' +
32263232
'{% if offset is not none %}\nOFFSET {{ offset }}{% endif %}',
32273233
group_by_exprs: '{{ group_by | map(attribute=\'index\') | join(\', \') }}',
3234+
join: '{{ join_type }} JOIN {{ source }} ON {{ condition }}',
3235+
cte: '{{ alias }} AS ({{ query | indent(2, true) }})'
32283236
},
32293237
expressions: {
3238+
column_reference: '{% if table_name %}{{ table_name }}.{% endif %}{{ name }}',
32303239
column_aliased: '{{expr}} {{quoted_alias}}',
3240+
query_aliased: '{{ query }} AS {{ quoted_alias }}',
32313241
case: 'CASE{% if expr %} {{ expr }}{% endif %}{% for when, then in when_then %} WHEN {{ when }} THEN {{ then }}{% endfor %}{% if else_expr %} ELSE {{ else_expr }}{% endif %} END',
32323242
is_null: '{{ expr }} IS {% if negate %}NOT {% endif %}NULL',
32333243
binary: '({{ left }} {{ op }} {{ right }})',
32343244
sort: '{{ expr }} {% if asc %}ASC{% else %}DESC{% endif %} NULLS {% if nulls_first %}FIRST{% else %}LAST{% endif %}',
3245+
order_by: '{% if index %} {{ index }} {% else %} {{ expr }} {% endif %} {% if asc %}ASC{% else %}DESC{% endif %}{% if nulls_first %} NULLS FIRST{% endif %}',
32353246
cast: 'CAST({{ expr }} AS {{ data_type }})',
32363247
window_function: '{{ fun_call }} OVER ({% if partition_by_concat %}PARTITION BY {{ partition_by_concat }}{% if order_by_concat or window_frame %} {% endif %}{% endif %}{% if order_by_concat %}ORDER BY {{ order_by_concat }}{% if window_frame %} {% endif %}{% endif %}{% if window_frame %}{{ window_frame }}{% endif %})',
32373248
window_frame_bounds: '{{ frame_type }} BETWEEN {{ frame_start }} AND {{ frame_end }}',
@@ -3260,7 +3271,8 @@ export class BaseQuery {
32603271
gt: '{{ column }} > {{ param }}',
32613272
gte: '{{ column }} >= {{ param }}',
32623273
lt: '{{ column }} < {{ param }}',
3263-
lte: '{{ column }} <= {{ param }}'
3274+
lte: '{{ column }} <= {{ param }}',
3275+
always_true: '1 == 1'
32643276

32653277
},
32663278
quotes: {
@@ -3270,6 +3282,10 @@ export class BaseQuery {
32703282
params: {
32713283
param: '?'
32723284
},
3285+
join_types: {
3286+
inner: 'INNER',
3287+
left: 'LEFT'
3288+
},
32733289
window_frame_types: {
32743290
rows: 'ROWS',
32753291
range: 'RANGE',

rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/sql_templates_render.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use std::marker::PhantomData;
99
pub trait SqlTemplatesRender {
1010
fn contains_template(&self, template_name: &str) -> bool;
1111
fn render_template(&self, name: &str, ctx: Value) -> Result<String, CubeError>;
12+
fn get_template(&self, template_name: &str) -> Result<&String, CubeError>;
1213
}
1314

1415
pub struct NativeSqlTemplatesRender<IT: InnerTypes> {
@@ -44,6 +45,12 @@ impl<IT: InnerTypes> SqlTemplatesRender for NativeSqlTemplatesRender<IT> {
4445
self.templates.contains_key(template_name)
4546
}
4647

48+
fn get_template(&self, template_name: &str) -> Result<&String, CubeError> {
49+
self.templates
50+
.get(template_name)
51+
.ok_or_else(|| CubeError::user("{template_name} template not found".to_string()))
52+
}
53+
4754
fn render_template(&self, name: &str, ctx: Value) -> Result<String, CubeError> {
4855
Ok(self
4956
.jinja

rust/cubesqlplanner/cubesqlplanner/src/plan/aggregation.rs

Lines changed: 0 additions & 16 deletions
This file was deleted.

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

Lines changed: 0 additions & 3 deletions
This file was deleted.
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
use crate::plan::{Join, JoinCondition, JoinItem, QueryPlan, Schema, Select, SingleAliasedSource};
2+
use crate::planner::BaseCube;
3+
use std::rc::Rc;
4+
5+
pub struct JoinBuilder {
6+
root: SingleAliasedSource,
7+
joins: Vec<JoinItem>,
8+
}
9+
10+
impl JoinBuilder {
11+
pub fn new(root: SingleAliasedSource) -> Self {
12+
Self {
13+
root,
14+
joins: vec![],
15+
}
16+
}
17+
18+
pub fn new_from_cube(cube: Rc<BaseCube>, alias: Option<String>) -> Self {
19+
Self::new(SingleAliasedSource::new_from_cube(cube, alias))
20+
}
21+
22+
pub fn new_from_table_reference(
23+
reference: String,
24+
schema: Rc<Schema>,
25+
alias: Option<String>,
26+
) -> Self {
27+
Self::new(SingleAliasedSource::new_from_table_reference(
28+
reference, schema, alias,
29+
))
30+
}
31+
32+
pub fn new_from_subquery(plan: Rc<QueryPlan>, alias: String) -> Self {
33+
Self::new(SingleAliasedSource::new_from_subquery(plan, alias))
34+
}
35+
36+
pub fn new_from_subselect(plan: Rc<Select>, alias: String) -> Self {
37+
Self::new(SingleAliasedSource::new_from_subquery(
38+
Rc::new(QueryPlan::Select(plan)),
39+
alias,
40+
))
41+
}
42+
43+
pub fn left_join_subselect(&mut self, subquery: Rc<Select>, alias: String, on: JoinCondition) {
44+
self.join_subselect(subquery, alias, on, false)
45+
}
46+
47+
pub fn inner_join_subselect(&mut self, subquery: Rc<Select>, alias: String, on: JoinCondition) {
48+
self.join_subselect(subquery, alias, on, true)
49+
}
50+
51+
pub fn left_join_cube(&mut self, cube: Rc<BaseCube>, alias: Option<String>, on: JoinCondition) {
52+
self.join_cube(cube, alias, on, false)
53+
}
54+
55+
pub fn inner_join_cube(
56+
&mut self,
57+
cube: Rc<BaseCube>,
58+
alias: Option<String>,
59+
on: JoinCondition,
60+
) {
61+
self.join_cube(cube, alias, on, true)
62+
}
63+
64+
pub fn left_join_table_reference(
65+
&mut self,
66+
reference: String,
67+
schema: Rc<Schema>,
68+
alias: Option<String>,
69+
on: JoinCondition,
70+
) {
71+
self.join_table_reference(reference, schema, alias, on, false)
72+
}
73+
74+
pub fn inner_join_table_reference(
75+
&mut self,
76+
reference: String,
77+
schema: Rc<Schema>,
78+
alias: Option<String>,
79+
on: JoinCondition,
80+
) {
81+
self.join_table_reference(reference, schema, alias, on, true)
82+
}
83+
84+
pub fn build(self) -> Rc<Join> {
85+
Rc::new(Join {
86+
root: self.root,
87+
joins: self.joins,
88+
})
89+
}
90+
91+
fn join_subselect(
92+
&mut self,
93+
subquery: Rc<Select>,
94+
alias: String,
95+
on: JoinCondition,
96+
is_inner: bool,
97+
) {
98+
let subquery = Rc::new(QueryPlan::Select(subquery));
99+
let from = SingleAliasedSource::new_from_subquery(subquery, alias);
100+
self.joins.push(JoinItem { from, on, is_inner })
101+
}
102+
103+
fn join_cube(
104+
&mut self,
105+
cube: Rc<BaseCube>,
106+
alias: Option<String>,
107+
on: JoinCondition,
108+
is_inner: bool,
109+
) {
110+
let from = SingleAliasedSource::new_from_cube(cube, alias);
111+
self.joins.push(JoinItem { from, on, is_inner })
112+
}
113+
114+
fn join_table_reference(
115+
&mut self,
116+
reference: String,
117+
schema: Rc<Schema>,
118+
alias: Option<String>,
119+
on: JoinCondition,
120+
is_inner: bool,
121+
) {
122+
let from = SingleAliasedSource::new_from_table_reference(reference, schema, alias);
123+
self.joins.push(JoinItem { from, on, is_inner })
124+
}
125+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pub mod join;
2+
pub mod select;
3+
4+
pub use join::JoinBuilder;
5+
pub use select::SelectBuilder;
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
use crate::plan::{
2+
AliasedExpr, Cte, Expr, Filter, From, MemberExpression, OrderBy, Schema, Select,
3+
};
4+
use crate::planner::{BaseMember, VisitorContext};
5+
use std::rc::Rc;
6+
7+
pub struct SelectBuilder {
8+
projection_columns: Vec<AliasedExpr>,
9+
from: From,
10+
filter: Option<Filter>,
11+
group_by: Vec<Expr>,
12+
having: Option<Filter>,
13+
order_by: Vec<OrderBy>,
14+
context: Rc<VisitorContext>,
15+
ctes: Vec<Rc<Cte>>,
16+
is_distinct: bool,
17+
limit: Option<usize>,
18+
offset: Option<usize>,
19+
input_schema: Rc<Schema>,
20+
}
21+
22+
impl SelectBuilder {
23+
pub fn new(from: From, context: VisitorContext) -> Self {
24+
let input_schema = from.schema.clone();
25+
Self {
26+
projection_columns: vec![],
27+
from,
28+
filter: None,
29+
group_by: vec![],
30+
having: None,
31+
order_by: vec![],
32+
context: Rc::new(context),
33+
ctes: vec![],
34+
is_distinct: false,
35+
limit: None,
36+
offset: None,
37+
input_schema,
38+
}
39+
}
40+
41+
pub fn add_projection_member(
42+
&mut self,
43+
member: &Rc<dyn BaseMember>,
44+
source: Option<String>,
45+
alias: Option<String>,
46+
) {
47+
let alias = if let Some(alias) = alias {
48+
alias
49+
} else {
50+
self.input_schema.resolve_member_alias(&member, &source)
51+
};
52+
let expr = Expr::Member(MemberExpression::new(member.clone(), source));
53+
let aliased_expr = AliasedExpr {
54+
expr,
55+
alias: alias.clone(),
56+
};
57+
58+
self.projection_columns.push(aliased_expr);
59+
}
60+
61+
pub fn set_filter(&mut self, filter: Option<Filter>) {
62+
self.filter = filter;
63+
}
64+
65+
pub fn set_group_by(&mut self, group_by: Vec<Expr>) {
66+
self.group_by = group_by;
67+
}
68+
69+
pub fn set_having(&mut self, having: Option<Filter>) {
70+
self.having = having;
71+
}
72+
73+
pub fn set_order_by(&mut self, order_by: Vec<OrderBy>) {
74+
self.order_by = order_by;
75+
}
76+
77+
pub fn set_distinct(&mut self) {
78+
self.is_distinct = true;
79+
}
80+
81+
pub fn set_limit(&mut self, limit: Option<usize>) {
82+
self.limit = limit;
83+
}
84+
85+
pub fn set_offset(&mut self, offset: Option<usize>) {
86+
self.offset = offset;
87+
}
88+
pub fn set_ctes(&mut self, ctes: Vec<Rc<Cte>>) {
89+
self.ctes = ctes;
90+
}
91+
92+
pub fn build(self) -> Select {
93+
Select {
94+
projection_columns: self.projection_columns,
95+
from: self.from,
96+
filter: self.filter,
97+
group_by: self.group_by,
98+
having: self.having,
99+
order_by: self.order_by,
100+
context: self.context.clone(),
101+
ctes: self.ctes,
102+
is_distinct: self.is_distinct,
103+
limit: self.limit,
104+
offset: self.offset,
105+
}
106+
}
107+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
use super::{QueryPlan, Schema, Select};
2+
use crate::planner::sql_templates::PlanSqlTemplates;
3+
use cubenativeutils::CubeError;
4+
5+
use std::rc::Rc;
6+
7+
#[derive(Clone)]
8+
pub struct Cte {
9+
query: Rc<QueryPlan>,
10+
name: String,
11+
}
12+
13+
impl Cte {
14+
pub fn new(query: Rc<QueryPlan>, name: String) -> Self {
15+
Self { query, name }
16+
}
17+
18+
pub fn new_from_select(select: Rc<Select>, name: String) -> Self {
19+
Self {
20+
query: Rc::new(QueryPlan::Select(select)),
21+
name,
22+
}
23+
}
24+
25+
pub fn make_schema(&self) -> Schema {
26+
self.query.make_schema(Some(self.name().clone()))
27+
}
28+
29+
pub fn query(&self) -> &Rc<QueryPlan> {
30+
&self.query
31+
}
32+
33+
pub fn name(&self) -> &String {
34+
&self.name
35+
}
36+
37+
pub fn to_sql(&self, templates: &PlanSqlTemplates) -> Result<String, CubeError> {
38+
let sql = format!("({})", self.query.to_sql(templates)?);
39+
Ok(sql)
40+
}
41+
}

0 commit comments

Comments
 (0)