main
1use anyhow::{Context, Result};
2use sqlparser::dialect::GenericDialect;
3use sqlparser::parser::Parser;
4use std::io::{self, Read};
5
6mod formatter;
7
8use formatter::format_statement;
9
10fn main() {
11 match run() {
12 Ok(()) => std::process::exit(0),
13 Err(_) => std::process::exit(1),
14 }
15}
16
17fn run() -> Result<()> {
18 let mut input = String::new();
19 io::stdin()
20 .read_to_string(&mut input)
21 .context("Failed to read from stdin")?;
22
23 let input = input.trim();
24 if input.is_empty() {
25 return Ok(());
26 }
27
28 let has_semicolon = input.ends_with(';');
29
30 let dialect = GenericDialect {};
31 match Parser::parse_sql(&dialect, input) {
32 Ok(statements) => {
33 let mut output = Vec::new();
34 for (i, statement) in statements.iter().enumerate() {
35 if i > 0 {
36 output.push("\n".to_string());
37 }
38 output.push(format_statement(statement, 0));
39 }
40 let mut formatted = output.join("");
41 formatted = cleanup_whitespace(&formatted);
42 if has_semicolon {
43 formatted.push(';');
44 }
45 println!("{}", formatted);
46 Ok(())
47 }
48 Err(_) => {
49 print!("{}", input);
50 if !input.ends_with('\n') {
51 println!();
52 }
53 Err(anyhow::anyhow!("Parse error"))
54 }
55 }
56}
57
58fn cleanup_whitespace(sql: &str) -> String {
59 sql.trim_end()
60 .lines()
61 .map(|line| line.trim_end())
62 .collect::<Vec<_>>()
63 .join("\n")
64}