Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions src/backend/constraint_builder.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use crate::*;

#[derive(Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum ConstraintMode {
Alter,
TableAlter,
}

pub trait ConstraintBuilder: IndexBuilder {
/// Translate [`ConstraintCreateStatement`] into SQL statement.
fn prepare_constraint_create_statement(
&self,
create: &ConstraintCreateStatement,
sql: &mut impl SqlWriter,
) {
self.prepare_constraint_create_statement_internal(create, sql, ConstraintMode::Alter)
}

#[doc(hidden)]
/// Internal function to factor constraint with alter and without
fn prepare_constraint_create_statement_internal(
&self,
create: &ConstraintCreateStatement,
sql: &mut impl SqlWriter,
mode: ConstraintMode,
);
}
7 changes: 6 additions & 1 deletion src/backend/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@ pub use postgres::*;
#[cfg(feature = "backend-sqlite")]
pub use sqlite::*;

mod constraint_builder;
mod foreign_key_builder;
mod index_builder;
mod query_builder;
mod table_builder;
mod table_ref_builder;

pub use self::constraint_builder::*;
pub use self::foreign_key_builder::*;
pub use self::index_builder::*;
pub use self::query_builder::*;
Expand All @@ -34,7 +36,10 @@ pub use self::table_ref_builder::*;

pub trait GenericBuilder: QueryBuilder + SchemaBuilder {}

pub trait SchemaBuilder: TableBuilder + IndexBuilder + ForeignKeyBuilder {}
pub trait SchemaBuilder:
TableBuilder + IndexBuilder + ForeignKeyBuilder + ConstraintBuilder
{
}

pub trait QuotedBuilder {
/// The type of quote the builder uses.
Expand Down
95 changes: 95 additions & 0 deletions src/backend/mysql/constraint.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
use super::*;

impl ConstraintBuilder for MysqlQueryBuilder {
fn prepare_constraint_create_statement_internal(
&self,
create: &ConstraintCreateStatement,
sql: &mut impl SqlWriter,
mode: ConstraintMode,
) {
let Some(constraint_type) = &create.constraint.constraint_type else {
panic!("No constraint type found");
};

assert!(
create.constraint.using_index.is_none(),
"MySQL does not support USING INDEX in ADD CONSTRAINT"
);
assert!(
!create.constraint.nulls_not_distinct,
"MySQL does not support NULLS NOT DISTINCT in ADD CONSTRAINT"
);
assert!(
create.constraint.include_columns.is_empty(),
"MySQL does not support INCLUDE columns in ADD CONSTRAINT"
);
if matches!(constraint_type, ConstraintCreateStatementType::Check(_)) {
assert!(
create.constraint.index.name.is_none()
&& create.constraint.index.columns.is_empty(),
"MySQL does not support columns or index options on CHECK constraints"
);
} else {
assert!(
!matches!(constraint_type, ConstraintCreateStatementType::PrimaryKey)
|| create.constraint.index.name.is_none(),
"MySQL does not support index names on PRIMARY KEY constraints"
);
if let Some(index_type) = &create.constraint.index_type {
assert!(
matches!(index_type, IndexType::BTree | IndexType::Hash),
"MySQL supports only BTREE or HASH index types in ADD CONSTRAINT UNIQUE/PRIMARY KEY"
);
}
}

if mode == ConstraintMode::Alter {
sql.write_str("ALTER TABLE ").unwrap();
if let Some(table) = &create.table {
self.prepare_table_ref_table_stmt(table, sql);
sql.write_str(" ").unwrap();
}
}

sql.write_str("ADD ").unwrap();

match constraint_type {
ConstraintCreateStatementType::Check(check) => {
self.prepare_check_constraint(check, sql)
}
value => {
if let Some(constraint_name) = &create.constraint.name {
sql.write_str("CONSTRAINT ").unwrap();
sql.write_char(self.quote().left()).unwrap();
sql.write_str(constraint_name).unwrap();
sql.write_char(self.quote().right()).unwrap();
sql.write_str(" ").unwrap();
}

match value {
ConstraintCreateStatementType::PrimaryKey => {
sql.write_str("PRIMARY KEY ").unwrap()
}
ConstraintCreateStatementType::Unique => {
sql.write_str("UNIQUE KEY ").unwrap();
}
_ => unreachable!(),
}

if let Some(index_name) = &create.constraint.index.name {
sql.write_char(self.quote().left()).unwrap();
sql.write_str(index_name).unwrap();
sql.write_char(self.quote().right()).unwrap();
sql.write_str(" ").unwrap();
}

self.prepare_index_type(&create.constraint.index_type, sql);
if matches!(create.constraint.index_type, Some(IndexType::FullText)) {
sql.write_str(" ").unwrap();
}

self.prepare_index_columns(&create.constraint.index.columns, sql);
}
}
}
}
1 change: 1 addition & 0 deletions src/backend/mysql/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub(crate) mod constraint;
pub(crate) mod foreign_key;
pub(crate) mod index;
pub(crate) mod query;
Expand Down
11 changes: 11 additions & 0 deletions src/backend/mysql/table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,17 @@ impl TableBuilder for MysqlQueryBuilder {
sql.write_str("DROP CONSTRAINT ").unwrap();
self.prepare_iden(name, sql);
}
TableAlterOption::AddConstraint(constraint) => {
let create = ConstraintCreateStatement {
constraint: constraint.to_owned(),
table: None,
};
self.prepare_constraint_create_statement_internal(
&create,
sql,
ConstraintMode::TableAlter,
);
}
};
}
);
Expand Down
100 changes: 100 additions & 0 deletions src/backend/postgres/constraint.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
use super::*;

impl ConstraintBuilder for PostgresQueryBuilder {
fn prepare_constraint_create_statement_internal(
&self,
create: &ConstraintCreateStatement,
sql: &mut impl SqlWriter,
mode: ConstraintMode,
) {
let Some(constraint_type) = &create.constraint.constraint_type else {
panic!("No constraint type found");
};

assert!(
create.constraint.index_type.is_none(),
"Postgres does not support index types in ADD CONSTRAINT"
);
if create.constraint.using_index.is_some() {
assert!(
create.constraint.index.columns.is_empty()
&& create.constraint.include_columns.is_empty()
&& !create.constraint.nulls_not_distinct,
"Postgres does not support combining USING INDEX with columns or index options"
);
}
if matches!(constraint_type, ConstraintCreateStatementType::Check(_)) {
assert!(
create.constraint.using_index.is_none(),
"Postgres does not support USING INDEX on CHECK constraints"
);
assert!(
create.constraint.index.columns.is_empty()
&& create.constraint.include_columns.is_empty()
&& !create.constraint.nulls_not_distinct,
"Postgres does not support columns or index options on CHECK constraints"
);
} else {
assert!(
!matches!(constraint_type, ConstraintCreateStatementType::PrimaryKey)
|| !create.constraint.nulls_not_distinct,
"Postgres does not support NULLS NOT DISTINCT on PRIMARY KEY constraints"
);
}

if mode == ConstraintMode::Alter {
sql.write_str("ALTER TABLE ").unwrap();
if let Some(table) = &create.table {
self.prepare_table_ref_table_stmt(table, sql);
sql.write_str(" ").unwrap();
}
}

sql.write_str("ADD ").unwrap();

match constraint_type {
ConstraintCreateStatementType::Check(check) => {
self.prepare_check_constraint(check, sql)
}
ConstraintCreateStatementType::PrimaryKey | ConstraintCreateStatementType::Unique => {
if let Some(name) = &create.constraint.name {
sql.write_str("CONSTRAINT ").unwrap();
sql.write_char(self.quote().left()).unwrap();
sql.write_str(name).unwrap();
sql.write_char(self.quote().right()).unwrap();
sql.write_str(" ").unwrap();
}

match constraint_type {
ConstraintCreateStatementType::PrimaryKey => {
sql.write_str("PRIMARY KEY ").unwrap();
}
ConstraintCreateStatementType::Unique => {
sql.write_str("UNIQUE ").unwrap();
}
ConstraintCreateStatementType::Check(_) => unreachable!(),
}

if let Some(using_index) = &create.constraint.using_index {
sql.write_str("USING INDEX ").unwrap();
self.prepare_iden(using_index, sql);
sql.write_str(" ").unwrap();
}

if create.constraint.nulls_not_distinct {
sql.write_str("NULLS NOT DISTINCT ").unwrap();
}

self.prepare_index_columns(&create.constraint.index.columns, sql);

if !create.constraint.include_columns.is_empty() {
sql.write_str(" ").unwrap();
self.prepare_include_columns(&create.constraint.include_columns, sql);
}

// Used only with `EXCLUDE` constraint
// self.prepare_filter(&create.r#where, sql);
}
};
}
}
2 changes: 1 addition & 1 deletion src/backend/postgres/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ impl IndexBuilder for PostgresQueryBuilder {
}

impl PostgresQueryBuilder {
fn prepare_include_columns(&self, columns: &[DynIden], sql: &mut impl SqlWriter) {
pub(crate) fn prepare_include_columns(&self, columns: &[DynIden], sql: &mut impl SqlWriter) {
sql.write_str("INCLUDE (").unwrap();

let mut cols = columns.iter();
Expand Down
1 change: 1 addition & 0 deletions src/backend/postgres/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub(crate) mod constraint;
pub(crate) mod extension;
pub(crate) mod foreign_key;
pub(crate) mod index;
Expand Down
11 changes: 11 additions & 0 deletions src/backend/postgres/table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,17 @@ impl TableBuilder for PostgresQueryBuilder {
sql.write_str("DROP CONSTRAINT ").unwrap();
self.prepare_iden(name, sql);
}
TableAlterOption::AddConstraint(constraint) => {
let create = ConstraintCreateStatement {
constraint: constraint.to_owned(),
table: None,
};
self.prepare_constraint_create_statement_internal(
&create,
sql,
ConstraintMode::TableAlter,
);
}
}
}
);
Expand Down
12 changes: 12 additions & 0 deletions src/backend/sqlite/constraint.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
use super::*;

impl ConstraintBuilder for SqliteQueryBuilder {
fn prepare_constraint_create_statement_internal(
&self,
_create: &ConstraintCreateStatement,
_sql: &mut impl SqlWriter,
_mode: ConstraintMode,
) {
panic!("Sqlite does not support modification of constraints to existing tables");
}
}
1 change: 1 addition & 0 deletions src/backend/sqlite/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub(crate) mod constraint;
pub(crate) mod foreign_key;
pub(crate) mod index;
pub(crate) mod query;
Expand Down
3 changes: 3 additions & 0 deletions src/backend/sqlite/table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ impl TableBuilder for SqliteQueryBuilder {
TableAlterOption::DropConstraint(_) => {
panic!("Sqlite does not support dropping constraints from existing tables");
}
TableAlterOption::AddConstraint(_) => {
panic!("Sqlite does not support modification of constraints to existing tables");
}
}
}

Expand Down
Loading
Loading