mod blueprint;
mod column;
use crate::{Driver, Error};
pub use blueprint::{Action, Blueprint, ForeignKey};
pub use column::Column;
#[derive(Clone, Copy, PartialEq, Eq)]
#[allow(dead_code)]
pub(crate) enum Dialect {
MySql,
Postgres,
Sqlite,
}
impl Dialect {
pub(crate) fn of(driver: Driver) -> Self {
match driver {
#[cfg(feature = "mysql")]
Driver::MySql => Self::MySql,
#[cfg(feature = "postgres")]
Driver::Postgres => Self::Postgres,
#[cfg(feature = "sqlite")]
Driver::Sqlite => Self::Sqlite,
}
}
}
#[derive(Debug, Clone)]
pub struct Statement {
kind: Kind,
}
#[derive(Debug, Clone)]
enum Kind {
Create { table: String, blueprint: Blueprint },
Drop { table: String, if_exists: bool },
}
pub fn create(table: &str, f: impl FnOnce(&mut Blueprint)) -> Statement {
let mut blueprint = Blueprint::new();
f(&mut blueprint);
Statement {
kind: Kind::Create {
table: table.to_owned(),
blueprint,
},
}
}
pub fn drop(table: &str) -> Statement {
Statement {
kind: Kind::Drop {
table: table.to_owned(),
if_exists: false,
},
}
}
pub fn drop_if_exists(table: &str) -> Statement {
Statement {
kind: Kind::Drop {
table: table.to_owned(),
if_exists: true,
},
}
}
impl Statement {
pub fn to_sql(&self, driver: Driver) -> Vec<String> {
self.try_to_sql(driver)
.unwrap_or_else(|e| panic!("cannot render the schema statement: {e}"))
}
pub fn try_to_sql(&self, driver: Driver) -> Result<Vec<String>, Error> {
let dialect = Dialect::of(driver);
match &self.kind {
Kind::Create { table, blueprint } => blueprint.render(driver, dialect, table),
Kind::Drop { table, if_exists } => {
crate::query::validate(table)?;
let exists = if *if_exists { "IF EXISTS " } else { "" };
Ok(vec![format!("DROP TABLE {exists}{}", driver.quote(table))])
}
}
}
}