use super::{display_comma_separated, DataType, Expr, Ident, ObjectName};
use std::fmt;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum AlterTableOperation {
AddColumn(ColumnDef),
AddConstraint(TableConstraint),
DropColumn {
column: Ident,
if_exists: bool,
cascade: bool,
},
DropConstraint {
name: Ident,
},
}
impl fmt::Display for AlterTableOperation {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
AlterTableOperation::AddColumn(column_def) => write!(f, "ADD COLUMN {}", column_def),
AlterTableOperation::AddConstraint(c) => write!(f, "ADD {}", c),
AlterTableOperation::DropColumn {
column,
if_exists,
cascade,
} => write!(
f,
"DROP COLUMN {}{} {}",
if *if_exists { "IF EXISTS " } else { " " },
column,
if *cascade { "CASCADE" } else { "" }
),
AlterTableOperation::DropConstraint { name } => write!(f, "DROP CONSTRAINT {}", name),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum TableConstraint {
Unique {
name: Option<Ident>,
columns: Vec<Ident>,
is_primary: bool,
},
ForeignKey {
name: Option<Ident>,
columns: Vec<Ident>,
foreign_table: ObjectName,
referred_columns: Vec<Ident>,
},
Check {
name: Option<Ident>,
expr: Box<Expr>,
},
}
impl fmt::Display for TableConstraint {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
TableConstraint::Unique {
name,
columns,
is_primary,
} => write!(
f,
"{}{} ({})",
display_constraint_name(name),
if *is_primary { "PRIMARY KEY" } else { "UNIQUE" },
display_comma_separated(columns)
),
TableConstraint::ForeignKey {
name,
columns,
foreign_table,
referred_columns,
} => write!(
f,
"{}FOREIGN KEY ({}) REFERENCES {}({})",
display_constraint_name(name),
display_comma_separated(columns),
foreign_table,
display_comma_separated(referred_columns)
),
TableConstraint::Check { name, expr } => {
write!(f, "{}CHECK ({})", display_constraint_name(name), expr)
}
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ColumnDef {
pub name: Ident,
pub data_type: DataType,
pub collation: Option<ObjectName>,
pub options: Vec<ColumnOptionDef>,
}
impl fmt::Display for ColumnDef {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} {}", self.name, self.data_type)?;
for option in &self.options {
write!(f, " {}", option)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ColumnOptionDef {
pub name: Option<Ident>,
pub option: ColumnOption,
}
impl fmt::Display for ColumnOptionDef {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}{}", display_constraint_name(&self.name), self.option)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum ColumnOption {
Null,
NotNull,
Default(Expr),
Unique {
is_primary: bool,
},
ForeignKey {
foreign_table: ObjectName,
referred_columns: Vec<Ident>,
},
Check(Expr),
}
impl fmt::Display for ColumnOption {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use ColumnOption::*;
match self {
Null => write!(f, "NULL"),
NotNull => write!(f, "NOT NULL"),
Default(expr) => write!(f, "DEFAULT {}", expr),
Unique { is_primary } => {
write!(f, "{}", if *is_primary { "PRIMARY KEY" } else { "UNIQUE" })
}
ForeignKey {
foreign_table,
referred_columns,
} => write!(
f,
"REFERENCES {} ({})",
foreign_table,
display_comma_separated(referred_columns)
),
Check(expr) => write!(f, "CHECK ({})", expr),
}
}
}
fn display_constraint_name<'a>(name: &'a Option<Ident>) -> impl fmt::Display + 'a {
struct ConstraintName<'a>(&'a Option<Ident>);
impl<'a> fmt::Display for ConstraintName<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(name) = self.0 {
write!(f, "CONSTRAINT {} ", name)?;
}
Ok(())
}
}
ConstraintName(name)
}