Skip to main content

chryso_core/
sql_format.rs

1use crate::ast::{Expr, Statement};
2
3pub fn format_statement(statement: &Statement) -> String {
4    crate::ast::statement_to_sql(statement)
5}
6
7pub fn format_expr(expr: &Expr) -> String {
8    expr.to_sql()
9}
10
11#[cfg(test)]
12mod tests {
13    use super::format_statement;
14    use crate::ast::{InsertSource, SelectItem, SelectStatement, Statement, TableFactor, TableRef};
15
16    #[test]
17    fn format_simple_select() {
18        let stmt = Statement::Select(SelectStatement {
19            distinct: false,
20            distinct_on: Vec::new(),
21            projection: vec![SelectItem {
22                expr: crate::ast::Expr::Identifier("id".to_string()),
23                alias: None,
24            }],
25            from: Some(TableRef {
26                factor: TableFactor::Table {
27                    name: "users".to_string(),
28                },
29                alias: None,
30                column_aliases: Vec::new(),
31                joins: Vec::new(),
32            }),
33            selection: None,
34            group_by: Vec::new(),
35            having: None,
36            qualify: None,
37            order_by: Vec::new(),
38            limit: None,
39            offset: None,
40        });
41        let output = format_statement(&stmt);
42        assert_eq!(output, "select id from users");
43    }
44
45    #[test]
46    fn format_update_statement() {
47        let stmt = Statement::Update(crate::ast::UpdateStatement {
48            table: "users".to_string(),
49            assignments: vec![crate::ast::Assignment {
50                column: "name".to_string(),
51                value: crate::ast::Expr::Literal(crate::ast::Literal::String("bob".to_string())),
52            }],
53            selection: Some(crate::ast::Expr::BinaryOp {
54                left: Box::new(crate::ast::Expr::Identifier("id".to_string())),
55                op: crate::ast::BinaryOperator::Eq,
56                right: Box::new(crate::ast::Expr::Literal(crate::ast::Literal::Number(1.0))),
57            }),
58            returning: Vec::new(),
59        });
60        let output = format_statement(&stmt);
61        assert_eq!(output, "update users set name = 'bob' where id = 1");
62    }
63
64    #[test]
65    fn format_insert_multi_values() {
66        let stmt = Statement::Insert(crate::ast::InsertStatement {
67            table: "users".to_string(),
68            columns: vec!["id".to_string(), "name".to_string()],
69            source: InsertSource::Values(vec![
70                vec![
71                    crate::ast::Expr::Literal(crate::ast::Literal::Number(1.0)),
72                    crate::ast::Expr::Literal(crate::ast::Literal::String("alice".to_string())),
73                ],
74                vec![
75                    crate::ast::Expr::Literal(crate::ast::Literal::Number(2.0)),
76                    crate::ast::Expr::Literal(crate::ast::Literal::String("bob".to_string())),
77                ],
78            ]),
79            returning: Vec::new(),
80        });
81        let output = format_statement(&stmt);
82        assert_eq!(
83            output,
84            "insert into users (id, name) values (1, 'alice'), (2, 'bob')"
85        );
86    }
87
88    #[test]
89    fn format_insert_default_values() {
90        let stmt = Statement::Insert(crate::ast::InsertStatement {
91            table: "users".to_string(),
92            columns: Vec::new(),
93            source: InsertSource::DefaultValues,
94            returning: Vec::new(),
95        });
96        let output = format_statement(&stmt);
97        assert_eq!(output, "insert into users default values");
98    }
99
100    #[test]
101    fn format_insert_select() {
102        let select = Statement::Select(SelectStatement {
103            distinct: false,
104            distinct_on: Vec::new(),
105            projection: vec![SelectItem {
106                expr: crate::ast::Expr::Identifier("id".to_string()),
107                alias: None,
108            }],
109            from: Some(TableRef {
110                factor: TableFactor::Table {
111                    name: "staging".to_string(),
112                },
113                alias: None,
114                column_aliases: Vec::new(),
115                joins: Vec::new(),
116            }),
117            selection: None,
118            group_by: Vec::new(),
119            having: None,
120            qualify: None,
121            order_by: Vec::new(),
122            limit: None,
123            offset: None,
124        });
125        let stmt = Statement::Insert(crate::ast::InsertStatement {
126            table: "users".to_string(),
127            columns: vec!["id".to_string()],
128            source: InsertSource::Query(Box::new(select)),
129            returning: Vec::new(),
130        });
131        let output = format_statement(&stmt);
132        assert_eq!(output, "insert into users (id) select id from staging");
133    }
134
135    #[test]
136    fn format_select_without_from() {
137        let stmt = Statement::Select(SelectStatement {
138            distinct: false,
139            distinct_on: Vec::new(),
140            projection: vec![SelectItem {
141                expr: crate::ast::Expr::Literal(crate::ast::Literal::Number(1.0)),
142                alias: None,
143            }],
144            from: None,
145            selection: None,
146            group_by: Vec::new(),
147            having: None,
148            qualify: None,
149            order_by: Vec::new(),
150            limit: None,
151            offset: None,
152        });
153        let output = format_statement(&stmt);
154        assert_eq!(output, "select 1");
155    }
156
157    #[test]
158    fn format_select_without_from_with_order_limit() {
159        let stmt = Statement::Select(SelectStatement {
160            distinct: false,
161            distinct_on: Vec::new(),
162            projection: vec![SelectItem {
163                expr: crate::ast::Expr::Literal(crate::ast::Literal::Number(1.0)),
164                alias: None,
165            }],
166            from: None,
167            selection: None,
168            group_by: Vec::new(),
169            having: None,
170            qualify: None,
171            order_by: vec![crate::ast::OrderByExpr {
172                expr: crate::ast::Expr::Literal(crate::ast::Literal::Number(1.0)),
173                asc: true,
174                nulls_first: None,
175            }],
176            limit: Some(2),
177            offset: Some(1),
178        });
179        let output = format_statement(&stmt);
180        assert_eq!(output, "select 1 order by 1 asc limit 2 offset 1");
181    }
182
183    #[test]
184    fn format_create_table_if_not_exists() {
185        let stmt = Statement::CreateTable(crate::ast::CreateTableStatement {
186            name: "users".to_string(),
187            if_not_exists: true,
188            columns: Vec::new(),
189        });
190        let output = format_statement(&stmt);
191        assert_eq!(output, "create table if not exists users");
192    }
193
194    #[test]
195    fn format_create_table_with_columns() {
196        let stmt = Statement::CreateTable(crate::ast::CreateTableStatement {
197            name: "users".to_string(),
198            if_not_exists: false,
199            columns: vec![
200                crate::ast::ColumnDef {
201                    name: "id".to_string(),
202                    data_type: "integer".to_string(),
203                },
204                crate::ast::ColumnDef {
205                    name: "name".to_string(),
206                    data_type: "varchar(20)".to_string(),
207                },
208            ],
209        });
210        let output = format_statement(&stmt);
211        assert_eq!(output, "create table users (id integer, name varchar(20))");
212    }
213}