use std::collections::HashSet;
use std::fmt::{Display, Formatter};
use sqlparser::ast::{Expr, ObjectName, Query, SetExpr, SqlOption, TableFactor, Value};
use crate::error::{InvalidTableOptionValueSnafu, Result};
pub fn format_raw_object_name(name: &ObjectName) -> String {
struct Inner<'a> {
name: &'a ObjectName,
}
impl Display for Inner<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let mut delim = "";
for ident in self.name.0.iter() {
write!(f, "{delim}")?;
delim = ".";
write!(f, "{}", ident.value)?;
}
Ok(())
}
}
format!("{}", Inner { name })
}
pub fn parse_option_string(option: SqlOption) -> Result<(String, String)> {
let (key, value) = (option.name, option.value);
let v = match value {
Expr::Value(Value::SingleQuotedString(v)) | Expr::Value(Value::DoubleQuotedString(v)) => v,
Expr::Identifier(v) => v.value,
Expr::Value(Value::Number(v, _)) => v.to_string(),
value => return InvalidTableOptionValueSnafu { key, value }.fail(),
};
let k = key.value.to_lowercase();
Ok((k, v))
}
pub fn extract_tables_from_query(query: &Query) -> impl Iterator<Item = ObjectName> {
let mut names = HashSet::new();
extract_tables_from_set_expr(&query.body, &mut names);
names.into_iter()
}
fn extract_tables_from_set_expr(set_expr: &SetExpr, names: &mut HashSet<ObjectName>) {
match set_expr {
SetExpr::Select(select) => {
for from in &select.from {
table_factor_to_object_name(&from.relation, names);
for join in &from.joins {
table_factor_to_object_name(&join.relation, names);
}
}
}
SetExpr::Query(query) => {
extract_tables_from_set_expr(&query.body, names);
}
SetExpr::SetOperation { left, right, .. } => {
extract_tables_from_set_expr(left, names);
extract_tables_from_set_expr(right, names);
}
SetExpr::Values(_) | SetExpr::Insert(_) | SetExpr::Update(_) | SetExpr::Table(_) => {}
};
}
fn table_factor_to_object_name(table_factor: &TableFactor, names: &mut HashSet<ObjectName>) {
if let TableFactor::Table { name, .. } = table_factor {
names.insert(name.to_owned());
}
}