From 4c99f7ac3260c585ac950c5263656e5013c12761 Mon Sep 17 00:00:00 2001 From: Yiu Tin Cheung Ivan Date: Tue, 15 Aug 2023 19:00:08 +0800 Subject: [PATCH 01/23] adds find_with_linked test --- tests/active_enum_tests.rs | 42 ++++++++++++++++++++++++++++++++++++++ tests/crud/updates.rs | 1 + tests/value_type_tests.rs | 1 + 3 files changed, 44 insertions(+) diff --git a/tests/active_enum_tests.rs b/tests/active_enum_tests.rs index 14ebb436b..e1aff3f98 100644 --- a/tests/active_enum_tests.rs +++ b/tests/active_enum_tests.rs @@ -371,6 +371,27 @@ pub async fn find_linked_active_enum(db: &DatabaseConnection) -> Result<(), DbEr }) )] ); + assert_eq!( + ActiveEnum::find() + .find_with_linked(active_enum::ActiveEnumChildLink) + .all(db) + .await?, + [( + 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!( active_enum_child::Model { @@ -411,6 +432,27 @@ pub async fn find_linked_active_enum(db: &DatabaseConnection) -> Result<(), DbEr }) )] ); + assert_eq!( + ActiveEnumChild::find() + .find_with_linked(active_enum_child::ActiveEnumLink) + .all(db) + .await?, + [( + 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), + }] + )] + ); Ok(()) } diff --git a/tests/crud/updates.rs b/tests/crud/updates.rs index 5c1f39d90..6dbd29e93 100644 --- a/tests/crud/updates.rs +++ b/tests/crud/updates.rs @@ -52,6 +52,7 @@ pub async fn test_update_cake(db: &DbConn) { let cake_model = cake.unwrap(); assert_eq!(cake_model.name, "Extra chocolate mud cake"); assert_eq!(cake_model.price, dec!(20.00)); + assert!(!cake_model.gluten_free); } pub async fn test_update_bakery(db: &DbConn) { diff --git a/tests/value_type_tests.rs b/tests/value_type_tests.rs index 227186606..6c2748d3d 100644 --- a/tests/value_type_tests.rs +++ b/tests/value_type_tests.rs @@ -71,6 +71,7 @@ pub fn type_test() { assert_eq!(Integer::array_type(), ArrayType::Int); assert_eq!(Boolbean::column_type(), ColumnType::Boolean); assert_eq!(Boolbean::array_type(), ArrayType::Bool); + // self implied assert_eq!( StringVec::column_type(), From cdc75efd44f8d3e25cb6f603176e3240ed29bd19 Mon Sep 17 00:00:00 2001 From: Yiu Tin Cheung Ivan Date: Tue, 15 Aug 2023 19:00:25 +0800 Subject: [PATCH 02/23] WIP(related test) --- tests/relational_tests.rs | 294 +++++++++++++++++++++++++++++++++++++- 1 file changed, 292 insertions(+), 2 deletions(-) diff --git a/tests/relational_tests.rs b/tests/relational_tests.rs index a2994ee84..d93398dc7 100644 --- a/tests/relational_tests.rs +++ b/tests/relational_tests.rs @@ -494,6 +494,270 @@ pub async fn having() { ctx.delete().await; } +#[sea_orm_macros::test] +#[cfg(any( + feature = "sqlx-mysql", + feature = "sqlx-sqlite", + feature = "sqlx-postgres" +))] +pub async fn related() -> Result<(), DbErr> { + use sea_orm::{SelectA, SelectB}; + use sea_query::{Alias, Expr}; + + let ctx = TestContext::new("test_related").await; + create_tables(&ctx.db).await?; + + // SeaSide Bakery + let seaside_bakery = bakery::ActiveModel { + name: Set("SeaSide Bakery".to_owned()), + profit_margin: Set(10.4), + ..Default::default() + }; + let seaside_bakery_res = Bakery::insert(seaside_bakery).exec(&ctx.db).await?; + + // Bob's Baker + let baker_bob = baker::ActiveModel { + name: Set("Baker Bob".to_owned()), + contact_details: Set(serde_json::json!({ + "mobile": "+61424000000", + "home": "0395555555", + "address": "12 Test St, Testville, Vic, Australia" + })), + bakery_id: Set(Some(seaside_bakery_res.last_insert_id)), + ..Default::default() + }; + let baker_bob_res = Baker::insert(baker_bob).exec(&ctx.db).await?; + + // Bobby's Baker + let baker_bobby = baker::ActiveModel { + name: Set("Baker Bobby".to_owned()), + contact_details: Set(serde_json::json!({ + "mobile": "+85212345678", + })), + bakery_id: Set(Some(seaside_bakery_res.last_insert_id)), + ..Default::default() + }; + let baker_bobby_res = Baker::insert(baker_bobby).exec(&ctx.db).await?; + + // Terres Bakery + let terres_bakery = bakery::ActiveModel { + name: Set("Terres Bakery".to_owned()), + profit_margin: Set(13.5), + ..Default::default() + }; + let terres_bakery_res = Bakery::insert(terres_bakery).exec(&ctx.db).await?; + + // Ada's Baker + let baker_ada = baker::ActiveModel { + name: Set("Baker Ada".to_owned()), + contact_details: Set(serde_json::json!({ + "mobile": "+61424000000", + "home": "0395555555", + "address": "12 Test St, Testville, Vic, Australia" + })), + bakery_id: Set(Some(terres_bakery_res.last_insert_id)), + ..Default::default() + }; + let baker_ada_res = Baker::insert(baker_ada).exec(&ctx.db).await?; + + // Stone Bakery, with no baker + let stone_bakery = bakery::ActiveModel { + name: Set("Stone Bakery".to_owned()), + profit_margin: Set(13.5), + ..Default::default() + }; + let stone_bakery_res = Bakery::insert(stone_bakery).exec(&ctx.db).await?; + + #[derive(Debug, FromQueryResult, PartialEq)] + struct BakerLite { + name: String, + } + + #[derive(Debug, FromQueryResult, PartialEq)] + struct BakeryLite { + name: String, + } + + let bakers_in_bakery: Vec<(BakeryLite, Option)> = Bakery::find() + .find_also_related(Baker) + .select_only() + .column_as(bakery::Column::Name, (SelectA, bakery::Column::Name)) + .column_as( + Expr::col((Alias::new("r"), baker::Column::Name)), + (SelectB, baker::Column::Name), + ) + .group_by(bakery::Column::Id) + .group_by(Expr::col((Alias::new("r"), baker::Column::Id))) + .order_by_asc(bakery::Column::Id) + .order_by_asc(Expr::col((Alias::new("r"), baker::Column::Id))) + .into_model() + .all(&ctx.db) + .await?; + + assert_eq!( + bakers_in_bakery, + [ + ( + BakeryLite { + name: "Seaside Bakery".to_owned(), + }, + Some(BakerLite { + name: "Bob".to_owned(), + }) + ), + ( + BakeryLite { + name: "Seaside Bakery".to_owned(), + }, + Some(BakerLite { + name: "Bobby".to_owned(), + }) + ), + ( + BakeryLite { + name: "Terres Bakery".to_owned(), + }, + Some(BakerLite { + name: "Ada".to_owned(), + }) + ), + ( + BakeryLite { + name: "Stone bakery".to_owned(), + }, + None, + ), + ] + ); + + let seaside_bakery = Bakery::find() + .filter(bakery::Column::Id.eq(1)) + .one(&ctx.db) + .await? + .unwrap(); + + let bakers = seaside_bakery + .find_related(bakery::Relation::Baker) + .all(&ctx.db) + .await?; + + assert_eq!( + bakers, + [baker::Model { + id: 1, + name: "Baker Bob".to_owned(), + contact_details: serde_json::json!({ + "mobile": "+61424000000", + "home": "0395555555", + "address": "12 Test St, Testville, Vic, Australia" + }), + bakery_id: Some(1), + }, + baker::Model { + id: 1, + name: "Baker Bobby".to_owned(), + contact_details: serde_json::json!({ + "mobile": "+85212345678", + }), + bakery_id: Some(1), + }] + ); + + // let select_baker_with_customer = Baker::find() + // .find_with_linked(baker::BakedForCustomer) + // .order_by_asc(baker::Column::Id) + // .order_by_asc(Expr::col((Alias::new("r4"), customer::Column::Id))); + + // assert_eq!( + // select_baker_with_customer + // .build(sea_orm::DatabaseBackend::MySql) + // .to_string(), + // [ + // "SELECT `baker`.`id` AS `A_id`,", + // "`baker`.`name` AS `A_name`,", + // "`baker`.`contact_details` AS `A_contact_details`,", + // "`baker`.`bakery_id` AS `A_bakery_id`,", + // "`r4`.`id` AS `B_id`,", + // "`r4`.`name` AS `B_name`,", + // "`r4`.`notes` AS `B_notes`", + // "FROM `baker`", + // "LEFT JOIN `cakes_bakers` AS `r0` ON `baker`.`id` = `r0`.`baker_id`", + // "LEFT JOIN `cake` AS `r1` ON `r0`.`cake_id` = `r1`.`id`", + // "LEFT JOIN `lineitem` AS `r2` ON `r1`.`id` = `r2`.`cake_id`", + // "LEFT JOIN `order` AS `r3` ON `r2`.`order_id` = `r3`.`id`", + // "LEFT JOIN `customer` AS `r4` ON `r3`.`customer_id` = `r4`.`id`", + // "ORDER BY `baker`.`id` ASC, `r4`.`id` ASC" + // ] + // .join(" ") + // ); + + // assert_eq!( + // select_baker_with_customer.all(&ctx.db).await?, + // [ + // ( + // baker::Model { + // id: 1, + // name: "Baker Bob".into(), + // contact_details: serde_json::json!({ + // "mobile": "+61424000000", + // "home": "0395555555", + // "address": "12 Test St, Testville, Vic, Australia", + // }), + // bakery_id: Some(1), + // }, + // vec![customer::Model { + // id: 2, + // name: "Kara".into(), + // notes: Some("Loves all cakes".into()), + // }] + // ), + // ( + // baker::Model { + // id: 2, + // name: "Baker Bobby".into(), + // contact_details: serde_json::json!({ + // "mobile": "+85212345678", + // }), + // bakery_id: Some(1), + // }, + // vec![ + // customer::Model { + // id: 1, + // name: "Kate".into(), + // notes: Some("Loves cheese cake".into()), + // }, + // customer::Model { + // id: 1, + // name: "Kate".into(), + // notes: Some("Loves cheese cake".into()), + // }, + // customer::Model { + // id: 2, + // name: "Kara".into(), + // notes: Some("Loves all cakes".into()), + // }, + // ] + // ), + // ( + // baker::Model { + // id: 3, + // name: "Freerider".into(), + // contact_details: serde_json::json!({ + // "mobile": "+85298765432", + // }), + // bakery_id: Some(1), + // }, + // vec![] + // ), + // ] + // ); + + ctx.delete().await; + + Ok(()) +} + + #[sea_orm_macros::test] #[cfg(any( feature = "sqlx-mysql", @@ -586,6 +850,17 @@ pub async fn linked() -> Result<(), DbErr> { .exec(&ctx.db) .await?; + // Freerider's Baker, no cake baked + let baker_freerider = baker::ActiveModel { + name: Set("Freerider".to_owned()), + contact_details: Set(serde_json::json!({ + "mobile": "+85298765432", + })), + bakery_id: Set(Some(seaside_bakery_res.last_insert_id)), + ..Default::default() + }; + let _baker_freerider_res = Baker::insert(baker_freerider).exec(&ctx.db).await?; + // Kate's Customer, Order & Line Item let customer_kate = customer::ActiveModel { name: Set("Kate".to_owned()), @@ -690,8 +965,6 @@ pub async fn linked() -> Result<(), DbErr> { ) .group_by(baker::Column::Id) .group_by(Expr::col((Alias::new("r4"), customer::Column::Id))) - .group_by(baker::Column::Name) - .group_by(Expr::col((Alias::new("r4"), customer::Column::Name))) .order_by_asc(baker::Column::Id) .order_by_asc(Expr::col((Alias::new("r4"), customer::Column::Id))) .into_model() @@ -725,6 +998,12 @@ pub async fn linked() -> Result<(), DbErr> { name: "Kara".to_owned(), }) ), + ( + BakerLite { + name: "Freerider".to_owned(), + }, + None, + ), ] ); @@ -823,6 +1102,17 @@ pub async fn linked() -> Result<(), DbErr> { }, ] ), + ( + baker::Model { + id: 3, + name: "Freerider".into(), + contact_details: serde_json::json!({ + "mobile": "+85298765432", + }), + bakery_id: Some(1), + }, + vec![] + ), ] ); From ff9babad122ec9cc8fa7ca1da5749915ab66fc97 Mon Sep 17 00:00:00 2001 From: Yiu Tin Cheung Ivan Date: Wed, 16 Aug 2023 15:15:14 +0800 Subject: [PATCH 03/23] mock related test done --- tests/relational_tests.rs | 252 ++++++++++++++++++++++++++++++++------ tests/value_type_tests.rs | 2 +- 2 files changed, 217 insertions(+), 37 deletions(-) diff --git a/tests/relational_tests.rs b/tests/relational_tests.rs index d93398dc7..1c6be6ce7 100644 --- a/tests/relational_tests.rs +++ b/tests/relational_tests.rs @@ -494,6 +494,190 @@ pub async fn having() { ctx.delete().await; } +#[sea_orm_macros::test] +#[cfg(any( + feature = "mock", +))] +pub async fn mock_also_related() -> Result<(), DbErr> { + use sea_orm::{MockDatabase, DbBackend, Transaction}; + + + #[derive(Debug, FromQueryResult, PartialEq)] + struct BakerLite { + name: String, + } + + #[derive(Debug, FromQueryResult, PartialEq)] + struct BakeryLite { + name: String, + } + + let db = MockDatabase::new(DbBackend::Postgres) + .append_query_results([[ + ( + bakery::Model { + id: 1, + name: "SeaSide Bakery".to_string(), + profit_margin: 10.3, + }, + baker::Model { + id: 1, + name: "Baker Bob".to_owned(), + contact_details: serde_json::json!({ + "mobile": "+61424000000", + "home": "0395555555", + "address": "12 Test St, Testville, Vic, Australia" + }), + bakery_id: Some(1), + }, + ) + ]]) + .into_connection(); + + assert_eq!( + Bakery::find() + .find_also_related(Baker) + .select_only() + .column(bakery::Column::Name) + .column(baker::Column::Name) + .all(&db) + .await?, + [ + ( + bakery::Model { + id: 1, + name: "SeaSide Bakery".to_string(), + profit_margin: 10.3, + }, + Some(baker::Model { + id: 1, + name: "Baker Bob".to_owned(), + contact_details: serde_json::json!({ + "mobile": "+61424000000", + "home": "0395555555", + "address": "12 Test St, Testville, Vic, Australia" + }), + bakery_id: Some(1), + }), + ) + ] + ); + + Ok(()) +} + +#[sea_orm_macros::test] +#[cfg(any( + feature = "mock", +))] +pub async fn mock_with_related() -> Result<(), DbErr> { + use sea_orm::{MockDatabase, DbBackend, Transaction}; + + #[derive(Debug, FromQueryResult, PartialEq)] + struct BakerLite { + name: String, + } + + #[derive(Debug, FromQueryResult, PartialEq)] + struct BakeryLite { + name: String, + } + + let db = MockDatabase::new(DbBackend::Postgres) + .append_query_results([[ + ( + bakery::Model { + id: 1, + name: "SeaSide Bakery".to_string(), + profit_margin: 10.3, + }, + baker::Model { + id: 1, + name: "Baker Bob".to_owned(), + contact_details: serde_json::json!({ + "mobile": "+61424000000", + "home": "0395555555", + "address": "12 Test St, Testville, Vic, Australia" + }), + bakery_id: Some(1), + } + ), + ( + bakery::Model { + id: 1, + name: "SeaSide Bakery".to_string(), + profit_margin: 10.3, + }, + baker::Model { + id: 2, + name: "Baker Bobby".to_owned(), + contact_details: serde_json::json!({ + "mobile": "+85212345678", + }), + bakery_id: Some(1), + } + ) + ]]) + .into_connection(); + + assert_eq!( + Bakery::find() + .find_with_related(Baker) + .select_only() + .column(bakery::Column::Name) + .column(baker::Column::Name) + .all(&db) + .await?, + [ + ( + bakery::Model { + id: 1, + name: "SeaSide Bakery".to_string(), + profit_margin: 10.3, + }, + vec![baker::Model { + id: 1, + name: "Baker Bob".to_owned(), + contact_details: serde_json::json!({ + "mobile": "+61424000000", + "home": "0395555555", + "address": "12 Test St, Testville, Vic, Australia" + }), + bakery_id: Some(1), + }, + { + baker::Model { + id: 2, + name: "Baker Bobby".to_owned(), + contact_details: serde_json::json!({ + "mobile": "+85212345678", + }), + bakery_id: Some(1), + } + }], + ) + ] + ); + + assert_eq!( + db.into_transaction_log(), + [Transaction::many([Statement::from_sql_and_values( + DbBackend::Postgres, + [ + r#"SELECT "bakery"."name", "baker"."name""#, + r#"FROM "bakery""#, + r#"LEFT JOIN "baker" ON "bakery"."id" = "baker"."bakery_id""#, + r#"ORDER BY "bakery"."id" ASC"# + ] + .join(" ") + .as_str(), + [] + ),])] + ); + + Ok(()) +} + #[sea_orm_macros::test] #[cfg(any( feature = "sqlx-mysql", @@ -578,18 +762,15 @@ pub async fn related() -> Result<(), DbErr> { name: String, } - let bakers_in_bakery: Vec<(BakeryLite, Option)> = Bakery::find() + let bakers_in_bakery: Vec<(BakeryLite, Option)> = Bakery::find() .find_also_related(Baker) .select_only() .column_as(bakery::Column::Name, (SelectA, bakery::Column::Name)) - .column_as( - Expr::col((Alias::new("r"), baker::Column::Name)), - (SelectB, baker::Column::Name), - ) + .column_as(baker::Column::Name, (SelectB, baker::Column::Name)) .group_by(bakery::Column::Id) - .group_by(Expr::col((Alias::new("r"), baker::Column::Id))) + .group_by(baker::Column::Id) .order_by_asc(bakery::Column::Id) - .order_by_asc(Expr::col((Alias::new("r"), baker::Column::Id))) + .order_by_asc(baker::Column::Id) .into_model() .all(&ctx.db) .await?; @@ -599,18 +780,18 @@ pub async fn related() -> Result<(), DbErr> { [ ( BakeryLite { - name: "Seaside Bakery".to_owned(), + name: "SeaSide Bakery".to_owned(), }, Some(BakerLite { - name: "Bob".to_owned(), + name: "Baker Bob".to_owned(), }) ), ( BakeryLite { - name: "Seaside Bakery".to_owned(), + name: "SeaSide Bakery".to_owned(), }, Some(BakerLite { - name: "Bobby".to_owned(), + name: "Baker Bobby".to_owned(), }) ), ( @@ -618,12 +799,12 @@ pub async fn related() -> Result<(), DbErr> { name: "Terres Bakery".to_owned(), }, Some(BakerLite { - name: "Ada".to_owned(), + name: "Baker Ada".to_owned(), }) ), ( BakeryLite { - name: "Stone bakery".to_owned(), + name: "Stone Bakery".to_owned(), }, None, ), @@ -636,33 +817,33 @@ pub async fn related() -> Result<(), DbErr> { .await? .unwrap(); - let bakers = seaside_bakery - .find_related(bakery::Relation::Baker) - .all(&ctx.db) - .await?; + let bakers = seaside_bakery.find_related(Baker).all(&ctx.db).await?; assert_eq!( bakers, - [baker::Model { - id: 1, - name: "Baker Bob".to_owned(), - contact_details: serde_json::json!({ - "mobile": "+61424000000", - "home": "0395555555", - "address": "12 Test St, Testville, Vic, Australia" - }), - bakery_id: Some(1), - }, - baker::Model { - id: 1, - name: "Baker Bobby".to_owned(), - contact_details: serde_json::json!({ - "mobile": "+85212345678", - }), - bakery_id: Some(1), - }] + [ + baker::Model { + id: 1, + name: "Baker Bob".to_owned(), + contact_details: serde_json::json!({ + "mobile": "+61424000000", + "home": "0395555555", + "address": "12 Test St, Testville, Vic, Australia" + }), + bakery_id: Some(1), + }, + baker::Model { + id: 2, + name: "Baker Bobby".to_owned(), + contact_details: serde_json::json!({ + "mobile": "+85212345678", + }), + bakery_id: Some(1), + } + ] ); + // TODO // let select_baker_with_customer = Baker::find() // .find_with_linked(baker::BakedForCustomer) // .order_by_asc(baker::Column::Id) @@ -757,7 +938,6 @@ pub async fn related() -> Result<(), DbErr> { Ok(()) } - #[sea_orm_macros::test] #[cfg(any( feature = "sqlx-mysql", diff --git a/tests/value_type_tests.rs b/tests/value_type_tests.rs index 6c2748d3d..1898f22a3 100644 --- a/tests/value_type_tests.rs +++ b/tests/value_type_tests.rs @@ -71,7 +71,7 @@ pub fn type_test() { assert_eq!(Integer::array_type(), ArrayType::Int); assert_eq!(Boolbean::column_type(), ColumnType::Boolean); assert_eq!(Boolbean::array_type(), ArrayType::Bool); - + // self implied assert_eq!( StringVec::column_type(), From b35fe7f3dfafca0586e549a413fe290d7219939a Mon Sep 17 00:00:00 2001 From: Yiu Tin Cheung Ivan Date: Wed, 16 Aug 2023 15:33:45 +0800 Subject: [PATCH 04/23] complete relation test --- tests/relational_tests.rs | 169 ++++++++++++++++++-------------------- 1 file changed, 80 insertions(+), 89 deletions(-) diff --git a/tests/relational_tests.rs b/tests/relational_tests.rs index 1c6be6ce7..428ce45ec 100644 --- a/tests/relational_tests.rs +++ b/tests/relational_tests.rs @@ -843,95 +843,86 @@ pub async fn related() -> Result<(), DbErr> { ] ); - // TODO - // let select_baker_with_customer = Baker::find() - // .find_with_linked(baker::BakedForCustomer) - // .order_by_asc(baker::Column::Id) - // .order_by_asc(Expr::col((Alias::new("r4"), customer::Column::Id))); - - // assert_eq!( - // select_baker_with_customer - // .build(sea_orm::DatabaseBackend::MySql) - // .to_string(), - // [ - // "SELECT `baker`.`id` AS `A_id`,", - // "`baker`.`name` AS `A_name`,", - // "`baker`.`contact_details` AS `A_contact_details`,", - // "`baker`.`bakery_id` AS `A_bakery_id`,", - // "`r4`.`id` AS `B_id`,", - // "`r4`.`name` AS `B_name`,", - // "`r4`.`notes` AS `B_notes`", - // "FROM `baker`", - // "LEFT JOIN `cakes_bakers` AS `r0` ON `baker`.`id` = `r0`.`baker_id`", - // "LEFT JOIN `cake` AS `r1` ON `r0`.`cake_id` = `r1`.`id`", - // "LEFT JOIN `lineitem` AS `r2` ON `r1`.`id` = `r2`.`cake_id`", - // "LEFT JOIN `order` AS `r3` ON `r2`.`order_id` = `r3`.`id`", - // "LEFT JOIN `customer` AS `r4` ON `r3`.`customer_id` = `r4`.`id`", - // "ORDER BY `baker`.`id` ASC, `r4`.`id` ASC" - // ] - // .join(" ") - // ); - - // assert_eq!( - // select_baker_with_customer.all(&ctx.db).await?, - // [ - // ( - // baker::Model { - // id: 1, - // name: "Baker Bob".into(), - // contact_details: serde_json::json!({ - // "mobile": "+61424000000", - // "home": "0395555555", - // "address": "12 Test St, Testville, Vic, Australia", - // }), - // bakery_id: Some(1), - // }, - // vec![customer::Model { - // id: 2, - // name: "Kara".into(), - // notes: Some("Loves all cakes".into()), - // }] - // ), - // ( - // baker::Model { - // id: 2, - // name: "Baker Bobby".into(), - // contact_details: serde_json::json!({ - // "mobile": "+85212345678", - // }), - // bakery_id: Some(1), - // }, - // vec![ - // customer::Model { - // id: 1, - // name: "Kate".into(), - // notes: Some("Loves cheese cake".into()), - // }, - // customer::Model { - // id: 1, - // name: "Kate".into(), - // notes: Some("Loves cheese cake".into()), - // }, - // customer::Model { - // id: 2, - // name: "Kara".into(), - // notes: Some("Loves all cakes".into()), - // }, - // ] - // ), - // ( - // baker::Model { - // id: 3, - // name: "Freerider".into(), - // contact_details: serde_json::json!({ - // "mobile": "+85298765432", - // }), - // bakery_id: Some(1), - // }, - // vec![] - // ), - // ] - // ); + let select_bakery_with_baker = Bakery::find() + .find_with_related(Baker) + .order_by_asc(baker::Column::Id); + + assert_eq!( + select_bakery_with_baker + .build(sea_orm::DatabaseBackend::MySql) + .to_string(), + [ + "SELECT `bakery`.`id` AS `A_id`,", + "`bakery`.`name` AS `A_name`,", + "`bakery`.`profit_margin` AS `A_profit_margin`,", + "`baker`.`id` AS `B_id`,", + "`baker`.`name` AS `B_name`,", + "`baker`.`contact_details` AS `B_contact_details`,", + "`baker`.`bakery_id` AS `B_bakery_id`", + "FROM `bakery`", + "LEFT JOIN `baker` ON `bakery`.`id` = `baker`.`bakery_id`", + "ORDER BY `bakery`.`id` ASC, `baker`.`id` ASC" + ] + .join(" ") + ); + + assert_eq!( + select_bakery_with_baker.all(&ctx.db).await?, + [ + ( + bakery::Model { + id: 1, + name: "SeaSide Bakery".to_owned(), + profit_margin: 10.4, + }, + vec![baker::Model { + id: 1, + name: "Baker Bob".to_owned(), + contact_details: serde_json::json!({ + "mobile": "+61424000000", + "home": "0395555555", + "address": "12 Test St, Testville, Vic, Australia" + }), + bakery_id: Some(seaside_bakery_res.last_insert_id), + }, + baker::Model { + id: 2, + name: "Baker Bobby".to_owned(), + contact_details: serde_json::json!({ + "mobile": "+85212345678", + }), + bakery_id: Some(seaside_bakery_res.last_insert_id), + }] + ), + ( + bakery::Model { + id: 2, + name: "Terres Bakery".to_owned(), + profit_margin: 13.5, + }, + vec![ + baker::Model { + id: 3, + name: "Baker Ada".to_owned(), + contact_details: serde_json::json!({ + "mobile": "+61424000000", + "home": "0395555555", + "address": "12 Test St, Testville, Vic, Australia" + }), + bakery_id: Some(terres_bakery_res.last_insert_id), + } + ] + ), + ( + bakery::Model { + id: 3, + name: "Stone Bakery".to_owned(), + profit_margin: 13.5, + }, + vec![] + ), + ] + ); ctx.delete().await; From 7f5db77d4f3ef32fba0b01613c6868e65cd0844c Mon Sep 17 00:00:00 2001 From: Yiu Tin Cheung Ivan Date: Wed, 16 Aug 2023 16:00:45 +0800 Subject: [PATCH 05/23] loader update --- tests/loader_tests.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/loader_tests.rs b/tests/loader_tests.rs index c0cb408b1..4938ae7df 100644 --- a/tests/loader_tests.rs +++ b/tests/loader_tests.rs @@ -47,6 +47,7 @@ async fn loader_load_many() -> Result<(), DbErr> { let bakery_1 = insert_bakery(&ctx.db, "SeaSide Bakery").await?; let bakery_2 = insert_bakery(&ctx.db, "Offshore Bakery").await?; + let bakery_3 = insert_bakery(&ctx.db, "Offshore Bakery").await?; let baker_1 = insert_baker(&ctx.db, "Baker 1", bakery_1.id).await?; let baker_2 = insert_baker(&ctx.db, "Baker 2", bakery_1.id).await?; @@ -115,6 +116,7 @@ async fn loader_load_many_multi() -> Result<(), DbErr> { let bakery_1 = insert_bakery(&ctx.db, "SeaSide Bakery").await?; let bakery_2 = insert_bakery(&ctx.db, "Offshore Bakery").await?; + let bakery_3 = insert_bakery(&ctx.db, "Onshore Bakery").await?; let baker_1 = insert_baker(&ctx.db, "John", bakery_1.id).await?; let baker_2 = insert_baker(&ctx.db, "Jane", bakery_1.id).await?; @@ -129,9 +131,9 @@ async fn loader_load_many_multi() -> Result<(), DbErr> { let bakers = bakeries.load_many(baker::Entity, &ctx.db).await?; let cakes = bakeries.load_many(cake::Entity, &ctx.db).await?; - assert_eq!(bakeries, [bakery_1, bakery_2]); - assert_eq!(bakers, [vec![baker_1, baker_2], vec![baker_3]]); - assert_eq!(cakes, [vec![cake_1], vec![cake_2, cake_3]]); + assert_eq!(bakeries, [bakery_1, bakery_2, bakery_3]); + assert_eq!(bakers, [vec![baker_1, baker_2], vec![baker_3], vec![]]); + assert_eq!(cakes, [vec![cake_1], vec![cake_2, cake_3], vec![]]); Ok(()) } From 8592857380d4d046a88bbb5f0b47cc323606ab3c Mon Sep 17 00:00:00 2001 From: Yiu Tin Cheung Ivan Date: Wed, 16 Aug 2023 18:56:45 +0800 Subject: [PATCH 06/23] find_with/also_related missing test case for empty from other side --- src/query/join.rs | 288 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 288 insertions(+) diff --git a/src/query/join.rs b/src/query/join.rs index 6ed56de0c..3af5400ef 100644 --- a/src/query/join.rs +++ b/src/query/join.rs @@ -637,4 +637,292 @@ mod tests { .join(" ") ); } + + fn cake_fruit_model(cake_id: i32, cake_name: String, fruit_id: i32, fruit_name: String) + -> (sea_orm::tests_cfg::cake::Model, sea_orm::tests_cfg::fruit::Model) { + (cake_model(cake_id, cake_name), fruit_model(fruit_id, fruit_name, Some(cake_id))) + } + + fn cake_model(id: i32, name: String) -> sea_orm::tests_cfg::cake::Model { + sea_orm::tests_cfg::cake::Model { + id, + name, + } + } + + fn fruit_model(id: i32, name: String, cake_id: Option) -> sea_orm::tests_cfg::fruit::Model { + sea_orm::tests_cfg::fruit::Model { + id, + name, + cake_id + } + } + + #[smol_potat::test] + pub async fn also_related() -> Result<(), sea_orm::DbErr> { + use sea_orm::{MockDatabase, DbBackend, EntityTrait, QuerySelect, Transaction, Statement}; + use sea_orm::tests_cfg::*; + + let db = MockDatabase::new(DbBackend::Postgres) + .append_query_results([[ + cake_fruit_model(1, "apple cake".to_owned(), 1, "apple".to_owned()) + ]]) + .into_connection(); + + assert_eq!( + Cake::find() + .find_also_related(Fruit) + .select_only() + .column(cake::Column::Name) + .column(fruit::Column::Name) + .all(&db) + .await?, + [ + ( + cake_model(1, "apple cake".to_owned()), + Some(fruit_model(1, "apple".to_owned(), Some(1))) + ) + ] + ); + + assert_eq!( + db.into_transaction_log(), + [Transaction::many([Statement::from_sql_and_values( + DbBackend::Postgres, + [ + r#"SELECT "cake"."name", "fruit"."name""#, + r#"FROM "cake""#, + r#"LEFT JOIN "fruit" ON "cake"."id" = "fruit"."cake_id""# + ] + .join(" ") + .as_str(), + [] + ),])] + ); + + Ok(()) + } + + #[smol_potat::test] + pub async fn also_related_2() -> Result<(), sea_orm::DbErr> { + use sea_orm::{MockDatabase, DbBackend, EntityTrait, QuerySelect}; + use sea_orm::tests_cfg::*; + + let db = MockDatabase::new(DbBackend::Postgres) + .append_query_results([[ + cake_fruit_model(1, "apple cake".to_owned(), 1, "apple".to_owned()), + cake_fruit_model(1, "apple cake".to_owned(), 2, "orange".to_owned()) + ]]) + .into_connection(); + + assert_eq!( + Cake::find() + .find_also_related(Fruit) + .select_only() + .column(cake::Column::Name) + .column(fruit::Column::Name) + .all(&db) + .await?, + [ + ( + cake_model(1, "apple cake".to_owned()), + Some(fruit_model(1, "apple".to_owned(), Some(1))) + ), ( + cake_model(1, "apple cake".to_owned()), + Some(fruit_model(2, "orange".to_owned(), Some(1))) + ) + ] + ); + + Ok(()) + } + + #[smol_potat::test] + pub async fn also_related_3() -> Result<(), sea_orm::DbErr> { + use sea_orm::{MockDatabase, DbBackend, EntityTrait, QuerySelect}; + use sea_orm::tests_cfg::*; + + let db = MockDatabase::new(DbBackend::Postgres) + .append_query_results([[ + cake_fruit_model(1, "apple cake".to_owned(), 1, "apple".to_owned()), + cake_fruit_model(1, "apple cake".to_owned(), 2, "orange".to_owned()), + cake_fruit_model(2, "orange cake".to_owned(), 2, "orange".to_owned()) + ]]) + .into_connection(); + + assert_eq!( + Cake::find() + .find_also_related(Fruit) + .select_only() + .column(cake::Column::Name) + .column(fruit::Column::Name) + .all(&db) + .await?, + [ + ( + cake_model(1, "apple cake".to_owned()), + Some(fruit_model(1, "apple".to_owned(), Some(1))) + ), + ( + cake_model(1, "apple cake".to_owned()), + Some(fruit_model(2, "orange".to_owned(), Some(1))) + ), + ( + cake_model(2, "orange cake".to_owned()), + Some(fruit_model(2, "orange".to_owned(), Some(2))) + ) + ] + ); + + Ok(()) + } + + // fixme: unsure on how to insert a cake with no fruit into query_result + // #[smol_potat::test] + pub async fn also_related_4() -> Result<(), sea_orm::DbErr> { + use sea_orm::{MockDatabase, DbBackend, EntityTrait, QuerySelect}; + use sea_orm::tests_cfg::*; + + let db = MockDatabase::new(DbBackend::Postgres) + .append_query_results([[ + cake_fruit_model(1, "apple cake".to_owned(), 1, "apple".to_owned()), + cake_fruit_model(1, "apple cake".to_owned(), 2, "orange".to_owned()), + cake_fruit_model(2, "orange cake".to_owned(), 2, "orange".to_owned()), + ]]) + .append_query_results([[ + cake_model(3, "chocolate cake".to_owned()) // no fruit in cake + ]]) + .into_connection(); + + assert_eq!( + Cake::find() + .find_also_related(Fruit) + .select_only() + .column(cake::Column::Name) + .column(fruit::Column::Name) + .all(&db) + .await?, + [ + ( + cake_model(1, "apple cake".to_owned()), + Some(fruit_model(1, "apple".to_owned(), Some(1))) + ), + ( + cake_model(1, "apple cake".to_owned()), + Some(fruit_model(2, "orange".to_owned(), Some(1))) + ), + ( + cake_model(2, "orange cake".to_owned()), + Some(fruit_model(2, "orange".to_owned(), Some(2))) + ), + ( + cake_model(3, "chocolate cake".to_owned()), + None + ) + ] + ); + + Ok(()) + } + + #[smol_potat::test] + #[cfg(any( + feature = "mock", + ))] + pub async fn with_related() -> Result<(), sea_orm::DbErr> { + use sea_orm::{MockDatabase, DbBackend, EntityTrait, QuerySelect, Transaction, Statement}; + use sea_orm::tests_cfg::*; + + let db = MockDatabase::new(DbBackend::Postgres) + .append_query_results([[ + cake_fruit_model(1, "apple cake".to_owned(), 1, "apple".to_owned()), + cake_fruit_model(1, "apple cake".to_owned(), 2, "orange".to_owned()) + ]]) + .into_connection(); + + assert_eq!( + Cake::find() + .find_with_related(Fruit) + .select_only() + .column(cake::Column::Name) + .column(fruit::Column::Name) + .all(&db) + .await?, + [ + ( + cake_model(1, "apple cake".to_owned()), + vec![ + fruit_model(1, "apple".to_owned(), Some(1)), + fruit_model(2, "orange".to_owned(), Some(1)) + ] + ) + ] + ); + + assert_eq!( + db.into_transaction_log(), + [Transaction::many([Statement::from_sql_and_values( + DbBackend::Postgres, + [ + r#"SELECT "cake"."name", "fruit"."name""#, + r#"FROM "cake""#, + r#"LEFT JOIN "fruit" ON "cake"."id" = "fruit"."cake_id""#, + r#"ORDER BY "cake"."id" ASC"# + ] + .join(" ") + .as_str(), + [] + ),])] + ); + + Ok(()) + } + + #[smol_potat::test] + #[cfg(any( + feature = "mock", + ))] + pub async fn with_related_2() -> Result<(), sea_orm::DbErr> { + use sea_orm::{MockDatabase, DbBackend, EntityTrait, QuerySelect}; + use sea_orm::tests_cfg::*; + + let db = MockDatabase::new(DbBackend::Postgres) + .append_query_results([[ + cake_fruit_model(1, "apple cake".to_owned(), 1, "apple".to_owned()), + cake_fruit_model(2, "fruit cake".to_owned(), 1, "apple".to_owned()), + cake_fruit_model(2, "fruit cake".to_owned(), 2, "orange".to_owned()), + cake_fruit_model(2, "fruit cake".to_owned(), 3, "grape".to_owned()), + cake_fruit_model(2, "fruit cake".to_owned(), 4, "melon".to_owned()), + ]]) + .into_connection(); + + assert_eq!( + Cake::find() + .find_with_related(Fruit) + .select_only() + .column(cake::Column::Name) + .column(fruit::Column::Name) + .all(&db) + .await?, + [ + ( + cake_model(1, "apple cake".to_owned()), + vec![ + fruit_model(1, "apple".to_owned(), Some(1)), + ] + ), + ( + cake_model(2, "fruit cake".to_owned()), + vec![ + fruit_model(1, "apple".to_owned(), Some(2)), + fruit_model(2, "orange".to_owned(), Some(2)), + fruit_model(3, "grape".to_owned(), Some(2)), + fruit_model(4, "melon".to_owned(), Some(2)), + ] + ) + ] + ); + + Ok(()) + } } From e28db211de663f56c54d54fd70410a529f5dea89 Mon Sep 17 00:00:00 2001 From: Yiu Tin Cheung Ivan Date: Wed, 16 Aug 2023 21:49:59 +0800 Subject: [PATCH 07/23] comments fixup --- src/entity/base_entity.rs | 1 - src/executor/select.rs | 294 ++++++++++++++++++++++++ src/query/join.rs | 456 ++++++++++++++------------------------ tests/relational_tests.rs | 187 +--------------- 4 files changed, 468 insertions(+), 470 deletions(-) diff --git a/src/entity/base_entity.rs b/src/entity/base_entity.rs index 02917749f..5f7422e33 100644 --- a/src/entity/base_entity.rs +++ b/src/entity/base_entity.rs @@ -960,7 +960,6 @@ mod tests { ); } - delete_by_id("UUID".to_string()); delete_by_id("UUID".to_string()); delete_by_id("UUID"); delete_by_id(Cow::from("UUID")); diff --git a/src/executor/select.rs b/src/executor/select.rs index cd7d122cb..7796e2755 100644 --- a/src/executor/select.rs +++ b/src/executor/select.rs @@ -1107,3 +1107,297 @@ where } acc } + +#[cfg(test)] +mod tests { + use crate::tests_cfg::{cake_filling, cake_filling_price, entity_linked, filling, fruit}; + use crate::{DbBackend, ModelTrait, QueryFilter, QueryTrait, RelationTrait}; + use pretty_assertions::assert_eq; + use sea_query::{ConditionType, Expr, IntoCondition, JoinType}; + + fn cake_fruit_model( + cake_id: i32, + cake_name: String, + fruit_id: i32, + fruit_name: String, + ) -> ( + sea_orm::tests_cfg::cake::Model, + sea_orm::tests_cfg::fruit::Model, + ) { + ( + cake_model(cake_id, cake_name), + fruit_model(fruit_id, fruit_name, Some(cake_id)), + ) + } + + fn cake_model(id: i32, name: String) -> sea_orm::tests_cfg::cake::Model { + sea_orm::tests_cfg::cake::Model { id, name } + } + + fn fruit_model( + id: i32, + name: String, + cake_id: Option, + ) -> sea_orm::tests_cfg::fruit::Model { + sea_orm::tests_cfg::fruit::Model { id, name, cake_id } + } + + #[smol_potat::test] + pub async fn also_related() -> Result<(), sea_orm::DbErr> { + use sea_orm::tests_cfg::*; + use sea_orm::{DbBackend, EntityTrait, MockDatabase, QuerySelect, Statement, Transaction}; + + let db = MockDatabase::new(DbBackend::Postgres) + .append_query_results([[cake_fruit_model( + 1, + "apple cake".to_owned(), + 1, + "apple".to_owned(), + )]]) + .into_connection(); + + assert_eq!( + Cake::find() + .find_also_related(Fruit) + .select_only() + .column(cake::Column::Name) + .column(fruit::Column::Name) + .all(&db) + .await?, + [( + cake_model(1, "apple cake".to_owned()), + Some(fruit_model(1, "apple".to_owned(), Some(1))) + )] + ); + + assert_eq!( + db.into_transaction_log(), + [Transaction::many([Statement::from_sql_and_values( + DbBackend::Postgres, + [ + r#"SELECT "cake"."name", "fruit"."name""#, + r#"FROM "cake""#, + r#"LEFT JOIN "fruit" ON "cake"."id" = "fruit"."cake_id""# + ] + .join(" ") + .as_str(), + [] + ),])] + ); + + Ok(()) + } + + #[smol_potat::test] + pub async fn also_related_2() -> Result<(), sea_orm::DbErr> { + use sea_orm::tests_cfg::*; + use sea_orm::{DbBackend, EntityTrait, MockDatabase, QuerySelect}; + + let db = MockDatabase::new(DbBackend::Postgres) + .append_query_results([[ + cake_fruit_model(1, "apple cake".to_owned(), 1, "apple".to_owned()), + cake_fruit_model(1, "apple cake".to_owned(), 2, "orange".to_owned()), + ]]) + .into_connection(); + + assert_eq!( + Cake::find() + .find_also_related(Fruit) + .select_only() + .column(cake::Column::Name) + .column(fruit::Column::Name) + .all(&db) + .await?, + [ + ( + cake_model(1, "apple cake".to_owned()), + Some(fruit_model(1, "apple".to_owned(), Some(1))) + ), + ( + cake_model(1, "apple cake".to_owned()), + Some(fruit_model(2, "orange".to_owned(), Some(1))) + ) + ] + ); + + Ok(()) + } + + #[smol_potat::test] + pub async fn also_related_3() -> Result<(), sea_orm::DbErr> { + use sea_orm::tests_cfg::*; + use sea_orm::{DbBackend, EntityTrait, MockDatabase, QuerySelect}; + + let db = MockDatabase::new(DbBackend::Postgres) + .append_query_results([[ + cake_fruit_model(1, "apple cake".to_owned(), 1, "apple".to_owned()), + cake_fruit_model(1, "apple cake".to_owned(), 2, "orange".to_owned()), + cake_fruit_model(2, "orange cake".to_owned(), 2, "orange".to_owned()), + ]]) + .into_connection(); + + assert_eq!( + Cake::find() + .find_also_related(Fruit) + .select_only() + .column(cake::Column::Name) + .column(fruit::Column::Name) + .all(&db) + .await?, + [ + ( + cake_model(1, "apple cake".to_owned()), + Some(fruit_model(1, "apple".to_owned(), Some(1))) + ), + ( + cake_model(1, "apple cake".to_owned()), + Some(fruit_model(2, "orange".to_owned(), Some(1))) + ), + ( + cake_model(2, "orange cake".to_owned()), + Some(fruit_model(2, "orange".to_owned(), Some(2))) + ) + ] + ); + + Ok(()) + } + + // fixme: unsure on how to insert a cake with no fruit into query_result + // #[smol_potat::test] + pub async fn also_related_4() -> Result<(), sea_orm::DbErr> { + use sea_orm::tests_cfg::*; + use sea_orm::{DbBackend, EntityTrait, MockDatabase, QuerySelect}; + + let db = MockDatabase::new(DbBackend::Postgres) + .append_query_results([[ + cake_fruit_model(1, "apple cake".to_owned(), 1, "apple".to_owned()), + cake_fruit_model(1, "apple cake".to_owned(), 2, "orange".to_owned()), + cake_fruit_model(2, "orange cake".to_owned(), 2, "orange".to_owned()), + ]]) + .append_query_results([[ + cake_model(3, "chocolate cake".to_owned()), // no fruit in cake + ]]) + .into_connection(); + + assert_eq!( + Cake::find() + .find_also_related(Fruit) + .select_only() + .column(cake::Column::Name) + .column(fruit::Column::Name) + .all(&db) + .await?, + [ + ( + cake_model(1, "apple cake".to_owned()), + Some(fruit_model(1, "apple".to_owned(), Some(1))) + ), + ( + cake_model(1, "apple cake".to_owned()), + Some(fruit_model(2, "orange".to_owned(), Some(1))) + ), + ( + cake_model(2, "orange cake".to_owned()), + Some(fruit_model(2, "orange".to_owned(), Some(2))) + ), + (cake_model(3, "chocolate cake".to_owned()), None) + ] + ); + + Ok(()) + } + + #[smol_potat::test] + #[cfg(any(feature = "mock",))] + pub async fn with_related() -> Result<(), sea_orm::DbErr> { + use sea_orm::tests_cfg::*; + use sea_orm::{DbBackend, EntityTrait, MockDatabase, QuerySelect, Statement, Transaction}; + + let db = MockDatabase::new(DbBackend::Postgres) + .append_query_results([[ + cake_fruit_model(1, "apple cake".to_owned(), 1, "apple".to_owned()), + cake_fruit_model(1, "apple cake".to_owned(), 2, "orange".to_owned()), + ]]) + .into_connection(); + + assert_eq!( + Cake::find() + .find_with_related(Fruit) + .select_only() + .column(cake::Column::Name) + .column(fruit::Column::Name) + .all(&db) + .await?, + [( + cake_model(1, "apple cake".to_owned()), + vec![ + fruit_model(1, "apple".to_owned(), Some(1)), + fruit_model(2, "orange".to_owned(), Some(1)) + ] + )] + ); + + assert_eq!( + db.into_transaction_log(), + [Transaction::many([Statement::from_sql_and_values( + DbBackend::Postgres, + [ + r#"SELECT "cake"."name", "fruit"."name""#, + r#"FROM "cake""#, + r#"LEFT JOIN "fruit" ON "cake"."id" = "fruit"."cake_id""#, + r#"ORDER BY "cake"."id" ASC"# + ] + .join(" ") + .as_str(), + [] + ),])] + ); + + Ok(()) + } + + #[smol_potat::test] + #[cfg(any(feature = "mock",))] + pub async fn with_related_2() -> Result<(), sea_orm::DbErr> { + use sea_orm::tests_cfg::*; + use sea_orm::{DbBackend, EntityTrait, MockDatabase, QuerySelect}; + + let db = MockDatabase::new(DbBackend::Postgres) + .append_query_results([[ + cake_fruit_model(1, "apple cake".to_owned(), 1, "apple".to_owned()), + cake_fruit_model(2, "fruit cake".to_owned(), 1, "apple".to_owned()), + cake_fruit_model(2, "fruit cake".to_owned(), 2, "orange".to_owned()), + cake_fruit_model(2, "fruit cake".to_owned(), 3, "grape".to_owned()), + cake_fruit_model(2, "fruit cake".to_owned(), 4, "melon".to_owned()), + ]]) + .into_connection(); + + assert_eq!( + Cake::find() + .find_with_related(Fruit) + .select_only() + .column(cake::Column::Name) + .column(fruit::Column::Name) + .all(&db) + .await?, + [ + ( + cake_model(1, "apple cake".to_owned()), + vec![fruit_model(1, "apple".to_owned(), Some(1)),] + ), + ( + cake_model(2, "fruit cake".to_owned()), + vec![ + fruit_model(1, "apple".to_owned(), Some(2)), + fruit_model(2, "orange".to_owned(), Some(2)), + fruit_model(3, "grape".to_owned(), Some(2)), + fruit_model(4, "melon".to_owned(), Some(2)), + ] + ) + ] + ); + + Ok(()) + } +} diff --git a/src/query/join.rs b/src/query/join.rs index 3af5400ef..17efa1708 100644 --- a/src/query/join.rs +++ b/src/query/join.rs @@ -638,291 +638,177 @@ mod tests { ); } - fn cake_fruit_model(cake_id: i32, cake_name: String, fruit_id: i32, fruit_name: String) - -> (sea_orm::tests_cfg::cake::Model, sea_orm::tests_cfg::fruit::Model) { - (cake_model(cake_id, cake_name), fruit_model(fruit_id, fruit_name, Some(cake_id))) - } - - fn cake_model(id: i32, name: String) -> sea_orm::tests_cfg::cake::Model { - sea_orm::tests_cfg::cake::Model { - id, - name, - } - } - - fn fruit_model(id: i32, name: String, cake_id: Option) -> sea_orm::tests_cfg::fruit::Model { - sea_orm::tests_cfg::fruit::Model { - id, - name, - cake_id - } - } - - #[smol_potat::test] - pub async fn also_related() -> Result<(), sea_orm::DbErr> { - use sea_orm::{MockDatabase, DbBackend, EntityTrait, QuerySelect, Transaction, Statement}; - use sea_orm::tests_cfg::*; - - let db = MockDatabase::new(DbBackend::Postgres) - .append_query_results([[ - cake_fruit_model(1, "apple cake".to_owned(), 1, "apple".to_owned()) - ]]) - .into_connection(); - - assert_eq!( - Cake::find() - .find_also_related(Fruit) - .select_only() - .column(cake::Column::Name) - .column(fruit::Column::Name) - .all(&db) - .await?, - [ - ( - cake_model(1, "apple cake".to_owned()), - Some(fruit_model(1, "apple".to_owned(), Some(1))) - ) - ] - ); - - assert_eq!( - db.into_transaction_log(), - [Transaction::many([Statement::from_sql_and_values( - DbBackend::Postgres, - [ - r#"SELECT "cake"."name", "fruit"."name""#, - r#"FROM "cake""#, - r#"LEFT JOIN "fruit" ON "cake"."id" = "fruit"."cake_id""# - ] - .join(" ") - .as_str(), - [] - ),])] - ); - - Ok(()) - } - - #[smol_potat::test] - pub async fn also_related_2() -> Result<(), sea_orm::DbErr> { - use sea_orm::{MockDatabase, DbBackend, EntityTrait, QuerySelect}; - use sea_orm::tests_cfg::*; - - let db = MockDatabase::new(DbBackend::Postgres) - .append_query_results([[ - cake_fruit_model(1, "apple cake".to_owned(), 1, "apple".to_owned()), - cake_fruit_model(1, "apple cake".to_owned(), 2, "orange".to_owned()) - ]]) - .into_connection(); - - assert_eq!( - Cake::find() - .find_also_related(Fruit) - .select_only() - .column(cake::Column::Name) - .column(fruit::Column::Name) - .all(&db) - .await?, - [ - ( - cake_model(1, "apple cake".to_owned()), - Some(fruit_model(1, "apple".to_owned(), Some(1))) - ), ( - cake_model(1, "apple cake".to_owned()), - Some(fruit_model(2, "orange".to_owned(), Some(1))) - ) - ] - ); - - Ok(()) - } - - #[smol_potat::test] - pub async fn also_related_3() -> Result<(), sea_orm::DbErr> { - use sea_orm::{MockDatabase, DbBackend, EntityTrait, QuerySelect}; - use sea_orm::tests_cfg::*; - - let db = MockDatabase::new(DbBackend::Postgres) - .append_query_results([[ - cake_fruit_model(1, "apple cake".to_owned(), 1, "apple".to_owned()), - cake_fruit_model(1, "apple cake".to_owned(), 2, "orange".to_owned()), - cake_fruit_model(2, "orange cake".to_owned(), 2, "orange".to_owned()) - ]]) - .into_connection(); - - assert_eq!( - Cake::find() - .find_also_related(Fruit) - .select_only() - .column(cake::Column::Name) - .column(fruit::Column::Name) - .all(&db) - .await?, - [ - ( - cake_model(1, "apple cake".to_owned()), - Some(fruit_model(1, "apple".to_owned(), Some(1))) - ), - ( - cake_model(1, "apple cake".to_owned()), - Some(fruit_model(2, "orange".to_owned(), Some(1))) - ), - ( - cake_model(2, "orange cake".to_owned()), - Some(fruit_model(2, "orange".to_owned(), Some(2))) - ) - ] - ); - - Ok(()) - } - - // fixme: unsure on how to insert a cake with no fruit into query_result + // TODO: change schema since moving from tests into src files // #[smol_potat::test] - pub async fn also_related_4() -> Result<(), sea_orm::DbErr> { - use sea_orm::{MockDatabase, DbBackend, EntityTrait, QuerySelect}; - use sea_orm::tests_cfg::*; - - let db = MockDatabase::new(DbBackend::Postgres) - .append_query_results([[ - cake_fruit_model(1, "apple cake".to_owned(), 1, "apple".to_owned()), - cake_fruit_model(1, "apple cake".to_owned(), 2, "orange".to_owned()), - cake_fruit_model(2, "orange cake".to_owned(), 2, "orange".to_owned()), - ]]) - .append_query_results([[ - cake_model(3, "chocolate cake".to_owned()) // no fruit in cake - ]]) - .into_connection(); - - assert_eq!( - Cake::find() - .find_also_related(Fruit) - .select_only() - .column(cake::Column::Name) - .column(fruit::Column::Name) - .all(&db) - .await?, - [ - ( - cake_model(1, "apple cake".to_owned()), - Some(fruit_model(1, "apple".to_owned(), Some(1))) - ), - ( - cake_model(1, "apple cake".to_owned()), - Some(fruit_model(2, "orange".to_owned(), Some(1))) - ), - ( - cake_model(2, "orange cake".to_owned()), - Some(fruit_model(2, "orange".to_owned(), Some(2))) - ), - ( - cake_model(3, "chocolate cake".to_owned()), - None - ) - ] - ); - - Ok(()) - } - - #[smol_potat::test] - #[cfg(any( - feature = "mock", - ))] - pub async fn with_related() -> Result<(), sea_orm::DbErr> { - use sea_orm::{MockDatabase, DbBackend, EntityTrait, QuerySelect, Transaction, Statement}; - use sea_orm::tests_cfg::*; - - let db = MockDatabase::new(DbBackend::Postgres) - .append_query_results([[ - cake_fruit_model(1, "apple cake".to_owned(), 1, "apple".to_owned()), - cake_fruit_model(1, "apple cake".to_owned(), 2, "orange".to_owned()) - ]]) - .into_connection(); - - assert_eq!( - Cake::find() - .find_with_related(Fruit) - .select_only() - .column(cake::Column::Name) - .column(fruit::Column::Name) - .all(&db) - .await?, - [ - ( - cake_model(1, "apple cake".to_owned()), - vec![ - fruit_model(1, "apple".to_owned(), Some(1)), - fruit_model(2, "orange".to_owned(), Some(1)) - ] - ) - ] - ); - - assert_eq!( - db.into_transaction_log(), - [Transaction::many([Statement::from_sql_and_values( - DbBackend::Postgres, - [ - r#"SELECT "cake"."name", "fruit"."name""#, - r#"FROM "cake""#, - r#"LEFT JOIN "fruit" ON "cake"."id" = "fruit"."cake_id""#, - r#"ORDER BY "cake"."id" ASC"# - ] - .join(" ") - .as_str(), - [] - ),])] - ); - - Ok(()) - } + // #[cfg(any( + // feature = "mock", + // ))] + // pub async fn mock_also_related() -> Result<(), sea_orm::DbErr> { + // use sea_orm::{MockDatabase, DbBackend, Transaction}; + + // let db = MockDatabase::new(DbBackend::Postgres) + // .append_query_results([[ + // ( + // bakery::Model { + // id: 1, + // name: "SeaSide Bakery".to_string(), + // profit_margin: 10.3, + // }, + // baker::Model { + // id: 1, + // name: "Baker Bob".to_owned(), + // contact_details: serde_json::json!({ + // "mobile": "+61424000000", + // "home": "0395555555", + // "address": "12 Test St, Testville, Vic, Australia" + // }), + // bakery_id: Some(1), + // }, + // ) + // ]]) + // .into_connection(); + + // assert_eq!( + // Bakery::find() + // .find_also_related(Baker) + // .select_only() + // .column(bakery::Column::Name) + // .column(baker::Column::Name) + // .all(&db) + // .await?, + // [ + // ( + // bakery::Model { + // id: 1, + // name: "SeaSide Bakery".to_string(), + // profit_margin: 10.3, + // }, + // Some(baker::Model { + // id: 1, + // name: "Baker Bob".to_owned(), + // contact_details: serde_json::json!({ + // "mobile": "+61424000000", + // "home": "0395555555", + // "address": "12 Test St, Testville, Vic, Australia" + // }), + // bakery_id: Some(1), + // }), + // ) + // ] + // ); + + // Ok(()) + // } - #[smol_potat::test] - #[cfg(any( - feature = "mock", - ))] - pub async fn with_related_2() -> Result<(), sea_orm::DbErr> { - use sea_orm::{MockDatabase, DbBackend, EntityTrait, QuerySelect}; - use sea_orm::tests_cfg::*; - - let db = MockDatabase::new(DbBackend::Postgres) - .append_query_results([[ - cake_fruit_model(1, "apple cake".to_owned(), 1, "apple".to_owned()), - cake_fruit_model(2, "fruit cake".to_owned(), 1, "apple".to_owned()), - cake_fruit_model(2, "fruit cake".to_owned(), 2, "orange".to_owned()), - cake_fruit_model(2, "fruit cake".to_owned(), 3, "grape".to_owned()), - cake_fruit_model(2, "fruit cake".to_owned(), 4, "melon".to_owned()), - ]]) - .into_connection(); - - assert_eq!( - Cake::find() - .find_with_related(Fruit) - .select_only() - .column(cake::Column::Name) - .column(fruit::Column::Name) - .all(&db) - .await?, - [ - ( - cake_model(1, "apple cake".to_owned()), - vec![ - fruit_model(1, "apple".to_owned(), Some(1)), - ] - ), - ( - cake_model(2, "fruit cake".to_owned()), - vec![ - fruit_model(1, "apple".to_owned(), Some(2)), - fruit_model(2, "orange".to_owned(), Some(2)), - fruit_model(3, "grape".to_owned(), Some(2)), - fruit_model(4, "melon".to_owned(), Some(2)), - ] - ) - ] - ); - - Ok(()) - } + // #[smol_potat::test] + // #[cfg(any( + // feature = "mock", + // ))] + // pub async fn mock_with_related() -> Result<(), sea_orm::DbErr> { + // use sea_orm::{MockDatabase, DbBackend, Transaction}; + + // #[derive(Debug, FromQueryResult, PartialEq)] + // struct BakerLite { + // name: String, + // } + + // #[derive(Debug, FromQueryResult, PartialEq)] + // struct BakeryLite { + // name: String, + // } + + // let db = MockDatabase::new(DbBackend::Postgres) + // .append_query_results([[ + // ( + // bakery::Model { + // id: 1, + // name: "SeaSide Bakery".to_string(), + // profit_margin: 10.3, + // }, + // baker::Model { + // id: 1, + // name: "Baker Bob".to_owned(), + // contact_details: serde_json::json!({ + // "mobile": "+61424000000", + // "home": "0395555555", + // "address": "12 Test St, Testville, Vic, Australia" + // }), + // bakery_id: Some(1), + // } + // ), + // ( + // bakery::Model { + // id: 1, + // name: "SeaSide Bakery".to_string(), + // profit_margin: 10.3, + // }, + // baker::Model { + // id: 2, + // name: "Baker Bobby".to_owned(), + // contact_details: serde_json::json!({ + // "mobile": "+85212345678", + // }), + // bakery_id: Some(1), + // } + // ) + // ]]) + // .into_connection(); + + // assert_eq!( + // Bakery::find() + // .find_with_related(Baker) + // .select_only() + // .column(bakery::Column::Name) + // .column(baker::Column::Name) + // .all(&db) + // .await?, + // [ + // ( + // bakery::Model { + // id: 1, + // name: "SeaSide Bakery".to_string(), + // profit_margin: 10.3, + // }, + // vec![baker::Model { + // id: 1, + // name: "Baker Bob".to_owned(), + // contact_details: serde_json::json!({ + // "mobile": "+61424000000", + // "home": "0395555555", + // "address": "12 Test St, Testville, Vic, Australia" + // }), + // bakery_id: Some(1), + // }, + // { + // baker::Model { + // id: 2, + // name: "Baker Bobby".to_owned(), + // contact_details: serde_json::json!({ + // "mobile": "+85212345678", + // }), + // bakery_id: Some(1), + // } + // }], + // ) + // ] + // ); + + // assert_eq!( + // db.into_transaction_log(), + // [Transaction::many([Statement::from_sql_and_values( + // DbBackend::Postgres, + // [ + // r#"SELECT "bakery"."name", "baker"."name""#, + // r#"FROM "bakery""#, + // r#"LEFT JOIN "baker" ON "bakery"."id" = "baker"."bakery_id""#, + // r#"ORDER BY "bakery"."id" ASC"# + // ] + // .join(" ") + // .as_str(), + // [] + // ),])] + // ); + + // Ok(()) + // } } diff --git a/tests/relational_tests.rs b/tests/relational_tests.rs index 428ce45ec..63fe481e3 100644 --- a/tests/relational_tests.rs +++ b/tests/relational_tests.rs @@ -494,190 +494,6 @@ pub async fn having() { ctx.delete().await; } -#[sea_orm_macros::test] -#[cfg(any( - feature = "mock", -))] -pub async fn mock_also_related() -> Result<(), DbErr> { - use sea_orm::{MockDatabase, DbBackend, Transaction}; - - - #[derive(Debug, FromQueryResult, PartialEq)] - struct BakerLite { - name: String, - } - - #[derive(Debug, FromQueryResult, PartialEq)] - struct BakeryLite { - name: String, - } - - let db = MockDatabase::new(DbBackend::Postgres) - .append_query_results([[ - ( - bakery::Model { - id: 1, - name: "SeaSide Bakery".to_string(), - profit_margin: 10.3, - }, - baker::Model { - id: 1, - name: "Baker Bob".to_owned(), - contact_details: serde_json::json!({ - "mobile": "+61424000000", - "home": "0395555555", - "address": "12 Test St, Testville, Vic, Australia" - }), - bakery_id: Some(1), - }, - ) - ]]) - .into_connection(); - - assert_eq!( - Bakery::find() - .find_also_related(Baker) - .select_only() - .column(bakery::Column::Name) - .column(baker::Column::Name) - .all(&db) - .await?, - [ - ( - bakery::Model { - id: 1, - name: "SeaSide Bakery".to_string(), - profit_margin: 10.3, - }, - Some(baker::Model { - id: 1, - name: "Baker Bob".to_owned(), - contact_details: serde_json::json!({ - "mobile": "+61424000000", - "home": "0395555555", - "address": "12 Test St, Testville, Vic, Australia" - }), - bakery_id: Some(1), - }), - ) - ] - ); - - Ok(()) -} - -#[sea_orm_macros::test] -#[cfg(any( - feature = "mock", -))] -pub async fn mock_with_related() -> Result<(), DbErr> { - use sea_orm::{MockDatabase, DbBackend, Transaction}; - - #[derive(Debug, FromQueryResult, PartialEq)] - struct BakerLite { - name: String, - } - - #[derive(Debug, FromQueryResult, PartialEq)] - struct BakeryLite { - name: String, - } - - let db = MockDatabase::new(DbBackend::Postgres) - .append_query_results([[ - ( - bakery::Model { - id: 1, - name: "SeaSide Bakery".to_string(), - profit_margin: 10.3, - }, - baker::Model { - id: 1, - name: "Baker Bob".to_owned(), - contact_details: serde_json::json!({ - "mobile": "+61424000000", - "home": "0395555555", - "address": "12 Test St, Testville, Vic, Australia" - }), - bakery_id: Some(1), - } - ), - ( - bakery::Model { - id: 1, - name: "SeaSide Bakery".to_string(), - profit_margin: 10.3, - }, - baker::Model { - id: 2, - name: "Baker Bobby".to_owned(), - contact_details: serde_json::json!({ - "mobile": "+85212345678", - }), - bakery_id: Some(1), - } - ) - ]]) - .into_connection(); - - assert_eq!( - Bakery::find() - .find_with_related(Baker) - .select_only() - .column(bakery::Column::Name) - .column(baker::Column::Name) - .all(&db) - .await?, - [ - ( - bakery::Model { - id: 1, - name: "SeaSide Bakery".to_string(), - profit_margin: 10.3, - }, - vec![baker::Model { - id: 1, - name: "Baker Bob".to_owned(), - contact_details: serde_json::json!({ - "mobile": "+61424000000", - "home": "0395555555", - "address": "12 Test St, Testville, Vic, Australia" - }), - bakery_id: Some(1), - }, - { - baker::Model { - id: 2, - name: "Baker Bobby".to_owned(), - contact_details: serde_json::json!({ - "mobile": "+85212345678", - }), - bakery_id: Some(1), - } - }], - ) - ] - ); - - assert_eq!( - db.into_transaction_log(), - [Transaction::many([Statement::from_sql_and_values( - DbBackend::Postgres, - [ - r#"SELECT "bakery"."name", "baker"."name""#, - r#"FROM "bakery""#, - r#"LEFT JOIN "baker" ON "bakery"."id" = "baker"."bakery_id""#, - r#"ORDER BY "bakery"."id" ASC"# - ] - .join(" ") - .as_str(), - [] - ),])] - ); - - Ok(()) -} - #[sea_orm_macros::test] #[cfg(any( feature = "sqlx-mysql", @@ -762,6 +578,7 @@ pub async fn related() -> Result<(), DbErr> { name: String, } + // get all bakery and baker's name and put them into tuples let bakers_in_bakery: Vec<(BakeryLite, Option)> = Bakery::find() .find_also_related(Baker) .select_only() @@ -1136,6 +953,8 @@ pub async fn linked() -> Result<(), DbErr> { ) .group_by(baker::Column::Id) .group_by(Expr::col((Alias::new("r4"), customer::Column::Id))) + .group_by(baker::Column::Name) + .group_by(Expr::col((Alias::new("r4"), customer::Column::Name))) .order_by_asc(baker::Column::Id) .order_by_asc(Expr::col((Alias::new("r4"), customer::Column::Id))) .into_model() From ba655fa95735ec415ef5b58ec5baf851a0bff278 Mon Sep 17 00:00:00 2001 From: Yiu Tin Cheung Ivan Date: Thu, 17 Aug 2023 10:28:12 +0800 Subject: [PATCH 08/23] revert loader test --- tests/loader_tests.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tests/loader_tests.rs b/tests/loader_tests.rs index 4938ae7df..c0cb408b1 100644 --- a/tests/loader_tests.rs +++ b/tests/loader_tests.rs @@ -47,7 +47,6 @@ async fn loader_load_many() -> Result<(), DbErr> { let bakery_1 = insert_bakery(&ctx.db, "SeaSide Bakery").await?; let bakery_2 = insert_bakery(&ctx.db, "Offshore Bakery").await?; - let bakery_3 = insert_bakery(&ctx.db, "Offshore Bakery").await?; let baker_1 = insert_baker(&ctx.db, "Baker 1", bakery_1.id).await?; let baker_2 = insert_baker(&ctx.db, "Baker 2", bakery_1.id).await?; @@ -116,7 +115,6 @@ async fn loader_load_many_multi() -> Result<(), DbErr> { let bakery_1 = insert_bakery(&ctx.db, "SeaSide Bakery").await?; let bakery_2 = insert_bakery(&ctx.db, "Offshore Bakery").await?; - let bakery_3 = insert_bakery(&ctx.db, "Onshore Bakery").await?; let baker_1 = insert_baker(&ctx.db, "John", bakery_1.id).await?; let baker_2 = insert_baker(&ctx.db, "Jane", bakery_1.id).await?; @@ -131,9 +129,9 @@ async fn loader_load_many_multi() -> Result<(), DbErr> { let bakers = bakeries.load_many(baker::Entity, &ctx.db).await?; let cakes = bakeries.load_many(cake::Entity, &ctx.db).await?; - assert_eq!(bakeries, [bakery_1, bakery_2, bakery_3]); - assert_eq!(bakers, [vec![baker_1, baker_2], vec![baker_3], vec![]]); - assert_eq!(cakes, [vec![cake_1], vec![cake_2, cake_3], vec![]]); + assert_eq!(bakeries, [bakery_1, bakery_2]); + assert_eq!(bakers, [vec![baker_1, baker_2], vec![baker_3]]); + assert_eq!(cakes, [vec![cake_1], vec![cake_2, cake_3]]); Ok(()) } From 133e16dded3b6fba6e235de5864754736e6c0057 Mon Sep 17 00:00:00 2001 From: Yiu Tin Cheung Ivan Date: Thu, 17 Aug 2023 10:53:39 +0800 Subject: [PATCH 09/23] related select test done --- src/database/mock.rs | 27 +++++++++++++++++++++++++ src/executor/select.rs | 45 ++++++++++++++++++++++++------------------ 2 files changed, 53 insertions(+), 19 deletions(-) diff --git a/src/database/mock.rs b/src/database/mock.rs index df222d8ee..e760ceaf7 100644 --- a/src/database/mock.rs +++ b/src/database/mock.rs @@ -285,6 +285,33 @@ where } } +impl IntoMockRow for (M, Option) +where + M: ModelTrait, + N: ModelTrait, +{ + fn into_mock_row(self) -> MockRow { + let mut mapped_join = BTreeMap::new(); + + for column in <::Entity as EntityTrait>::Column::iter() { + mapped_join.insert( + format!("{}{}", SelectA.as_str(), column.as_str()), + self.0.get(column), + ); + } + if let Some(b_entity) = self.1 { + for column in <::Entity as EntityTrait>::Column::iter() { + mapped_join.insert( + format!("{}{}", SelectB.as_str(), column.as_str()), + b_entity.get(column), + ); + } + } + + mapped_join.into_mock_row() + } +} + impl IntoMockRow for BTreeMap where T: Into, diff --git a/src/executor/select.rs b/src/executor/select.rs index 7796e2755..9c68ca545 100644 --- a/src/executor/select.rs +++ b/src/executor/select.rs @@ -1263,20 +1263,17 @@ mod tests { Ok(()) } - // fixme: unsure on how to insert a cake with no fruit into query_result - // #[smol_potat::test] + #[smol_potat::test] pub async fn also_related_4() -> Result<(), sea_orm::DbErr> { use sea_orm::tests_cfg::*; - use sea_orm::{DbBackend, EntityTrait, MockDatabase, QuerySelect}; + use sea_orm::{DbBackend, EntityTrait, MockDatabase, QuerySelect, IntoMockRow}; let db = MockDatabase::new(DbBackend::Postgres) .append_query_results([[ - cake_fruit_model(1, "apple cake".to_owned(), 1, "apple".to_owned()), - cake_fruit_model(1, "apple cake".to_owned(), 2, "orange".to_owned()), - cake_fruit_model(2, "orange cake".to_owned(), 2, "orange".to_owned()), - ]]) - .append_query_results([[ - cake_model(3, "chocolate cake".to_owned()), // no fruit in cake + cake_fruit_model(1, "apple cake".to_owned(), 1, "apple".to_owned()).into_mock_row(), + cake_fruit_model(1, "apple cake".to_owned(), 2, "orange".to_owned()).into_mock_row(), + cake_fruit_model(2, "orange cake".to_owned(), 2, "orange".to_owned()).into_mock_row(), + (cake_model(3, "chocolate cake".to_owned()), None::).into_mock_row(), ]]) .into_connection(); @@ -1317,7 +1314,8 @@ mod tests { let db = MockDatabase::new(DbBackend::Postgres) .append_query_results([[ cake_fruit_model(1, "apple cake".to_owned(), 1, "apple".to_owned()), - cake_fruit_model(1, "apple cake".to_owned(), 2, "orange".to_owned()), + cake_fruit_model(2, "fruit cake".to_owned(), 1, "apple".to_owned()), + cake_fruit_model(2, "fruit cake".to_owned(), 2, "orange".to_owned()), ]]) .into_connection(); @@ -1332,8 +1330,14 @@ mod tests { [( cake_model(1, "apple cake".to_owned()), vec![ - fruit_model(1, "apple".to_owned(), Some(1)), - fruit_model(2, "orange".to_owned(), Some(1)) + fruit_model(1, "apple".to_owned(), Some(1)) + ] + ), + ( + cake_model(2, "fruit cake".to_owned()), + vec![ + fruit_model(1, "apple".to_owned(), Some(2)), + fruit_model(2, "orange".to_owned(), Some(2)) ] )] ); @@ -1361,15 +1365,15 @@ mod tests { #[cfg(any(feature = "mock",))] pub async fn with_related_2() -> Result<(), sea_orm::DbErr> { use sea_orm::tests_cfg::*; - use sea_orm::{DbBackend, EntityTrait, MockDatabase, QuerySelect}; + use sea_orm::{DbBackend, EntityTrait, MockDatabase, QuerySelect, IntoMockRow}; let db = MockDatabase::new(DbBackend::Postgres) .append_query_results([[ - cake_fruit_model(1, "apple cake".to_owned(), 1, "apple".to_owned()), - cake_fruit_model(2, "fruit cake".to_owned(), 1, "apple".to_owned()), - cake_fruit_model(2, "fruit cake".to_owned(), 2, "orange".to_owned()), - cake_fruit_model(2, "fruit cake".to_owned(), 3, "grape".to_owned()), - cake_fruit_model(2, "fruit cake".to_owned(), 4, "melon".to_owned()), + cake_fruit_model(1, "apple cake".to_owned(), 1, "apple".to_owned()).into_mock_row(), + cake_fruit_model(2, "fruit cake".to_owned(), 1, "apple".to_owned()).into_mock_row(), + cake_fruit_model(2, "fruit cake".to_owned(), 2, "orange".to_owned()).into_mock_row(), + (cake_model(2, "fruit cake".to_owned()), Some(fruit_model(3, "grape".to_owned(), Some(2)))).into_mock_row(), + (cake_model(3, "chocolate cake".to_owned()), None::).into_mock_row() ]]) .into_connection(); @@ -1392,8 +1396,11 @@ mod tests { fruit_model(1, "apple".to_owned(), Some(2)), fruit_model(2, "orange".to_owned(), Some(2)), fruit_model(3, "grape".to_owned(), Some(2)), - fruit_model(4, "melon".to_owned(), Some(2)), ] + ), + ( + cake_model(3, "chocolate cake".to_owned()), + vec![] ) ] ); From 4bb7b1e07c5546a2c1e18e9c76cb7f71fa8a9176 Mon Sep 17 00:00:00 2001 From: Yiu Tin Cheung Ivan Date: Thu, 17 Aug 2023 14:07:40 +0800 Subject: [PATCH 10/23] find with/also linked test cases --- src/executor/select.rs | 268 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 246 insertions(+), 22 deletions(-) diff --git a/src/executor/select.rs b/src/executor/select.rs index 9c68ca545..d6559c072 100644 --- a/src/executor/select.rs +++ b/src/executor/select.rs @@ -595,7 +595,7 @@ where /// /// > `SelectTwoMany::one()` method has been dropped (#486) /// > - /// > You can get `(Entity, Vec)` by first querying a single model from Entity, + /// > You can get `(Entity, Vec)` by first querying a single model from Entity, /// > then use [`ModelTrait::find_related`] on the model. /// > /// > See https://www.sea-ql.org/SeaORM/docs/basic-crud/select#lazy-loading for details. @@ -1159,9 +1159,6 @@ mod tests { assert_eq!( Cake::find() .find_also_related(Fruit) - .select_only() - .column(cake::Column::Name) - .column(fruit::Column::Name) .all(&db) .await?, [( @@ -1175,9 +1172,10 @@ mod tests { [Transaction::many([Statement::from_sql_and_values( DbBackend::Postgres, [ - r#"SELECT "cake"."name", "fruit"."name""#, + r#"SELECT "cake"."id" AS "A_id", "cake"."name" AS "A_name","#, + r#""fruit"."id" AS "B_id", "fruit"."name" AS "B_name", "fruit"."cake_id" AS "B_cake_id""#, r#"FROM "cake""#, - r#"LEFT JOIN "fruit" ON "cake"."id" = "fruit"."cake_id""# + r#"LEFT JOIN "fruit" ON "cake"."id" = "fruit"."cake_id""#, ] .join(" ") .as_str(), @@ -1203,9 +1201,6 @@ mod tests { assert_eq!( Cake::find() .find_also_related(Fruit) - .select_only() - .column(cake::Column::Name) - .column(fruit::Column::Name) .all(&db) .await?, [ @@ -1239,9 +1234,6 @@ mod tests { assert_eq!( Cake::find() .find_also_related(Fruit) - .select_only() - .column(cake::Column::Name) - .column(fruit::Column::Name) .all(&db) .await?, [ @@ -1280,9 +1272,6 @@ mod tests { assert_eq!( Cake::find() .find_also_related(Fruit) - .select_only() - .column(cake::Column::Name) - .column(fruit::Column::Name) .all(&db) .await?, [ @@ -1322,9 +1311,6 @@ mod tests { assert_eq!( Cake::find() .find_with_related(Fruit) - .select_only() - .column(cake::Column::Name) - .column(fruit::Column::Name) .all(&db) .await?, [( @@ -1347,7 +1333,8 @@ mod tests { [Transaction::many([Statement::from_sql_and_values( DbBackend::Postgres, [ - r#"SELECT "cake"."name", "fruit"."name""#, + r#"SELECT "cake"."id" AS "A_id", "cake"."name" AS "A_name","#, + r#""fruit"."id" AS "B_id", "fruit"."name" AS "B_name", "fruit"."cake_id" AS "B_cake_id""#, r#"FROM "cake""#, r#"LEFT JOIN "fruit" ON "cake"."id" = "fruit"."cake_id""#, r#"ORDER BY "cake"."id" ASC"# @@ -1380,9 +1367,6 @@ mod tests { assert_eq!( Cake::find() .find_with_related(Fruit) - .select_only() - .column(cake::Column::Name) - .column(fruit::Column::Name) .all(&db) .await?, [ @@ -1407,4 +1391,244 @@ mod tests { Ok(()) } + + fn cake_filling_link( + cake_id: i32, + cake_name: String, + filling_id: i32, + filling_name: String, + ) -> ( + sea_orm::tests_cfg::cake::Model, + sea_orm::tests_cfg::filling::Model, + ) { + ( + cake_model(cake_id, cake_name), + filling_model(filling_id, filling_name), + ) + } + + fn cake_filling_model ( + cake_id: i32, + filling_id: i32, + ) -> sea_orm::tests_cfg::cake_filling::Model { + sea_orm::tests_cfg::cake_filling::Model { cake_id, filling_id } + } + + fn filling_model( + id: i32, + name: String, + ) -> sea_orm::tests_cfg::filling::Model { + sea_orm::tests_cfg::filling::Model { id, name, vendor_id:None, ignored_attr:0 } + } + + #[smol_potat::test] + pub async fn also_linked() -> Result<(), sea_orm::DbErr> { + use sea_orm::tests_cfg::*; + use sea_orm::{DbBackend, EntityTrait, MockDatabase, QuerySelect, Statement, Transaction}; + + let db = MockDatabase::new(DbBackend::Postgres) + .append_query_results([[cake_filling_link( + 1, + "apple cake".to_owned(), + 1, + "apple juice".to_owned(), + )]]) + .into_connection(); + + assert_eq!( + Cake::find() + .find_also_linked(entity_linked::CakeToFilling) + .all(&db) + .await?, + [( + cake_model(1, "apple cake".to_owned()), + Some(filling_model(1, "apple juice".to_owned())) + )] + ); + + assert_eq!( + db.into_transaction_log(), + [Transaction::many([Statement::from_sql_and_values( + DbBackend::Postgres, + [ + r#"SELECT "cake"."id" AS "A_id", "cake"."name" AS "A_name","#, + r#""r1"."id" AS "B_id", "r1"."name" AS "B_name", "r1"."vendor_id" AS "B_vendor_id""#, + r#"FROM "cake""#, + r#"LEFT JOIN "cake_filling" AS "r0" ON "cake"."id" = "r0"."cake_id""#, + r#"LEFT JOIN "filling" AS "r1" ON "r0"."filling_id" = "r1"."id""#, + ] + .join(" ") + .as_str(), + [] + ),])] + ); + + Ok(()) + } + + #[smol_potat::test] + pub async fn also_linked_2() -> Result<(), sea_orm::DbErr> { + use sea_orm::tests_cfg::*; + use sea_orm::{DbBackend, EntityTrait, MockDatabase, QuerySelect, Statement, Transaction}; + + let db = MockDatabase::new(DbBackend::Postgres) + .append_query_results([[ + cake_filling_link(1, "apple cake".to_owned(), 1, "apple juice".to_owned()), + cake_filling_link(2, "fruit cake".to_owned(), 1, "apple juice".to_owned()), + cake_filling_link(2, "fruit cake".to_owned(), 2, "orange jam".to_owned()), + ]]) + .into_connection(); + + assert_eq!( + Cake::find() + .find_also_linked(entity_linked::CakeToFilling) + .all(&db) + .await?, + [( + cake_model(1, "apple cake".to_owned()), + Some(filling_model(1, "apple juice".to_owned())) + ), ( + cake_model(2, "fruit cake".to_owned()), + Some(filling_model(1, "apple juice".to_owned())) + ), ( + cake_model(2, "fruit cake".to_owned()), + Some(filling_model(2, "orange jam".to_owned())) + )] + ); + + Ok(()) + } + + #[smol_potat::test] + pub async fn also_linked_3() -> Result<(), sea_orm::DbErr> { + use sea_orm::tests_cfg::*; + use sea_orm::{DbBackend, EntityTrait, MockDatabase, QuerySelect, Statement, Transaction, IntoMockRow}; + + let db = MockDatabase::new(DbBackend::Postgres) + .append_query_results([[ + cake_filling_link(1, "apple cake".to_owned(), 1, "apple juice".to_owned()).into_mock_row(), + cake_filling_link(2, "fruit cake".to_owned(), 1, "apple juice".to_owned()).into_mock_row(), + cake_filling_link(2, "fruit cake".to_owned(), 2, "orange jam".to_owned()).into_mock_row(), + (cake_model(3, "chocolate cake".to_owned()), None::).into_mock_row() + ]]) + .into_connection(); + + assert_eq!( + Cake::find() + .find_also_linked(entity_linked::CakeToFilling) + .all(&db) + .await?, + [( + cake_model(1, "apple cake".to_owned()), + Some(filling_model(1, "apple juice".to_owned())) + ), ( + cake_model(2, "fruit cake".to_owned()), + Some(filling_model(1, "apple juice".to_owned())) + ), ( + cake_model(2, "fruit cake".to_owned()), + Some(filling_model(2, "orange jam".to_owned())) + ), ( + cake_model(3, "chocolate cake".to_owned()), + None + )] + ); + + Ok(()) + } + + #[smol_potat::test] + #[cfg(any(feature = "mock",))] + pub async fn with_linked() -> Result<(), sea_orm::DbErr> { + use sea_orm::tests_cfg::*; + use sea_orm::{DbBackend, EntityTrait, MockDatabase, QuerySelect, Statement, Transaction}; + + let db = MockDatabase::new(DbBackend::Postgres) + .append_query_results([[ + cake_filling_link(1, "apple cake".to_owned(), 1, "apple juice".to_owned()), + cake_filling_link(2, "fruit cake".to_owned(), 1, "apple juice".to_owned()), + cake_filling_link(2, "fruit cake".to_owned(), 2, "orange jam".to_owned()), + ]]) + .into_connection(); + + assert_eq!( + Cake::find() + .find_with_linked(entity_linked::CakeToFilling) + .all(&db) + .await?, + [( + cake_model(1, "apple cake".to_owned()), + vec![ + filling_model(1, "apple juice".to_owned()) + ] + ), + ( + cake_model(2, "fruit cake".to_owned()), + vec![ + filling_model(1, "apple juice".to_owned()), + filling_model(2, "orange jam".to_owned()) + ] + )] + ); + + assert_eq!( + db.into_transaction_log(), + [Transaction::many([Statement::from_sql_and_values( + DbBackend::Postgres, + [ + r#"SELECT "cake"."id" AS "A_id", "cake"."name" AS "A_name","#, + r#""r1"."id" AS "B_id", "r1"."name" AS "B_name", "r1"."vendor_id" AS "B_vendor_id""#, + r#"FROM "cake""#, + r#"LEFT JOIN "cake_filling" AS "r0" ON "cake"."id" = "r0"."cake_id""#, + r#"LEFT JOIN "filling" AS "r1" ON "r0"."filling_id" = "r1"."id""#, + ] + .join(" ") + .as_str(), + [] + ),])] + ); + + Ok(()) + } + + #[smol_potat::test] + #[cfg(any(feature = "mock",))] + pub async fn with_linked_2() -> Result<(), sea_orm::DbErr> { + use sea_orm::tests_cfg::*; + use sea_orm::{DbBackend, EntityTrait, MockDatabase, QuerySelect, IntoMockRow}; + + let db = MockDatabase::new(DbBackend::Postgres) + .append_query_results([[ + cake_filling_link(1, "apple cake".to_owned(), 1, "apple juice".to_owned()).into_mock_row(), + cake_filling_link(2, "fruit cake".to_owned(), 1, "apple juice".to_owned()).into_mock_row(), + cake_filling_link(2, "fruit cake".to_owned(), 2, "orange jam".to_owned()).into_mock_row(), + (cake_model(3, "chocolate cake".to_owned()), None::).into_mock_row() + ]]) + .into_connection(); + + assert_eq!( + Cake::find() + .find_with_linked(entity_linked::CakeToFilling) + .all(&db) + .await?, + [ + ( + cake_model(1, "apple cake".to_owned()), + vec![filling_model(1, "apple juice".to_owned()),] + ), + ( + cake_model(2, "fruit cake".to_owned()), + vec![ + filling_model(1, "apple juice".to_owned()), + filling_model(2, "orange jam".to_owned()), + ] + ), + ( + cake_model(3, "chocolate cake".to_owned()), + vec![] + ) + ] + ); + + Ok(()) + } } From 80158e1ac5061114b86ae4f98988140ba579ba43 Mon Sep 17 00:00:00 2001 From: Yiu Tin Cheung Ivan Date: Thu, 17 Aug 2023 14:30:09 +0800 Subject: [PATCH 11/23] removed due to it being functionally same as the new one --- src/query/join.rs | 176 +--------------------------------------------- 1 file changed, 1 insertion(+), 175 deletions(-) diff --git a/src/query/join.rs b/src/query/join.rs index 17efa1708..8371b58be 100644 --- a/src/query/join.rs +++ b/src/query/join.rs @@ -637,178 +637,4 @@ mod tests { .join(" ") ); } - - // TODO: change schema since moving from tests into src files - // #[smol_potat::test] - // #[cfg(any( - // feature = "mock", - // ))] - // pub async fn mock_also_related() -> Result<(), sea_orm::DbErr> { - // use sea_orm::{MockDatabase, DbBackend, Transaction}; - - // let db = MockDatabase::new(DbBackend::Postgres) - // .append_query_results([[ - // ( - // bakery::Model { - // id: 1, - // name: "SeaSide Bakery".to_string(), - // profit_margin: 10.3, - // }, - // baker::Model { - // id: 1, - // name: "Baker Bob".to_owned(), - // contact_details: serde_json::json!({ - // "mobile": "+61424000000", - // "home": "0395555555", - // "address": "12 Test St, Testville, Vic, Australia" - // }), - // bakery_id: Some(1), - // }, - // ) - // ]]) - // .into_connection(); - - // assert_eq!( - // Bakery::find() - // .find_also_related(Baker) - // .select_only() - // .column(bakery::Column::Name) - // .column(baker::Column::Name) - // .all(&db) - // .await?, - // [ - // ( - // bakery::Model { - // id: 1, - // name: "SeaSide Bakery".to_string(), - // profit_margin: 10.3, - // }, - // Some(baker::Model { - // id: 1, - // name: "Baker Bob".to_owned(), - // contact_details: serde_json::json!({ - // "mobile": "+61424000000", - // "home": "0395555555", - // "address": "12 Test St, Testville, Vic, Australia" - // }), - // bakery_id: Some(1), - // }), - // ) - // ] - // ); - - // Ok(()) - // } - - // #[smol_potat::test] - // #[cfg(any( - // feature = "mock", - // ))] - // pub async fn mock_with_related() -> Result<(), sea_orm::DbErr> { - // use sea_orm::{MockDatabase, DbBackend, Transaction}; - - // #[derive(Debug, FromQueryResult, PartialEq)] - // struct BakerLite { - // name: String, - // } - - // #[derive(Debug, FromQueryResult, PartialEq)] - // struct BakeryLite { - // name: String, - // } - - // let db = MockDatabase::new(DbBackend::Postgres) - // .append_query_results([[ - // ( - // bakery::Model { - // id: 1, - // name: "SeaSide Bakery".to_string(), - // profit_margin: 10.3, - // }, - // baker::Model { - // id: 1, - // name: "Baker Bob".to_owned(), - // contact_details: serde_json::json!({ - // "mobile": "+61424000000", - // "home": "0395555555", - // "address": "12 Test St, Testville, Vic, Australia" - // }), - // bakery_id: Some(1), - // } - // ), - // ( - // bakery::Model { - // id: 1, - // name: "SeaSide Bakery".to_string(), - // profit_margin: 10.3, - // }, - // baker::Model { - // id: 2, - // name: "Baker Bobby".to_owned(), - // contact_details: serde_json::json!({ - // "mobile": "+85212345678", - // }), - // bakery_id: Some(1), - // } - // ) - // ]]) - // .into_connection(); - - // assert_eq!( - // Bakery::find() - // .find_with_related(Baker) - // .select_only() - // .column(bakery::Column::Name) - // .column(baker::Column::Name) - // .all(&db) - // .await?, - // [ - // ( - // bakery::Model { - // id: 1, - // name: "SeaSide Bakery".to_string(), - // profit_margin: 10.3, - // }, - // vec![baker::Model { - // id: 1, - // name: "Baker Bob".to_owned(), - // contact_details: serde_json::json!({ - // "mobile": "+61424000000", - // "home": "0395555555", - // "address": "12 Test St, Testville, Vic, Australia" - // }), - // bakery_id: Some(1), - // }, - // { - // baker::Model { - // id: 2, - // name: "Baker Bobby".to_owned(), - // contact_details: serde_json::json!({ - // "mobile": "+85212345678", - // }), - // bakery_id: Some(1), - // } - // }], - // ) - // ] - // ); - - // assert_eq!( - // db.into_transaction_log(), - // [Transaction::many([Statement::from_sql_and_values( - // DbBackend::Postgres, - // [ - // r#"SELECT "bakery"."name", "baker"."name""#, - // r#"FROM "bakery""#, - // r#"LEFT JOIN "baker" ON "bakery"."id" = "baker"."bakery_id""#, - // r#"ORDER BY "bakery"."id" ASC"# - // ] - // .join(" ") - // .as_str(), - // [] - // ),])] - // ); - - // Ok(()) - // } -} +} \ No newline at end of file From 99c3a573a9b8fafac7a7ea3b061766886a72f457 Mon Sep 17 00:00:00 2001 From: Yiu Tin Cheung Ivan Date: Thu, 17 Aug 2023 15:35:43 +0800 Subject: [PATCH 12/23] fmt, remove excess import --- src/executor/select.rs | 251 +++++++++++++++++++------------------- src/query/join.rs | 2 +- tests/relational_tests.rs | 65 +++++----- 3 files changed, 158 insertions(+), 160 deletions(-) diff --git a/src/executor/select.rs b/src/executor/select.rs index d6559c072..d4b0472d5 100644 --- a/src/executor/select.rs +++ b/src/executor/select.rs @@ -1110,10 +1110,7 @@ where #[cfg(test)] mod tests { - use crate::tests_cfg::{cake_filling, cake_filling_price, entity_linked, filling, fruit}; - use crate::{DbBackend, ModelTrait, QueryFilter, QueryTrait, RelationTrait}; use pretty_assertions::assert_eq; - use sea_query::{ConditionType, Expr, IntoCondition, JoinType}; fn cake_fruit_model( cake_id: i32, @@ -1145,7 +1142,7 @@ mod tests { #[smol_potat::test] pub async fn also_related() -> Result<(), sea_orm::DbErr> { use sea_orm::tests_cfg::*; - use sea_orm::{DbBackend, EntityTrait, MockDatabase, QuerySelect, Statement, Transaction}; + use sea_orm::{DbBackend, EntityTrait, MockDatabase, Statement, Transaction}; let db = MockDatabase::new(DbBackend::Postgres) .append_query_results([[cake_fruit_model( @@ -1157,10 +1154,7 @@ mod tests { .into_connection(); assert_eq!( - Cake::find() - .find_also_related(Fruit) - .all(&db) - .await?, + Cake::find().find_also_related(Fruit).all(&db).await?, [( cake_model(1, "apple cake".to_owned()), Some(fruit_model(1, "apple".to_owned(), Some(1))) @@ -1189,7 +1183,7 @@ mod tests { #[smol_potat::test] pub async fn also_related_2() -> Result<(), sea_orm::DbErr> { use sea_orm::tests_cfg::*; - use sea_orm::{DbBackend, EntityTrait, MockDatabase, QuerySelect}; + use sea_orm::{DbBackend, EntityTrait, MockDatabase}; let db = MockDatabase::new(DbBackend::Postgres) .append_query_results([[ @@ -1199,10 +1193,7 @@ mod tests { .into_connection(); assert_eq!( - Cake::find() - .find_also_related(Fruit) - .all(&db) - .await?, + Cake::find().find_also_related(Fruit).all(&db).await?, [ ( cake_model(1, "apple cake".to_owned()), @@ -1232,10 +1223,7 @@ mod tests { .into_connection(); assert_eq!( - Cake::find() - .find_also_related(Fruit) - .all(&db) - .await?, + Cake::find().find_also_related(Fruit).all(&db).await?, [ ( cake_model(1, "apple cake".to_owned()), @@ -1258,22 +1246,25 @@ mod tests { #[smol_potat::test] pub async fn also_related_4() -> Result<(), sea_orm::DbErr> { use sea_orm::tests_cfg::*; - use sea_orm::{DbBackend, EntityTrait, MockDatabase, QuerySelect, IntoMockRow}; + use sea_orm::{DbBackend, EntityTrait, IntoMockRow, MockDatabase}; let db = MockDatabase::new(DbBackend::Postgres) .append_query_results([[ cake_fruit_model(1, "apple cake".to_owned(), 1, "apple".to_owned()).into_mock_row(), - cake_fruit_model(1, "apple cake".to_owned(), 2, "orange".to_owned()).into_mock_row(), - cake_fruit_model(2, "orange cake".to_owned(), 2, "orange".to_owned()).into_mock_row(), - (cake_model(3, "chocolate cake".to_owned()), None::).into_mock_row(), + cake_fruit_model(1, "apple cake".to_owned(), 2, "orange".to_owned()) + .into_mock_row(), + cake_fruit_model(2, "orange cake".to_owned(), 2, "orange".to_owned()) + .into_mock_row(), + ( + cake_model(3, "chocolate cake".to_owned()), + None::, + ) + .into_mock_row(), ]]) .into_connection(); assert_eq!( - Cake::find() - .find_also_related(Fruit) - .all(&db) - .await?, + Cake::find().find_also_related(Fruit).all(&db).await?, [ ( cake_model(1, "apple cake".to_owned()), @@ -1295,10 +1286,9 @@ mod tests { } #[smol_potat::test] - #[cfg(any(feature = "mock",))] pub async fn with_related() -> Result<(), sea_orm::DbErr> { use sea_orm::tests_cfg::*; - use sea_orm::{DbBackend, EntityTrait, MockDatabase, QuerySelect, Statement, Transaction}; + use sea_orm::{DbBackend, EntityTrait, MockDatabase, Statement, Transaction}; let db = MockDatabase::new(DbBackend::Postgres) .append_query_results([[ @@ -1309,23 +1299,20 @@ mod tests { .into_connection(); assert_eq!( - Cake::find() - .find_with_related(Fruit) - .all(&db) - .await?, - [( - cake_model(1, "apple cake".to_owned()), - vec![ - fruit_model(1, "apple".to_owned(), Some(1)) - ] - ), - ( - cake_model(2, "fruit cake".to_owned()), - vec![ - fruit_model(1, "apple".to_owned(), Some(2)), - fruit_model(2, "orange".to_owned(), Some(2)) - ] - )] + Cake::find().find_with_related(Fruit).all(&db).await?, + [ + ( + cake_model(1, "apple cake".to_owned()), + vec![fruit_model(1, "apple".to_owned(), Some(1))] + ), + ( + cake_model(2, "fruit cake".to_owned()), + vec![ + fruit_model(1, "apple".to_owned(), Some(2)), + fruit_model(2, "orange".to_owned(), Some(2)) + ] + ) + ] ); assert_eq!( @@ -1349,26 +1336,31 @@ mod tests { } #[smol_potat::test] - #[cfg(any(feature = "mock",))] pub async fn with_related_2() -> Result<(), sea_orm::DbErr> { use sea_orm::tests_cfg::*; - use sea_orm::{DbBackend, EntityTrait, MockDatabase, QuerySelect, IntoMockRow}; + use sea_orm::{DbBackend, EntityTrait, IntoMockRow, MockDatabase}; let db = MockDatabase::new(DbBackend::Postgres) .append_query_results([[ cake_fruit_model(1, "apple cake".to_owned(), 1, "apple".to_owned()).into_mock_row(), cake_fruit_model(2, "fruit cake".to_owned(), 1, "apple".to_owned()).into_mock_row(), - cake_fruit_model(2, "fruit cake".to_owned(), 2, "orange".to_owned()).into_mock_row(), - (cake_model(2, "fruit cake".to_owned()), Some(fruit_model(3, "grape".to_owned(), Some(2)))).into_mock_row(), - (cake_model(3, "chocolate cake".to_owned()), None::).into_mock_row() + cake_fruit_model(2, "fruit cake".to_owned(), 2, "orange".to_owned()) + .into_mock_row(), + ( + cake_model(2, "fruit cake".to_owned()), + Some(fruit_model(3, "grape".to_owned(), Some(2))), + ) + .into_mock_row(), + ( + cake_model(3, "chocolate cake".to_owned()), + None::, + ) + .into_mock_row(), ]]) .into_connection(); assert_eq!( - Cake::find() - .find_with_related(Fruit) - .all(&db) - .await?, + Cake::find().find_with_related(Fruit).all(&db).await?, [ ( cake_model(1, "apple cake".to_owned()), @@ -1382,10 +1374,7 @@ mod tests { fruit_model(3, "grape".to_owned(), Some(2)), ] ), - ( - cake_model(3, "chocolate cake".to_owned()), - vec![] - ) + (cake_model(3, "chocolate cake".to_owned()), vec![]) ] ); @@ -1407,24 +1396,19 @@ mod tests { ) } - fn cake_filling_model ( - cake_id: i32, - filling_id: i32, - ) -> sea_orm::tests_cfg::cake_filling::Model { - sea_orm::tests_cfg::cake_filling::Model { cake_id, filling_id } - } - - fn filling_model( - id: i32, - name: String, - ) -> sea_orm::tests_cfg::filling::Model { - sea_orm::tests_cfg::filling::Model { id, name, vendor_id:None, ignored_attr:0 } + fn filling_model(id: i32, name: String) -> sea_orm::tests_cfg::filling::Model { + sea_orm::tests_cfg::filling::Model { + id, + name, + vendor_id: None, + ignored_attr: 0, + } } #[smol_potat::test] pub async fn also_linked() -> Result<(), sea_orm::DbErr> { use sea_orm::tests_cfg::*; - use sea_orm::{DbBackend, EntityTrait, MockDatabase, QuerySelect, Statement, Transaction}; + use sea_orm::{DbBackend, EntityTrait, MockDatabase, Statement, Transaction}; let db = MockDatabase::new(DbBackend::Postgres) .append_query_results([[cake_filling_link( @@ -1469,14 +1453,14 @@ mod tests { #[smol_potat::test] pub async fn also_linked_2() -> Result<(), sea_orm::DbErr> { use sea_orm::tests_cfg::*; - use sea_orm::{DbBackend, EntityTrait, MockDatabase, QuerySelect, Statement, Transaction}; + use sea_orm::{DbBackend, EntityTrait, MockDatabase}; let db = MockDatabase::new(DbBackend::Postgres) .append_query_results([[ cake_filling_link(1, "apple cake".to_owned(), 1, "apple juice".to_owned()), cake_filling_link(2, "fruit cake".to_owned(), 1, "apple juice".to_owned()), cake_filling_link(2, "fruit cake".to_owned(), 2, "orange jam".to_owned()), - ]]) + ]]) .into_connection(); assert_eq!( @@ -1484,16 +1468,20 @@ mod tests { .find_also_linked(entity_linked::CakeToFilling) .all(&db) .await?, - [( - cake_model(1, "apple cake".to_owned()), - Some(filling_model(1, "apple juice".to_owned())) - ), ( - cake_model(2, "fruit cake".to_owned()), - Some(filling_model(1, "apple juice".to_owned())) - ), ( - cake_model(2, "fruit cake".to_owned()), - Some(filling_model(2, "orange jam".to_owned())) - )] + [ + ( + cake_model(1, "apple cake".to_owned()), + Some(filling_model(1, "apple juice".to_owned())) + ), + ( + cake_model(2, "fruit cake".to_owned()), + Some(filling_model(1, "apple juice".to_owned())) + ), + ( + cake_model(2, "fruit cake".to_owned()), + Some(filling_model(2, "orange jam".to_owned())) + ) + ] ); Ok(()) @@ -1502,15 +1490,22 @@ mod tests { #[smol_potat::test] pub async fn also_linked_3() -> Result<(), sea_orm::DbErr> { use sea_orm::tests_cfg::*; - use sea_orm::{DbBackend, EntityTrait, MockDatabase, QuerySelect, Statement, Transaction, IntoMockRow}; + use sea_orm::{DbBackend, EntityTrait, IntoMockRow, MockDatabase}; let db = MockDatabase::new(DbBackend::Postgres) .append_query_results([[ - cake_filling_link(1, "apple cake".to_owned(), 1, "apple juice".to_owned()).into_mock_row(), - cake_filling_link(2, "fruit cake".to_owned(), 1, "apple juice".to_owned()).into_mock_row(), - cake_filling_link(2, "fruit cake".to_owned(), 2, "orange jam".to_owned()).into_mock_row(), - (cake_model(3, "chocolate cake".to_owned()), None::).into_mock_row() - ]]) + cake_filling_link(1, "apple cake".to_owned(), 1, "apple juice".to_owned()) + .into_mock_row(), + cake_filling_link(2, "fruit cake".to_owned(), 1, "apple juice".to_owned()) + .into_mock_row(), + cake_filling_link(2, "fruit cake".to_owned(), 2, "orange jam".to_owned()) + .into_mock_row(), + ( + cake_model(3, "chocolate cake".to_owned()), + None::, + ) + .into_mock_row(), + ]]) .into_connection(); assert_eq!( @@ -1518,29 +1513,30 @@ mod tests { .find_also_linked(entity_linked::CakeToFilling) .all(&db) .await?, - [( - cake_model(1, "apple cake".to_owned()), - Some(filling_model(1, "apple juice".to_owned())) - ), ( - cake_model(2, "fruit cake".to_owned()), - Some(filling_model(1, "apple juice".to_owned())) - ), ( - cake_model(2, "fruit cake".to_owned()), - Some(filling_model(2, "orange jam".to_owned())) - ), ( - cake_model(3, "chocolate cake".to_owned()), - None - )] + [ + ( + cake_model(1, "apple cake".to_owned()), + Some(filling_model(1, "apple juice".to_owned())) + ), + ( + cake_model(2, "fruit cake".to_owned()), + Some(filling_model(1, "apple juice".to_owned())) + ), + ( + cake_model(2, "fruit cake".to_owned()), + Some(filling_model(2, "orange jam".to_owned())) + ), + (cake_model(3, "chocolate cake".to_owned()), None) + ] ); Ok(()) } #[smol_potat::test] - #[cfg(any(feature = "mock",))] pub async fn with_linked() -> Result<(), sea_orm::DbErr> { use sea_orm::tests_cfg::*; - use sea_orm::{DbBackend, EntityTrait, MockDatabase, QuerySelect, Statement, Transaction}; + use sea_orm::{DbBackend, EntityTrait, MockDatabase, Statement, Transaction}; let db = MockDatabase::new(DbBackend::Postgres) .append_query_results([[ @@ -1555,19 +1551,19 @@ mod tests { .find_with_linked(entity_linked::CakeToFilling) .all(&db) .await?, - [( - cake_model(1, "apple cake".to_owned()), - vec![ - filling_model(1, "apple juice".to_owned()) - ] - ), - ( - cake_model(2, "fruit cake".to_owned()), - vec![ - filling_model(1, "apple juice".to_owned()), - filling_model(2, "orange jam".to_owned()) - ] - )] + [ + ( + cake_model(1, "apple cake".to_owned()), + vec![filling_model(1, "apple juice".to_owned())] + ), + ( + cake_model(2, "fruit cake".to_owned()), + vec![ + filling_model(1, "apple juice".to_owned()), + filling_model(2, "orange jam".to_owned()) + ] + ) + ] ); assert_eq!( @@ -1591,17 +1587,23 @@ mod tests { } #[smol_potat::test] - #[cfg(any(feature = "mock",))] pub async fn with_linked_2() -> Result<(), sea_orm::DbErr> { use sea_orm::tests_cfg::*; - use sea_orm::{DbBackend, EntityTrait, MockDatabase, QuerySelect, IntoMockRow}; + use sea_orm::{DbBackend, EntityTrait, IntoMockRow, MockDatabase}; let db = MockDatabase::new(DbBackend::Postgres) .append_query_results([[ - cake_filling_link(1, "apple cake".to_owned(), 1, "apple juice".to_owned()).into_mock_row(), - cake_filling_link(2, "fruit cake".to_owned(), 1, "apple juice".to_owned()).into_mock_row(), - cake_filling_link(2, "fruit cake".to_owned(), 2, "orange jam".to_owned()).into_mock_row(), - (cake_model(3, "chocolate cake".to_owned()), None::).into_mock_row() + cake_filling_link(1, "apple cake".to_owned(), 1, "apple juice".to_owned()) + .into_mock_row(), + cake_filling_link(2, "fruit cake".to_owned(), 1, "apple juice".to_owned()) + .into_mock_row(), + cake_filling_link(2, "fruit cake".to_owned(), 2, "orange jam".to_owned()) + .into_mock_row(), + ( + cake_model(3, "chocolate cake".to_owned()), + None::, + ) + .into_mock_row(), ]]) .into_connection(); @@ -1622,10 +1624,7 @@ mod tests { filling_model(2, "orange jam".to_owned()), ] ), - ( - cake_model(3, "chocolate cake".to_owned()), - vec![] - ) + (cake_model(3, "chocolate cake".to_owned()), vec![]) ] ); diff --git a/src/query/join.rs b/src/query/join.rs index 8371b58be..6ed56de0c 100644 --- a/src/query/join.rs +++ b/src/query/join.rs @@ -637,4 +637,4 @@ mod tests { .join(" ") ); } -} \ No newline at end of file +} diff --git a/tests/relational_tests.rs b/tests/relational_tests.rs index 63fe481e3..d0e3f1b13 100644 --- a/tests/relational_tests.rs +++ b/tests/relational_tests.rs @@ -502,7 +502,6 @@ pub async fn having() { ))] pub async fn related() -> Result<(), DbErr> { use sea_orm::{SelectA, SelectB}; - use sea_query::{Alias, Expr}; let ctx = TestContext::new("test_related").await; create_tables(&ctx.db).await?; @@ -526,7 +525,7 @@ pub async fn related() -> Result<(), DbErr> { bakery_id: Set(Some(seaside_bakery_res.last_insert_id)), ..Default::default() }; - let baker_bob_res = Baker::insert(baker_bob).exec(&ctx.db).await?; + let _baker_bob_res = Baker::insert(baker_bob).exec(&ctx.db).await?; // Bobby's Baker let baker_bobby = baker::ActiveModel { @@ -537,7 +536,7 @@ pub async fn related() -> Result<(), DbErr> { bakery_id: Set(Some(seaside_bakery_res.last_insert_id)), ..Default::default() }; - let baker_bobby_res = Baker::insert(baker_bobby).exec(&ctx.db).await?; + let _baker_bobby_res = Baker::insert(baker_bobby).exec(&ctx.db).await?; // Terres Bakery let terres_bakery = bakery::ActiveModel { @@ -558,7 +557,7 @@ pub async fn related() -> Result<(), DbErr> { bakery_id: Set(Some(terres_bakery_res.last_insert_id)), ..Default::default() }; - let baker_ada_res = Baker::insert(baker_ada).exec(&ctx.db).await?; + let _baker_ada_res = Baker::insert(baker_ada).exec(&ctx.db).await?; // Stone Bakery, with no baker let stone_bakery = bakery::ActiveModel { @@ -566,7 +565,7 @@ pub async fn related() -> Result<(), DbErr> { profit_margin: Set(13.5), ..Default::default() }; - let stone_bakery_res = Bakery::insert(stone_bakery).exec(&ctx.db).await?; + let _stone_bakery_res = Bakery::insert(stone_bakery).exec(&ctx.db).await?; #[derive(Debug, FromQueryResult, PartialEq)] struct BakerLite { @@ -692,44 +691,44 @@ pub async fn related() -> Result<(), DbErr> { name: "SeaSide Bakery".to_owned(), profit_margin: 10.4, }, - vec![baker::Model { - id: 1, - name: "Baker Bob".to_owned(), - contact_details: serde_json::json!({ - "mobile": "+61424000000", - "home": "0395555555", - "address": "12 Test St, Testville, Vic, Australia" - }), - bakery_id: Some(seaside_bakery_res.last_insert_id), - }, - baker::Model { - id: 2, - name: "Baker Bobby".to_owned(), - contact_details: serde_json::json!({ - "mobile": "+85212345678", - }), - bakery_id: Some(seaside_bakery_res.last_insert_id), - }] - ), - ( - bakery::Model { - id: 2, - name: "Terres Bakery".to_owned(), - profit_margin: 13.5, - }, vec![ baker::Model { - id: 3, - name: "Baker Ada".to_owned(), + id: 1, + name: "Baker Bob".to_owned(), contact_details: serde_json::json!({ "mobile": "+61424000000", "home": "0395555555", "address": "12 Test St, Testville, Vic, Australia" }), - bakery_id: Some(terres_bakery_res.last_insert_id), + bakery_id: Some(seaside_bakery_res.last_insert_id), + }, + baker::Model { + id: 2, + name: "Baker Bobby".to_owned(), + contact_details: serde_json::json!({ + "mobile": "+85212345678", + }), + bakery_id: Some(seaside_bakery_res.last_insert_id), } ] ), + ( + bakery::Model { + id: 2, + name: "Terres Bakery".to_owned(), + profit_margin: 13.5, + }, + vec![baker::Model { + id: 3, + name: "Baker Ada".to_owned(), + contact_details: serde_json::json!({ + "mobile": "+61424000000", + "home": "0395555555", + "address": "12 Test St, Testville, Vic, Australia" + }), + bakery_id: Some(terres_bakery_res.last_insert_id), + }] + ), ( bakery::Model { id: 3, From 946f5cb84e724109d7786cc51d98ae99ec07aadf Mon Sep 17 00:00:00 2001 From: Yiu Tin Cheung Ivan Date: Thu, 17 Aug 2023 19:07:39 +0800 Subject: [PATCH 13/23] improved model generation --- src/executor/select.rs | 492 ++++++++++++++++++++------------------ src/query/loader.rs | 158 ++++++++---- tests/relational_tests.rs | 2 - 3 files changed, 375 insertions(+), 277 deletions(-) diff --git a/src/executor/select.rs b/src/executor/select.rs index d4b0472d5..e3b78766c 100644 --- a/src/executor/select.rs +++ b/src/executor/select.rs @@ -1112,53 +1112,76 @@ where mod tests { use pretty_assertions::assert_eq; + use crate::tests_cfg::entity_linked; + fn cake_fruit_model( cake_id: i32, - cake_name: String, fruit_id: i32, - fruit_name: String, ) -> ( sea_orm::tests_cfg::cake::Model, sea_orm::tests_cfg::fruit::Model, ) { - ( - cake_model(cake_id, cake_name), - fruit_model(fruit_id, fruit_name, Some(cake_id)), - ) + (cake_model(cake_id), fruit_model(fruit_id, Some(cake_id))) } - fn cake_model(id: i32, name: String) -> sea_orm::tests_cfg::cake::Model { + fn cake_model(id: i32) -> sea_orm::tests_cfg::cake::Model { + let name = match id { + 1 => "apple cake", + 2 => "orange cake", + 3 => "fruit cake", + 4 => "chocolate cake", + _ => "", + } + .to_string(); sea_orm::tests_cfg::cake::Model { id, name } } - fn fruit_model( - id: i32, - name: String, - cake_id: Option, - ) -> sea_orm::tests_cfg::fruit::Model { + fn fruit_model(id: i32, cake_id: Option) -> sea_orm::tests_cfg::fruit::Model { + let name = match id { + 1 => "apple", + 2 => "orange", + 3 => "grape", + 4 => "strawberry", + _ => "", + } + .to_string(); sea_orm::tests_cfg::fruit::Model { id, name, cake_id } } + fn cake_vendor_link( + cake_id: i32, + vendor_id: i32, + ) -> ( + sea_orm::tests_cfg::cake::Model, + sea_orm::tests_cfg::vendor::Model, + ) { + (cake_model(cake_id), vendor_model(vendor_id)) + } + + fn vendor_model(id: i32) -> sea_orm::tests_cfg::vendor::Model { + let name = match id { + 1 => "Apollo", + 2 => "Benny", + 3 => "Christine", + 4 => "David", + _ => "", + } + .to_string(); + sea_orm::tests_cfg::vendor::Model { id, name } + } + #[smol_potat::test] pub async fn also_related() -> Result<(), sea_orm::DbErr> { use sea_orm::tests_cfg::*; use sea_orm::{DbBackend, EntityTrait, MockDatabase, Statement, Transaction}; let db = MockDatabase::new(DbBackend::Postgres) - .append_query_results([[cake_fruit_model( - 1, - "apple cake".to_owned(), - 1, - "apple".to_owned(), - )]]) + .append_query_results([[cake_fruit_model(1, 1)]]) .into_connection(); assert_eq!( Cake::find().find_also_related(Fruit).all(&db).await?, - [( - cake_model(1, "apple cake".to_owned()), - Some(fruit_model(1, "apple".to_owned(), Some(1))) - )] + [(cake_model(1), Some(fruit_model(1, Some(1))))] ); assert_eq!( @@ -1186,23 +1209,14 @@ mod tests { use sea_orm::{DbBackend, EntityTrait, MockDatabase}; let db = MockDatabase::new(DbBackend::Postgres) - .append_query_results([[ - cake_fruit_model(1, "apple cake".to_owned(), 1, "apple".to_owned()), - cake_fruit_model(1, "apple cake".to_owned(), 2, "orange".to_owned()), - ]]) + .append_query_results([[cake_fruit_model(1, 1), cake_fruit_model(1, 2)]]) .into_connection(); assert_eq!( Cake::find().find_also_related(Fruit).all(&db).await?, [ - ( - cake_model(1, "apple cake".to_owned()), - Some(fruit_model(1, "apple".to_owned(), Some(1))) - ), - ( - cake_model(1, "apple cake".to_owned()), - Some(fruit_model(2, "orange".to_owned(), Some(1))) - ) + (cake_model(1), Some(fruit_model(1, Some(1)))), + (cake_model(1), Some(fruit_model(2, Some(1)))) ] ); @@ -1216,27 +1230,18 @@ mod tests { let db = MockDatabase::new(DbBackend::Postgres) .append_query_results([[ - cake_fruit_model(1, "apple cake".to_owned(), 1, "apple".to_owned()), - cake_fruit_model(1, "apple cake".to_owned(), 2, "orange".to_owned()), - cake_fruit_model(2, "orange cake".to_owned(), 2, "orange".to_owned()), + cake_fruit_model(1, 1), + cake_fruit_model(1, 2), + cake_fruit_model(2, 2), ]]) .into_connection(); assert_eq!( Cake::find().find_also_related(Fruit).all(&db).await?, [ - ( - cake_model(1, "apple cake".to_owned()), - Some(fruit_model(1, "apple".to_owned(), Some(1))) - ), - ( - cake_model(1, "apple cake".to_owned()), - Some(fruit_model(2, "orange".to_owned(), Some(1))) - ), - ( - cake_model(2, "orange cake".to_owned()), - Some(fruit_model(2, "orange".to_owned(), Some(2))) - ) + (cake_model(1), Some(fruit_model(1, Some(1)))), + (cake_model(1), Some(fruit_model(2, Some(1)))), + (cake_model(2), Some(fruit_model(2, Some(2)))) ] ); @@ -1250,35 +1255,20 @@ mod tests { let db = MockDatabase::new(DbBackend::Postgres) .append_query_results([[ - cake_fruit_model(1, "apple cake".to_owned(), 1, "apple".to_owned()).into_mock_row(), - cake_fruit_model(1, "apple cake".to_owned(), 2, "orange".to_owned()) - .into_mock_row(), - cake_fruit_model(2, "orange cake".to_owned(), 2, "orange".to_owned()) - .into_mock_row(), - ( - cake_model(3, "chocolate cake".to_owned()), - None::, - ) - .into_mock_row(), + cake_fruit_model(1, 1).into_mock_row(), + cake_fruit_model(1, 2).into_mock_row(), + cake_fruit_model(2, 2).into_mock_row(), + (cake_model(3.to_owned()), None::).into_mock_row(), ]]) .into_connection(); assert_eq!( Cake::find().find_also_related(Fruit).all(&db).await?, [ - ( - cake_model(1, "apple cake".to_owned()), - Some(fruit_model(1, "apple".to_owned(), Some(1))) - ), - ( - cake_model(1, "apple cake".to_owned()), - Some(fruit_model(2, "orange".to_owned(), Some(1))) - ), - ( - cake_model(2, "orange cake".to_owned()), - Some(fruit_model(2, "orange".to_owned(), Some(2))) - ), - (cake_model(3, "chocolate cake".to_owned()), None) + (cake_model(1), Some(fruit_model(1, Some(1)))), + (cake_model(1), Some(fruit_model(2, Some(1)))), + (cake_model(2), Some(fruit_model(2, Some(2)))), + (cake_model(3.to_owned()), None) ] ); @@ -1292,25 +1282,19 @@ mod tests { let db = MockDatabase::new(DbBackend::Postgres) .append_query_results([[ - cake_fruit_model(1, "apple cake".to_owned(), 1, "apple".to_owned()), - cake_fruit_model(2, "fruit cake".to_owned(), 1, "apple".to_owned()), - cake_fruit_model(2, "fruit cake".to_owned(), 2, "orange".to_owned()), + cake_fruit_model(1, 1), + cake_fruit_model(2, 2), + cake_fruit_model(2, 3), ]]) .into_connection(); assert_eq!( Cake::find().find_with_related(Fruit).all(&db).await?, [ + (cake_model(1), vec![fruit_model(1, Some(1))]), ( - cake_model(1, "apple cake".to_owned()), - vec![fruit_model(1, "apple".to_owned(), Some(1))] - ), - ( - cake_model(2, "fruit cake".to_owned()), - vec![ - fruit_model(1, "apple".to_owned(), Some(2)), - fruit_model(2, "orange".to_owned(), Some(2)) - ] + cake_model(2), + vec![fruit_model(2, Some(2)), fruit_model(3, Some(2))] ) ] ); @@ -1342,92 +1326,80 @@ mod tests { let db = MockDatabase::new(DbBackend::Postgres) .append_query_results([[ - cake_fruit_model(1, "apple cake".to_owned(), 1, "apple".to_owned()).into_mock_row(), - cake_fruit_model(2, "fruit cake".to_owned(), 1, "apple".to_owned()).into_mock_row(), - cake_fruit_model(2, "fruit cake".to_owned(), 2, "orange".to_owned()) - .into_mock_row(), - ( - cake_model(2, "fruit cake".to_owned()), - Some(fruit_model(3, "grape".to_owned(), Some(2))), - ) - .into_mock_row(), - ( - cake_model(3, "chocolate cake".to_owned()), - None::, - ) - .into_mock_row(), + cake_fruit_model(1, 1).into_mock_row(), + cake_fruit_model(2, 1).into_mock_row(), + cake_fruit_model(2, 2).into_mock_row(), + cake_fruit_model(2, 3).into_mock_row(), ]]) .into_connection(); assert_eq!( Cake::find().find_with_related(Fruit).all(&db).await?, [ + (cake_model(1), vec![fruit_model(1, Some(1)),]), ( - cake_model(1, "apple cake".to_owned()), - vec![fruit_model(1, "apple".to_owned(), Some(1)),] - ), - ( - cake_model(2, "fruit cake".to_owned()), + cake_model(2), vec![ - fruit_model(1, "apple".to_owned(), Some(2)), - fruit_model(2, "orange".to_owned(), Some(2)), - fruit_model(3, "grape".to_owned(), Some(2)), + fruit_model(1, Some(2)), + fruit_model(2, Some(2)), + fruit_model(3, Some(2)), ] ), - (cake_model(3, "chocolate cake".to_owned()), vec![]) ] ); Ok(()) } - fn cake_filling_link( - cake_id: i32, - cake_name: String, - filling_id: i32, - filling_name: String, - ) -> ( - sea_orm::tests_cfg::cake::Model, - sea_orm::tests_cfg::filling::Model, - ) { - ( - cake_model(cake_id, cake_name), - filling_model(filling_id, filling_name), - ) - } - - fn filling_model(id: i32, name: String) -> sea_orm::tests_cfg::filling::Model { - sea_orm::tests_cfg::filling::Model { - id, - name, - vendor_id: None, - ignored_attr: 0, - } + #[smol_potat::test] + pub async fn with_related_empty() -> Result<(), sea_orm::DbErr> { + use sea_orm::tests_cfg::*; + use sea_orm::{DbBackend, EntityTrait, IntoMockRow, MockDatabase}; + + let db = MockDatabase::new(DbBackend::Postgres) + .append_query_results([[ + cake_fruit_model(1, 1).into_mock_row(), + cake_fruit_model(2, 1).into_mock_row(), + cake_fruit_model(2, 2).into_mock_row(), + cake_fruit_model(2, 3).into_mock_row(), + (cake_model(3.to_owned()), None::).into_mock_row(), + ]]) + .into_connection(); + + assert_eq!( + Cake::find().find_with_related(Fruit).all(&db).await?, + [ + (cake_model(1), vec![fruit_model(1, Some(1)),]), + ( + cake_model(2), + vec![ + fruit_model(1, Some(2)), + fruit_model(2, Some(2)), + fruit_model(3, Some(2)), + ] + ), + (cake_model(3), vec![]) + ] + ); + + Ok(()) } #[smol_potat::test] - pub async fn also_linked() -> Result<(), sea_orm::DbErr> { + pub async fn also_linked_base() -> Result<(), sea_orm::DbErr> { use sea_orm::tests_cfg::*; use sea_orm::{DbBackend, EntityTrait, MockDatabase, Statement, Transaction}; let db = MockDatabase::new(DbBackend::Postgres) - .append_query_results([[cake_filling_link( - 1, - "apple cake".to_owned(), - 1, - "apple juice".to_owned(), - )]]) + .append_query_results([[cake_vendor_link(1, 1)]]) .into_connection(); assert_eq!( Cake::find() - .find_also_linked(entity_linked::CakeToFilling) + .find_also_linked(entity_linked::CakeToFillingVendor) .all(&db) .await?, - [( - cake_model(1, "apple cake".to_owned()), - Some(filling_model(1, "apple juice".to_owned())) - )] + [(cake_model(1), Some(vendor_model(1)))] ); assert_eq!( @@ -1436,10 +1408,11 @@ mod tests { DbBackend::Postgres, [ r#"SELECT "cake"."id" AS "A_id", "cake"."name" AS "A_name","#, - r#""r1"."id" AS "B_id", "r1"."name" AS "B_name", "r1"."vendor_id" AS "B_vendor_id""#, + r#""r2"."id" AS "B_id", "r2"."name" AS "B_name""#, r#"FROM "cake""#, r#"LEFT JOIN "cake_filling" AS "r0" ON "cake"."id" = "r0"."cake_id""#, r#"LEFT JOIN "filling" AS "r1" ON "r0"."filling_id" = "r1"."id""#, + r#"LEFT JOIN "vendor" AS "r2" ON "r1"."vendor_id" = "r2"."id""#, ] .join(" ") .as_str(), @@ -1451,36 +1424,27 @@ mod tests { } #[smol_potat::test] - pub async fn also_linked_2() -> Result<(), sea_orm::DbErr> { + pub async fn also_linked_same_cake() -> Result<(), sea_orm::DbErr> { use sea_orm::tests_cfg::*; use sea_orm::{DbBackend, EntityTrait, MockDatabase}; let db = MockDatabase::new(DbBackend::Postgres) .append_query_results([[ - cake_filling_link(1, "apple cake".to_owned(), 1, "apple juice".to_owned()), - cake_filling_link(2, "fruit cake".to_owned(), 1, "apple juice".to_owned()), - cake_filling_link(2, "fruit cake".to_owned(), 2, "orange jam".to_owned()), + cake_vendor_link(1, 1), + cake_vendor_link(1, 2), + cake_vendor_link(2, 3), ]]) .into_connection(); assert_eq!( Cake::find() - .find_also_linked(entity_linked::CakeToFilling) + .find_also_linked(entity_linked::CakeToFillingVendor) .all(&db) .await?, [ - ( - cake_model(1, "apple cake".to_owned()), - Some(filling_model(1, "apple juice".to_owned())) - ), - ( - cake_model(2, "fruit cake".to_owned()), - Some(filling_model(1, "apple juice".to_owned())) - ), - ( - cake_model(2, "fruit cake".to_owned()), - Some(filling_model(2, "orange jam".to_owned())) - ) + (cake_model(1), Some(vendor_model(1))), + (cake_model(1), Some(vendor_model(2))), + (cake_model(2), Some(vendor_model(3))) ] ); @@ -1488,45 +1452,85 @@ mod tests { } #[smol_potat::test] - pub async fn also_linked_3() -> Result<(), sea_orm::DbErr> { + pub async fn also_linked_same_vendor() -> Result<(), sea_orm::DbErr> { use sea_orm::tests_cfg::*; use sea_orm::{DbBackend, EntityTrait, IntoMockRow, MockDatabase}; let db = MockDatabase::new(DbBackend::Postgres) .append_query_results([[ - cake_filling_link(1, "apple cake".to_owned(), 1, "apple juice".to_owned()) - .into_mock_row(), - cake_filling_link(2, "fruit cake".to_owned(), 1, "apple juice".to_owned()) - .into_mock_row(), - cake_filling_link(2, "fruit cake".to_owned(), 2, "orange jam".to_owned()) - .into_mock_row(), - ( - cake_model(3, "chocolate cake".to_owned()), - None::, - ) - .into_mock_row(), + cake_vendor_link(1, 1).into_mock_row(), + cake_vendor_link(2, 1).into_mock_row(), + cake_vendor_link(3, 2).into_mock_row(), ]]) .into_connection(); assert_eq!( Cake::find() - .find_also_linked(entity_linked::CakeToFilling) + .find_also_linked(entity_linked::CakeToFillingVendor) .all(&db) .await?, [ - ( - cake_model(1, "apple cake".to_owned()), - Some(filling_model(1, "apple juice".to_owned())) - ), - ( - cake_model(2, "fruit cake".to_owned()), - Some(filling_model(1, "apple juice".to_owned())) - ), - ( - cake_model(2, "fruit cake".to_owned()), - Some(filling_model(2, "orange jam".to_owned())) - ), - (cake_model(3, "chocolate cake".to_owned()), None) + (cake_model(1), Some(vendor_model(1))), + (cake_model(2), Some(vendor_model(1))), + (cake_model(3), Some(vendor_model(2))), + ] + ); + + Ok(()) + } + + #[smol_potat::test] + pub async fn also_linked_many_to_many() -> Result<(), sea_orm::DbErr> { + use sea_orm::tests_cfg::*; + use sea_orm::{DbBackend, EntityTrait, IntoMockRow, MockDatabase}; + + let db = MockDatabase::new(DbBackend::Postgres) + .append_query_results([[ + cake_vendor_link(1, 1).into_mock_row(), + cake_vendor_link(2, 1).into_mock_row(), + cake_vendor_link(2, 2).into_mock_row(), + ]]) + .into_connection(); + + assert_eq!( + Cake::find() + .find_also_linked(entity_linked::CakeToFillingVendor) + .all(&db) + .await?, + [ + (cake_model(1), Some(vendor_model(1))), + (cake_model(2), Some(vendor_model(1))), + (cake_model(2), Some(vendor_model(2))), + ] + ); + + Ok(()) + } + + #[smol_potat::test] + pub async fn also_linked_empty() -> Result<(), sea_orm::DbErr> { + use sea_orm::tests_cfg::*; + use sea_orm::{DbBackend, EntityTrait, IntoMockRow, MockDatabase}; + + let db = MockDatabase::new(DbBackend::Postgres) + .append_query_results([[ + cake_vendor_link(1, 1).into_mock_row(), + cake_vendor_link(2, 2).into_mock_row(), + cake_vendor_link(3, 3).into_mock_row(), + (cake_model(4), None::).into_mock_row(), + ]]) + .into_connection(); + + assert_eq!( + Cake::find() + .find_also_linked(entity_linked::CakeToFillingVendor) + .all(&db) + .await?, + [ + (cake_model(1), Some(vendor_model(1))), + (cake_model(2), Some(vendor_model(2))), + (cake_model(3), Some(vendor_model(3))), + (cake_model(4), None) ] ); @@ -1534,35 +1538,26 @@ mod tests { } #[smol_potat::test] - pub async fn with_linked() -> Result<(), sea_orm::DbErr> { + pub async fn with_linked_base() -> Result<(), sea_orm::DbErr> { use sea_orm::tests_cfg::*; use sea_orm::{DbBackend, EntityTrait, MockDatabase, Statement, Transaction}; let db = MockDatabase::new(DbBackend::Postgres) .append_query_results([[ - cake_filling_link(1, "apple cake".to_owned(), 1, "apple juice".to_owned()), - cake_filling_link(2, "fruit cake".to_owned(), 1, "apple juice".to_owned()), - cake_filling_link(2, "fruit cake".to_owned(), 2, "orange jam".to_owned()), + cake_vendor_link(1, 1), + cake_vendor_link(2, 2), + cake_vendor_link(2, 3), ]]) .into_connection(); assert_eq!( Cake::find() - .find_with_linked(entity_linked::CakeToFilling) + .find_with_linked(entity_linked::CakeToFillingVendor) .all(&db) .await?, [ - ( - cake_model(1, "apple cake".to_owned()), - vec![filling_model(1, "apple juice".to_owned())] - ), - ( - cake_model(2, "fruit cake".to_owned()), - vec![ - filling_model(1, "apple juice".to_owned()), - filling_model(2, "orange jam".to_owned()) - ] - ) + (cake_model(1), vec![vendor_model(1)]), + (cake_model(2), vec![vendor_model(2), vendor_model(3)]) ] ); @@ -1572,10 +1567,10 @@ mod tests { DbBackend::Postgres, [ r#"SELECT "cake"."id" AS "A_id", "cake"."name" AS "A_name","#, - r#""r1"."id" AS "B_id", "r1"."name" AS "B_name", "r1"."vendor_id" AS "B_vendor_id""#, - r#"FROM "cake""#, + r#""r2"."id" AS "B_id", "r2"."name" AS "B_name" FROM "cake""#, r#"LEFT JOIN "cake_filling" AS "r0" ON "cake"."id" = "r0"."cake_id""#, r#"LEFT JOIN "filling" AS "r1" ON "r0"."filling_id" = "r1"."id""#, + r#"LEFT JOIN "vendor" AS "r2" ON "r1"."vendor_id" = "r2"."id""#, ] .join(" ") .as_str(), @@ -1587,44 +1582,85 @@ mod tests { } #[smol_potat::test] - pub async fn with_linked_2() -> Result<(), sea_orm::DbErr> { + pub async fn with_linked_same_vendor() -> Result<(), sea_orm::DbErr> { use sea_orm::tests_cfg::*; use sea_orm::{DbBackend, EntityTrait, IntoMockRow, MockDatabase}; let db = MockDatabase::new(DbBackend::Postgres) .append_query_results([[ - cake_filling_link(1, "apple cake".to_owned(), 1, "apple juice".to_owned()) - .into_mock_row(), - cake_filling_link(2, "fruit cake".to_owned(), 1, "apple juice".to_owned()) - .into_mock_row(), - cake_filling_link(2, "fruit cake".to_owned(), 2, "orange jam".to_owned()) - .into_mock_row(), - ( - cake_model(3, "chocolate cake".to_owned()), - None::, - ) - .into_mock_row(), + cake_vendor_link(1, 1).into_mock_row(), + cake_vendor_link(2, 2).into_mock_row(), + cake_vendor_link(3, 2).into_mock_row(), ]]) .into_connection(); assert_eq!( Cake::find() - .find_with_linked(entity_linked::CakeToFilling) + .find_with_linked(entity_linked::CakeToFillingVendor) .all(&db) .await?, [ - ( - cake_model(1, "apple cake".to_owned()), - vec![filling_model(1, "apple juice".to_owned()),] - ), - ( - cake_model(2, "fruit cake".to_owned()), - vec![ - filling_model(1, "apple juice".to_owned()), - filling_model(2, "orange jam".to_owned()), - ] - ), - (cake_model(3, "chocolate cake".to_owned()), vec![]) + (cake_model(1), vec![vendor_model(1)]), + (cake_model(2), vec![vendor_model(2),]), + (cake_model(3), vec![vendor_model(2)]) + ] + ); + + Ok(()) + } + + #[smol_potat::test] + pub async fn with_linked_empty() -> Result<(), sea_orm::DbErr> { + use sea_orm::tests_cfg::*; + use sea_orm::{DbBackend, EntityTrait, IntoMockRow, MockDatabase}; + + let db = MockDatabase::new(DbBackend::Postgres) + .append_query_results([[ + cake_vendor_link(1, 1).into_mock_row(), + cake_vendor_link(2, 1).into_mock_row(), + cake_vendor_link(2, 2).into_mock_row(), + (cake_model(3), None::).into_mock_row(), + ]]) + .into_connection(); + + assert_eq!( + Cake::find() + .find_with_linked(entity_linked::CakeToFillingVendor) + .all(&db) + .await?, + [ + (cake_model(1), vec![vendor_model(1)]), + (cake_model(2), vec![vendor_model(1), vendor_model(2),]), + (cake_model(3), vec![]) + ] + ); + + Ok(()) + } + + // this should not happen? + #[smol_potat::test] + pub async fn with_linked_repeated() -> Result<(), sea_orm::DbErr> { + use sea_orm::tests_cfg::*; + use sea_orm::{DbBackend, EntityTrait, IntoMockRow, MockDatabase}; + + let db = MockDatabase::new(DbBackend::Postgres) + .append_query_results([[ + cake_vendor_link(1, 1).into_mock_row(), + cake_vendor_link(1, 1).into_mock_row(), + cake_vendor_link(2, 1).into_mock_row(), + cake_vendor_link(2, 2).into_mock_row(), + ]]) + .into_connection(); + + assert_eq!( + Cake::find() + .find_with_linked(entity_linked::CakeToFillingVendor) + .all(&db) + .await?, + [ + (cake_model(1), vec![vendor_model(1), vendor_model(1)]), + (cake_model(2), vec![vendor_model(1), vendor_model(2),]), ] ); diff --git a/src/query/loader.rs b/src/query/loader.rs index 28663898e..54e3f7c4a 100644 --- a/src/query/loader.rs +++ b/src/query/loader.rs @@ -440,72 +440,121 @@ fn table_column(tbl: &TableRef, col: &DynIden) -> ColumnRef { #[cfg(test)] mod tests { + fn cake_model(id: i32) -> sea_orm::tests_cfg::cake::Model { + let name = match id { + 1 => "apple cake", + 2 => "orange cake", + 3 => "fruit cake", + 4 => "chocolate cake", + _ => "", + } + .to_string(); + sea_orm::tests_cfg::cake::Model { id, name } + } + + fn fruit_model(id: i32, cake_id: Option) -> sea_orm::tests_cfg::fruit::Model { + let name = match id { + 1 => "apple", + 2 => "orange", + 3 => "grape", + 4 => "strawberry", + _ => "", + } + .to_string(); + sea_orm::tests_cfg::fruit::Model { id, name, cake_id } + } + #[tokio::test] async fn test_load_one() { - use crate::{ + use sea_orm::{ entity::prelude::*, tests_cfg::*, DbBackend, IntoMockRow, LoaderTrait, MockDatabase, }; let db = MockDatabase::new(DbBackend::Postgres) - .append_query_results([[ - cake::Model { - id: 1, - name: "New York Cheese".to_owned(), - } - .into_mock_row(), - cake::Model { - id: 2, - name: "London Cheese".to_owned(), - } - .into_mock_row(), - ]]) + .append_query_results([[cake_model(1), cake_model(2)]]) .into_connection(); - let fruits = vec![fruit::Model { - id: 1, - name: "Apple".to_owned(), - cake_id: Some(1), - }]; + let fruits = vec![fruit_model(1, Some(1))]; let cakes = fruits .load_one(cake::Entity::find(), &db) .await .expect("Should return something"); - assert_eq!( - cakes, - [Some(cake::Model { - id: 1, - name: "New York Cheese".to_owned(), - })] - ); + assert_eq!(cakes, [Some(cake_model(1))]); + } + + #[tokio::test] + async fn test_load_one_same_cake() { + use sea_orm::{ + entity::prelude::*, tests_cfg::*, DbBackend, IntoMockRow, LoaderTrait, MockDatabase, + }; + + let db = MockDatabase::new(DbBackend::Postgres) + .append_query_results([[cake_model(1), cake_model(2)]]) + .into_connection(); + + let fruits = vec![fruit_model(1, Some(1)), fruit_model(2, Some(1))]; + + let cakes = fruits + .load_one(cake::Entity::find(), &db) + .await + .expect("Should return something"); + + assert_eq!(cakes, [Some(cake_model(1)), Some(cake_model(1))]); + } + + #[tokio::test] + async fn test_load_one_empty() { + use sea_orm::{ + entity::prelude::*, tests_cfg::*, DbBackend, IntoMockRow, LoaderTrait, MockDatabase, + }; + + let db = MockDatabase::new(DbBackend::Postgres) + .append_query_results([[cake_model(1), cake_model(2)]]) + .into_connection(); + + let fruits: Vec = vec![]; + + let cakes = fruits + .load_one(cake::Entity::find(), &db) + .await + .expect("Should return something"); + + assert_eq!(cakes, []); } #[tokio::test] async fn test_load_many() { - use crate::{ + use sea_orm::{ entity::prelude::*, tests_cfg::*, DbBackend, IntoMockRow, LoaderTrait, MockDatabase, }; let db = MockDatabase::new(DbBackend::Postgres) - .append_query_results([[fruit::Model { - id: 1, - name: "Apple".to_owned(), - cake_id: Some(1), - } - .into_mock_row()]]) + .append_query_results([[fruit_model(1, Some(1))]]) .into_connection(); - let cakes = vec![ - cake::Model { - id: 1, - name: "New York Cheese".to_owned(), - }, - cake::Model { - id: 2, - name: "London Cheese".to_owned(), - }, - ]; + let cakes = vec![cake_model(1), cake_model(2)]; + + let fruits = cakes + .load_many(fruit::Entity::find(), &db) + .await + .expect("Should return something"); + + assert_eq!(fruits, [vec![fruit_model(1, Some(1))], vec![]]); + } + + #[tokio::test] + async fn test_load_many_2() { + use sea_orm::{ + entity::prelude::*, tests_cfg::*, DbBackend, IntoMockRow, LoaderTrait, MockDatabase, + }; + + let db = MockDatabase::new(DbBackend::Postgres) + .append_query_results([[fruit_model(1, Some(1)), fruit_model(2, Some(1))]]) + .into_connection(); + + let cakes = vec![cake_model(1), cake_model(2)]; let fruits = cakes .load_many(fruit::Entity::find(), &db) @@ -515,13 +564,28 @@ mod tests { assert_eq!( fruits, [ - vec![fruit::Model { - id: 1, - name: "Apple".to_owned(), - cake_id: Some(1), - }], + vec![fruit_model(1, Some(1)), fruit_model(2, Some(1))], vec![] ] ); } + + // FIXME: load many with empty vector will panic + // #[tokio::test] + async fn test_load_many_empty() { + use sea_orm::{entity::prelude::*, tests_cfg::*, DbBackend, IntoMockRow, MockDatabase}; + + let db = MockDatabase::new(DbBackend::Postgres) + .append_query_results([[fruit_model(1, Some(1)), fruit_model(2, Some(1))]]) + .into_connection(); + + let cakes: Vec = vec![]; + + let fruits = cakes + .load_many(fruit::Entity::find(), &db) + .await + .expect("Should return something"); + + assert_eq!(fruits, [vec![], vec![]]); + } } diff --git a/tests/relational_tests.rs b/tests/relational_tests.rs index d0e3f1b13..7ff53dfae 100644 --- a/tests/relational_tests.rs +++ b/tests/relational_tests.rs @@ -583,8 +583,6 @@ pub async fn related() -> Result<(), DbErr> { .select_only() .column_as(bakery::Column::Name, (SelectA, bakery::Column::Name)) .column_as(baker::Column::Name, (SelectB, baker::Column::Name)) - .group_by(bakery::Column::Id) - .group_by(baker::Column::Id) .order_by_asc(bakery::Column::Id) .order_by_asc(baker::Column::Id) .into_model() From 0a22f247d9a811c854bb97894fcdf56071262b0c Mon Sep 17 00:00:00 2001 From: Yiu Tin Cheung Ivan Date: Fri, 18 Aug 2023 15:16:05 +0800 Subject: [PATCH 14/23] issue related test case #1790 --- issues/1790/insert_test.rs | 55 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 issues/1790/insert_test.rs diff --git a/issues/1790/insert_test.rs b/issues/1790/insert_test.rs new file mode 100644 index 000000000..45e9cc084 --- /dev/null +++ b/issues/1790/insert_test.rs @@ -0,0 +1,55 @@ +mod tests { + #[test] + fn insert_do_nothing_postgres() { + assert_eq!( + Insert::::new() + .add(cake::Model { + id: 1, + name: "Apple Pie".to_owned(), + }) + .on_conflict(OnConflict::new() + .do_nothing() + .to_owned() + ) + .build(DbBackend::Postgres) + .to_string(), + r#"INSERT INTO "cake" ("id", "name") VALUES (1, 'Apple Pie') ON CONFLICT DO NOTHING"#, + ); + } + + #[test] + fn insert_do_nothing_mysql() { + assert_eq!( + Insert::::new() + .add(cake::Model { + id: 1, + name: "Apple Pie".to_owned(), + }) + .on_conflict(OnConflict::new() + .do_nothing() + .to_owned() + ) + .build(DbBackend::Mysql) + .to_string(), + r#"INSERT IGNORE INTO "cake" ("id", "name") VALUES (1, 'Apple Pie')"#, + ); + } + + #[test] + fn insert_do_nothing() { + assert_eq!( + Insert::::new() + .add(cake::Model { + id: 1, + name: "Apple Pie".to_owned(), + }) + .on_conflict(OnConflict::new() + .do_nothing() + .to_owned() + ) + .build(DbBackend::Sqlite) + .to_string(), + r#"INSERT IGNORE INTO "cake" ("id", "name") VALUES (1, 'Apple Pie')"#, + ); + } +} \ No newline at end of file From 2356129a03969847790b194103a3f0f30ebe3569 Mon Sep 17 00:00:00 2001 From: Yiu Tin Cheung Ivan Date: Fri, 18 Aug 2023 15:31:53 +0800 Subject: [PATCH 15/23] added loader test cases and slight improvement to find_related/linked --- src/executor/select.rs | 8 +++++-- src/query/loader.rs | 38 ++++++++++++++++++++++++++++++++ tests/loader_tests.rs | 50 +++++++++++++++++++++++++++++++++++++----- 3 files changed, 89 insertions(+), 7 deletions(-) diff --git a/src/executor/select.rs b/src/executor/select.rs index e3b78766c..be42a248e 100644 --- a/src/executor/select.rs +++ b/src/executor/select.rs @@ -1487,6 +1487,8 @@ mod tests { let db = MockDatabase::new(DbBackend::Postgres) .append_query_results([[ cake_vendor_link(1, 1).into_mock_row(), + cake_vendor_link(1, 2).into_mock_row(), + cake_vendor_link(1, 3).into_mock_row(), cake_vendor_link(2, 1).into_mock_row(), cake_vendor_link(2, 2).into_mock_row(), ]]) @@ -1499,6 +1501,8 @@ mod tests { .await?, [ (cake_model(1), Some(vendor_model(1))), + (cake_model(1), Some(vendor_model(2))), + (cake_model(1), Some(vendor_model(3))), (cake_model(2), Some(vendor_model(1))), (cake_model(2), Some(vendor_model(2))), ] @@ -1601,7 +1605,7 @@ mod tests { .await?, [ (cake_model(1), vec![vendor_model(1)]), - (cake_model(2), vec![vendor_model(2),]), + (cake_model(2), vec![vendor_model(2)]), (cake_model(3), vec![vendor_model(2)]) ] ); @@ -1638,7 +1642,7 @@ mod tests { Ok(()) } - // this should not happen? + // normally would not happen #[smol_potat::test] pub async fn with_linked_repeated() -> Result<(), sea_orm::DbErr> { use sea_orm::tests_cfg::*; diff --git a/src/query/loader.rs b/src/query/loader.rs index 54e3f7c4a..5512da55e 100644 --- a/src/query/loader.rs +++ b/src/query/loader.rs @@ -464,6 +464,19 @@ mod tests { sea_orm::tests_cfg::fruit::Model { id, name, cake_id } } + fn filling_model(id: i32) -> sea_orm::tests_cfg::filling::Model { + let name = match id { + 1 => "apple juice", + 2 => "orange jam", + 3 => "chocolate crust", + 4 => "strawberry jam", + _ => "", + } + .to_string(); + sea_orm::tests_cfg::filling::Model { id, name, vendor_id: Some(1), ignored_attr: 0 } + } + + #[tokio::test] async fn test_load_one() { use sea_orm::{ @@ -588,4 +601,29 @@ mod tests { assert_eq!(fruits, [vec![], vec![]]); } + + // not sure how to test + // #[tokio::test] + async fn test_load_many_to_many() { + use sea_orm::{ + entity::prelude::*, tests_cfg::*, DbBackend, IntoMockRow, LoaderTrait, MockDatabase, + }; + + let db = MockDatabase::new(DbBackend::Postgres) + .append_query_results([[ + (cake_filling::Model { cake_id:1, filling_id: 1}, + filling_model(1)) + ]]) + .into_connection(); + + let cakes = vec![cake_model(1)]; + + let fillings = cakes + .load_many_to_many(Filling, CakeFilling , &db) + .await + .expect("Should return something"); + + assert_eq!(fillings, [vec![filling_model(1)], vec![]]); + } + } diff --git a/tests/loader_tests.rs b/tests/loader_tests.rs index c0cb408b1..d86df29ad 100644 --- a/tests/loader_tests.rs +++ b/tests/loader_tests.rs @@ -1,7 +1,7 @@ pub mod common; pub use common::{bakery_chain::*, setup::*, TestContext}; -use sea_orm::{entity::*, query::*, DbConn, DbErr}; +use sea_orm::{entity::*, query::*, DbConn, DbErr, RuntimeErr}; #[sea_orm_macros::test] #[cfg(any( @@ -35,6 +35,43 @@ async fn loader_load_one() -> Result<(), DbErr> { Ok(()) } +#[sea_orm_macros::test] +#[cfg(any( + feature = "sqlx-mysql", + feature = "sqlx-sqlite", + feature = "sqlx-postgres" +))] +async fn loader_load_one_edge_case() -> Result<(), DbErr> { + let ctx = TestContext::new("loader_test_load_one").await; + create_tables(&ctx.db).await?; + + let bakery_0 = insert_bakery(&ctx.db, "SeaSide Bakery").await?; + let bakery_1 = insert_bakery(&ctx.db, "SeaSide Bakery").await?; + + let baker_1 = insert_baker(&ctx.db, "Baker 1", bakery_0.id).await?; + let baker_2 = insert_baker(&ctx.db, "Baker 2", bakery_0.id).await?; + let baker_3 = baker::ActiveModel { + name: Set("Baker 3".to_owned()), + contact_details: Set(serde_json::json!({})), + bakery_id: Set(None), + ..Default::default() + } + .insert(&ctx.db) + .await?; + + let bakers = baker::Entity::find().all(&ctx.db).await?; + let bakeries = bakers.load_one(bakery::Entity, &ctx.db).await?; + + assert_eq!(bakers, [baker_1, baker_2, baker_3]); + assert_eq!(bakeries, [Some(bakery_0.clone()), Some(bakery_0), None]); + + let bakeries = bakery::Entity::find().all(&ctx.db).await?; + let bakers = bakeries.load_one(baker::Entity, &ctx.db).await; + + assert_eq!(bakers, Err(DbErr::Query(RuntimeErr::Internal("Relation is HasMany instead of HasOne".to_string())))); + Ok(()) +} + #[sea_orm_macros::test] #[cfg(any( feature = "sqlx-mysql", @@ -47,6 +84,7 @@ async fn loader_load_many() -> Result<(), DbErr> { let bakery_1 = insert_bakery(&ctx.db, "SeaSide Bakery").await?; let bakery_2 = insert_bakery(&ctx.db, "Offshore Bakery").await?; + let bakery_3 = insert_bakery(&ctx.db, "Rocky Bakery").await?; let baker_1 = insert_baker(&ctx.db, "Baker 1", bakery_1.id).await?; let baker_2 = insert_baker(&ctx.db, "Baker 2", bakery_1.id).await?; @@ -57,12 +95,13 @@ async fn loader_load_many() -> Result<(), DbErr> { let bakeries = bakery::Entity::find().all(&ctx.db).await?; let bakers = bakeries.load_many(baker::Entity, &ctx.db).await?; - assert_eq!(bakeries, [bakery_1.clone(), bakery_2.clone()]); + assert_eq!(bakeries, [bakery_1.clone(), bakery_2.clone(), bakery_3.clone()]); assert_eq!( bakers, [ - [baker_1.clone(), baker_2.clone()], - [baker_3.clone(), baker_4.clone()] + vec![baker_1.clone(), baker_2.clone()], + vec![baker_3.clone(), baker_4.clone()], + vec![] ] ); @@ -79,7 +118,8 @@ async fn loader_load_many() -> Result<(), DbErr> { bakers, [ vec![baker_1.clone(), baker_2.clone()], - vec![baker_4.clone()] + vec![baker_4.clone()], + vec![] ] ); From b8a07d85deebb4631440f69fd0386f275f029a29 Mon Sep 17 00:00:00 2001 From: Yiu Tin Cheung Ivan Date: Fri, 18 Aug 2023 16:26:32 +0800 Subject: [PATCH 16/23] miscellaneous changes --- src/query/loader.rs | 2 +- tests/relational_tests.rs | 3 +++ tests/sql_err_tests.rs | 3 +++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/query/loader.rs b/src/query/loader.rs index 5512da55e..adbf9b89b 100644 --- a/src/query/loader.rs +++ b/src/query/loader.rs @@ -602,7 +602,7 @@ mod tests { assert_eq!(fruits, [vec![], vec![]]); } - // not sure how to test + // TODO: not sure how to test // #[tokio::test] async fn test_load_many_to_many() { use sea_orm::{ diff --git a/tests/relational_tests.rs b/tests/relational_tests.rs index 7ff53dfae..c8c41b17a 100644 --- a/tests/relational_tests.rs +++ b/tests/relational_tests.rs @@ -940,6 +940,7 @@ pub async fn linked() -> Result<(), DbErr> { name: String, } + // filtered find let baked_for_customers: Vec<(BakerLite, Option)> = Baker::find() .find_also_linked(baker::BakedForCustomer) .select_only() @@ -994,6 +995,7 @@ pub async fn linked() -> Result<(), DbErr> { ] ); + // try to use find_linked instead let baker_bob = Baker::find() .filter(baker::Column::Id.eq(1)) .one(&ctx.db) @@ -1014,6 +1016,7 @@ pub async fn linked() -> Result<(), DbErr> { }] ); + // find full model using with_linked let select_baker_with_customer = Baker::find() .find_with_linked(baker::BakedForCustomer) .order_by_asc(baker::Column::Id) diff --git a/tests/sql_err_tests.rs b/tests/sql_err_tests.rs index e73b3afe5..e086d730c 100644 --- a/tests/sql_err_tests.rs +++ b/tests/sql_err_tests.rs @@ -64,4 +64,7 @@ pub async fn test_error(db: &DatabaseConnection) { fk_error.sql_err(), Some(SqlErr::ForeignKeyConstraintViolation(_)) )); + + let invalid_error = DbErr::Custom("random error".to_string()); + assert_eq!(invalid_error.sql_err(), None) } From ff6bd178dfc87d40065047cfd16d98adf0c6daec Mon Sep 17 00:00:00 2001 From: Yiu Tin Cheung Ivan Date: Fri, 18 Aug 2023 17:40:51 +0800 Subject: [PATCH 17/23] added empty insert, merge load_one test case --- src/executor/select.rs | 10 ++++----- tests/empty_insert_tests.rs | 16 ++++++++++++++ tests/loader_tests.rs | 43 ++++++------------------------------- 3 files changed, 28 insertions(+), 41 deletions(-) diff --git a/src/executor/select.rs b/src/executor/select.rs index be42a248e..06ed4882c 100644 --- a/src/executor/select.rs +++ b/src/executor/select.rs @@ -1258,7 +1258,7 @@ mod tests { cake_fruit_model(1, 1).into_mock_row(), cake_fruit_model(1, 2).into_mock_row(), cake_fruit_model(2, 2).into_mock_row(), - (cake_model(3.to_owned()), None::).into_mock_row(), + (cake_model(3), None::).into_mock_row(), ]]) .into_connection(); @@ -1268,7 +1268,7 @@ mod tests { (cake_model(1), Some(fruit_model(1, Some(1)))), (cake_model(1), Some(fruit_model(2, Some(1)))), (cake_model(2), Some(fruit_model(2, Some(2)))), - (cake_model(3.to_owned()), None) + (cake_model(3), None) ] ); @@ -1362,7 +1362,7 @@ mod tests { cake_fruit_model(2, 1).into_mock_row(), cake_fruit_model(2, 2).into_mock_row(), cake_fruit_model(2, 3).into_mock_row(), - (cake_model(3.to_owned()), None::).into_mock_row(), + (cake_model(3), None::).into_mock_row(), ]]) .into_connection(); @@ -1634,7 +1634,7 @@ mod tests { .await?, [ (cake_model(1), vec![vendor_model(1)]), - (cake_model(2), vec![vendor_model(1), vendor_model(2),]), + (cake_model(2), vec![vendor_model(1), vendor_model(2)]), (cake_model(3), vec![]) ] ); @@ -1664,7 +1664,7 @@ mod tests { .await?, [ (cake_model(1), vec![vendor_model(1), vendor_model(1)]), - (cake_model(2), vec![vendor_model(1), vendor_model(2),]), + (cake_model(2), vec![vendor_model(1), vendor_model(2)]), ] ); diff --git a/tests/empty_insert_tests.rs b/tests/empty_insert_tests.rs index e3a8bfa76..f46fa354e 100644 --- a/tests/empty_insert_tests.rs +++ b/tests/empty_insert_tests.rs @@ -9,6 +9,7 @@ pub use sea_orm::{ pub use crud::*; // use common::bakery_chain::*; use sea_orm::{DbConn, TryInsertResult}; +use sea_query::OnConflict; #[sea_orm_macros::test] #[cfg(any( @@ -37,6 +38,21 @@ pub async fn test(db: &DbConn) { assert!(matches!(res, Ok(TryInsertResult::Inserted(_)))); + let double_seaside_bakery = bakery::ActiveModel { + name: Set("SeaSide Bakery".to_owned()), + profit_margin: Set(10.4), + id: Set(1), + }; + + let res = Bakery::insert(double_seaside_bakery) + .on_conflict(OnConflict::column(bakery::Column::Id).do_nothing().to_owned()) + .on_empty_do_nothing() + .exec(db) + .await; + + dbg!(&res); + assert!(matches!(res, Ok(TryInsertResult::Conflicted))); + let empty_insert = Bakery::insert_many(std::iter::empty::()) .on_empty_do_nothing() .exec(db) diff --git a/tests/loader_tests.rs b/tests/loader_tests.rs index d86df29ad..ae621e500 100644 --- a/tests/loader_tests.rs +++ b/tests/loader_tests.rs @@ -32,43 +32,12 @@ async fn loader_load_one() -> Result<(), DbErr> { assert_eq!(bakers, [baker_1, baker_2, baker_3]); assert_eq!(bakeries, [Some(bakery_0.clone()), Some(bakery_0), None]); - Ok(()) -} - -#[sea_orm_macros::test] -#[cfg(any( - feature = "sqlx-mysql", - feature = "sqlx-sqlite", - feature = "sqlx-postgres" -))] -async fn loader_load_one_edge_case() -> Result<(), DbErr> { - let ctx = TestContext::new("loader_test_load_one").await; - create_tables(&ctx.db).await?; - - let bakery_0 = insert_bakery(&ctx.db, "SeaSide Bakery").await?; - let bakery_1 = insert_bakery(&ctx.db, "SeaSide Bakery").await?; - - let baker_1 = insert_baker(&ctx.db, "Baker 1", bakery_0.id).await?; - let baker_2 = insert_baker(&ctx.db, "Baker 2", bakery_0.id).await?; - let baker_3 = baker::ActiveModel { - name: Set("Baker 3".to_owned()), - contact_details: Set(serde_json::json!({})), - bakery_id: Set(None), - ..Default::default() - } - .insert(&ctx.db) - .await?; - - let bakers = baker::Entity::find().all(&ctx.db).await?; - let bakeries = bakers.load_one(bakery::Entity, &ctx.db).await?; - - assert_eq!(bakers, [baker_1, baker_2, baker_3]); - assert_eq!(bakeries, [Some(bakery_0.clone()), Some(bakery_0), None]); - + // has many find, should use load_many instead let bakeries = bakery::Entity::find().all(&ctx.db).await?; let bakers = bakeries.load_one(baker::Entity, &ctx.db).await; assert_eq!(bakers, Err(DbErr::Query(RuntimeErr::Internal("Relation is HasMany instead of HasOne".to_string())))); + Ok(()) } @@ -190,6 +159,7 @@ async fn loader_load_many_to_many() -> Result<(), DbErr> { let baker_1 = insert_baker(&ctx.db, "Jane", bakery_1.id).await?; let baker_2 = insert_baker(&ctx.db, "Peter", bakery_1.id).await?; + let baker_3 = insert_baker(&ctx.db, "Fred", bakery_1.id).await?; // does not make cake let cake_1 = insert_cake(&ctx.db, "Cheesecake", None).await?; let cake_2 = insert_cake(&ctx.db, "Coffee", None).await?; @@ -206,12 +176,13 @@ async fn loader_load_many_to_many() -> Result<(), DbErr> { .load_many_to_many(cake::Entity, cakes_bakers::Entity, &ctx.db) .await?; - assert_eq!(bakers, [baker_1.clone(), baker_2.clone()]); + assert_eq!(bakers, [baker_1.clone(), baker_2.clone(), baker_3.clone()]); assert_eq!( cakes, [ vec![cake_1.clone(), cake_2.clone()], - vec![cake_2.clone(), cake_3.clone()] + vec![cake_2.clone(), cake_3.clone()], + vec![] ] ); @@ -224,7 +195,7 @@ async fn loader_load_many_to_many() -> Result<(), DbErr> { &ctx.db, ) .await?; - assert_eq!(cakes, [vec![cake_1.clone()], vec![cake_3.clone()]]); + assert_eq!(cakes, [vec![cake_1.clone()], vec![cake_3.clone()], vec![]]); // now, start again from cakes From 9c5ff07af804947e7e2e01741a6e8444e03b81df Mon Sep 17 00:00:00 2001 From: Yiu Tin Cheung Ivan Date: Fri, 18 Aug 2023 18:31:39 +0800 Subject: [PATCH 18/23] completed loader many to many test case, fmt --- src/executor/select.rs | 4 +- src/query/loader.rs | 127 ++++++++++++++++++++++++++++-------- tests/empty_insert_tests.rs | 6 +- tests/loader_tests.rs | 12 +++- 4 files changed, 115 insertions(+), 34 deletions(-) diff --git a/src/executor/select.rs b/src/executor/select.rs index 06ed4882c..ae2ac5eb2 100644 --- a/src/executor/select.rs +++ b/src/executor/select.rs @@ -1112,8 +1112,6 @@ where mod tests { use pretty_assertions::assert_eq; - use crate::tests_cfg::entity_linked; - fn cake_fruit_model( cake_id: i32, fruit_id: i32, @@ -1226,7 +1224,7 @@ mod tests { #[smol_potat::test] pub async fn also_related_3() -> Result<(), sea_orm::DbErr> { use sea_orm::tests_cfg::*; - use sea_orm::{DbBackend, EntityTrait, MockDatabase, QuerySelect}; + use sea_orm::{DbBackend, EntityTrait, MockDatabase}; let db = MockDatabase::new(DbBackend::Postgres) .append_query_results([[ diff --git a/src/query/loader.rs b/src/query/loader.rs index adbf9b89b..2f3693a30 100644 --- a/src/query/loader.rs +++ b/src/query/loader.rs @@ -473,15 +473,27 @@ mod tests { _ => "", } .to_string(); - sea_orm::tests_cfg::filling::Model { id, name, vendor_id: Some(1), ignored_attr: 0 } + sea_orm::tests_cfg::filling::Model { + id, + name, + vendor_id: Some(1), + ignored_attr: 0, + } } + fn cake_filling_model( + cake_id: i32, + filling_id: i32, + ) -> sea_orm::tests_cfg::cake_filling::Model { + sea_orm::tests_cfg::cake_filling::Model { + cake_id, + filling_id, + } + } #[tokio::test] async fn test_load_one() { - use sea_orm::{ - entity::prelude::*, tests_cfg::*, DbBackend, IntoMockRow, LoaderTrait, MockDatabase, - }; + use sea_orm::{entity::prelude::*, tests_cfg::*, DbBackend, LoaderTrait, MockDatabase}; let db = MockDatabase::new(DbBackend::Postgres) .append_query_results([[cake_model(1), cake_model(2)]]) @@ -499,9 +511,7 @@ mod tests { #[tokio::test] async fn test_load_one_same_cake() { - use sea_orm::{ - entity::prelude::*, tests_cfg::*, DbBackend, IntoMockRow, LoaderTrait, MockDatabase, - }; + use sea_orm::{entity::prelude::*, tests_cfg::*, DbBackend, LoaderTrait, MockDatabase}; let db = MockDatabase::new(DbBackend::Postgres) .append_query_results([[cake_model(1), cake_model(2)]]) @@ -519,9 +529,7 @@ mod tests { #[tokio::test] async fn test_load_one_empty() { - use sea_orm::{ - entity::prelude::*, tests_cfg::*, DbBackend, IntoMockRow, LoaderTrait, MockDatabase, - }; + use sea_orm::{entity::prelude::*, tests_cfg::*, DbBackend, LoaderTrait, MockDatabase}; let db = MockDatabase::new(DbBackend::Postgres) .append_query_results([[cake_model(1), cake_model(2)]]) @@ -539,9 +547,7 @@ mod tests { #[tokio::test] async fn test_load_many() { - use sea_orm::{ - entity::prelude::*, tests_cfg::*, DbBackend, IntoMockRow, LoaderTrait, MockDatabase, - }; + use sea_orm::{entity::prelude::*, tests_cfg::*, DbBackend, LoaderTrait, MockDatabase}; let db = MockDatabase::new(DbBackend::Postgres) .append_query_results([[fruit_model(1, Some(1))]]) @@ -558,10 +564,8 @@ mod tests { } #[tokio::test] - async fn test_load_many_2() { - use sea_orm::{ - entity::prelude::*, tests_cfg::*, DbBackend, IntoMockRow, LoaderTrait, MockDatabase, - }; + async fn test_load_many_same_fruit() { + use sea_orm::{entity::prelude::*, tests_cfg::*, DbBackend, LoaderTrait, MockDatabase}; let db = MockDatabase::new(DbBackend::Postgres) .append_query_results([[fruit_model(1, Some(1)), fruit_model(2, Some(1))]]) @@ -586,7 +590,7 @@ mod tests { // FIXME: load many with empty vector will panic // #[tokio::test] async fn test_load_many_empty() { - use sea_orm::{entity::prelude::*, tests_cfg::*, DbBackend, IntoMockRow, MockDatabase}; + use sea_orm::{entity::prelude::*, tests_cfg::*, DbBackend, MockDatabase}; let db = MockDatabase::new(DbBackend::Postgres) .append_query_results([[fruit_model(1, Some(1)), fruit_model(2, Some(1))]]) @@ -599,31 +603,98 @@ mod tests { .await .expect("Should return something"); - assert_eq!(fruits, [vec![], vec![]]); + let empty_vec: Vec> = vec![]; + + assert_eq!(fruits, empty_vec); } - // TODO: not sure how to test - // #[tokio::test] - async fn test_load_many_to_many() { + #[tokio::test] + async fn test_load_many_to_many_base() { use sea_orm::{ entity::prelude::*, tests_cfg::*, DbBackend, IntoMockRow, LoaderTrait, MockDatabase, }; let db = MockDatabase::new(DbBackend::Postgres) - .append_query_results([[ - (cake_filling::Model { cake_id:1, filling_id: 1}, - filling_model(1)) - ]]) + .append_query_results([ + [cake_filling_model(1, 1).into_mock_row()], + [filling_model(1).into_mock_row()], + ]) .into_connection(); let cakes = vec![cake_model(1)]; let fillings = cakes - .load_many_to_many(Filling, CakeFilling , &db) + .load_many_to_many(Filling, CakeFilling, &db) + .await + .expect("Should return something"); + + assert_eq!(fillings, vec![vec![filling_model(1)]]); + } + + #[tokio::test] + async fn test_load_many_to_many_complex() { + use sea_orm::{ + entity::prelude::*, tests_cfg::*, DbBackend, IntoMockRow, LoaderTrait, MockDatabase, + }; + + let db = MockDatabase::new(DbBackend::Postgres) + .append_query_results([ + [ + cake_filling_model(1, 1).into_mock_row(), + cake_filling_model(1, 2).into_mock_row(), + cake_filling_model(1, 3).into_mock_row(), + cake_filling_model(2, 1).into_mock_row(), + cake_filling_model(2, 2).into_mock_row(), + ], + [ + filling_model(1).into_mock_row(), + filling_model(2).into_mock_row(), + filling_model(3).into_mock_row(), + filling_model(4).into_mock_row(), + filling_model(5).into_mock_row(), + ], + ]) + .into_connection(); + + let cakes = vec![cake_model(1), cake_model(2), cake_model(3)]; + + let fillings = cakes + .load_many_to_many(Filling, CakeFilling, &db) .await .expect("Should return something"); - assert_eq!(fillings, [vec![filling_model(1)], vec![]]); + assert_eq!( + fillings, + vec![ + vec![filling_model(1), filling_model(2), filling_model(3)], + vec![filling_model(1), filling_model(2)], + vec![], + ] + ); } + #[tokio::test] + async fn test_load_many_to_many_empty() { + use sea_orm::{ + entity::prelude::*, tests_cfg::*, DbBackend, IntoMockRow, LoaderTrait, MockDatabase, + }; + + let db = MockDatabase::new(DbBackend::Postgres) + .append_query_results([ + [cake_filling_model(1, 1).into_mock_row()], + [filling_model(1).into_mock_row()], + ]) + .into_connection(); + + let cakes: Vec = vec![]; + + let fillings = cakes + .load_many_to_many(Filling, CakeFilling, &db) + .await + .expect("Should return something"); + + let empty_vec: Vec> = vec![]; + + assert_eq!(fillings, empty_vec); + } } diff --git a/tests/empty_insert_tests.rs b/tests/empty_insert_tests.rs index f46fa354e..adfdbfa17 100644 --- a/tests/empty_insert_tests.rs +++ b/tests/empty_insert_tests.rs @@ -45,7 +45,11 @@ pub async fn test(db: &DbConn) { }; let res = Bakery::insert(double_seaside_bakery) - .on_conflict(OnConflict::column(bakery::Column::Id).do_nothing().to_owned()) + .on_conflict( + OnConflict::column(bakery::Column::Id) + .do_nothing() + .to_owned(), + ) .on_empty_do_nothing() .exec(db) .await; diff --git a/tests/loader_tests.rs b/tests/loader_tests.rs index ae621e500..67341fdc6 100644 --- a/tests/loader_tests.rs +++ b/tests/loader_tests.rs @@ -36,7 +36,12 @@ async fn loader_load_one() -> Result<(), DbErr> { let bakeries = bakery::Entity::find().all(&ctx.db).await?; let bakers = bakeries.load_one(baker::Entity, &ctx.db).await; - assert_eq!(bakers, Err(DbErr::Query(RuntimeErr::Internal("Relation is HasMany instead of HasOne".to_string())))); + assert_eq!( + bakers, + Err(DbErr::Query(RuntimeErr::Internal( + "Relation is HasMany instead of HasOne".to_string() + ))) + ); Ok(()) } @@ -64,7 +69,10 @@ async fn loader_load_many() -> Result<(), DbErr> { let bakeries = bakery::Entity::find().all(&ctx.db).await?; let bakers = bakeries.load_many(baker::Entity, &ctx.db).await?; - assert_eq!(bakeries, [bakery_1.clone(), bakery_2.clone(), bakery_3.clone()]); + assert_eq!( + bakeries, + [bakery_1.clone(), bakery_2.clone(), bakery_3.clone()] + ); assert_eq!( bakers, [ From b8282fe852b4d57318525617e5f23ff28a185504 Mon Sep 17 00:00:00 2001 From: Yiu Tin Cheung Ivan Date: Fri, 18 Aug 2023 18:35:22 +0800 Subject: [PATCH 19/23] removed empty_insert test case for now --- tests/empty_insert_tests.rs | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/tests/empty_insert_tests.rs b/tests/empty_insert_tests.rs index adfdbfa17..ea61a37fb 100644 --- a/tests/empty_insert_tests.rs +++ b/tests/empty_insert_tests.rs @@ -44,19 +44,6 @@ pub async fn test(db: &DbConn) { id: Set(1), }; - let res = Bakery::insert(double_seaside_bakery) - .on_conflict( - OnConflict::column(bakery::Column::Id) - .do_nothing() - .to_owned(), - ) - .on_empty_do_nothing() - .exec(db) - .await; - - dbg!(&res); - assert!(matches!(res, Ok(TryInsertResult::Conflicted))); - let empty_insert = Bakery::insert_many(std::iter::empty::()) .on_empty_do_nothing() .exec(db) From c4b69e3a74e0f53093d8045e3d0065879b4f18db Mon Sep 17 00:00:00 2001 From: Yiu Tin Cheung Ivan Date: Fri, 18 Aug 2023 18:36:56 +0800 Subject: [PATCH 20/23] commented insert_test --- issues/1790/insert_test.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/issues/1790/insert_test.rs b/issues/1790/insert_test.rs index 45e9cc084..cf30e58c1 100644 --- a/issues/1790/insert_test.rs +++ b/issues/1790/insert_test.rs @@ -1,4 +1,5 @@ mod tests { + // currently ok #[test] fn insert_do_nothing_postgres() { assert_eq!( @@ -17,6 +18,7 @@ mod tests { ); } + //failed to run #[test] fn insert_do_nothing_mysql() { assert_eq!( @@ -35,6 +37,7 @@ mod tests { ); } + // currently ok #[test] fn insert_do_nothing() { assert_eq!( From 3b9f84b50484907f16e22daec6321d958b415480 Mon Sep 17 00:00:00 2001 From: Yiu Tin Cheung Ivan Date: Fri, 18 Aug 2023 18:42:41 +0800 Subject: [PATCH 21/23] added Cargo.toml for issue 1790's folder --- issues/1790/Cargo.toml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 issues/1790/Cargo.toml diff --git a/issues/1790/Cargo.toml b/issues/1790/Cargo.toml new file mode 100644 index 000000000..e3872e255 --- /dev/null +++ b/issues/1790/Cargo.toml @@ -0,0 +1,18 @@ +[workspace] +# A separate workspace + +[package] +name = "sea-orm-issues-1790" +version = "0.1.0" +edition = "2023" +publish = false + +[dependencies] +anyhow = "1" +serde = "1" +tokio = { version = "1", features = ["rt", "rt-multi-thread", "macros"] } + +[dependencies.sea-orm] +path = "../../" +default-features = false +features = ["macros", "runtime-tokio-native-tls", "sqlx-sqlite"] From 97731f0e94407cb5928170d103fe9a4e856a975b Mon Sep 17 00:00:00 2001 From: Yiu Tin Cheung Ivan Date: Fri, 18 Aug 2023 18:43:02 +0800 Subject: [PATCH 22/23] buffed salvo version for ci(0.49 yanked) --- examples/salvo_example/api/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/salvo_example/api/Cargo.toml b/examples/salvo_example/api/Cargo.toml index 460425de2..9f0463b32 100644 --- a/examples/salvo_example/api/Cargo.toml +++ b/examples/salvo_example/api/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] salvo-example-service = { path = "../service" } tokio = { version = "1.29.0", features = ["macros", "rt-multi-thread"] } -salvo = { version = "0.49", features = ["affix", "serve-static"] } +salvo = { version = "0.50", features = ["affix", "serve-static"] } tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } serde = { version = "1", features = ["derive"] } tera = "1.19.0" From eea87955d85d7c5cc2160956e35e5bf97748bab9 Mon Sep 17 00:00:00 2001 From: Yiu Tin Cheung Ivan Date: Fri, 18 Aug 2023 18:49:39 +0800 Subject: [PATCH 23/23] revert version for salvo example --- examples/salvo_example/api/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/salvo_example/api/Cargo.toml b/examples/salvo_example/api/Cargo.toml index 9f0463b32..460425de2 100644 --- a/examples/salvo_example/api/Cargo.toml +++ b/examples/salvo_example/api/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] salvo-example-service = { path = "../service" } tokio = { version = "1.29.0", features = ["macros", "rt-multi-thread"] } -salvo = { version = "0.50", features = ["affix", "serve-static"] } +salvo = { version = "0.49", features = ["affix", "serve-static"] } tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } serde = { version = "1", features = ["derive"] } tera = "1.19.0"