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::{NO_PARAMS, 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 From<SelectItem> for SelectItemNode<'_> {
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 From<&str> for SelectItemNode<'_> {
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) => parse_select_item(select_item)
51                .and_then(|item| translate_select_item(&item, NO_PARAMS)),
52            SelectItemNode::Expr(expr_node) => {
53                let expr = Expr::try_from(expr_node)?;
54                let label = expr.to_sql_unquoted();
55
56                Ok(SelectItem::Expr { expr, label })
57            }
58            SelectItemNode::ExprWithAliasNode(alias_node) => {
59                let (expr, label) = alias_node.try_into()?;
60
61                Ok(SelectItem::Expr { expr, label })
62            }
63        }
64    }
65}
66
67#[cfg(test)]
68mod tests {
69    use {
70        crate::{
71            ast::SelectItem,
72            ast_builder::{SelectItemNode, col},
73            parse_sql::parse_select_item,
74            translate::{NO_PARAMS, translate_select_item},
75        },
76        pretty_assertions::assert_eq,
77    };
78
79    fn test(actual: SelectItemNode, expected: &str) {
80        let parsed = &parse_select_item(expected).expect(expected);
81        let expected = translate_select_item(parsed, NO_PARAMS);
82        assert_eq!(actual.try_into(), expected);
83    }
84
85    #[test]
86    fn select_item() {
87        let actual = SelectItem::Wildcard.into();
88        let expected = "*";
89        test(actual, expected);
90
91        let actual = "Foo.*".into();
92        let expected = "Foo.*";
93        test(actual, expected);
94
95        let actual = "id as hello".into();
96        let expected = "id as hello";
97        test(actual, expected);
98
99        let actual = col("id").into();
100        let expected = "id";
101        test(actual, expected);
102    }
103}