Skip to main content

sea_orm/entity/compound/
has_one.rs

1use crate::{ActiveHasOne, EntityTrait};
2
3#[derive_where::derive_where(Debug, Clone, PartialEq, Eq, Hash; E::ModelEx)]
4#[derive(Default)]
5pub enum HasOne<E>
6where
7    E: EntityTrait,
8{
9    #[default]
10    Unloaded,
11    Loaded(Option<Box<E::ModelEx>>),
12}
13
14impl<E> HasOne<E>
15where
16    E: EntityTrait,
17{
18    pub fn loaded(model: Option<impl Into<E::ModelEx>>) -> Self {
19        Self::Loaded(model.map(|model| Box::new(model.into())))
20    }
21
22    /// Return true if variant is `Unloaded`
23    pub fn is_unloaded(&self) -> bool {
24        matches!(self, Self::Unloaded)
25    }
26
27    /// Return true if variant is `Loaded`
28    pub fn is_loaded(&self) -> bool {
29        matches!(self, Self::Loaded(_))
30    }
31
32    /// Return true if this relation was loaded and no model was found.
33    pub fn is_not_found(&self) -> bool {
34        matches!(self, Self::Loaded(None))
35    }
36
37    /// True if variant is `Unloaded` or `Loaded(None)`
38    pub fn is_none(&self) -> bool {
39        matches!(self, Self::Unloaded | Self::Loaded(None))
40    }
41
42    /// Get a reference, if loaded with a model
43    pub fn as_ref(&self) -> Option<&E::ModelEx> {
44        match self {
45            Self::Loaded(Some(model)) => Some(model.as_ref()),
46            Self::Unloaded | Self::Loaded(None) => None,
47        }
48    }
49
50    /// Get a mutable reference, if loaded with a model
51    pub fn as_mut(&mut self) -> Option<&mut E::ModelEx> {
52        match self {
53            Self::Loaded(Some(model)) => Some(model),
54            Self::Unloaded | Self::Loaded(None) => None,
55        }
56    }
57
58    /// Convert into an `Option<ModelEx>`
59    pub fn into_option(self) -> Option<E::ModelEx> {
60        match self {
61            Self::Loaded(Some(model)) => Some(*model),
62            Self::Unloaded | Self::Loaded(None) => None,
63        }
64    }
65
66    /// Take ownership of the contained Model, if loaded, leaving `Unloaded` in place.
67    pub fn take(&mut self) -> Option<E::ModelEx> {
68        std::mem::take(self).into_option()
69    }
70
71    /// # Panics
72    ///
73    /// Panics if called on an `Unloaded` or `Loaded(None)` value.
74    pub fn unwrap(self) -> E::ModelEx {
75        match self {
76            Self::Loaded(Some(model)) => *model,
77            Self::Unloaded => panic!("called `HasOne::unwrap()` on an `Unloaded` value"),
78            Self::Loaded(None) => panic!("called `HasOne::unwrap()` on a `Loaded(None)` value"),
79        }
80    }
81}
82
83impl<E> HasOne<E>
84where
85    E: EntityTrait,
86    E::ActiveModelEx: From<E::ModelEx>,
87{
88    pub fn into_active_model(self) -> ActiveHasOne<E> {
89        match self {
90            Self::Loaded(Some(model)) => ActiveHasOne::set(Some(*model)),
91            Self::Unloaded | Self::Loaded(None) => ActiveHasOne::NotSet,
92        }
93    }
94}
95
96impl<E: EntityTrait> From<HasOne<E>> for Option<Box<E::ModelEx>> {
97    fn from(value: HasOne<E>) -> Self {
98        match value {
99            HasOne::Loaded(model) => model,
100            HasOne::Unloaded => None,
101        }
102    }
103}
104
105impl<E: EntityTrait> From<Option<Box<E::ModelEx>>> for HasOne<E> {
106    fn from(value: Option<Box<E::ModelEx>>) -> Self {
107        Self::Loaded(value)
108    }
109}
110
111#[cfg(feature = "with-json")]
112impl<E> serde::Serialize for HasOne<E>
113where
114    E: EntityTrait,
115    E::ModelEx: serde::Serialize,
116{
117    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
118    where
119        S: serde::Serializer,
120    {
121        match self {
122            HasOne::Unloaded => None,
123            HasOne::Loaded(model) => model.as_ref(),
124        }
125        .serialize(serializer)
126    }
127}
128
129#[cfg(feature = "with-json")]
130impl<'de, E> serde::Deserialize<'de> for HasOne<E>
131where
132    E: EntityTrait,
133    E::ModelEx: serde::Deserialize<'de>,
134{
135    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
136    where
137        D: serde::Deserializer<'de>,
138    {
139        match <Option<E::ModelEx>>::deserialize(deserializer)? {
140            Some(model) => Ok(HasOne::Loaded(Some(Box::new(model)))),
141            None => Ok(HasOne::Unloaded),
142        }
143    }
144}