use super::{display_comma_separated, DataType, Expr, Ident, ObjectName};
use crate::ast::value::Value;
use std::fmt;
#[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 data_config: Vec<Value>,
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,
Autoincrement,
Collate,
Comment,
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"),
Autoincrement => write!(f, "AUTO_INCREMENT"),
Collate => write!(f, "COLLATE"),
Comment => write!(f, "COMMENT"),
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)
}