Commit e018ad6
Changed files (7)
src
tests
fixtures
create_table_statement
delete_statement
insert_statement
src/formatter.rs
@@ -1,26 +1,17 @@
-use sqlparser::ast::*;
+use sqlparser::ast::{*, Insert, Delete, CreateTable, FromTable};
pub fn format_statement(statement: &Statement, indent_level: usize) -> String {
match statement {
Statement::Query(query) => format_query(query, indent_level),
- Statement::Insert { .. } => {
- // TODO: Fix INSERT statement formatting for new API
- "INSERT statement".to_string()
- }
+ Statement::Insert(insert) => format_insert(insert, indent_level),
Statement::Update {
table,
assignments,
selection,
..
} => format_update(table, assignments, selection, indent_level),
- Statement::Delete { .. } => {
- // TODO: Fix DELETE statement formatting for new API
- "DELETE statement".to_string()
- }
- Statement::CreateTable { .. } => {
- // TODO: Fix CREATE TABLE statement formatting for new API
- "CREATE TABLE statement".to_string()
- }
+ Statement::Delete(delete) => format_delete(delete, indent_level),
+ Statement::CreateTable(create_table) => format_create_table(create_table, indent_level),
_ => statement.to_string(),
}
}
@@ -784,3 +775,145 @@ mod tests {
assert_eq!(parse_and_format(input), expected);
}
}
+
+fn format_insert(insert: &Insert, indent_level: usize) -> String {
+ let mut result = format!("{}INSERT INTO {}", " ".repeat(indent_level), insert.table);
+
+ if !insert.columns.is_empty() {
+ result.push_str(" (");
+ if insert.columns.len() == 1 {
+ result.push_str(&insert.columns[0].value);
+ } else {
+ result.push('\n');
+ for (i, column) in insert.columns.iter().enumerate() {
+ if i > 0 {
+ result.push_str(",\n");
+ }
+ result.push_str(&format!("{} {}", " ".repeat(indent_level), column.value));
+ }
+ result.push('\n');
+ result.push_str(&format!("{}", " ".repeat(indent_level)));
+ }
+ result.push(')');
+ }
+
+ if let Some(source) = &insert.source {
+ result.push('\n');
+ result.push_str(&format!("{}VALUES", " ".repeat(indent_level)));
+ if let SetExpr::Values(values) = &*source.body {
+ for (i, row) in values.rows.iter().enumerate() {
+ if i > 0 {
+ result.push_str(",\n");
+ result.push_str(&format!("{} ", " ".repeat(indent_level)));
+ } else {
+ result.push_str(" (");
+ if row.len() > 1 {
+ result.push('\n');
+ }
+ }
+
+ if row.len() == 1 {
+ result.push_str(&format_expr(&row[0]));
+ } else {
+ for (j, value) in row.iter().enumerate() {
+ if j > 0 {
+ result.push_str(",\n");
+ }
+ result.push_str(&format!("{} {}", " ".repeat(indent_level), format_expr(value)));
+ }
+ result.push('\n');
+ result.push_str(&format!("{}", " ".repeat(indent_level)));
+ }
+ result.push(')');
+ }
+ }
+ }
+
+ result
+}
+
+fn format_delete(delete: &Delete, indent_level: usize) -> String {
+ let mut result = format!("{}DELETE", " ".repeat(indent_level));
+
+ if !delete.tables.is_empty() {
+ result.push(' ');
+ for (i, table) in delete.tables.iter().enumerate() {
+ if i > 0 {
+ result.push_str(", ");
+ }
+ result.push_str(&table.to_string());
+ }
+ }
+
+ match &delete.from {
+ FromTable::WithFromKeyword(tables) => {
+ result.push_str(" FROM");
+ if !tables.is_empty() {
+ result.push(' ');
+ result.push_str(&tables[0].to_string());
+ }
+ }
+ FromTable::WithoutKeyword(tables) => {
+ if !tables.is_empty() {
+ result.push_str(" FROM ");
+ result.push_str(&tables[0].to_string());
+ }
+ }
+ }
+
+ if let Some(selection) = &delete.selection {
+ result.push('\n');
+ result.push_str(&format!(
+ "{}WHERE {}",
+ " ".repeat(indent_level),
+ format_where_expr(selection, indent_level + 2)
+ ));
+ }
+
+ result
+}
+
+fn format_create_table(create_table: &CreateTable, indent_level: usize) -> String {
+ let mut result = format!("{}CREATE TABLE {} (", " ".repeat(indent_level), create_table.name);
+
+ if create_table.columns.len() == 1 {
+ result.push_str(&format_column_def(&create_table.columns[0]));
+ } else {
+ result.push('\n');
+ for (i, column) in create_table.columns.iter().enumerate() {
+ if i > 0 {
+ result.push_str(",\n");
+ }
+ result.push_str(&format!("{} {}", " ".repeat(indent_level), format_column_def(column)));
+ }
+ result.push('\n');
+ result.push_str(&format!("{}", " ".repeat(indent_level)));
+ }
+
+ result.push(')');
+ result
+}
+
+fn format_column_def(column: &ColumnDef) -> String {
+ let mut result = format!("{} {}", column.name.value, column.data_type);
+
+ for option in &column.options {
+ match &option.option {
+ ColumnOption::NotNull => result.push_str(" NOT NULL"),
+ ColumnOption::Null => result.push_str(" NULL"),
+ ColumnOption::Default(expr) => {
+ result.push_str(&format!(" DEFAULT {}", format_expr(expr)));
+ }
+ ColumnOption::Unique { is_primary, .. } => {
+ if *is_primary {
+ result.push_str(" PRIMARY KEY");
+ } else {
+ result.push_str(" UNIQUE");
+ }
+ }
+ _ => {}
+ }
+ }
+
+ result
+}
tests/fixtures/create_table_statement/input.sql
@@ -0,0 +1,1 @@
+CREATE TABLE users (id INTEGER PRIMARY KEY, name VARCHAR(100) NOT NULL, email VARCHAR(255) UNIQUE, active BOOLEAN DEFAULT true)
\ No newline at end of file
tests/fixtures/create_table_statement/output.sql
@@ -0,0 +1,6 @@
+CREATE TABLE users (
+ id INTEGER PRIMARY KEY,
+ name VARCHAR(100) NOT NULL,
+ email VARCHAR(255) UNIQUE,
+ active BOOLEAN DEFAULT TRUE
+);
\ No newline at end of file
tests/fixtures/delete_statement/input.sql
@@ -0,0 +1,1 @@
+DELETE FROM users WHERE active = false AND last_login < '2020-01-01'
\ No newline at end of file
tests/fixtures/delete_statement/output.sql
@@ -0,0 +1,3 @@
+DELETE FROM users
+WHERE active = FALSE
+ AND last_login < '2020-01-01';
\ No newline at end of file
tests/fixtures/insert_statement/input.sql
@@ -0,0 +1,1 @@
+INSERT INTO users (id, name, email, active) VALUES (1, 'John Doe', 'john@example.com', true)
\ No newline at end of file
tests/fixtures/insert_statement/output.sql
@@ -0,0 +1,12 @@
+INSERT INTO users (
+ id,
+ name,
+ email,
+ active
+)
+VALUES (
+ 1,
+ 'John Doe',
+ 'john@example.com',
+ TRUE
+);
\ No newline at end of file