Skip to content

Commit

Permalink
feat(sqlplanner): Extract alias logic from the symbols (#8919)
Browse files Browse the repository at this point in the history
  • Loading branch information
waralexrom authored Nov 27, 2024
1 parent fe62933 commit d1b07f1
Show file tree
Hide file tree
Showing 69 changed files with 2,397 additions and 1,233 deletions.
22 changes: 19 additions & 3 deletions packages/cubejs-schema-compiler/src/adapter/BaseQuery.js
Original file line number Diff line number Diff line change
Expand Up @@ -3214,24 +3214,35 @@ export class BaseQuery {
DATE: 'DATE({{ args_concat }})',
},
statements: {
select: 'SELECT {% if distinct %}DISTINCT {% endif %}' +
select: '{% if ctes %} WITH \n' +
'{{ ctes | join(\',\n\') }}\n' +
'{% endif %}' +
'SELECT {% if distinct %}DISTINCT {% endif %}' +
'{{ select_concat | map(attribute=\'aliased\') | join(\', \') }} {% if from %}\n' +
'FROM (\n' +
'{{ from | indent(2, true) }}\n' +
') AS {{ from_alias }}{% endif %}' +
') AS {{ from_alias }}{% elif from_prepared %}\n' +
'FROM {{ from_prepared }}' +
'{% endif %}' +
'{% if filter %}\nWHERE {{ filter }}{% endif %}' +
'{% if group_by %}\nGROUP BY {{ group_by }}{% endif %}' +
'{% if having %}\nHAVING {{ having }}{% endif %}' +
'{% if order_by %}\nORDER BY {{ order_by | map(attribute=\'expr\') | join(\', \') }}{% endif %}' +
'{% if limit is not none %}\nLIMIT {{ limit }}{% endif %}' +
'{% if offset is not none %}\nOFFSET {{ offset }}{% endif %}',
group_by_exprs: '{{ group_by | map(attribute=\'index\') | join(\', \') }}',
join: '{{ join_type }} JOIN {{ source }} ON {{ condition }}',
cte: '{{ alias }} AS ({{ query | indent(2, true) }})'
},
expressions: {
column_reference: '{% if table_name %}{{ table_name }}.{% endif %}{{ name }}',
column_aliased: '{{expr}} {{quoted_alias}}',
query_aliased: '{{ query }} AS {{ quoted_alias }}',
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',
is_null: '{{ expr }} IS {% if negate %}NOT {% endif %}NULL',
binary: '({{ left }} {{ op }} {{ right }})',
sort: '{{ expr }} {% if asc %}ASC{% else %}DESC{% endif %} NULLS {% if nulls_first %}FIRST{% else %}LAST{% endif %}',
order_by: '{% if index %} {{ index }} {% else %} {{ expr }} {% endif %} {% if asc %}ASC{% else %}DESC{% endif %}{% if nulls_first %} NULLS FIRST{% endif %}',
cast: 'CAST({{ expr }} AS {{ data_type }})',
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 %})',
window_frame_bounds: '{{ frame_type }} BETWEEN {{ frame_start }} AND {{ frame_end }}',
Expand Down Expand Up @@ -3260,7 +3271,8 @@ export class BaseQuery {
gt: '{{ column }} > {{ param }}',
gte: '{{ column }} >= {{ param }}',
lt: '{{ column }} < {{ param }}',
lte: '{{ column }} <= {{ param }}'
lte: '{{ column }} <= {{ param }}',
always_true: '1 == 1'

},
quotes: {
Expand All @@ -3270,6 +3282,10 @@ export class BaseQuery {
params: {
param: '?'
},
join_types: {
inner: 'INNER',
left: 'LEFT'
},
window_frame_types: {
rows: 'ROWS',
range: 'RANGE',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use std::marker::PhantomData;
pub trait SqlTemplatesRender {
fn contains_template(&self, template_name: &str) -> bool;
fn render_template(&self, name: &str, ctx: Value) -> Result<String, CubeError>;
fn get_template(&self, template_name: &str) -> Result<&String, CubeError>;
}

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

fn get_template(&self, template_name: &str) -> Result<&String, CubeError> {
self.templates
.get(template_name)
.ok_or_else(|| CubeError::user("{template_name} template not found".to_string()))
}

fn render_template(&self, name: &str, ctx: Value) -> Result<String, CubeError> {
Ok(self
.jinja
Expand Down
16 changes: 0 additions & 16 deletions rust/cubesqlplanner/cubesqlplanner/src/plan/aggregation.rs

This file was deleted.

3 changes: 0 additions & 3 deletions rust/cubesqlplanner/cubesqlplanner/src/plan/builder.rs

This file was deleted.

125 changes: 125 additions & 0 deletions rust/cubesqlplanner/cubesqlplanner/src/plan/builder/join.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
use crate::plan::{Join, JoinCondition, JoinItem, QueryPlan, Schema, Select, SingleAliasedSource};
use crate::planner::BaseCube;
use std::rc::Rc;

pub struct JoinBuilder {
root: SingleAliasedSource,
joins: Vec<JoinItem>,
}

impl JoinBuilder {
pub fn new(root: SingleAliasedSource) -> Self {
Self {
root,
joins: vec![],
}
}

pub fn new_from_cube(cube: Rc<BaseCube>, alias: Option<String>) -> Self {
Self::new(SingleAliasedSource::new_from_cube(cube, alias))
}

pub fn new_from_table_reference(
reference: String,
schema: Rc<Schema>,
alias: Option<String>,
) -> Self {
Self::new(SingleAliasedSource::new_from_table_reference(
reference, schema, alias,
))
}

pub fn new_from_subquery(plan: Rc<QueryPlan>, alias: String) -> Self {
Self::new(SingleAliasedSource::new_from_subquery(plan, alias))
}

pub fn new_from_subselect(plan: Rc<Select>, alias: String) -> Self {
Self::new(SingleAliasedSource::new_from_subquery(
Rc::new(QueryPlan::Select(plan)),
alias,
))
}

pub fn left_join_subselect(&mut self, subquery: Rc<Select>, alias: String, on: JoinCondition) {
self.join_subselect(subquery, alias, on, false)
}

pub fn inner_join_subselect(&mut self, subquery: Rc<Select>, alias: String, on: JoinCondition) {
self.join_subselect(subquery, alias, on, true)
}

pub fn left_join_cube(&mut self, cube: Rc<BaseCube>, alias: Option<String>, on: JoinCondition) {
self.join_cube(cube, alias, on, false)
}

pub fn inner_join_cube(
&mut self,
cube: Rc<BaseCube>,
alias: Option<String>,
on: JoinCondition,
) {
self.join_cube(cube, alias, on, true)
}

pub fn left_join_table_reference(
&mut self,
reference: String,
schema: Rc<Schema>,
alias: Option<String>,
on: JoinCondition,
) {
self.join_table_reference(reference, schema, alias, on, false)
}

pub fn inner_join_table_reference(
&mut self,
reference: String,
schema: Rc<Schema>,
alias: Option<String>,
on: JoinCondition,
) {
self.join_table_reference(reference, schema, alias, on, true)
}

pub fn build(self) -> Rc<Join> {
Rc::new(Join {
root: self.root,
joins: self.joins,
})
}

fn join_subselect(
&mut self,
subquery: Rc<Select>,
alias: String,
on: JoinCondition,
is_inner: bool,
) {
let subquery = Rc::new(QueryPlan::Select(subquery));
let from = SingleAliasedSource::new_from_subquery(subquery, alias);
self.joins.push(JoinItem { from, on, is_inner })
}

fn join_cube(
&mut self,
cube: Rc<BaseCube>,
alias: Option<String>,
on: JoinCondition,
is_inner: bool,
) {
let from = SingleAliasedSource::new_from_cube(cube, alias);
self.joins.push(JoinItem { from, on, is_inner })
}

fn join_table_reference(
&mut self,
reference: String,
schema: Rc<Schema>,
alias: Option<String>,
on: JoinCondition,
is_inner: bool,
) {
let from = SingleAliasedSource::new_from_table_reference(reference, schema, alias);
self.joins.push(JoinItem { from, on, is_inner })
}
}
5 changes: 5 additions & 0 deletions rust/cubesqlplanner/cubesqlplanner/src/plan/builder/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pub mod join;
pub mod select;

pub use join::JoinBuilder;
pub use select::SelectBuilder;
107 changes: 107 additions & 0 deletions rust/cubesqlplanner/cubesqlplanner/src/plan/builder/select.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
use crate::plan::{
AliasedExpr, Cte, Expr, Filter, From, MemberExpression, OrderBy, Schema, Select,
};
use crate::planner::{BaseMember, VisitorContext};
use std::rc::Rc;

pub struct SelectBuilder {
projection_columns: Vec<AliasedExpr>,
from: From,
filter: Option<Filter>,
group_by: Vec<Expr>,
having: Option<Filter>,
order_by: Vec<OrderBy>,
context: Rc<VisitorContext>,
ctes: Vec<Rc<Cte>>,
is_distinct: bool,
limit: Option<usize>,
offset: Option<usize>,
input_schema: Rc<Schema>,
}

impl SelectBuilder {
pub fn new(from: From, context: VisitorContext) -> Self {
let input_schema = from.schema.clone();
Self {
projection_columns: vec![],
from,
filter: None,
group_by: vec![],
having: None,
order_by: vec![],
context: Rc::new(context),
ctes: vec![],
is_distinct: false,
limit: None,
offset: None,
input_schema,
}
}

pub fn add_projection_member(
&mut self,
member: &Rc<dyn BaseMember>,
source: Option<String>,
alias: Option<String>,
) {
let alias = if let Some(alias) = alias {
alias
} else {
self.input_schema.resolve_member_alias(&member, &source)
};
let expr = Expr::Member(MemberExpression::new(member.clone(), source));
let aliased_expr = AliasedExpr {
expr,
alias: alias.clone(),
};

self.projection_columns.push(aliased_expr);
}

pub fn set_filter(&mut self, filter: Option<Filter>) {
self.filter = filter;
}

pub fn set_group_by(&mut self, group_by: Vec<Expr>) {
self.group_by = group_by;
}

pub fn set_having(&mut self, having: Option<Filter>) {
self.having = having;
}

pub fn set_order_by(&mut self, order_by: Vec<OrderBy>) {
self.order_by = order_by;
}

pub fn set_distinct(&mut self) {
self.is_distinct = true;
}

pub fn set_limit(&mut self, limit: Option<usize>) {
self.limit = limit;
}

pub fn set_offset(&mut self, offset: Option<usize>) {
self.offset = offset;
}
pub fn set_ctes(&mut self, ctes: Vec<Rc<Cte>>) {
self.ctes = ctes;
}

pub fn build(self) -> Select {
Select {
projection_columns: self.projection_columns,
from: self.from,
filter: self.filter,
group_by: self.group_by,
having: self.having,
order_by: self.order_by,
context: self.context.clone(),
ctes: self.ctes,
is_distinct: self.is_distinct,
limit: self.limit,
offset: self.offset,
}
}
}
41 changes: 41 additions & 0 deletions rust/cubesqlplanner/cubesqlplanner/src/plan/cte.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
use super::{QueryPlan, Schema, Select};
use crate::planner::sql_templates::PlanSqlTemplates;
use cubenativeutils::CubeError;

use std::rc::Rc;

#[derive(Clone)]
pub struct Cte {
query: Rc<QueryPlan>,
name: String,
}

impl Cte {
pub fn new(query: Rc<QueryPlan>, name: String) -> Self {
Self { query, name }
}

pub fn new_from_select(select: Rc<Select>, name: String) -> Self {
Self {
query: Rc::new(QueryPlan::Select(select)),
name,
}
}

pub fn make_schema(&self) -> Schema {
self.query.make_schema(Some(self.name().clone()))
}

pub fn query(&self) -> &Rc<QueryPlan> {
&self.query
}

pub fn name(&self) -> &String {
&self.name
}

pub fn to_sql(&self, templates: &PlanSqlTemplates) -> Result<String, CubeError> {
let sql = format!("({})", self.query.to_sql(templates)?);
Ok(sql)
}
}
Loading

0 comments on commit d1b07f1

Please sign in to comment.