mod blueprint;
mod column;
use crate::{Driver, Error};
pub use blueprint::{Action, Blueprint, ForeignKey, Index};
pub use column::Column;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Dialect {
MySql,
Postgres,
Sqlite,
}
impl Dialect {
pub 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,
only: Option<Dialect>,
}
#[derive(Debug, Clone)]
enum Kind {
Create {
table: String,
blueprint: Blueprint,
if_not_exists: bool,
},
Alter {
table: String,
blueprint: Blueprint,
},
Drop {
table: String,
if_exists: bool,
},
Raw(String),
}
pub fn create(table: &str, f: impl FnOnce(&mut Blueprint)) -> Statement {
creating(table, f, false)
}
pub fn create_if_not_exists(table: &str, f: impl FnOnce(&mut Blueprint)) -> Statement {
creating(table, f, true)
}
fn creating(table: &str, f: impl FnOnce(&mut Blueprint), if_not_exists: bool) -> Statement {
let mut blueprint = Blueprint::new();
f(&mut blueprint);
Statement {
kind: Kind::Create {
table: table.to_owned(),
blueprint,
if_not_exists,
},
only: None,
}
}
pub fn table(table: &str, f: impl FnOnce(&mut Blueprint)) -> Statement {
let mut blueprint = Blueprint::new();
f(&mut blueprint);
Statement {
kind: Kind::Alter {
table: table.to_owned(),
blueprint,
},
only: None,
}
}
pub fn drop(table: &str) -> Statement {
Statement {
kind: Kind::Drop {
table: table.to_owned(),
if_exists: false,
},
only: None,
}
}
pub fn drop_if_exists(table: &str) -> Statement {
Statement {
kind: Kind::Drop {
table: table.to_owned(),
if_exists: true,
},
only: None,
}
}
pub fn statement(sql: impl Into<String>) -> Statement {
Statement {
kind: Kind::Raw(sql.into()),
only: None,
}
}
impl Statement {
pub fn only(mut self, dialect: Dialect) -> Self {
self.only = Some(dialect);
self
}
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);
if self.only.is_some_and(|only| only != dialect) {
return Ok(Vec::new());
}
match &self.kind {
Kind::Create {
table,
blueprint,
if_not_exists,
} => blueprint.render_create(driver, dialect, table, *if_not_exists),
Kind::Alter { table, blueprint } => blueprint.render_alter(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))])
}
Kind::Raw(sql) => Ok(vec![sql.clone()]),
}
}
}