sea_orm/entity/
active_value.rs

1use crate::Value;
2use sea_query::Nullable;
3use std::fmt::Debug;
4
5pub use ActiveValue::{NotSet, Set, Unchanged};
6
7/// The state of a field in an [ActiveModel][ActiveModelTrait].
8///
9/// There are three possible states represented by three enum variants:
10///
11/// - [Set] - a value that's explicitly set by the application and sent to the database.
12/// - [Unchanged] - an existing, unchanged value from the database.
13/// - [NotSet] - an undefined value (nothing is sent to the database).
14///
15/// The difference between these states is useful
16/// when constructing `INSERT` and `UPDATE` SQL statements (see an example below).
17/// It's also useful for knowing which fields have changed in a record.
18///
19/// # Examples
20///
21/// ```
22/// use sea_orm::tests_cfg::{cake, fruit};
23/// use sea_orm::{DbBackend, entity::*, query::*};
24///
25/// // Here, we use `NotSet` to let the database automatically generate an `id`.
26/// // This is different from `Set(None)` that explicitly sets `cake_id` to `NULL`.
27/// assert_eq!(
28///     Insert::one(fruit::ActiveModel {
29///         id: ActiveValue::NotSet,
30///         name: ActiveValue::Set("Orange".to_owned()),
31///         cake_id: ActiveValue::Set(None),
32///     })
33///     .build(DbBackend::Postgres)
34///     .to_string(),
35///     r#"INSERT INTO "fruit" ("name", "cake_id") VALUES ('Orange', NULL)"#
36/// );
37///
38/// // Here, we update the record, set `cake_id` to the new value
39/// // and use `NotSet` to avoid updating the `name` field.
40/// // `id` is the primary key, so it's used in the condition and not updated.
41/// assert_eq!(
42///     Update::one(fruit::ActiveModel {
43///         id: ActiveValue::Unchanged(1),
44///         name: ActiveValue::NotSet,
45///         cake_id: ActiveValue::Set(Some(2)),
46///     })
47///     .validate()
48///     .unwrap()
49///     .build(DbBackend::Postgres)
50///     .to_string(),
51///     r#"UPDATE "fruit" SET "cake_id" = 2 WHERE "fruit"."id" = 1"#
52/// );
53/// ```
54#[derive(Clone, Debug)]
55pub enum ActiveValue<V>
56where
57    V: Into<Value>,
58{
59    /// A [Value] that's explicitly set by the application and sent to the database.
60    ///
61    /// Use this to insert or set a specific value.
62    ///
63    /// When editing an existing value, you can use [set_if_not_equals][ActiveValue::set_if_not_equals]
64    /// to preserve the [Unchanged] state when the new value is the same as the old one.
65    /// Then you can meaningfully use methods like [ActiveModelTrait::is_changed].
66    Set(V),
67    /// An existing, unchanged [Value] from the database.
68    ///
69    /// You get these when you query an existing [Model][crate::ModelTrait]
70    /// from the database and convert it into an [ActiveModel][ActiveModelTrait].
71    ///
72    /// When you edit it, you can use [set_if_not_equals][ActiveValue::set_if_not_equals]
73    /// to preserve this "unchanged" state if the new value is the same as the old one.
74    /// Then you can meaningfully use methods like [ActiveModelTrait::is_changed].
75    Unchanged(V),
76    /// An undefined [Value]. Nothing is sent to the database.
77    ///
78    /// When you create a new [ActiveModel][ActiveModelTrait],
79    /// its fields are [NotSet][ActiveValue::NotSet] by default.
80    ///
81    /// This can be useful when:
82    ///
83    /// - You insert a new record and want the database to generate a default value (e.g., an id).
84    /// - In an `UPDATE` statement, you don't want to update some field.
85    NotSet,
86}
87
88/// Defines an not set operation on an [ActiveValue]
89#[deprecated(
90    since = "0.5.0",
91    note = "Please use [`ActiveValue::NotSet`] or [`NotSet`]"
92)]
93#[allow(non_snake_case)]
94pub fn Unset<V>(_: Option<bool>) -> ActiveValue<V>
95where
96    V: Into<Value>,
97{
98    ActiveValue::not_set()
99}
100
101/// Any type that can be converted into an [ActiveValue]
102pub trait IntoActiveValue<V>
103where
104    V: Into<Value>,
105{
106    /// Method to perform the conversion
107    fn into_active_value(self) -> ActiveValue<V>;
108}
109
110impl<V> IntoActiveValue<Option<V>> for Option<V>
111where
112    V: IntoActiveValue<V> + Into<Value> + Nullable,
113{
114    fn into_active_value(self) -> ActiveValue<Option<V>> {
115        match self {
116            Some(value) => Set(Some(value)),
117            None => NotSet,
118        }
119    }
120}
121
122impl<V> IntoActiveValue<Option<V>> for Option<Option<V>>
123where
124    V: IntoActiveValue<V> + Into<Value> + Nullable,
125{
126    fn into_active_value(self) -> ActiveValue<Option<V>> {
127        match self {
128            Some(value) => Set(value),
129            None => NotSet,
130        }
131    }
132}
133
134macro_rules! impl_into_active_value {
135    ($ty: ty) => {
136        impl IntoActiveValue<$ty> for $ty {
137            fn into_active_value(self) -> ActiveValue<$ty> {
138                Set(self)
139            }
140        }
141    };
142}
143
144impl_into_active_value!(bool);
145impl_into_active_value!(i8);
146impl_into_active_value!(i16);
147impl_into_active_value!(i32);
148impl_into_active_value!(i64);
149impl_into_active_value!(u8);
150impl_into_active_value!(u16);
151impl_into_active_value!(u32);
152impl_into_active_value!(u64);
153impl_into_active_value!(f32);
154impl_into_active_value!(f64);
155impl_into_active_value!(&'static str);
156impl_into_active_value!(String);
157impl_into_active_value!(Vec<u8>);
158
159#[cfg(feature = "with-json")]
160#[cfg_attr(docsrs, doc(cfg(feature = "with-json")))]
161impl_into_active_value!(crate::prelude::Json);
162
163#[cfg(feature = "with-chrono")]
164#[cfg_attr(docsrs, doc(cfg(feature = "with-chrono")))]
165impl_into_active_value!(crate::prelude::Date);
166
167#[cfg(feature = "with-chrono")]
168#[cfg_attr(docsrs, doc(cfg(feature = "with-chrono")))]
169impl_into_active_value!(crate::prelude::Time);
170
171#[cfg(feature = "with-chrono")]
172#[cfg_attr(docsrs, doc(cfg(feature = "with-chrono")))]
173impl_into_active_value!(crate::prelude::DateTime);
174
175#[cfg(feature = "with-chrono")]
176#[cfg_attr(docsrs, doc(cfg(feature = "with-chrono")))]
177impl_into_active_value!(crate::prelude::DateTimeWithTimeZone);
178
179#[cfg(feature = "with-chrono")]
180#[cfg_attr(docsrs, doc(cfg(feature = "with-chrono")))]
181impl_into_active_value!(crate::prelude::DateTimeUtc);
182
183#[cfg(feature = "with-chrono")]
184#[cfg_attr(docsrs, doc(cfg(feature = "with-chrono")))]
185impl_into_active_value!(crate::prelude::DateTimeLocal);
186
187#[cfg(feature = "with-rust_decimal")]
188#[cfg_attr(docsrs, doc(cfg(feature = "with-rust_decimal")))]
189impl_into_active_value!(crate::prelude::Decimal);
190
191#[cfg(feature = "with-bigdecimal")]
192#[cfg_attr(docsrs, doc(cfg(feature = "with-bigdecimal")))]
193impl_into_active_value!(crate::prelude::BigDecimal);
194
195#[cfg(feature = "with-uuid")]
196#[cfg_attr(docsrs, doc(cfg(feature = "with-uuid")))]
197impl_into_active_value!(crate::prelude::Uuid);
198
199#[cfg(feature = "with-time")]
200#[cfg_attr(docsrs, doc(cfg(feature = "with-time")))]
201impl_into_active_value!(crate::prelude::TimeDate);
202
203#[cfg(feature = "with-time")]
204#[cfg_attr(docsrs, doc(cfg(feature = "with-time")))]
205impl_into_active_value!(crate::prelude::TimeTime);
206
207#[cfg(feature = "with-time")]
208#[cfg_attr(docsrs, doc(cfg(feature = "with-time")))]
209impl_into_active_value!(crate::prelude::TimeDateTime);
210
211#[cfg(feature = "with-time")]
212#[cfg_attr(docsrs, doc(cfg(feature = "with-time")))]
213impl_into_active_value!(crate::prelude::TimeDateTimeWithTimeZone);
214
215#[cfg(feature = "with-ipnetwork")]
216#[cfg_attr(docsrs, doc(cfg(feature = "with-ipnetwork")))]
217impl_into_active_value!(crate::prelude::IpNetwork);
218
219impl<V> Default for ActiveValue<V>
220where
221    V: Into<Value>,
222{
223    /// Create an [ActiveValue::NotSet]
224    fn default() -> Self {
225        Self::NotSet
226    }
227}
228
229impl<V> ActiveValue<V>
230where
231    V: Into<Value>,
232{
233    /// Create an [ActiveValue::Set]
234    pub fn set(value: V) -> Self {
235        Self::Set(value)
236    }
237
238    /// Check if the [ActiveValue] is [ActiveValue::Set]
239    pub fn is_set(&self) -> bool {
240        matches!(self, Self::Set(_))
241    }
242
243    /// Create an [ActiveValue::Unchanged]
244    pub fn unchanged(value: V) -> Self {
245        Self::Unchanged(value)
246    }
247
248    /// Check if the [ActiveValue] is [ActiveValue::Unchanged]
249    pub fn is_unchanged(&self) -> bool {
250        matches!(self, Self::Unchanged(_))
251    }
252
253    /// Create an [ActiveValue::NotSet]
254    pub fn not_set() -> Self {
255        Self::default()
256    }
257
258    /// Check if the [ActiveValue] is [ActiveValue::NotSet]
259    pub fn is_not_set(&self) -> bool {
260        matches!(self, Self::NotSet)
261    }
262
263    /// Take ownership of the inner value, also setting self to `NotSet`
264    pub fn take(&mut self) -> Option<V> {
265        match std::mem::take(self) {
266            ActiveValue::Set(value) | ActiveValue::Unchanged(value) => Some(value),
267            ActiveValue::NotSet => None,
268        }
269    }
270
271    /// Get an owned value of the [ActiveValue]
272    ///
273    /// # Panics
274    ///
275    /// Panics if it is [ActiveValue::NotSet]
276    pub fn unwrap(self) -> V {
277        match self {
278            ActiveValue::Set(value) | ActiveValue::Unchanged(value) => value,
279            ActiveValue::NotSet => panic!("Cannot unwrap ActiveValue::NotSet"),
280        }
281    }
282
283    /// Take ownership of the inner value, consuming self
284    pub fn into_value(self) -> Option<Value> {
285        match self {
286            ActiveValue::Set(value) | ActiveValue::Unchanged(value) => Some(value.into()),
287            ActiveValue::NotSet => None,
288        }
289    }
290
291    /// Wrap the [Value] into a `ActiveValue<Value>`
292    pub fn into_wrapped_value(self) -> ActiveValue<Value> {
293        match self {
294            Self::Set(value) => ActiveValue::set(value.into()),
295            Self::Unchanged(value) => ActiveValue::unchanged(value.into()),
296            Self::NotSet => ActiveValue::not_set(),
297        }
298    }
299
300    /// Reset the value from [ActiveValue::Unchanged] to [ActiveValue::Set],
301    /// leaving [ActiveValue::NotSet] untouched.
302    pub fn reset(&mut self) {
303        *self = match self.take() {
304            Some(value) => ActiveValue::Set(value),
305            None => ActiveValue::NotSet,
306        };
307    }
308
309    /// `Set(value)`, except when [`self.is_unchanged()`][ActiveValue#method.is_unchanged]
310    /// and `value` equals the current [Unchanged][ActiveValue::Unchanged] value.
311    ///
312    /// This is useful when you have an [Unchanged][ActiveValue::Unchanged] value from the database,
313    /// then update it using this method,
314    /// and then use [`.is_unchanged()`][ActiveValue#method.is_unchanged] to see whether it has *actually* changed.
315    ///
316    /// The same nice effect applies to the entire `ActiveModel`.
317    /// You can now meaningfully use [ActiveModelTrait::is_changed][ActiveModelTrait#method.is_changed]
318    /// to see whether are any changes that need to be saved to the database.
319    ///
320    /// ## Examples
321    ///
322    /// ```
323    /// # use sea_orm::ActiveValue;
324    /// #
325    /// let mut value = ActiveValue::Unchanged("old");
326    ///
327    /// // This wouldn't be the case if we used plain `value = Set("old");`
328    /// value.set_if_not_equals("old");
329    /// assert!(value.is_unchanged());
330    ///
331    /// // Only when we change the actual `&str` value, it becomes `Set`
332    /// value.set_if_not_equals("new");
333    /// assert_eq!(value.is_unchanged(), false);
334    /// assert_eq!(value, ActiveValue::Set("new"));
335    /// ```
336    pub fn set_if_not_equals(&mut self, value: V)
337    where
338        V: PartialEq,
339    {
340        match self {
341            ActiveValue::Unchanged(current) if &value == current => {}
342            _ => *self = ActiveValue::Set(value),
343        }
344    }
345
346    /// Get the inner value, unless `self` is [NotSet][ActiveValue::NotSet].
347    ///
348    /// There's also a panicking version: [ActiveValue::as_ref].
349    ///
350    /// ## Examples
351    ///
352    /// ```
353    /// # use sea_orm::ActiveValue;
354    /// #
355    /// assert_eq!(ActiveValue::Unchanged(42).try_as_ref(), Some(&42));
356    /// assert_eq!(ActiveValue::Set(42).try_as_ref(), Some(&42));
357    /// assert_eq!(ActiveValue::NotSet.try_as_ref(), None::<&i32>);
358    /// ```
359    pub fn try_as_ref(&self) -> Option<&V> {
360        match self {
361            ActiveValue::Set(value) | ActiveValue::Unchanged(value) => Some(value),
362            ActiveValue::NotSet => None,
363        }
364    }
365}
366
367impl<V> std::convert::AsRef<V> for ActiveValue<V>
368where
369    V: Into<Value>,
370{
371    /// # Panics
372    ///
373    /// Panics if it is [ActiveValue::NotSet].
374    ///
375    /// See [ActiveValue::try_as_ref] for a fallible non-panicking version.
376    fn as_ref(&self) -> &V {
377        match self {
378            ActiveValue::Set(value) | ActiveValue::Unchanged(value) => value,
379            ActiveValue::NotSet => panic!("Cannot borrow ActiveValue::NotSet"),
380        }
381    }
382}
383
384impl<V> PartialEq for ActiveValue<V>
385where
386    V: Into<Value> + std::cmp::PartialEq,
387{
388    fn eq(&self, other: &Self) -> bool {
389        match (self, other) {
390            (ActiveValue::Set(l), ActiveValue::Set(r)) => l == r,
391            (ActiveValue::Unchanged(l), ActiveValue::Unchanged(r)) => l == r,
392            (ActiveValue::NotSet, ActiveValue::NotSet) => true,
393            _ => false,
394        }
395    }
396}
397
398impl<V> From<ActiveValue<V>> for ActiveValue<Option<V>>
399where
400    V: Into<Value> + Nullable,
401{
402    fn from(value: ActiveValue<V>) -> Self {
403        match value {
404            ActiveValue::Set(value) => ActiveValue::set(Some(value)),
405            ActiveValue::Unchanged(value) => ActiveValue::unchanged(Some(value)),
406            ActiveValue::NotSet => ActiveValue::not_set(),
407        }
408    }
409}