sea-orm/src/schema/entity.rs
2021-10-27 15:23:21 +08:00

217 lines
7.2 KiB
Rust

use crate::{
unpack_table_ref, ColumnTrait, ColumnType, DbBackend, EntityTrait, Identity, Iterable,
PrimaryKeyToColumn, PrimaryKeyTrait, RelationTrait, Schema,
};
use sea_query::{
extension::postgres::{Type, TypeCreateStatement},
Alias, ColumnDef, ForeignKeyCreateStatement, Iden, Index, TableCreateStatement,
};
impl Schema {
pub fn create_enum_from_entity<E>(entity: E, db_backend: DbBackend) -> Vec<TypeCreateStatement>
where
E: EntityTrait,
{
create_enum_from_entity(entity, db_backend)
}
pub fn create_table_from_entity<E>(entity: E, db_backend: DbBackend) -> TableCreateStatement
where
E: EntityTrait,
{
create_table_from_entity(entity, db_backend)
}
}
pub(crate) fn create_enum_from_entity<E>(_: E, db_backend: DbBackend) -> Vec<TypeCreateStatement>
where
E: EntityTrait,
{
if matches!(db_backend, DbBackend::MySql | DbBackend::Sqlite) {
return Vec::new();
}
let mut vec = Vec::new();
for col in E::Column::iter() {
let col_def = col.def();
let col_type = col_def.get_column_type();
if !matches!(col_type, ColumnType::Enum(_, _)) {
continue;
}
let (name, values) = match col_type {
ColumnType::Enum(s, v) => (s.as_str(), v),
_ => unreachable!(),
};
let stmt = Type::create()
.as_enum(Alias::new(name))
.values(values.iter().map(|val| Alias::new(val.as_str())))
.to_owned();
vec.push(stmt);
}
vec
}
pub(crate) fn create_table_from_entity<E>(entity: E, db_backend: DbBackend) -> TableCreateStatement
where
E: EntityTrait,
{
let mut stmt = TableCreateStatement::new();
for column in E::Column::iter() {
let orm_column_def = column.def();
let types = match orm_column_def.col_type {
ColumnType::Enum(s, variants) => match db_backend {
DbBackend::MySql => {
ColumnType::Custom(format!("ENUM('{}')", variants.join("', '")))
}
DbBackend::Postgres => ColumnType::Custom(s),
DbBackend::Sqlite => ColumnType::Text,
}
.into(),
_ => orm_column_def.col_type.into(),
};
let mut column_def = ColumnDef::new_with_type(column, types);
if !orm_column_def.null {
column_def.not_null();
}
if orm_column_def.unique {
column_def.unique_key();
}
for primary_key in E::PrimaryKey::iter() {
if column.to_string() == primary_key.into_column().to_string() {
if E::PrimaryKey::auto_increment() {
column_def.auto_increment();
}
if E::PrimaryKey::iter().count() == 1 {
column_def.primary_key();
}
}
}
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);
}
if E::PrimaryKey::iter().count() > 1 {
let mut idx_pk = Index::create();
for primary_key in E::PrimaryKey::iter() {
idx_pk.col(primary_key);
}
stmt.primary_key(idx_pk.name(&format!("pk-{}", entity.to_string())).primary());
}
for relation in E::Relation::iter() {
let relation = relation.def();
if relation.is_owner {
continue;
}
let mut foreign_key_stmt = ForeignKeyCreateStatement::new();
let from_tbl = unpack_table_ref(&relation.from_tbl);
let to_tbl = unpack_table_ref(&relation.to_tbl);
match relation.from_col {
Identity::Unary(o1) => {
foreign_key_stmt.from_col(o1);
}
Identity::Binary(o1, o2) => {
foreign_key_stmt.from_col(o1);
foreign_key_stmt.from_col(o2);
}
Identity::Ternary(o1, o2, o3) => {
foreign_key_stmt.from_col(o1);
foreign_key_stmt.from_col(o2);
foreign_key_stmt.from_col(o3);
}
}
match relation.to_col {
Identity::Unary(o1) => {
foreign_key_stmt.to_col(o1);
}
Identity::Binary(o1, o2) => {
foreign_key_stmt.to_col(o1);
foreign_key_stmt.to_col(o2);
}
crate::Identity::Ternary(o1, o2, o3) => {
foreign_key_stmt.to_col(o1);
foreign_key_stmt.to_col(o2);
foreign_key_stmt.to_col(o3);
}
}
if let Some(action) = relation.on_delete {
foreign_key_stmt.on_delete(action);
}
if let Some(action) = relation.on_update {
foreign_key_stmt.on_update(action);
}
stmt.foreign_key(
foreign_key_stmt
.name(&format!(
"fk-{}-{}",
from_tbl.to_string(),
to_tbl.to_string()
))
.from_tbl(from_tbl)
.to_tbl(to_tbl),
);
}
stmt.table(entity).take()
}
#[cfg(test)]
mod tests {
use crate::{sea_query::*, tests_cfg::*, DbBackend, Schema};
use pretty_assertions::assert_eq;
#[test]
fn test_create_table_from_entity() {
assert_eq!(
Schema::create_table_from_entity(CakeFillingPrice, DbBackend::MySql)
.to_string(MysqlQueryBuilder),
Table::create()
.table(CakeFillingPrice)
.col(
ColumnDef::new(cake_filling_price::Column::CakeId)
.integer()
.not_null()
)
.col(
ColumnDef::new(cake_filling_price::Column::FillingId)
.integer()
.not_null()
)
.col(
ColumnDef::new(cake_filling_price::Column::Price)
.decimal()
.not_null()
)
.primary_key(
Index::create()
.name("pk-cake_filling_price")
.col(cake_filling_price::Column::CakeId)
.col(cake_filling_price::Column::FillingId)
.primary()
)
.foreign_key(
ForeignKeyCreateStatement::new()
.name("fk-cake_filling_price-cake_filling")
.from_tbl(CakeFillingPrice)
.from_col(cake_filling_price::Column::CakeId)
.from_col(cake_filling_price::Column::FillingId)
.to_tbl(CakeFilling)
.to_col(cake_filling::Column::CakeId)
.to_col(cake_filling::Column::FillingId)
)
.to_string(MysqlQueryBuilder)
);
}
}