Allow for creation of indexes for PostgeSQL and SQLite (#593)
* Allow for creation of indexes for PostgeSQL and SQLite PostgreSQL and SQLite do not allow creation of general indexes within a `CREATE TABLE` statement, so a method is required to generate `CREATE INDEX` statements for these. `create_table_from_entity` avoids creating invalid statements for non-MySQL backends, forcing uses to explicitly run `create_index_from_entity`. Ideally creating indexes would be removed from `create_table_from_entity` entirely, but this would introduce a breaking change for MySQL use. * Remove index creation from create_table_from_entity Use `create_index_from_entity` for all index creation for consistency across all backends. This is a backwards incompatible change, affecting those using MySQL backend when creating the schema only. * Revert change to join_8 test after migration to new indexes entity
This commit is contained in:
parent
fe1f763feb
commit
a09790ef81
@ -5,6 +5,7 @@ use crate::{
|
|||||||
use sea_query::{
|
use sea_query::{
|
||||||
extension::postgres::{Type, TypeCreateStatement},
|
extension::postgres::{Type, TypeCreateStatement},
|
||||||
Alias, ColumnDef, ForeignKeyCreateStatement, Iden, Index, TableCreateStatement,
|
Alias, ColumnDef, ForeignKeyCreateStatement, Iden, Index, TableCreateStatement,
|
||||||
|
IndexCreateStatement,
|
||||||
};
|
};
|
||||||
|
|
||||||
impl Schema {
|
impl Schema {
|
||||||
@ -24,13 +25,22 @@ impl Schema {
|
|||||||
create_enum_from_entity(entity, self.backend)
|
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<E>(&self, entity: E) -> TableCreateStatement
|
pub fn create_table_from_entity<E>(&self, entity: E) -> TableCreateStatement
|
||||||
where
|
where
|
||||||
E: EntityTrait,
|
E: EntityTrait,
|
||||||
{
|
{
|
||||||
create_table_from_entity(entity, self.backend)
|
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<E>(&self, entity: E) -> Vec<IndexCreateStatement>
|
||||||
|
where
|
||||||
|
E: EntityTrait,
|
||||||
|
{
|
||||||
|
create_index_from_entity(entity, self.backend)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn create_enum_from_active_enum<A>(backend: DbBackend) -> TypeCreateStatement
|
pub(crate) fn create_enum_from_active_enum<A>(backend: DbBackend) -> TypeCreateStatement
|
||||||
@ -77,6 +87,31 @@ where
|
|||||||
vec
|
vec
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn create_index_from_entity<E>(entity: E, _backend: DbBackend) -> Vec<IndexCreateStatement>
|
||||||
|
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<E>(entity: E, backend: DbBackend) -> TableCreateStatement
|
pub(crate) fn create_table_from_entity<E>(entity: E, backend: DbBackend) -> TableCreateStatement
|
||||||
where
|
where
|
||||||
E: EntityTrait,
|
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);
|
stmt.col(&mut column_def);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,12 +229,12 @@ mod tests {
|
|||||||
let schema = Schema::new(builder);
|
let schema = Schema::new(builder);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
builder.build(&schema.create_table_from_entity(CakeFillingPrice)),
|
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()
|
Table::create()
|
||||||
.col(
|
.col(
|
||||||
ColumnDef::new(cake_filling_price::Column::CakeId)
|
ColumnDef::new(cake_filling_price::Column::CakeId)
|
||||||
@ -247,4 +270,73 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.to_owned()
|
.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()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
67
src/tests_cfg/indexes.rs
Normal file
67
src/tests_cfg/indexes.rs
Normal file
@ -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 {}
|
@ -9,6 +9,7 @@ pub mod filling;
|
|||||||
pub mod fruit;
|
pub mod fruit;
|
||||||
pub mod rust_keyword;
|
pub mod rust_keyword;
|
||||||
pub mod vendor;
|
pub mod vendor;
|
||||||
|
pub mod indexes;
|
||||||
|
|
||||||
pub use cake::Entity as Cake;
|
pub use cake::Entity as Cake;
|
||||||
pub use cake_expanded::Entity as CakeExpanded;
|
pub use cake_expanded::Entity as CakeExpanded;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user