diff --git a/src/schema/entity.rs b/src/schema/entity.rs index 70f0d4ef..5cc3e728 100644 --- a/src/schema/entity.rs +++ b/src/schema/entity.rs @@ -5,6 +5,7 @@ use crate::{ use sea_query::{ extension::postgres::{Type, TypeCreateStatement}, Alias, ColumnDef, ForeignKeyCreateStatement, Iden, Index, TableCreateStatement, + IndexCreateStatement, }; impl Schema { @@ -24,13 +25,22 @@ impl Schema { create_enum_from_entity(entity, self.backend) } - /// Creates a table from an Entity. See [TableCreateStatement] for more details + /// Creates a table from an Entity. See [TableCreateStatement] for more details. pub fn create_table_from_entity(&self, entity: E) -> TableCreateStatement where E: EntityTrait, { create_table_from_entity(entity, self.backend) } + + /// Creates the indexes from an Entity, returning an empty Vec if there are none + /// to create. See [IndexCreateStatement] for more details + pub fn create_index_from_entity(&self, entity: E) -> Vec + where + E: EntityTrait, + { + create_index_from_entity(entity, self.backend) + } } pub(crate) fn create_enum_from_active_enum(backend: DbBackend) -> TypeCreateStatement @@ -77,6 +87,31 @@ where vec } +pub(crate) fn create_index_from_entity(entity: E, _backend: DbBackend) -> Vec + where + E: EntityTrait, +{ + let mut vec = Vec::new(); + for column in E::Column::iter() { + let column_def = column.def(); + if !column_def.indexed { + continue; + } + let stmt = Index::create() + .name(&format!( + "idx-{}-{}", + entity.to_string(), + column.to_string() + )) + .table(entity) + .col(column) + .to_owned(); + vec.push(stmt) + } + vec +} + + pub(crate) fn create_table_from_entity(entity: E, backend: DbBackend) -> TableCreateStatement where E: EntityTrait, @@ -116,18 +151,6 @@ where } } } - if orm_column_def.indexed { - stmt.index( - Index::create() - .name(&format!( - "idx-{}-{}", - entity.to_string(), - column.to_string() - )) - .table(entity) - .col(column), - ); - } stmt.col(&mut column_def); } @@ -206,12 +229,12 @@ mod tests { let schema = Schema::new(builder); assert_eq!( builder.build(&schema.create_table_from_entity(CakeFillingPrice)), - builder.build(&get_stmt().table(CakeFillingPrice.table_ref()).to_owned()) + builder.build(&get_cake_filling_price_stmt().table(CakeFillingPrice.table_ref()).to_owned()) ); } } - fn get_stmt() -> TableCreateStatement { + fn get_cake_filling_price_stmt() -> TableCreateStatement { Table::create() .col( ColumnDef::new(cake_filling_price::Column::CakeId) @@ -247,4 +270,73 @@ mod tests { ) .to_owned() } + + + #[test] + fn test_create_index_from_entity_table_ref() { + for builder in [DbBackend::MySql, DbBackend::Postgres, DbBackend::Sqlite] { + let schema = Schema::new(builder); + + assert_eq!( + builder.build(&schema.create_table_from_entity(indexes::Entity)), + builder.build(&get_indexes_stmt().table(indexes::Entity.table_ref()).to_owned()) + ); + + + let stmts = schema.create_index_from_entity(indexes::Entity); + assert_eq!(stmts.len(), 2); + + + let idx: IndexCreateStatement = Index::create() + .name("idx-indexes-index1_attr") + .table(indexes::Entity) + .col(indexes::Column::Index1Attr) + .to_owned(); + assert_eq!( + builder.build(&stmts[0]), + builder.build(&idx) + ); + + let idx: IndexCreateStatement = Index::create() + .name("idx-indexes-index2_attr") + .table(indexes::Entity) + .col(indexes::Column::Index2Attr) + .to_owned(); + assert_eq!( + builder.build(&stmts[1]), + builder.build(&idx) + ); + } + } + + + fn get_indexes_stmt() -> TableCreateStatement { + Table::create() + .col( + ColumnDef::new(indexes::Column::IndexesId) + .integer() + .not_null() + .auto_increment() + .primary_key(), + ) + .col( + ColumnDef::new(indexes::Column::UniqueAttr) + .integer() + .not_null() + .unique_key(), + ) + .col( + ColumnDef::new(indexes::Column::Index1Attr) + .integer() + .not_null(), + ) + .col( + ColumnDef::new(indexes::Column::Index2Attr) + .integer() + .not_null() + .unique_key(), + ) + .to_owned() + } + } diff --git a/src/tests_cfg/indexes.rs b/src/tests_cfg/indexes.rs new file mode 100644 index 00000000..36738817 --- /dev/null +++ b/src/tests_cfg/indexes.rs @@ -0,0 +1,67 @@ +//! An entity definition for testing table index creation. +use crate as sea_orm; +use crate::entity::prelude::*; + +#[derive(Copy, Clone, Default, Debug, DeriveEntity)] +pub struct Entity; + +impl EntityName for Entity { + fn schema_name(&self) -> Option<&str> { + Some("public") + } + + fn table_name(&self) -> &str { + "indexes" + } +} + +#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)] +pub struct Model { + pub indexes_id: i32, + pub unique_attr: i32, + pub index1_attr: i32, + pub index2_attr: i32, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)] +pub enum Column { + IndexesId, + UniqueAttr, + Index1Attr, + Index2Attr, +} + +#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)] +pub enum PrimaryKey { + IndexesId, +} + +impl PrimaryKeyTrait for PrimaryKey { + type ValueType = i32; + + fn auto_increment() -> bool { + true + } +} + +#[derive(Copy, Clone, Debug, EnumIter)] +pub enum Relation { } + +impl ColumnTrait for Column { + type EntityName = Entity; + + fn def(&self) -> ColumnDef { + match self { + Self::IndexesId => ColumnType::Integer.def(), + Self::UniqueAttr => ColumnType::Integer.def().unique(), + Self::Index1Attr => ColumnType::Integer.def().indexed(), + Self::Index2Attr => ColumnType::Integer.def().indexed().unique(), + } + } +} + +impl RelationTrait for Relation { + fn def(&self) -> RelationDef { panic!() } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/src/tests_cfg/mod.rs b/src/tests_cfg/mod.rs index d6c80b36..008c4f6b 100644 --- a/src/tests_cfg/mod.rs +++ b/src/tests_cfg/mod.rs @@ -9,6 +9,7 @@ pub mod filling; pub mod fruit; pub mod rust_keyword; pub mod vendor; +pub mod indexes; pub use cake::Entity as Cake; pub use cake_expanded::Entity as CakeExpanded;