use crate::expr::Expr;
use crate::iden::{Ident, IntoIden};
#[derive(Debug)]
pub struct Table;
impl Table {
pub fn create() -> CreateTable {
CreateTable::default()
}
pub fn alter() -> AlterTable {
AlterTable::default()
}
pub fn drop() -> DropTable {
DropTable::default()
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum ColumnType {
Integer,
Boolean,
Real,
Text,
String(Option<u32>),
Blob,
Date,
Time,
DateTime,
TimestampWithTimeZone,
Uuid,
Json,
Decimal,
Any,
Custom(String),
}
impl ColumnType {
pub fn declared(&self) -> &str {
match self {
ColumnType::Integer | ColumnType::Boolean => "INTEGER",
ColumnType::Real => "REAL",
ColumnType::Text
| ColumnType::String(_)
| ColumnType::Date
| ColumnType::Time
| ColumnType::DateTime
| ColumnType::TimestampWithTimeZone
| ColumnType::Uuid
| ColumnType::Json
| ColumnType::Decimal => "TEXT",
ColumnType::Blob => "BLOB",
ColumnType::Any => "ANY",
ColumnType::Custom(s) => s,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ForeignKeyAction {
NoAction,
Restrict,
Cascade,
SetNull,
SetDefault,
}
impl ForeignKeyAction {
pub(crate) fn sql(self) -> &'static str {
match self {
ForeignKeyAction::NoAction => "NO ACTION",
ForeignKeyAction::Restrict => "RESTRICT",
ForeignKeyAction::Cascade => "CASCADE",
ForeignKeyAction::SetNull => "SET NULL",
ForeignKeyAction::SetDefault => "SET DEFAULT",
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ForeignKey {
pub name: Option<Ident>,
pub columns: Vec<Ident>,
pub ref_table: Ident,
pub ref_columns: Vec<Ident>,
pub on_delete: Option<ForeignKeyAction>,
pub on_update: Option<ForeignKeyAction>,
}
impl ForeignKey {
pub fn new<C: IntoIden, R: IntoIden>(
columns: impl IntoIterator<Item = C>,
ref_table: impl IntoIden,
ref_columns: impl IntoIterator<Item = R>,
) -> Self {
Self {
name: None,
columns: columns.into_iter().map(IntoIden::into_iden).collect(),
ref_table: ref_table.into_iden(),
ref_columns: ref_columns.into_iter().map(IntoIden::into_iden).collect(),
on_delete: None,
on_update: None,
}
}
#[must_use]
pub fn name(mut self, name: impl IntoIden) -> Self {
self.name = Some(name.into_iden());
self
}
#[must_use]
pub fn on_delete(mut self, action: ForeignKeyAction) -> Self {
self.on_delete = Some(action);
self
}
#[must_use]
pub fn on_update(mut self, action: ForeignKeyAction) -> Self {
self.on_update = Some(action);
self
}
}
#[derive(Clone, Debug, PartialEq)]
#[allow(
clippy::struct_excessive_bools,
reason = "the flags mirror independent SQL column constraints"
)]
pub struct ColumnDef {
pub name: Ident,
pub ty: ColumnType,
pub not_null: bool,
pub primary_key: bool,
pub auto_increment: bool,
pub unique: bool,
pub default: Option<Expr>,
pub check: Option<Expr>,
}
impl ColumnDef {
pub fn new(name: impl IntoIden, ty: ColumnType) -> Self {
Self {
name: name.into_iden(),
ty,
not_null: false,
primary_key: false,
auto_increment: false,
unique: false,
default: None,
check: None,
}
}
pub fn integer(name: impl IntoIden) -> Self {
Self::new(name, ColumnType::Integer)
}
pub fn boolean(name: impl IntoIden) -> Self {
Self::new(name, ColumnType::Boolean)
}
pub fn real(name: impl IntoIden) -> Self {
Self::new(name, ColumnType::Real)
}
pub fn text(name: impl IntoIden) -> Self {
Self::new(name, ColumnType::Text)
}
pub fn string(name: impl IntoIden, len: Option<u32>) -> Self {
Self::new(name, ColumnType::String(len))
}
pub fn blob(name: impl IntoIden) -> Self {
Self::new(name, ColumnType::Blob)
}
pub fn date(name: impl IntoIden) -> Self {
Self::new(name, ColumnType::Date)
}
pub fn date_time(name: impl IntoIden) -> Self {
Self::new(name, ColumnType::DateTime)
}
pub fn timestamp_with_time_zone(name: impl IntoIden) -> Self {
Self::new(name, ColumnType::TimestampWithTimeZone)
}
pub fn uuid(name: impl IntoIden) -> Self {
Self::new(name, ColumnType::Uuid)
}
pub fn json(name: impl IntoIden) -> Self {
Self::new(name, ColumnType::Json)
}
pub fn decimal(name: impl IntoIden) -> Self {
Self::new(name, ColumnType::Decimal)
}
#[must_use]
pub fn not_null(mut self) -> Self {
self.not_null = true;
self
}
#[must_use]
pub fn null(mut self) -> Self {
self.not_null = false;
self
}
#[must_use]
pub fn primary_key(mut self) -> Self {
self.primary_key = true;
self
}
#[must_use]
pub fn auto_increment(mut self) -> Self {
self.auto_increment = true;
self
}
#[must_use]
pub fn unique_key(mut self) -> Self {
self.unique = true;
self
}
#[must_use]
pub fn default(mut self, value: impl Into<Expr>) -> Self {
self.default = Some(value.into());
self
}
#[must_use]
pub fn check(mut self, expr: Expr) -> Self {
self.check = Some(expr);
self
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum TableConstraint {
PrimaryKey(Vec<Ident>),
Unique(Vec<Ident>),
Check(Expr),
ForeignKey(ForeignKey),
}
#[derive(Clone, Debug, Default, PartialEq)]
pub struct CreateTable {
pub(crate) name: Option<Ident>,
pub(crate) if_not_exists: bool,
pub(crate) columns: Vec<ColumnDef>,
pub(crate) constraints: Vec<TableConstraint>,
pub(crate) strict: bool,
pub(crate) without_rowid: bool,
}
impl CreateTable {
#[must_use]
pub fn table(mut self, name: impl IntoIden) -> Self {
self.name = Some(name.into_iden());
self
}
#[must_use]
pub fn if_not_exists(mut self) -> Self {
self.if_not_exists = true;
self
}
#[must_use]
pub fn col(mut self, column: ColumnDef) -> Self {
self.columns.push(column);
self
}
#[must_use]
pub fn primary_key<C: IntoIden>(mut self, columns: impl IntoIterator<Item = C>) -> Self {
self.constraints.push(TableConstraint::PrimaryKey(
columns.into_iter().map(IntoIden::into_iden).collect(),
));
self
}
#[must_use]
pub fn unique<C: IntoIden>(mut self, columns: impl IntoIterator<Item = C>) -> Self {
self.constraints.push(TableConstraint::Unique(
columns.into_iter().map(IntoIden::into_iden).collect(),
));
self
}
#[must_use]
pub fn check(mut self, expr: Expr) -> Self {
self.constraints.push(TableConstraint::Check(expr));
self
}
#[must_use]
pub fn foreign_key(mut self, fk: ForeignKey) -> Self {
self.constraints.push(TableConstraint::ForeignKey(fk));
self
}
#[must_use]
pub fn strict(mut self) -> Self {
self.strict = true;
self
}
#[must_use]
pub fn without_rowid(mut self) -> Self {
self.without_rowid = true;
self
}
pub fn columns(&self) -> &[ColumnDef] {
&self.columns
}
pub fn name(&self) -> Option<&Ident> {
self.name.as_ref()
}
}
#[derive(Clone, Debug, PartialEq)]
pub(crate) enum AlterOp {
AddColumn(ColumnDef),
DropColumn(Ident),
RenameColumn(Ident, Ident),
RenameTo(Ident),
AlterColumn(Ident, ColumnDef),
}
#[derive(Clone, Debug, Default, PartialEq)]
pub struct AlterTable {
pub(crate) name: Option<Ident>,
pub(crate) op: Option<AlterOp>,
}
impl AlterTable {
#[must_use]
pub fn table(mut self, name: impl IntoIden) -> Self {
self.name = Some(name.into_iden());
self
}
#[must_use]
pub fn add_column(mut self, column: ColumnDef) -> Self {
self.op = Some(AlterOp::AddColumn(column));
self
}
#[must_use]
pub fn drop_column(mut self, column: impl IntoIden) -> Self {
self.op = Some(AlterOp::DropColumn(column.into_iden()));
self
}
#[must_use]
pub fn rename_column(mut self, from: impl IntoIden, to: impl IntoIden) -> Self {
self.op = Some(AlterOp::RenameColumn(from.into_iden(), to.into_iden()));
self
}
#[must_use]
pub fn rename_to(mut self, to: impl IntoIden) -> Self {
self.op = Some(AlterOp::RenameTo(to.into_iden()));
self
}
#[must_use]
pub fn alter_column(mut self, name: impl IntoIden, column: ColumnDef) -> Self {
self.op = Some(AlterOp::AlterColumn(name.into_iden(), column));
self
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct DropTable {
pub(crate) name: Option<Ident>,
pub(crate) if_exists: bool,
}
impl DropTable {
#[must_use]
pub fn table(mut self, name: impl IntoIden) -> Self {
self.name = Some(name.into_iden());
self
}
#[must_use]
pub fn if_exists(mut self) -> Self {
self.if_exists = true;
self
}
}
#[derive(Clone, Debug, Default, PartialEq)]
pub struct CreateIndex {
pub(crate) name: Option<Ident>,
pub(crate) table: Option<Ident>,
pub(crate) columns: Vec<(Ident, Option<crate::Order>)>,
pub(crate) unique: bool,
pub(crate) if_not_exists: bool,
pub(crate) r#where: Option<Expr>,
pub(crate) using: Option<&'static str>,
}
impl CreateIndex {
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn name(mut self, name: impl IntoIden) -> Self {
self.name = Some(name.into_iden());
self
}
#[must_use]
pub fn table(mut self, table: impl IntoIden) -> Self {
self.table = Some(table.into_iden());
self
}
#[must_use]
pub fn col(mut self, column: impl IntoIden) -> Self {
self.columns.push((column.into_iden(), None));
self
}
#[must_use]
pub fn col_order(mut self, column: impl IntoIden, order: crate::Order) -> Self {
self.columns.push((column.into_iden(), Some(order)));
self
}
#[must_use]
pub fn unique(mut self) -> Self {
self.unique = true;
self
}
#[must_use]
pub fn if_not_exists(mut self) -> Self {
self.if_not_exists = true;
self
}
#[must_use]
pub fn and_where(mut self, expr: Expr) -> Self {
self.r#where = Some(expr);
self
}
#[must_use]
pub fn using(mut self, method: &'static str) -> Self {
self.using = Some(method);
self
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct DropIndex {
pub(crate) name: Option<Ident>,
pub(crate) if_exists: bool,
}
impl DropIndex {
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn name(mut self, name: impl IntoIden) -> Self {
self.name = Some(name.into_iden());
self
}
#[must_use]
pub fn if_exists(mut self) -> Self {
self.if_exists = true;
self
}
}