diff --git a/sea-orm-sync/src/query/select.rs b/sea-orm-sync/src/query/select.rs index 67d2aea96..fb3ce336f 100644 --- a/sea-orm-sync/src/query/select.rs +++ b/sea-orm-sync/src/query/select.rs @@ -1,6 +1,6 @@ use crate::{ - ColumnTrait, EntityTrait, Iterable, Order, PrimaryKeyToColumn, QueryFilter, QueryOrder, - QuerySelect, QueryTrait, + ColumnTrait, EntityTrait, IdenStatic, Iterable, Order, PrimaryKeyToColumn, QueryFilter, + QueryOrder, QuerySelect, QueryTrait, }; use core::fmt::Debug; use core::marker::PhantomData; @@ -317,6 +317,18 @@ where } self } + + /// Select all columns of this entity except the given ones. + pub fn select_except(mut self, except: impl IntoIterator) -> Self { + let except: Vec<&str> = except.into_iter().map(|col| col.as_str()).collect(); + self.query.clear_selects(); + for col in E::Column::iter() { + if !except.contains(&col.as_str()) { + self.query.expr(col.select_as(col.into_expr())); + } + } + self + } } impl QueryTrait for Select diff --git a/sea-orm-sync/tests/query_tests.rs b/sea-orm-sync/tests/query_tests.rs index e17607662..f31ed2336 100644 --- a/sea-orm-sync/tests/query_tests.rs +++ b/sea-orm-sync/tests/query_tests.rs @@ -239,3 +239,58 @@ pub fn select_only_exclude_option_fields() { ctx.delete(); } + +#[sea_orm_macros::test] +pub fn select_except_excludes_option_fields() { + let ctx = TestContext::new("select_except_excludes_option_fields"); + create_bakery_table(&ctx.db).unwrap(); + create_baker_table(&ctx.db).unwrap(); + + let bakery = bakery::ActiveModel { + name: Set("Sweet Treats".to_owned()), + profit_margin: Set(0.5), + ..Default::default() + } + .save(&ctx.db) + .expect("could not insert bakery"); + + let _ = baker::ActiveModel { + name: Set("Alice".to_owned()), + contact_details: Set(serde_json::json!({ + "phone": "555-1234", + "email": "alice@example.com" + })), + bakery_id: Set(Some(bakery.id.clone().unwrap())), + ..Default::default() + } + .save(&ctx.db) + .expect("could not insert baker"); + + let bakers = Baker::find() + .select_except([baker::Column::BakeryId]) + .all(&ctx.db) + .unwrap(); + + assert_eq!(bakers.len(), 1); + assert_eq!(bakers[0].name, "Alice"); + assert_eq!( + bakers[0].contact_details, + serde_json::json!({ + "phone": "555-1234", + "email": "alice@example.com" + }) + ); + assert_eq!(bakers[0].bakery_id, None); + + let bakery_id: Option = Baker::find_by_id(bakers[0].id) + .select_only() + .column(baker::Column::BakeryId) + .into_tuple() + .one(&ctx.db) + .unwrap() + .unwrap(); + + assert_eq!(bakery_id, Some(bakery.id.unwrap())); + + ctx.delete(); +} diff --git a/src/query/select.rs b/src/query/select.rs index 67d2aea96..fb3ce336f 100644 --- a/src/query/select.rs +++ b/src/query/select.rs @@ -1,6 +1,6 @@ use crate::{ - ColumnTrait, EntityTrait, Iterable, Order, PrimaryKeyToColumn, QueryFilter, QueryOrder, - QuerySelect, QueryTrait, + ColumnTrait, EntityTrait, IdenStatic, Iterable, Order, PrimaryKeyToColumn, QueryFilter, + QueryOrder, QuerySelect, QueryTrait, }; use core::fmt::Debug; use core::marker::PhantomData; @@ -317,6 +317,18 @@ where } self } + + /// Select all columns of this entity except the given ones. + pub fn select_except(mut self, except: impl IntoIterator) -> Self { + let except: Vec<&str> = except.into_iter().map(|col| col.as_str()).collect(); + self.query.clear_selects(); + for col in E::Column::iter() { + if !except.contains(&col.as_str()) { + self.query.expr(col.select_as(col.into_expr())); + } + } + self + } } impl QueryTrait for Select diff --git a/tests/query_tests.rs b/tests/query_tests.rs index ff181f720..8682374b6 100644 --- a/tests/query_tests.rs +++ b/tests/query_tests.rs @@ -256,3 +256,62 @@ pub async fn select_only_exclude_option_fields() { ctx.delete().await; } + +#[sea_orm_macros::test] +pub async fn select_except_excludes_option_fields() { + let ctx = TestContext::new("select_except_excludes_option_fields").await; + create_bakery_table(&ctx.db).await.unwrap(); + create_baker_table(&ctx.db).await.unwrap(); + + let bakery = bakery::ActiveModel { + name: Set("Sweet Treats".to_owned()), + profit_margin: Set(0.5), + ..Default::default() + } + .save(&ctx.db) + .await + .expect("could not insert bakery"); + + let _ = baker::ActiveModel { + name: Set("Alice".to_owned()), + contact_details: Set(serde_json::json!({ + "phone": "555-1234", + "email": "alice@example.com" + })), + bakery_id: Set(Some(bakery.id.clone().unwrap())), + ..Default::default() + } + .save(&ctx.db) + .await + .expect("could not insert baker"); + + let bakers = Baker::find() + .select_except([baker::Column::BakeryId]) + .all(&ctx.db) + .await + .unwrap(); + + assert_eq!(bakers.len(), 1); + assert_eq!(bakers[0].name, "Alice"); + assert_eq!( + bakers[0].contact_details, + serde_json::json!({ + "phone": "555-1234", + "email": "alice@example.com" + }) + ); + assert_eq!(bakers[0].bakery_id, None); + + let bakery_id: Option = Baker::find_by_id(bakers[0].id) + .select_only() + .column(baker::Column::BakeryId) + .into_tuple() + .one(&ctx.db) + .await + .unwrap() + .unwrap(); + + assert_eq!(bakery_id, Some(bakery.id.unwrap())); + + ctx.delete().await; +}