From 0f164b62d5c4b36d9040d4ef933eeb1cb97a7359 Mon Sep 17 00:00:00 2001 From: Billy Chan <30400950+billy1624@users.noreply.github.com> Date: Fri, 10 Dec 2021 23:41:43 +0800 Subject: [PATCH] Fix related & linked with enum columns (#376) * Fix related & linked with enum columns * Add test cases --- src/entity/link.rs | 2 +- src/query/combine.rs | 30 +- src/query/join.rs | 25 +- tests/active_enum_tests.rs | 565 ++++++++++++++++++ tests/common/features/active_enum.rs | 51 +- tests/common/features/active_enum_child.rs | 43 ++ tests/common/features/mod.rs | 4 + tests/common/features/schema.rs | 59 +- tests/common/features/sea_orm_active_enums.rs | 28 + 9 files changed, 751 insertions(+), 56 deletions(-) create mode 100644 tests/common/features/active_enum_child.rs create mode 100644 tests/common/features/sea_orm_active_enums.rs diff --git a/src/entity/link.rs b/src/entity/link.rs index b929624d..4d91b8a0 100644 --- a/src/entity/link.rs +++ b/src/entity/link.rs @@ -30,7 +30,7 @@ pub trait Linked { select.query().join_as( JoinType::InnerJoin, - unpack_table_ref(&rel.from_tbl), + rel.from_tbl, SeaRc::clone(&from_tbl), join_tbl_on_condition(from_tbl, to_tbl, rel.from_col, rel.to_col), ); diff --git a/src/query/combine.rs b/src/query/combine.rs index a3dcc275..2baf3fa2 100644 --- a/src/query/combine.rs +++ b/src/query/combine.rs @@ -1,9 +1,12 @@ use crate::{ - EntityTrait, IdenStatic, IntoSimpleExpr, Iterable, QueryTrait, Select, SelectTwo, SelectTwoMany, + ColumnTrait, EntityTrait, IdenStatic, IntoSimpleExpr, Iterable, QueryTrait, Select, SelectTwo, + SelectTwoMany, }; use core::marker::PhantomData; pub use sea_query::JoinType; -use sea_query::{Alias, ColumnRef, Iden, Order, SeaRc, SelectExpr, SelectStatement, SimpleExpr}; +use sea_query::{ + Alias, ColumnRef, DynIden, Expr, Iden, Order, SeaRc, SelectExpr, SelectStatement, SimpleExpr, +}; macro_rules! select_def { ( $ident: ident, $str: expr ) => { @@ -42,10 +45,17 @@ where None => { let col = match &sel.expr { SimpleExpr::Column(col_ref) => match &col_ref { - ColumnRef::Column(col) => col, - ColumnRef::TableColumn(_, col) => col, + ColumnRef::Column(col) | ColumnRef::TableColumn(_, col) => col, }, - _ => panic!("cannot apply alias for expr other than Column"), + SimpleExpr::AsEnum(_, simple_expr) => match simple_expr.as_ref() { + SimpleExpr::Column(col_ref) => match &col_ref { + ColumnRef::Column(col) | ColumnRef::TableColumn(_, col) => col, + }, + _ => { + panic!("cannot apply alias for AsEnum with expr other than Column") + } + }, + _ => panic!("cannot apply alias for expr other than Column or AsEnum"), }; let alias = format!("{}{}", pre, col.to_string().as_str()); sel.alias = Some(SeaRc::new(Alias::new(&alias))); @@ -128,10 +138,18 @@ where F: EntityTrait, S: QueryTrait, { + let text_type = SeaRc::new(Alias::new("text")) as DynIden; for col in ::iter() { + let col_def = col.def(); + let col_type = col_def.get_column_type(); let alias = format!("{}{}", SelectB.as_str(), col.as_str()); + let expr = Expr::expr(col.into_simple_expr()); + let expr = match col_type.get_enum_name() { + Some(_) => expr.as_enum(text_type.clone()), + None => expr.into(), + }; selector.query().expr(SelectExpr { - expr: col.into_simple_expr(), + expr, alias: Some(SeaRc::new(Alias::new(&alias))), }); } diff --git a/src/query/join.rs b/src/query/join.rs index 8fb4e0e6..01f1dbd0 100644 --- a/src/query/join.rs +++ b/src/query/join.rs @@ -1,9 +1,9 @@ use crate::{ - join_tbl_on_condition, unpack_table_ref, EntityTrait, IdenStatic, Iterable, Linked, - QuerySelect, Related, Select, SelectA, SelectB, SelectTwo, SelectTwoMany, + join_tbl_on_condition, unpack_table_ref, ColumnTrait, EntityTrait, IdenStatic, Iterable, + Linked, QuerySelect, Related, Select, SelectA, SelectB, SelectTwo, SelectTwoMany, }; pub use sea_query::JoinType; -use sea_query::{Alias, Expr, IntoIden, SeaRc, SelectExpr}; +use sea_query::{Alias, DynIden, Expr, IntoIden, SeaRc, SelectExpr}; impl Select where @@ -79,21 +79,28 @@ where slf.query().join_as( JoinType::LeftJoin, - unpack_table_ref(&rel.to_tbl), + rel.to_tbl, SeaRc::clone(&to_tbl), join_tbl_on_condition(from_tbl, to_tbl, rel.from_col, rel.to_col), ); } slf = slf.apply_alias(SelectA.as_str()); + let text_type = SeaRc::new(Alias::new("text")) as DynIden; let mut select_two = SelectTwo::new_without_prepare(slf.query); for col in ::iter() { + let col_def = col.def(); + let col_type = col_def.get_column_type(); let alias = format!("{}{}", SelectB.as_str(), col.as_str()); + let expr = Expr::tbl( + Alias::new(&format!("r{}", l.link().len() - 1)).into_iden(), + col.into_iden(), + ); + let expr = match col_type.get_enum_name() { + Some(_) => expr.as_enum(text_type.clone()), + None => expr.into(), + }; select_two.query().expr(SelectExpr { - expr: Expr::tbl( - Alias::new(&format!("r{}", l.link().len() - 1)).into_iden(), - col.into_iden(), - ) - .into(), + expr, alias: Some(SeaRc::new(Alias::new(&alias))), }); } diff --git a/tests/active_enum_tests.rs b/tests/active_enum_tests.rs index aaad419b..79db6761 100644 --- a/tests/active_enum_tests.rs +++ b/tests/active_enum_tests.rs @@ -1,6 +1,9 @@ pub mod common; +use active_enum::Entity as ActiveEnum; +use active_enum_child::Entity as ActiveEnumChild; pub use common::{features::*, setup::*, TestContext}; +use pretty_assertions::assert_eq; use sea_orm::{entity::prelude::*, entity::*, DatabaseConnection}; #[sea_orm_macros::test] @@ -13,6 +16,9 @@ async fn main() -> Result<(), DbErr> { let ctx = TestContext::new("active_enum_tests").await; create_tables(&ctx.db).await?; insert_active_enum(&ctx.db).await?; + insert_active_enum_child(&ctx.db).await?; + find_related_active_enum(&ctx.db).await?; + find_linked_active_enum(&ctx.db).await?; ctx.delete().await; Ok(()) @@ -90,3 +96,562 @@ pub async fn insert_active_enum(db: &DatabaseConnection) -> Result<(), DbErr> { Ok(()) } + +pub async fn insert_active_enum_child(db: &DatabaseConnection) -> Result<(), DbErr> { + use active_enum_child::*; + + active_enum::ActiveModel { + category: Set(Some(Category::Small)), + color: Set(Some(Color::White)), + tea: Set(Some(Tea::BreakfastTea)), + ..Default::default() + } + .insert(db) + .await?; + + let am = ActiveModel { + parent_id: Set(2), + category: Set(None), + color: Set(None), + tea: Set(None), + ..Default::default() + } + .insert(db) + .await?; + + let model = Entity::find().one(db).await?.unwrap(); + assert_eq!( + model, + Model { + id: 1, + parent_id: 2, + category: None, + color: None, + tea: None, + } + ); + assert_eq!( + model, + Entity::find() + .filter(Column::Id.is_not_null()) + .filter(Column::Category.is_null()) + .filter(Column::Color.is_null()) + .filter(Column::Tea.is_null()) + .one(db) + .await? + .unwrap() + ); + + ActiveModel { + category: Set(Some(Category::Big)), + color: Set(Some(Color::Black)), + tea: Set(Some(Tea::EverydayTea)), + ..am + } + .save(db) + .await?; + + let model = Entity::find().one(db).await?.unwrap(); + assert_eq!( + model, + Model { + id: 1, + parent_id: 2, + category: Some(Category::Big), + color: Some(Color::Black), + tea: Some(Tea::EverydayTea), + } + ); + assert_eq!( + model, + Entity::find() + .filter(Column::Id.eq(1)) + .filter(Column::Category.eq(Category::Big)) + .filter(Column::Color.eq(Color::Black)) + .filter(Column::Tea.eq(Tea::EverydayTea)) + .one(db) + .await? + .unwrap() + ); + + Ok(()) +} + +pub async fn find_related_active_enum(db: &DatabaseConnection) -> Result<(), DbErr> { + assert_eq!( + active_enum::Model { + id: 2, + category: None, + color: None, + tea: None, + } + .find_related(ActiveEnumChild) + .all(db) + .await?, + vec![active_enum_child::Model { + id: 1, + parent_id: 2, + category: Some(Category::Big), + color: Some(Color::Black), + tea: Some(Tea::EverydayTea), + }] + ); + assert_eq!( + ActiveEnum::find() + .find_with_related(ActiveEnumChild) + .all(db) + .await?, + vec![( + active_enum::Model { + id: 2, + category: Some(Category::Small), + color: Some(Color::White), + tea: Some(Tea::BreakfastTea), + }, + vec![active_enum_child::Model { + id: 1, + parent_id: 2, + category: Some(Category::Big), + color: Some(Color::Black), + tea: Some(Tea::EverydayTea), + }] + )] + ); + assert_eq!( + ActiveEnum::find() + .find_also_related(ActiveEnumChild) + .all(db) + .await?, + vec![( + active_enum::Model { + id: 2, + category: Some(Category::Small), + color: Some(Color::White), + tea: Some(Tea::BreakfastTea), + }, + Some(active_enum_child::Model { + id: 1, + parent_id: 2, + category: Some(Category::Big), + color: Some(Color::Black), + tea: Some(Tea::EverydayTea), + }) + )] + ); + + assert_eq!( + active_enum_child::Model { + id: 1, + parent_id: 2, + category: None, + color: None, + tea: None, + } + .find_related(ActiveEnum) + .all(db) + .await?, + vec![active_enum::Model { + id: 2, + category: Some(Category::Small), + color: Some(Color::White), + tea: Some(Tea::BreakfastTea), + }] + ); + assert_eq!( + ActiveEnumChild::find() + .find_with_related(ActiveEnum) + .all(db) + .await?, + vec![( + active_enum_child::Model { + id: 1, + parent_id: 2, + category: Some(Category::Big), + color: Some(Color::Black), + tea: Some(Tea::EverydayTea), + }, + vec![active_enum::Model { + id: 2, + category: Some(Category::Small), + color: Some(Color::White), + tea: Some(Tea::BreakfastTea), + }] + )] + ); + assert_eq!( + ActiveEnumChild::find() + .find_also_related(ActiveEnum) + .all(db) + .await?, + vec![( + active_enum_child::Model { + id: 1, + parent_id: 2, + category: Some(Category::Big), + color: Some(Color::Black), + tea: Some(Tea::EverydayTea), + }, + Some(active_enum::Model { + id: 2, + category: Some(Category::Small), + color: Some(Color::White), + tea: Some(Tea::BreakfastTea), + }) + )] + ); + + Ok(()) +} + +pub async fn find_linked_active_enum(db: &DatabaseConnection) -> Result<(), DbErr> { + assert_eq!( + active_enum::Model { + id: 2, + category: None, + color: None, + tea: None, + } + .find_linked(active_enum::ActiveEnumChildLink) + .all(db) + .await?, + vec![active_enum_child::Model { + id: 1, + parent_id: 2, + category: Some(Category::Big), + color: Some(Color::Black), + tea: Some(Tea::EverydayTea), + }] + ); + assert_eq!( + ActiveEnum::find() + .find_also_linked(active_enum::ActiveEnumChildLink) + .all(db) + .await?, + vec![( + active_enum::Model { + id: 2, + category: Some(Category::Small), + color: Some(Color::White), + tea: Some(Tea::BreakfastTea), + }, + Some(active_enum_child::Model { + id: 1, + parent_id: 2, + category: Some(Category::Big), + color: Some(Color::Black), + tea: Some(Tea::EverydayTea), + }) + )] + ); + + assert_eq!( + active_enum_child::Model { + id: 1, + parent_id: 2, + category: None, + color: None, + tea: None, + } + .find_linked(active_enum_child::ActiveEnumLink) + .all(db) + .await?, + vec![active_enum::Model { + id: 2, + category: Some(Category::Small), + color: Some(Color::White), + tea: Some(Tea::BreakfastTea), + }] + ); + assert_eq!( + ActiveEnumChild::find() + .find_also_linked(active_enum_child::ActiveEnumLink) + .all(db) + .await?, + vec![( + active_enum_child::Model { + id: 1, + parent_id: 2, + category: Some(Category::Big), + color: Some(Color::Black), + tea: Some(Tea::EverydayTea), + }, + Some(active_enum::Model { + id: 2, + category: Some(Category::Small), + color: Some(Color::White), + tea: Some(Tea::BreakfastTea), + }) + )] + ); + + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + use pretty_assertions::assert_eq; + use sea_orm::{DbBackend, QueryTrait}; + + #[test] + fn active_enum_find_related() { + let active_enum_model = active_enum::Model { + id: 1, + category: None, + color: None, + tea: None, + }; + let select = active_enum_model.find_related(ActiveEnumChild); + assert_eq!( + select.build(DbBackend::MySql).to_string(), + select.build(DbBackend::Sqlite).to_string(), + ); + assert_eq!( + select.build(DbBackend::MySql).to_string(), + [ + "SELECT `active_enum_child`.`id`, `active_enum_child`.`parent_id`, `active_enum_child`.`category`, `active_enum_child`.`color`, `active_enum_child`.`tea`", + "FROM `active_enum_child`", + "INNER JOIN `active_enum` ON `active_enum`.`id` = `active_enum_child`.`parent_id`", + "WHERE `active_enum`.`id` = 1", + ] + .join(" ") + ); + assert_eq!( + select.build(DbBackend::Postgres).to_string(), + [ + r#"SELECT "active_enum_child"."id", "active_enum_child"."parent_id", "active_enum_child"."category", "active_enum_child"."color", CAST("active_enum_child"."tea" AS text)"#, + r#"FROM "public"."active_enum_child""#, + r#"INNER JOIN "public"."active_enum" ON "active_enum"."id" = "active_enum_child"."parent_id""#, + r#"WHERE "active_enum"."id" = 1"#, + ] + .join(" ") + ); + + let select = ActiveEnum::find().find_also_related(ActiveEnumChild); + assert_eq!( + select.build(DbBackend::MySql).to_string(), + select.build(DbBackend::Sqlite).to_string(), + ); + assert_eq!( + select + .build(DbBackend::MySql) + .to_string(), + [ + "SELECT `active_enum`.`id` AS `A_id`, `active_enum`.`category` AS `A_category`, `active_enum`.`color` AS `A_color`, `active_enum`.`tea` AS `A_tea`,", + "`active_enum_child`.`id` AS `B_id`, `active_enum_child`.`parent_id` AS `B_parent_id`, `active_enum_child`.`category` AS `B_category`, `active_enum_child`.`color` AS `B_color`, `active_enum_child`.`tea` AS `B_tea`", + "FROM `active_enum`", + "LEFT JOIN `active_enum_child` ON `active_enum`.`id` = `active_enum_child`.`parent_id`", + ] + .join(" ") + ); + assert_eq!( + select + .build(DbBackend::Postgres) + .to_string(), + [ + r#"SELECT "active_enum"."id" AS "A_id", "active_enum"."category" AS "A_category", "active_enum"."color" AS "A_color", CAST("active_enum"."tea" AS text) AS "A_tea","#, + r#""active_enum_child"."id" AS "B_id", "active_enum_child"."parent_id" AS "B_parent_id", "active_enum_child"."category" AS "B_category", "active_enum_child"."color" AS "B_color", CAST("active_enum_child"."tea" AS text) AS "B_tea""#, + r#"FROM "public"."active_enum""#, + r#"LEFT JOIN "public"."active_enum_child" ON "active_enum"."id" = "active_enum_child"."parent_id""#, + ] + .join(" ") + ); + } + + #[test] + fn active_enum_find_linked() { + let active_enum_model = active_enum::Model { + id: 1, + category: None, + color: None, + tea: None, + }; + let select = active_enum_model.find_linked(active_enum::ActiveEnumChildLink); + assert_eq!( + select.build(DbBackend::MySql).to_string(), + select.build(DbBackend::Sqlite).to_string(), + ); + assert_eq!( + select.build(DbBackend::MySql).to_string(), + [ + "SELECT `active_enum_child`.`id`, `active_enum_child`.`parent_id`, `active_enum_child`.`category`, `active_enum_child`.`color`, `active_enum_child`.`tea`", + "FROM `active_enum_child`", + "INNER JOIN `active_enum` AS `r0` ON `r0`.`id` = `active_enum_child`.`parent_id`", + "WHERE `r0`.`id` = 1", + ] + .join(" ") + ); + assert_eq!( + select.build(DbBackend::Postgres).to_string(), + [ + r#"SELECT "active_enum_child"."id", "active_enum_child"."parent_id", "active_enum_child"."category", "active_enum_child"."color", CAST("active_enum_child"."tea" AS text)"#, + r#"FROM "public"."active_enum_child""#, + r#"INNER JOIN "public"."active_enum" AS "r0" ON "r0"."id" = "active_enum_child"."parent_id""#, + r#"WHERE "r0"."id" = 1"#, + ] + .join(" ") + ); + + let select = ActiveEnum::find().find_also_linked(active_enum::ActiveEnumChildLink); + assert_eq!( + select.build(DbBackend::MySql).to_string(), + select.build(DbBackend::Sqlite).to_string(), + ); + assert_eq!( + select + .build(DbBackend::MySql) + .to_string(), + [ + "SELECT `active_enum`.`id` AS `A_id`, `active_enum`.`category` AS `A_category`, `active_enum`.`color` AS `A_color`, `active_enum`.`tea` AS `A_tea`,", + "`r0`.`id` AS `B_id`, `r0`.`parent_id` AS `B_parent_id`, `r0`.`category` AS `B_category`, `r0`.`color` AS `B_color`, `r0`.`tea` AS `B_tea`", + "FROM `active_enum`", + "LEFT JOIN `active_enum_child` AS `r0` ON `active_enum`.`id` = `r0`.`parent_id`", + ] + .join(" ") + ); + assert_eq!( + select + .build(DbBackend::Postgres) + .to_string(), + [ + r#"SELECT "active_enum"."id" AS "A_id", "active_enum"."category" AS "A_category", "active_enum"."color" AS "A_color", CAST("active_enum"."tea" AS text) AS "A_tea","#, + r#""r0"."id" AS "B_id", "r0"."parent_id" AS "B_parent_id", "r0"."category" AS "B_category", "r0"."color" AS "B_color", CAST("r0"."tea" AS text) AS "B_tea""#, + r#"FROM "public"."active_enum""#, + r#"LEFT JOIN "public"."active_enum_child" AS "r0" ON "active_enum"."id" = "r0"."parent_id""#, + ] + .join(" ") + ); + } + + #[test] + fn active_enum_child_find_related() { + let active_enum_child_model = active_enum_child::Model { + id: 1, + parent_id: 2, + category: None, + color: None, + tea: None, + }; + let select = active_enum_child_model.find_related(ActiveEnum); + assert_eq!( + select.build(DbBackend::MySql).to_string(), + select.build(DbBackend::Sqlite).to_string(), + ); + assert_eq!( + select.build(DbBackend::MySql).to_string(), + [ + "SELECT `active_enum`.`id`, `active_enum`.`category`, `active_enum`.`color`, `active_enum`.`tea`", + "FROM `active_enum`", + "INNER JOIN `active_enum_child` ON `active_enum_child`.`parent_id` = `active_enum`.`id`", + "WHERE `active_enum_child`.`id` = 1", + ] + .join(" ") + ); + assert_eq!( + select.build(DbBackend::Postgres).to_string(), + [ + r#"SELECT "active_enum"."id", "active_enum"."category", "active_enum"."color", CAST("active_enum"."tea" AS text)"#, + r#"FROM "public"."active_enum""#, + r#"INNER JOIN "public"."active_enum_child" ON "active_enum_child"."parent_id" = "active_enum"."id""#, + r#"WHERE "active_enum_child"."id" = 1"#, + ] + .join(" ") + ); + + let select = ActiveEnumChild::find().find_also_related(ActiveEnum); + assert_eq!( + select.build(DbBackend::MySql).to_string(), + select.build(DbBackend::Sqlite).to_string(), + ); + assert_eq!( + select + .build(DbBackend::MySql) + .to_string(), + [ + "SELECT `active_enum_child`.`id` AS `A_id`, `active_enum_child`.`parent_id` AS `A_parent_id`, `active_enum_child`.`category` AS `A_category`, `active_enum_child`.`color` AS `A_color`, `active_enum_child`.`tea` AS `A_tea`,", + "`active_enum`.`id` AS `B_id`, `active_enum`.`category` AS `B_category`, `active_enum`.`color` AS `B_color`, `active_enum`.`tea` AS `B_tea`", + "FROM `active_enum_child`", + "LEFT JOIN `active_enum` ON `active_enum_child`.`parent_id` = `active_enum`.`id`", + ] + .join(" ") + ); + assert_eq!( + select + .build(DbBackend::Postgres) + .to_string(), + [ + r#"SELECT "active_enum_child"."id" AS "A_id", "active_enum_child"."parent_id" AS "A_parent_id", "active_enum_child"."category" AS "A_category", "active_enum_child"."color" AS "A_color", CAST("active_enum_child"."tea" AS text) AS "A_tea","#, + r#""active_enum"."id" AS "B_id", "active_enum"."category" AS "B_category", "active_enum"."color" AS "B_color", CAST("active_enum"."tea" AS text) AS "B_tea""#, + r#"FROM "public"."active_enum_child""#, + r#"LEFT JOIN "public"."active_enum" ON "active_enum_child"."parent_id" = "active_enum"."id""#, + ] + .join(" ") + ); + } + + #[test] + fn active_enum_child_find_linked() { + let active_enum_child_model = active_enum_child::Model { + id: 1, + parent_id: 2, + category: None, + color: None, + tea: None, + }; + let select = active_enum_child_model.find_linked(active_enum_child::ActiveEnumLink); + assert_eq!( + select.build(DbBackend::MySql).to_string(), + select.build(DbBackend::Sqlite).to_string(), + ); + assert_eq!( + select.build(DbBackend::MySql).to_string(), + [ + "SELECT `active_enum`.`id`, `active_enum`.`category`, `active_enum`.`color`, `active_enum`.`tea`", + "FROM `active_enum`", + "INNER JOIN `active_enum_child` AS `r0` ON `r0`.`parent_id` = `active_enum`.`id`", + "WHERE `r0`.`id` = 1", + ] + .join(" ") + ); + assert_eq!( + select.build(DbBackend::Postgres).to_string(), + [ + r#"SELECT "active_enum"."id", "active_enum"."category", "active_enum"."color", CAST("active_enum"."tea" AS text)"#, + r#"FROM "public"."active_enum""#, + r#"INNER JOIN "public"."active_enum_child" AS "r0" ON "r0"."parent_id" = "active_enum"."id""#, + r#"WHERE "r0"."id" = 1"#, + ] + .join(" ") + ); + + let select = ActiveEnumChild::find().find_also_linked(active_enum_child::ActiveEnumLink); + assert_eq!( + select.build(DbBackend::MySql).to_string(), + select.build(DbBackend::Sqlite).to_string(), + ); + assert_eq!( + select + .build(DbBackend::MySql) + .to_string(), + [ + "SELECT `active_enum_child`.`id` AS `A_id`, `active_enum_child`.`parent_id` AS `A_parent_id`, `active_enum_child`.`category` AS `A_category`, `active_enum_child`.`color` AS `A_color`, `active_enum_child`.`tea` AS `A_tea`,", + "`r0`.`id` AS `B_id`, `r0`.`category` AS `B_category`, `r0`.`color` AS `B_color`, `r0`.`tea` AS `B_tea`", + "FROM `active_enum_child`", + "LEFT JOIN `active_enum` AS `r0` ON `active_enum_child`.`parent_id` = `r0`.`id`", + ] + .join(" ") + ); + assert_eq!( + select + .build(DbBackend::Postgres) + .to_string(), + [ + r#"SELECT "active_enum_child"."id" AS "A_id", "active_enum_child"."parent_id" AS "A_parent_id", "active_enum_child"."category" AS "A_category", "active_enum_child"."color" AS "A_color", CAST("active_enum_child"."tea" AS text) AS "A_tea","#, + r#""r0"."id" AS "B_id", "r0"."category" AS "B_category", "r0"."color" AS "B_color", CAST("r0"."tea" AS text) AS "B_tea""#, + r#"FROM "public"."active_enum_child""#, + r#"LEFT JOIN "public"."active_enum" AS "r0" ON "active_enum_child"."parent_id" = "r0"."id""#, + ] + .join(" ") + ); + } +} diff --git a/tests/common/features/active_enum.rs b/tests/common/features/active_enum.rs index 01945993..01422973 100644 --- a/tests/common/features/active_enum.rs +++ b/tests/common/features/active_enum.rs @@ -1,3 +1,4 @@ +use super::sea_orm_active_enums::*; use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel)] @@ -11,33 +12,27 @@ pub struct Model { } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] -pub enum Relation {} +pub enum Relation { + #[sea_orm(has_many = "super::active_enum_child::Entity")] + ActiveEnumChild, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::ActiveEnumChild.def() + } +} + +pub struct ActiveEnumChildLink; + +impl Linked for ActiveEnumChildLink { + type FromEntity = Entity; + + type ToEntity = super::active_enum_child::Entity; + + fn link(&self) -> Vec { + vec![Relation::ActiveEnumChild.def()] + } +} impl ActiveModelBehavior for ActiveModel {} - -#[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum)] -#[sea_orm(rs_type = "String", db_type = "String(Some(1))")] -pub enum Category { - #[sea_orm(string_value = "B")] - Big, - #[sea_orm(string_value = "S")] - Small, -} - -#[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum)] -#[sea_orm(rs_type = "i32", db_type = "Integer")] -pub enum Color { - #[sea_orm(num_value = 0)] - Black, - #[sea_orm(num_value = 1)] - White, -} - -#[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum)] -#[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "tea")] -pub enum Tea { - #[sea_orm(string_value = "EverydayTea")] - EverydayTea, - #[sea_orm(string_value = "BreakfastTea")] - BreakfastTea, -} diff --git a/tests/common/features/active_enum_child.rs b/tests/common/features/active_enum_child.rs new file mode 100644 index 00000000..9c98b280 --- /dev/null +++ b/tests/common/features/active_enum_child.rs @@ -0,0 +1,43 @@ +use super::sea_orm_active_enums::*; +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel)] +#[sea_orm(schema_name = "public", table_name = "active_enum_child")] +pub struct Model { + #[sea_orm(primary_key)] + pub id: i32, + pub parent_id: i32, + pub category: Option, + pub color: Option, + pub tea: Option, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm( + belongs_to = "super::active_enum::Entity", + from = "Column::ParentId", + to = "super::active_enum::Column::Id" + )] + ActiveEnum, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::ActiveEnum.def() + } +} + +pub struct ActiveEnumLink; + +impl Linked for ActiveEnumLink { + type FromEntity = Entity; + + type ToEntity = super::active_enum::Entity; + + fn link(&self) -> Vec { + vec![Relation::ActiveEnum.def()] + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/tests/common/features/mod.rs b/tests/common/features/mod.rs index e354292b..ea880fd2 100644 --- a/tests/common/features/mod.rs +++ b/tests/common/features/mod.rs @@ -1,15 +1,19 @@ pub mod active_enum; +pub mod active_enum_child; pub mod applog; pub mod byte_primary_key; pub mod metadata; pub mod repository; pub mod schema; +pub mod sea_orm_active_enums; pub mod self_join; pub use active_enum::Entity as ActiveEnum; +pub use active_enum_child::Entity as ActiveEnumChild; pub use applog::Entity as Applog; pub use byte_primary_key::Entity as BytePrimaryKey; pub use metadata::Entity as Metadata; pub use repository::Entity as Repository; pub use schema::*; +pub use sea_orm_active_enums::*; pub use self_join::Entity as SelfJoin; diff --git a/tests/common/features/schema.rs b/tests/common/features/schema.rs index 5184c263..91712c91 100644 --- a/tests/common/features/schema.rs +++ b/tests/common/features/schema.rs @@ -9,12 +9,25 @@ use sea_orm::{ use sea_query::{extension::postgres::Type, Alias, ColumnDef, ForeignKeyCreateStatement}; pub async fn create_tables(db: &DatabaseConnection) -> Result<(), DbErr> { + let db_backend = db.get_database_backend(); + create_log_table(db).await?; create_metadata_table(db).await?; create_repository_table(db).await?; create_self_join_table(db).await?; create_byte_primary_key_table(db).await?; + + let create_enum_stmts = match db_backend { + DbBackend::MySql | DbBackend::Sqlite => Vec::new(), + DbBackend::Postgres => vec![Type::create() + .as_enum(Alias::new("tea")) + .values(vec![Alias::new("EverydayTea"), Alias::new("BreakfastTea")]) + .to_owned()], + }; + create_enum(db, &create_enum_stmts, ActiveEnum).await?; + create_active_enum_table(db).await?; + create_active_enum_child_table(db).await?; Ok(()) } @@ -127,18 +140,6 @@ pub async fn create_byte_primary_key_table(db: &DbConn) -> Result Result { - let db_backend = db.get_database_backend(); - - let create_enum_stmts = match db_backend { - DbBackend::MySql | DbBackend::Sqlite => Vec::new(), - DbBackend::Postgres => vec![Type::create() - .as_enum(Alias::new("tea")) - .values(vec![Alias::new("EverydayTea"), Alias::new("BreakfastTea")]) - .to_owned()], - }; - - create_enum(db, &create_enum_stmts, ActiveEnum).await?; - let create_table_stmt = sea_query::Table::create() .table(active_enum::Entity.table_ref()) .col( @@ -158,3 +159,37 @@ pub async fn create_active_enum_table(db: &DbConn) -> Result create_table(db, &create_table_stmt, ActiveEnum).await } + +pub async fn create_active_enum_child_table(db: &DbConn) -> Result { + let create_table_stmt = sea_query::Table::create() + .table(active_enum_child::Entity.table_ref()) + .col( + ColumnDef::new(active_enum_child::Column::Id) + .integer() + .not_null() + .auto_increment() + .primary_key(), + ) + .col( + ColumnDef::new(active_enum_child::Column::ParentId) + .integer() + .not_null(), + ) + .col(ColumnDef::new(active_enum_child::Column::Category).string_len(1)) + .col(ColumnDef::new(active_enum_child::Column::Color).integer()) + .col( + ColumnDef::new(active_enum_child::Column::Tea) + .enumeration("tea", vec!["EverydayTea", "BreakfastTea"]), + ) + .foreign_key( + ForeignKeyCreateStatement::new() + .name("fk-active_enum_child-active_enum") + .from_tbl(ActiveEnumChild) + .from_col(active_enum_child::Column::ParentId) + .to_tbl(ActiveEnum) + .to_col(active_enum::Column::Id), + ) + .to_owned(); + + create_table(db, &create_table_stmt, ActiveEnumChild).await +} diff --git a/tests/common/features/sea_orm_active_enums.rs b/tests/common/features/sea_orm_active_enums.rs new file mode 100644 index 00000000..00bff5b0 --- /dev/null +++ b/tests/common/features/sea_orm_active_enums.rs @@ -0,0 +1,28 @@ +use sea_orm::entity::prelude::*; + +#[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum)] +#[sea_orm(rs_type = "String", db_type = "String(Some(1))")] +pub enum Category { + #[sea_orm(string_value = "B")] + Big, + #[sea_orm(string_value = "S")] + Small, +} + +#[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum)] +#[sea_orm(rs_type = "i32", db_type = "Integer")] +pub enum Color { + #[sea_orm(num_value = 0)] + Black, + #[sea_orm(num_value = 1)] + White, +} + +#[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum)] +#[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "tea")] +pub enum Tea { + #[sea_orm(string_value = "EverydayTea")] + EverydayTea, + #[sea_orm(string_value = "BreakfastTea")] + BreakfastTea, +}