From 79b9121cfbb1deee7af6b7e1a60f45a45bc8bda2 Mon Sep 17 00:00:00 2001 From: Izzy McCabe Date: Thu, 23 Jul 2026 16:49:48 -0700 Subject: [PATCH 1/3] flatten and flatten_ref --- src/entity/active_value.rs | 68 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/src/entity/active_value.rs b/src/entity/active_value.rs index 315fcbeb6..0994d938c 100644 --- a/src/entity/active_value.rs +++ b/src/entity/active_value.rs @@ -413,6 +413,74 @@ where ActiveValue::NotSet => None, } } + + /// Flattens `&ActiveValue>` into an `Option<&T>`, folding [NotSet][ActiveValue::NotSet] + /// and [None][Option::None] together, and [Set][ActiveValue::Set], [Unchanged][ActiveValue::Unchanged], + /// and [Some][Option::Some] together. This can replace `model.field.try_as_ref().and_then(Option::as_ref)`. + /// + /// For a version on owned [ActiveValue]s, see [ActiveValue::flatten]. + /// + /// ``` + /// use sea_orm::ActiveValue; + /// + /// let x: &ActiveValue> = &ActiveValue::Set(Some(0)); + /// let y: &ActiveValue> = &ActiveValue::Set(None); + /// let z: &ActiveValue> = &ActiveValue::NotSet; + /// + /// assert_eq!(x.flatten_ref(), Some(&0)); + /// assert_eq!(y.flatten_ref(), None); + /// assert_eq!(z.flatten_ref(), None); + /// ``` + pub fn flatten_ref<'a, T>(&self) -> Option<&'a T> + where V: AsRefOption<'a, T> { + match self { + ActiveValue::Set(value) | ActiveValue::Unchanged(value) => value.as_ref_opt().as_ref(), + ActiveValue::NotSet => None, + } + } + + /// Flattens `ActiveValue>` into an `Option`, folding [NotSet][ActiveValue::NotSet] + /// and [None][Option::None] together, and [Set][ActiveValue::Set], [Unchanged][ActiveValue::Unchanged], + /// and [Some][Option::Some] together. This can replace `model.field.take().flatten()`. + /// + /// For a version on owned [ActiveValue]s, see [ActiveValue::flatten]. + /// + /// ``` + /// use sea_orm::ActiveValue; + /// + /// let x: ActiveValue> = ActiveValue::Set(Some(0)); + /// let y: ActiveValue> = ActiveValue::Set(None); + /// let z: ActiveValue> = ActiveValue::NotSet; + /// + /// assert_eq!(x.flatten(), Some(0)); + /// assert_eq!(y.flatten(), None); + /// assert_eq!(z.flatten(), None); + /// ``` + pub fn flatten<'a, T>(&self) -> Option + where V: AsOwnedOption { + match self { + ActiveValue::Set(value) | ActiveValue::Unchanged(value) => value.as_opt().as_ref(), + ActiveValue::NotSet => None, + } + } +} + +trait AsRefOption<'a, T> { + fn as_ref_opt(self) -> &'a Option; +} +impl<'a, T> AsRefOption for &'a Option { + fn as_ref_opt(self) -> &'a Option { + self + } +} + +trait AsOwnedOption { + fn as_opt(self) -> Option; +} +impl AsOwnedOption for Option { + fn as_opt(self) -> Option { + self + } } impl std::convert::AsRef for ActiveValue From 825ea88f13c24fa0c0cd0b5cbc18b46791721b0a Mon Sep 17 00:00:00 2001 From: Izzy McCabe Date: Thu, 23 Jul 2026 17:20:42 -0700 Subject: [PATCH 2/3] make traits sealed + remove as_ref from flatten --- src/entity/active_value.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/entity/active_value.rs b/src/entity/active_value.rs index 0994d938c..3610efbd4 100644 --- a/src/entity/active_value.rs +++ b/src/entity/active_value.rs @@ -459,24 +459,30 @@ where pub fn flatten<'a, T>(&self) -> Option where V: AsOwnedOption { match self { - ActiveValue::Set(value) | ActiveValue::Unchanged(value) => value.as_opt().as_ref(), + ActiveValue::Set(value) | ActiveValue::Unchanged(value) => value.as_opt(), ActiveValue::NotSet => None, } } } -trait AsRefOption<'a, T> { +mod private { + trait RefOptSealed {} + trait OwnedOptSealed {} +} +pub trait AsRefOption<'a, T>: private::RefOptSealed { fn as_ref_opt(self) -> &'a Option; } +impl<'a, T> private::RefOptSealed for &'a Option {} impl<'a, T> AsRefOption for &'a Option { fn as_ref_opt(self) -> &'a Option { self } } -trait AsOwnedOption { +pub trait AsOwnedOption: OwnedOptSealed { fn as_opt(self) -> Option; } +impl private::OwnedOptSealed for Option {} impl AsOwnedOption for Option { fn as_opt(self) -> Option { self From c9d1d5da01a3c27e94ed7c39acd590158e1eedee Mon Sep 17 00:00:00 2001 From: Izzy McCabe Date: Thu, 23 Jul 2026 17:34:46 -0700 Subject: [PATCH 3/3] make sealed traits pub --- src/entity/active_value.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/entity/active_value.rs b/src/entity/active_value.rs index 3610efbd4..6465244e1 100644 --- a/src/entity/active_value.rs +++ b/src/entity/active_value.rs @@ -466,8 +466,8 @@ where } mod private { - trait RefOptSealed {} - trait OwnedOptSealed {} + pub trait RefOptSealed {} + pub trait OwnedOptSealed {} } pub trait AsRefOption<'a, T>: private::RefOptSealed { fn as_ref_opt(self) -> &'a Option;