gluesql_core/ast_builder/
select_item.rs

1use {
2    super::ExprNode,
3    crate::{
4        ast::{Expr, SelectItem, ToSqlUnquoted},
5        ast_builder::ExprWithAliasNode,
6        parse_sql::parse_select_item,
7        result::{Error, Result},
8        translate::translate_select_item,
9    },
10};
11
12#[derive(Clone, Debug)]
13pub enum SelectItemNode<'a> {
14    SelectItem(SelectItem),
15    Expr(ExprNode<'a>),
16    Text(String),
17    ExprWithAliasNode(ExprWithAliasNode<'a>),
18}
19
20impl<'a> From<SelectItem> for SelectItemNode<'a> {
21    fn from(select_item: SelectItem) -> Self {
22        Self::SelectItem(select_item)
23    }
24}
25
26impl<'a> From<ExprNode<'a>> for SelectItemNode<'a> {
27    fn from(expr_node: ExprNode<'a>) -> Self {
28        Self::Expr(expr_node)
29    }
30}
31
32impl<'a> From<&str> for SelectItemNode<'a> {
33    fn from(select_item: &str) -> Self {
34        Self::Text(select_item.to_owned())
35    }
36}
37
38impl<'a> From<ExprWithAliasNode<'a>> for SelectItemNode<'a> {
39    fn from(expr_node: ExprWithAliasNode<'a>) -> Self {
40        Self::ExprWithAliasNode(expr_node)
41    }
42}
43
44impl<'a> TryFrom<SelectItemNode<'a>> for SelectItem {
45    type Error = Error;
46
47    fn try_from(select_item_node: SelectItemNode<'a>) -> Result<Self> {
48        match select_item_node {
49            SelectItemNode::SelectItem(select_item) => Ok(select_item),
50            SelectItemNode::Text(select_item) => {
51                parse_select_item(select_item).and_then(|item| translate_select_item(&item))
52            }
53            SelectItemNode::Expr(expr_node) => {
54                let expr = Expr::try_from(expr_node)?;
55                let label = expr.to_sql_unquoted();
56
57                Ok(SelectItem::Expr { expr, label })
58            }
59            SelectItemNode::ExprWithAliasNode(alias_node) => {
60                let (expr, label) = alias_node.try_into()?;
61
62                Ok(SelectItem::Expr { expr, label })
63            }
64        }
65    }
66}
67
68#[cfg(test)]
69mod tests {
70    use {
71        crate::{
72            ast::SelectItem,
73            ast_builder::{SelectItemNode, col},
74            parse_sql::parse_select_item,
75            translate::translate_select_item,
76        },
77        pretty_assertions::assert_eq,
78    };
79
80    fn test(actual: SelectItemNode, expected: &str) {
81        let parsed = &parse_select_item(expected).expect(expected);
82        let expected = translate_select_item(parsed);
83        assert_eq!(actual.try_into(), expected);
84    }
85
86    #[test]
87    fn select_item() {
88        let actual = SelectItem::Wildcard.into();
89        let expected = "*";
90        test(actual, expected);
91
92        let actual = "Foo.*".into();
93        let expected = "Foo.*";
94        test(actual, expected);
95
96        let actual = "id as hello".into();
97        let expected = "id as hello";
98        test(actual, expected);
99
100        let actual = col("id").into();
101        let expected = "id";
102        test(actual, expected);
103    }
104}