Skip to content

Commit

Permalink
template engine
Browse files Browse the repository at this point in the history
  • Loading branch information
waralexrom committed Nov 7, 2024
1 parent e4c9680 commit b566c6e
Show file tree
Hide file tree
Showing 10 changed files with 289 additions and 123 deletions.
21 changes: 18 additions & 3 deletions packages/cubejs-schema-compiler/src/adapter/BaseQuery.js
Original file line number Diff line number Diff line change
Expand Up @@ -3213,25 +3213,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 %}{% if nulls_first %} NULLS FIRST{% 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 +3270,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 +3281,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 @@ -538,7 +538,7 @@ describe('SQL Generation', () => {
});
`);

it('simple join', async () => {
it('simple join 1', async () => {
await compiler.compile();

console.log(joinGraph.buildJoin(['visitor_checkins', 'visitors']));
Expand Down
16 changes: 0 additions & 16 deletions rust/cubesqlplanner/cubesqlplanner/src/plan/aggregation.rs

This file was deleted.

16 changes: 10 additions & 6 deletions rust/cubesqlplanner/cubesqlplanner/src/plan/filter.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use super::Schema;
use crate::planner::filter::BaseFilter;
use crate::planner::sql_templates::PlanSqlTemplates;
use crate::planner::VisitorContext;
use cubenativeutils::CubeError;
use std::fmt;
Expand Down Expand Up @@ -45,6 +46,7 @@ impl fmt::Display for FilterGroupOperator {
impl FilterItem {
pub fn to_sql(
&self,
templates: &PlanSqlTemplates,
context: Rc<VisitorContext>,
schema: Rc<Schema>,
) -> Result<String, CubeError> {
Expand All @@ -54,13 +56,14 @@ impl FilterItem {
let items_sql = group
.items
.iter()
.map(|itm| itm.to_sql(context.clone(), schema.clone()))
.map(|itm| itm.to_sql(templates, context.clone(), schema.clone()))
.collect::<Result<Vec<_>, _>>()?;
if items_sql.is_empty() {
format!("( 1 = 1 )")
let result = if items_sql.is_empty() {
templates.always_true()?
} else {
format!("({})", items_sql.join(&operator))
}
items_sql.join(&operator)
};
format!("({})", result)
}
FilterItem::Item(item) => {
let sql = item.to_sql(context.clone(), schema)?;
Expand All @@ -74,13 +77,14 @@ impl FilterItem {
impl Filter {
pub fn to_sql(
&self,
templates: &PlanSqlTemplates,
context: Rc<VisitorContext>,
schema: Rc<Schema>,
) -> Result<String, CubeError> {
let res = self
.items
.iter()
.map(|itm| itm.to_sql(context.clone(), schema.clone()))
.map(|itm| itm.to_sql(templates, context.clone(), schema.clone()))
.collect::<Result<Vec<_>, _>>()?
.join(" AND ");
Ok(res)
Expand Down
5 changes: 1 addition & 4 deletions rust/cubesqlplanner/cubesqlplanner/src/plan/from.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,7 @@ impl SingleAliasedSource {
) -> Result<String, CubeError> {
let sql = self.source.to_sql(templates, context)?;

Ok(format!(
"{sql} AS {}",
templates.quote_identifier(&self.alias)?
))
templates.query_aliased(&sql, &self.alias)
}

pub fn make_schema(&self) -> Schema {
Expand Down
28 changes: 7 additions & 21 deletions rust/cubesqlplanner/cubesqlplanner/src/plan/join.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,20 +68,7 @@ impl DimensionJoinCondition {
dimension,
schema.clone(),
)?;
let null_check = if self.null_check {
format!(
" OR ({} AND {})",
templates.is_null_expr(&left_column, false)?,
templates.is_null_expr(&right_column, false)?
)
} else {
format!("")
};

Ok(format!(
"({} = {}{})",
left_column, right_column, null_check
))
templates.join_by_dimension_conditions(&left_column, &right_column, self.null_check)
}

fn resolve_member_alias(
Expand Down Expand Up @@ -157,14 +144,13 @@ impl JoinItem {
context: Rc<VisitorContext>,
schema: Rc<Schema>,
) -> Result<String, CubeError> {
let operator = if self.is_inner { "INNER" } else { "LEFT" };
let on_sql = self.on.to_sql(templates, context.clone(), schema)?;
Ok(format!(
"{} JOIN {} ON {}",
operator,
self.from.to_sql(templates, context)?,
on_sql
))
let result = templates.join(
&self.from.to_sql(templates, context)?,
&on_sql,
self.is_inner,
)?;
Ok(result)
}
}

Expand Down
136 changes: 65 additions & 71 deletions rust/cubesqlplanner/cubesqlplanner/src/plan/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ use itertools::Itertools;

use super::{Cte, Expr, Filter, From, OrderBy, Schema, SchemaColumn};
use crate::planner::sql_templates::PlanSqlTemplates;
use crate::planner::sql_templates::{
TemplateGroupByColumn, TemplateOrderByColumn, TemplateProjectionColumn,
};
use crate::planner::VisitorContext;
use cubenativeutils::CubeError;
use std::rc::Rc;
Expand All @@ -21,12 +24,14 @@ impl AliasedExpr {
templates: &PlanSqlTemplates,
context: Rc<VisitorContext>,
schema: Rc<Schema>,
) -> Result<String, CubeError> {
Ok(format!(
"{} {}",
self.expr.to_sql(templates, context, schema)?,
templates.quote_identifier(&self.alias)?
))
) -> Result<TemplateProjectionColumn, CubeError> {
let expr = self.expr.to_sql(templates, context, schema)?;
let aliased = templates.column_aliased(&expr, &self.alias)?;
Ok(TemplateProjectionColumn {
expr,
alias: self.alias.clone(),
aliased,
})
}
}

Expand Down Expand Up @@ -76,90 +81,79 @@ impl Select {
.iter()
.map(|p| p.to_sql(templates, self.context.clone(), schema.clone()))
.collect::<Result<Vec<_>, _>>()?
.join(", ")
} else {
format!(" * ")
vec![TemplateProjectionColumn {
expr: format!("*"),
alias: format!(""),
aliased: format!("*"),
}]
};

let where_condition = if let Some(filter) = &self.filter {
format!(
" WHERE {}",
filter.to_sql(self.context.clone(), schema.clone())?
)
Some(filter.to_sql(templates, self.context.clone(), schema.clone())?)
} else {
format!("")
None
};

let group_by = if !self.group_by.is_empty() {
let str = self
.group_by
.iter()
.enumerate()
.map(|(i, _)| format!("{}", i + 1))
.join(", ");
format!(" GROUP BY {}", str)
} else {
format!("")
};
let group_by = self
.group_by
.iter()
.enumerate()
.map(|(i, expr)| -> Result<_, CubeError> {
let expr = expr.to_sql(templates, self.context.clone(), schema.clone())?;
Ok(TemplateGroupByColumn { expr, index: i + 1 })
})
.collect::<Result<Vec<_>, _>>()?;

let having = if let Some(having) = &self.having {
format!(
" HAVING {}",
having.to_sql(self.context.clone(), schema.clone())?
)
Some(having.to_sql(templates, self.context.clone(), schema.clone())?)
} else {
format!("")
None
};

let ctes = if !self.ctes.is_empty() {
let ctes_sql = self
.ctes
.iter()
.map(|cte| -> Result<_, CubeError> {
Ok(format!(
" {} as ({})",
cte.name(),
cte.query().to_sql(templates)?
))
})
.collect::<Result<Vec<_>, _>>()?
.join(",\n");
format!("WITH\n{ctes_sql}\n")
} else {
"".to_string()
};
let ctes = self
.ctes
.iter()
.map(|cte| -> Result<_, CubeError> {
templates.cte(&cte.query().to_sql(templates)?, &cte.name().clone())
})
.collect::<Result<Vec<_>, _>>()?;

let order_by = if !self.order_by.is_empty() {
let order_sql = self
.order_by
.iter()
.map(|itm| format!("{} {}", itm.pos, itm.asc_str()))
.collect::<Vec<_>>()
.join(", ");
format!(" ORDER BY {}", order_sql)
} else {
format!("")
};
let order_by = self
.order_by
.iter()
.map(|itm| -> Result<_, CubeError> {
let expr = templates.order_by(
&itm.expr
.to_sql(templates, self.context.clone(), schema.clone())?,
Some(itm.pos),
!itm.desc,
)?;
Ok(TemplateOrderByColumn { expr })
})
.collect::<Result<Vec<_>, _>>()?;

let distinct = if self.is_distinct { "DISTINCT " } else { "" };
let from = self.from.to_sql(templates, self.context.clone())?;
let limit = if let Some(limit) = self.limit {
format!(" LIMIT {limit}")
} else {
format!("")
};
let offset = if let Some(offset) = self.offset {
format!(" OFFSET {offset}")
} else {
format!("")
};

let res = format!(
let result = templates.select(
ctes,
&from,
projection,
where_condition,
group_by,
having,
order_by,
self.limit,
self.offset,
self.is_distinct,
)?;

/* let res = format!(
"{ctes}SELECT\
\n {distinct}{projection}\
\n FROM\
\n{from}{where_condition}{group_by}{having}{order_by}{limit}{offset}",
);
Ok(res)
); */
Ok(result)
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
pub mod filter;
pub mod plan;
pub mod structs;

pub use filter::FilterTemplates;
pub use plan::PlanSqlTemplates;
pub use structs::{TemplateGroupByColumn, TemplateOrderByColumn, TemplateProjectionColumn};
Loading

0 comments on commit b566c6e

Please sign in to comment.