mod query;
mod sql_operator;
mod sqltype;
mod table_key;
mod value;
pub use self::query::{
Cte, Join, JoinConstraint, JoinOperator, SQLOrderByExpr, SQLQuery, SQLSelect, SQLSelectItem,
SQLSetExpr, SQLSetOperator, TableFactor,
};
pub use self::sqltype::SQLType;
pub use self::table_key::{AlterOperation, Key, TableKey};
pub use self::value::Value;
pub use self::sql_operator::SQLOperator;
pub type SQLIdent = String;
#[derive(Debug, Clone, PartialEq)]
pub enum ASTNode {
SQLIdentifier(SQLIdent),
SQLWildcard,
SQLQualifiedWildcard(Vec<SQLIdent>),
SQLCompoundIdentifier(Vec<SQLIdent>),
SQLIsNull(Box<ASTNode>),
SQLIsNotNull(Box<ASTNode>),
SQLInList {
expr: Box<ASTNode>,
list: Vec<ASTNode>,
negated: bool,
},
SQLInSubquery {
expr: Box<ASTNode>,
subquery: Box<SQLQuery>,
negated: bool,
},
SQLBetween {
expr: Box<ASTNode>,
negated: bool,
low: Box<ASTNode>,
high: Box<ASTNode>,
},
SQLBinaryExpr {
left: Box<ASTNode>,
op: SQLOperator,
right: Box<ASTNode>,
},
SQLCast {
expr: Box<ASTNode>,
data_type: SQLType,
},
SQLNested(Box<ASTNode>),
SQLUnary {
operator: SQLOperator,
expr: Box<ASTNode>,
},
SQLValue(Value),
SQLFunction { id: SQLIdent, args: Vec<ASTNode> },
SQLCase {
conditions: Vec<ASTNode>,
results: Vec<ASTNode>,
else_result: Option<Box<ASTNode>>,
},
SQLSubquery(Box<SQLQuery>),
}
impl ToString for ASTNode {
fn to_string(&self) -> String {
match self {
ASTNode::SQLIdentifier(s) => s.to_string(),
ASTNode::SQLWildcard => "*".to_string(),
ASTNode::SQLQualifiedWildcard(q) => q.join(".") + "*",
ASTNode::SQLCompoundIdentifier(s) => s.join("."),
ASTNode::SQLIsNull(ast) => format!("{} IS NULL", ast.as_ref().to_string()),
ASTNode::SQLIsNotNull(ast) => format!("{} IS NOT NULL", ast.as_ref().to_string()),
ASTNode::SQLInList {
expr,
list,
negated,
} => format!(
"{} {}IN ({})",
expr.as_ref().to_string(),
if *negated { "NOT " } else { "" },
list.iter()
.map(|a| a.to_string())
.collect::<Vec<String>>()
.join(", ")
),
ASTNode::SQLInSubquery {
expr,
subquery,
negated,
} => format!(
"{} {}IN ({})",
expr.as_ref().to_string(),
if *negated { "NOT " } else { "" },
subquery.to_string()
),
ASTNode::SQLBetween {
expr,
negated,
low,
high,
} => format!(
"{} {}BETWEEN {} AND {}",
expr.to_string(),
if *negated { "NOT " } else { "" },
low.to_string(),
high.to_string()
),
ASTNode::SQLBinaryExpr { left, op, right } => format!(
"{} {} {}",
left.as_ref().to_string(),
op.to_string(),
right.as_ref().to_string()
),
ASTNode::SQLCast { expr, data_type } => format!(
"CAST({} AS {})",
expr.as_ref().to_string(),
data_type.to_string()
),
ASTNode::SQLNested(ast) => format!("({})", ast.as_ref().to_string()),
ASTNode::SQLUnary { operator, expr } => {
format!("{} {}", operator.to_string(), expr.as_ref().to_string())
}
ASTNode::SQLValue(v) => v.to_string(),
ASTNode::SQLFunction { id, args } => format!(
"{}({})",
id,
args.iter()
.map(|a| a.to_string())
.collect::<Vec<String>>()
.join(", ")
),
ASTNode::SQLCase {
conditions,
results,
else_result,
} => {
let mut s = format!(
"CASE {}",
conditions
.iter()
.zip(results)
.map(|(c, r)| format!("WHEN {} THEN {}", c.to_string(), r.to_string()))
.collect::<Vec<String>>()
.join(" ")
);
if let Some(else_result) = else_result {
s += &format!(" ELSE {}", else_result.to_string())
}
s + " END"
}
ASTNode::SQLSubquery(s) => format!("({})", s.to_string()),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum SQLStatement {
SQLSelect(SQLQuery),
SQLInsert {
table_name: SQLObjectName,
columns: Vec<SQLIdent>,
values: Vec<Vec<ASTNode>>,
},
SQLCopy {
table_name: SQLObjectName,
columns: Vec<SQLIdent>,
values: Vec<Option<String>>,
},
SQLUpdate {
table_name: SQLObjectName,
assignments: Vec<SQLAssignment>,
selection: Option<ASTNode>,
},
SQLDelete {
table_name: SQLObjectName,
selection: Option<ASTNode>,
},
SQLCreateView {
name: SQLObjectName,
query: SQLQuery,
materialized: bool,
},
SQLCreateTable {
name: SQLObjectName,
columns: Vec<SQLColumnDef>,
},
SQLAlterTable {
name: SQLObjectName,
operation: AlterOperation,
},
}
impl ToString for SQLStatement {
fn to_string(&self) -> String {
match self {
SQLStatement::SQLSelect(s) => s.to_string(),
SQLStatement::SQLInsert {
table_name,
columns,
values,
} => {
let mut s = format!("INSERT INTO {}", table_name.to_string());
if columns.len() > 0 {
s += &format!(" ({})", columns.join(", "));
}
if values.len() > 0 {
s += &format!(
" VALUES({})",
values
.iter()
.map(|row| row
.iter()
.map(|c| c.to_string())
.collect::<Vec<String>>()
.join(", "))
.collect::<Vec<String>>()
.join(", ")
);
}
s
}
SQLStatement::SQLCopy {
table_name,
columns,
values,
} => {
let mut s = format!("COPY {}", table_name.to_string());
if columns.len() > 0 {
s += &format!(
" ({})",
columns
.iter()
.map(|c| c.to_string())
.collect::<Vec<String>>()
.join(", ")
);
}
s += " FROM stdin; ";
if values.len() > 0 {
s += &format!(
"\n{}",
values
.iter()
.map(|v| v.clone().unwrap_or("\\N".to_string()))
.collect::<Vec<String>>()
.join("\t")
);
}
s += "\n\\.";
s
}
SQLStatement::SQLUpdate {
table_name,
assignments,
selection,
} => {
let mut s = format!("UPDATE {}", table_name.to_string());
if assignments.len() > 0 {
s += &format!(
"{}",
assignments
.iter()
.map(|ass| ass.to_string())
.collect::<Vec<String>>()
.join(", ")
);
}
if let Some(selection) = selection {
s += &format!(" WHERE {}", selection.to_string());
}
s
}
SQLStatement::SQLDelete {
table_name,
selection,
} => {
let mut s = format!("DELETE FROM {}", table_name.to_string());
if let Some(selection) = selection {
s += &format!(" WHERE {}", selection.to_string());
}
s
}
SQLStatement::SQLCreateView {
name,
query,
materialized,
} => {
let modifier = if *materialized { " MATERIALIZED" } else { "" };
format!(
"CREATE{} VIEW {} AS {}",
modifier,
name.to_string(),
query.to_string()
)
}
SQLStatement::SQLCreateTable { name, columns } => format!(
"CREATE TABLE {} ({})",
name.to_string(),
columns
.iter()
.map(|c| c.to_string())
.collect::<Vec<String>>()
.join(", ")
),
SQLStatement::SQLAlterTable { name, operation } => {
format!("ALTER TABLE {} {}", name.to_string(), operation.to_string())
}
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct SQLObjectName(pub Vec<SQLIdent>);
impl ToString for SQLObjectName {
fn to_string(&self) -> String {
self.0.join(".")
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct SQLAssignment {
id: SQLIdent,
value: ASTNode,
}
impl ToString for SQLAssignment {
fn to_string(&self) -> String {
format!("SET {} = {}", self.id, self.value.to_string())
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct SQLColumnDef {
pub name: SQLIdent,
pub data_type: SQLType,
pub is_primary: bool,
pub is_unique: bool,
pub default: Option<ASTNode>,
pub allow_null: bool,
}
impl ToString for SQLColumnDef {
fn to_string(&self) -> String {
let mut s = format!("{} {}", self.name, self.data_type.to_string());
if self.is_primary {
s += " PRIMARY KEY";
}
if self.is_unique {
s += " UNIQUE";
}
if let Some(ref default) = self.default {
s += &format!(" DEFAULT {}", default.to_string());
}
if !self.allow_null {
s += " NOT NULL";
}
s
}
}