Skip to content

Commit

Permalink
Support TableFactor::{Derived, Dictionary, Series} in AstBuilder (g…
Browse files Browse the repository at this point in the history
…luesql#1007)

From now, we can use Dictionary, SERIES(N) and Derived subquery even in AstBuilder!

e.g.
let actual = glue_objects().select().into();
let expected = "SELECT * FROM GLUE_OBJECTS";
test_query(actual, expected);

let actual = glue_tables().select().into();
let expected = "SELECT * FROM GLUE_TABLES";
test_query(actual, expected);

let actual = glue_indexes().select().into();
let expected = "SELECT * FROM GLUE_INDEXES";
test_query(actual, expected);

let actual = glue_table_columns().select().into();
let expected = "SELECT * FROM GLUE_TABLE_COLUMNS";
test_query(actual, expected);

let actual = series("1 + 2").select().into();
let expected = "SELECT * FROM SERIES(1 + 2)";
test_query(actual, expected);

let actual = table("Items").select().alias_as("Sub").select().into();
let expected = "SELECT * FROM (SELECT * FROM Items) AS Sub";
test_query(actual, expected);
  • Loading branch information
devgony committed Dec 1, 2022
1 parent 0c273cb commit 8c88b9b
Show file tree
Hide file tree
Showing 22 changed files with 814 additions and 140 deletions.
2 changes: 1 addition & 1 deletion core/src/ast_builder/expr/in_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ macro_rules! impl_from_select_nodes {
};
}

impl_from_select_nodes!(SelectNode);
impl_from_select_nodes!(SelectNode<'a>);
impl_from_select_nodes!(JoinNode<'a>);
impl_from_select_nodes!(JoinConstraintNode<'a>);
impl_from_select_nodes!(HashJoinNode<'a>);
Expand Down
15 changes: 6 additions & 9 deletions core/src/ast_builder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ mod select;
mod select_item;
mod select_item_list;
mod show_columns;
mod table;
mod table_factor;
mod table_name;
#[cfg(feature = "transaction")]
mod transaction;
mod update;
Expand Down Expand Up @@ -50,7 +51,10 @@ pub use {
select_item::SelectItemNode,
select_item_list::SelectItemList,
show_columns::ShowColumnsNode,
table::{TableAliasNode, TableNode},
table_factor::{
glue_indexes, glue_objects, glue_table_columns, glue_tables, series, TableFactorNode,
},
table_name::table,
update::UpdateNode,
};

Expand Down Expand Up @@ -79,13 +83,6 @@ pub use expr::{
},
};

/// Entry point function to build statement
pub fn table(table_name: &str) -> TableNode {
let table_name = table_name.to_owned();

TableNode { table_name }
}

/// Functions for building transaction statements
#[cfg(feature = "transaction")]
pub use transaction::{begin, commit, rollback};
Expand Down
50 changes: 46 additions & 4 deletions core/src/ast_builder/query.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use {
super::{
select::{NodeData, Prebuild},
table_factor::TableType,
ExprList, FilterNode, GroupByNode, HashJoinNode, HavingNode, JoinConstraintNode, JoinNode,
LimitNode, OffsetLimitNode, OffsetNode, OrderByNode, ProjectNode, SelectNode,
TableFactorNode,
},
crate::{
ast::{Expr, Query, SetExpr, Values},
Expand All @@ -16,7 +18,7 @@ use {
pub enum QueryNode<'a> {
Text(String),
Values(Vec<ExprList<'a>>),
SelectNode(SelectNode),
SelectNode(SelectNode<'a>),
JoinNode(JoinNode<'a>),
JoinConstraintNode(JoinConstraintNode<'a>),
HashJoinNode(HashJoinNode<'a>),
Expand All @@ -30,14 +32,27 @@ pub enum QueryNode<'a> {
OrderByNode(OrderByNode<'a>),
}

impl<'a> QueryNode<'a> {
pub fn alias_as(self, table_alias: &'a str) -> TableFactorNode<'a> {
TableFactorNode {
table_name: table_alias.to_owned(),
table_type: TableType::Derived {
subquery: Box::new(self),
alias: table_alias.to_owned(),
},
table_alias: None,
}
}
}

impl<'a> From<&str> for QueryNode<'a> {
fn from(query: &str) -> Self {
Self::Text(query.to_owned())
}
}

impl<'a> From<SelectNode> for QueryNode<'a> {
fn from(node: SelectNode) -> Self {
impl<'a> From<SelectNode<'a>> for QueryNode<'a> {
fn from(node: SelectNode<'a>) -> Self {
QueryNode::SelectNode(node)
}
}
Expand Down Expand Up @@ -111,7 +126,10 @@ mod test {
Join, JoinConstraint, JoinExecutor, JoinOperator, Query, Select, SetExpr,
TableFactor, TableWithJoins,
},
ast_builder::{col, table, test_query, SelectItemList},
ast_builder::{
col, glue_indexes, glue_objects, glue_table_columns, glue_tables, series, table,
test_query, SelectItemList,
},
},
};

Expand Down Expand Up @@ -218,5 +236,29 @@ mod test {
let actual = table("Foo").select().order_by("score DESC").into();
let expected = "SELECT * FROM Foo ORDER BY score DESC";
test_query(actual, expected);

let actual = glue_objects().select().into();
let expected = "SELECT * FROM GLUE_OBJECTS";
test_query(actual, expected);

let actual = glue_tables().select().into();
let expected = "SELECT * FROM GLUE_TABLES";
test_query(actual, expected);

let actual = glue_indexes().select().into();
let expected = "SELECT * FROM GLUE_INDEXES";
test_query(actual, expected);

let actual = glue_table_columns().select().into();
let expected = "SELECT * FROM GLUE_TABLE_COLUMNS";
test_query(actual, expected);

let actual = series("1 + 2").select().into();
let expected = "SELECT * FROM SERIES(1 + 2)";
test_query(actual, expected);

let actual = table("Items").select().alias_as("Sub").select().into();
let expected = "SELECT * FROM (SELECT * FROM Items) AS Sub";
test_query(actual, expected);
}
}
23 changes: 19 additions & 4 deletions core/src/ast_builder/select/filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,16 @@ use {
crate::{
ast_builder::{
ExprList, ExprNode, GroupByNode, HashJoinNode, JoinConstraintNode, JoinNode, LimitNode,
OffsetNode, OrderByExprList, OrderByNode, ProjectNode, SelectItemList,
OffsetNode, OrderByExprList, OrderByNode, ProjectNode, QueryNode, SelectItemList,
TableFactorNode,
},
result::Result,
},
};

#[derive(Clone)]
pub enum PrevNode<'a> {
Select(SelectNode),
Select(SelectNode<'a>),
Join(Box<JoinNode<'a>>),
JoinConstraint(Box<JoinConstraintNode<'a>>),
HashJoin(Box<HashJoinNode<'a>>),
Expand Down Expand Up @@ -46,8 +47,8 @@ impl<'a> From<HashJoinNode<'a>> for PrevNode<'a> {
}
}

impl<'a> From<SelectNode> for PrevNode<'a> {
fn from(node: SelectNode) -> Self {
impl<'a> From<SelectNode<'a>> for PrevNode<'a> {
fn from(node: SelectNode<'a>) -> Self {
PrevNode::Select(node)
}
}
Expand Down Expand Up @@ -90,6 +91,10 @@ impl<'a> FilterNode<'a> {
pub fn order_by<T: Into<OrderByExprList<'a>>>(self, order_by_exprs: T) -> OrderByNode<'a> {
OrderByNode::new(self, order_by_exprs)
}

pub fn alias_as(self, table_alias: &'a str) -> TableFactorNode {
QueryNode::FilterNode(self).alias_as(table_alias)
}
}

impl<'a> Prebuild for FilterNode<'a> {
Expand Down Expand Up @@ -229,5 +234,15 @@ mod tests {
}))
};
assert_eq!(actual, expected);

// select node -> filter node -> derived subquery
let actual = table("Bar")
.select()
.filter("id IS NULL")
.alias_as("Sub")
.select()
.build();
let expected = "SELECT * FROM (SELECT * FROM Bar WHERE id IS NULL) Sub";
test(actual, expected);
}
}
24 changes: 19 additions & 5 deletions core/src/ast_builder/select/group_by.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@ use {
crate::{
ast_builder::{
ExprList, ExprNode, FilterNode, HashJoinNode, HavingNode, JoinConstraintNode, JoinNode,
LimitNode, OffsetNode, OrderByExprList, OrderByNode, ProjectNode, SelectItemList,
SelectNode,
LimitNode, OffsetNode, OrderByExprList, OrderByNode, ProjectNode, QueryNode,
SelectItemList, SelectNode, TableFactorNode,
},
result::Result,
},
};

#[derive(Clone)]
pub enum PrevNode<'a> {
Select(SelectNode),
Select(SelectNode<'a>),
Join(Box<JoinNode<'a>>),
JoinConstraint(Box<JoinConstraintNode<'a>>),
HashJoin(Box<HashJoinNode<'a>>),
Expand All @@ -31,8 +31,8 @@ impl<'a> Prebuild for PrevNode<'a> {
}
}

impl<'a> From<SelectNode> for PrevNode<'a> {
fn from(node: SelectNode) -> Self {
impl<'a> From<SelectNode<'a>> for PrevNode<'a> {
fn from(node: SelectNode<'a>) -> Self {
PrevNode::Select(node)
}
}
Expand Down Expand Up @@ -94,6 +94,10 @@ impl<'a> GroupByNode<'a> {
pub fn order_by<T: Into<OrderByExprList<'a>>>(self, expr_list: T) -> OrderByNode<'a> {
OrderByNode::new(self, expr_list)
}

pub fn alias_as(self, table_alias: &'a str) -> TableFactorNode {
QueryNode::GroupByNode(self).alias_as(table_alias)
}
}

impl<'a> Prebuild for GroupByNode<'a> {
Expand Down Expand Up @@ -217,5 +221,15 @@ mod tests {
}))
};
assert_eq!(actual, expected);

// select -> group by -> derived subquery
let actual = table("Foo")
.select()
.group_by("a")
.alias_as("Sub")
.select()
.build();
let expected = "SELECT * FROM (SELECT * FROM Foo GROUP BY a) Sub";
test(actual, expected);
}
}
17 changes: 16 additions & 1 deletion core/src/ast_builder/select/having.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use {
crate::{
ast_builder::{
ExprNode, GroupByNode, LimitNode, OffsetNode, OrderByExprList, OrderByNode,
ProjectNode, SelectItemList,
ProjectNode, QueryNode, SelectItemList, TableFactorNode,
},
result::Result,
},
Expand Down Expand Up @@ -57,6 +57,10 @@ impl<'a> HavingNode<'a> {
pub fn order_by<T: Into<OrderByExprList<'a>>>(self, expr_list: T) -> OrderByNode<'a> {
OrderByNode::new(self, expr_list)
}

pub fn alias_as(self, table_alias: &'a str) -> TableFactorNode {
QueryNode::HavingNode(self).alias_as(table_alias)
}
}

impl<'a> Prebuild for HavingNode<'a> {
Expand Down Expand Up @@ -139,5 +143,16 @@ mod tests {
HAVING COUNT(id) > 10
";
test(actual, expected);

// select -> group by -> having -> derived subquery
let actual = table("Foo")
.select()
.group_by("a")
.having("a > 1")
.alias_as("Sub")
.select()
.build();
let expected = "SELECT * FROM (SELECT * FROM Foo GROUP BY a HAVING a > 1) Sub";
test(actual, expected);
}
}
79 changes: 77 additions & 2 deletions core/src/ast_builder/select/join/hash_join.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ use {
ast_builder::{
select::{NodeData, Prebuild},
ExprList, ExprNode, FilterNode, GroupByNode, JoinConstraintNode, JoinNode, LimitNode,
OffsetNode, OrderByExprList, OrderByNode, ProjectNode, SelectItemList,
OffsetNode, OrderByExprList, OrderByNode, ProjectNode, QueryNode, SelectItemList,
TableFactorNode,
},
result::Result,
},
Expand Down Expand Up @@ -106,6 +107,10 @@ impl<'a> HashJoinNode<'a> {

Ok(join_constraint_data)
}

pub fn alias_as(self, table_alias: &'a str) -> TableFactorNode {
QueryNode::HashJoinNode(self).alias_as(table_alias)
}
}

impl<'a> Prebuild for HashJoinNode<'a> {
Expand Down Expand Up @@ -141,7 +146,7 @@ mod tests {
use crate::{
ast::{
Join, JoinConstraint, JoinExecutor, JoinOperator, Query, Select, SetExpr, Statement,
TableFactor, TableWithJoins,
TableAlias, TableFactor, TableWithJoins,
},
ast_builder::{col, expr, table, Build, SelectItemList},
};
Expand Down Expand Up @@ -239,5 +244,75 @@ mod tests {
}))
};
assert_eq!(actual, expected, "with filter");

// join -> hash -> derived subquery
let actual = table("Foo")
.select()
.join("Bar")
.hash_executor("Foo.id", "Bar.id")
.alias_as("Sub")
.select()
.build();

let expected = {
let join = Join {
relation: TableFactor::Table {
name: "Bar".to_owned(),
alias: None,
index: None,
},
join_operator: JoinOperator::Inner(JoinConstraint::None),
join_executor: JoinExecutor::Hash {
key_expr: col("Foo.id").try_into().unwrap(),
value_expr: col("Bar.id").try_into().unwrap(),
where_clause: None,
},
};

let subquery = Select {
projection: SelectItemList::from("*").try_into().unwrap(),
from: TableWithJoins {
relation: TableFactor::Table {
name: "Foo".to_owned(),
alias: None,
index: None,
},
joins: vec![join],
},
selection: None,
group_by: Vec::new(),
having: None,
};

let select = Select {
projection: SelectItemList::from("*").try_into().unwrap(),
from: TableWithJoins {
relation: TableFactor::Derived {
subquery: Query {
body: SetExpr::Select(Box::new(subquery)),
order_by: Vec::new(),
limit: None,
offset: None,
},
alias: TableAlias {
name: "Sub".to_owned(),
columns: Vec::new(),
},
},
joins: Vec::new(),
},
selection: None,
group_by: Vec::new(),
having: None,
};

Ok(Statement::Query(Query {
body: SetExpr::Select(Box::new(select)),
order_by: Vec::new(),
limit: None,
offset: None,
}))
};
assert_eq!(actual, expected);
}
}

0 comments on commit 8c88b9b

Please sign in to comment.