sea_orm/entity/compound/
has_one.rs1use crate::{EntityTrait, HasOneModel};
2use std::hash::{Hash, Hasher};
3
4#[derive(Debug, Default, Clone)]
5pub enum HasOne<E: EntityTrait> {
6 #[default]
7 Unloaded,
8 NotFound,
9 Loaded(Box<E::ModelEx>),
10}
11
12impl<E: EntityTrait> HasOne<E> {
13 pub fn loaded<M: Into<E::ModelEx>>(model: M) -> Self {
15 Self::Loaded(Box::new(model.into()))
16 }
17
18 pub fn is_unloaded(&self) -> bool {
20 matches!(self, HasOne::Unloaded)
21 }
22
23 pub fn is_not_found(&self) -> bool {
25 matches!(self, HasOne::NotFound)
26 }
27
28 pub fn is_loaded(&self) -> bool {
30 matches!(self, HasOne::Loaded(_))
31 }
32
33 pub fn is_none(&self) -> bool {
35 matches!(self, HasOne::Unloaded | HasOne::NotFound)
36 }
37
38 pub fn as_ref(&self) -> Option<&E::ModelEx> {
40 match self {
41 HasOne::Loaded(model) => Some(model.as_ref()),
42 HasOne::Unloaded | HasOne::NotFound => None,
43 }
44 }
45
46 pub fn as_mut(&mut self) -> Option<&mut E::ModelEx> {
48 match self {
49 HasOne::Loaded(model) => Some(model),
50 HasOne::Unloaded | HasOne::NotFound => None,
51 }
52 }
53
54 pub fn into_option(self) -> Option<E::ModelEx> {
56 match self {
57 HasOne::Loaded(model) => Some(*model),
58 HasOne::Unloaded | HasOne::NotFound => None,
59 }
60 }
61
62 pub fn take(&mut self) -> Option<E::ModelEx> {
64 std::mem::take(self).into_option()
65 }
66
67 pub fn unwrap(self) -> E::ModelEx {
71 match self {
72 HasOne::Loaded(model) => *model,
73 HasOne::Unloaded => panic!("called `HasOne::unwrap()` on an `Unloaded` value"),
74 HasOne::NotFound => panic!("called `HasOne::unwrap()` on a `NotFound` value"),
75 }
76 }
77}
78
79impl<E> HasOne<E>
80where
81 E: EntityTrait,
82 E::ActiveModelEx: From<E::ModelEx>,
83{
84 pub fn into_active_model(self) -> HasOneModel<E> {
85 match self {
86 HasOne::Loaded(_) => {
87 let model = self.unwrap();
88 let active_model: E::ActiveModelEx = model.into();
89 HasOneModel::Set(active_model.into())
90 }
91 HasOne::Unloaded => HasOneModel::NotSet,
92 HasOne::NotFound => HasOneModel::NotSet,
93 }
94 }
95}
96
97impl<E> PartialEq for HasOne<E>
98where
99 E: EntityTrait,
100 E::ModelEx: PartialEq,
101{
102 fn eq(&self, other: &Self) -> bool {
103 match (self, other) {
104 (HasOne::Unloaded, HasOne::Unloaded) => true,
105 (HasOne::NotFound, HasOne::NotFound) => true,
106 (HasOne::Loaded(a), HasOne::Loaded(b)) => a == b,
107 _ => false,
108 }
109 }
110}
111
112impl<E> Eq for HasOne<E>
113where
114 E: EntityTrait,
115 E::ModelEx: Eq,
116{
117}
118
119impl<E: EntityTrait> From<HasOne<E>> for Option<Box<E::ModelEx>> {
121 fn from(value: HasOne<E>) -> Self {
122 match value {
123 HasOne::Loaded(model) => Some(model),
124 HasOne::Unloaded | HasOne::NotFound => None,
125 }
126 }
127}
128
129impl<E: EntityTrait> From<Option<Box<E::ModelEx>>> for HasOne<E> {
130 fn from(value: Option<Box<E::ModelEx>>) -> Self {
131 match value {
132 Some(model) => HasOne::Loaded(model),
133 None => HasOne::NotFound,
134 }
135 }
136}
137
138impl<E> PartialEq<Option<Box<E::ModelEx>>> for HasOne<E>
139where
140 E: EntityTrait,
141 E::ModelEx: PartialEq,
142{
143 fn eq(&self, other: &Option<Box<E::ModelEx>>) -> bool {
144 match (self, other) {
145 (HasOne::Loaded(a), Some(b)) => a.as_ref() == b.as_ref(),
146 (HasOne::Unloaded | HasOne::NotFound, None) => true,
147 _ => false,
148 }
149 }
150}
151
152impl<E> PartialEq<HasOne<E>> for Option<Box<E::ModelEx>>
153where
154 E: EntityTrait,
155 E::ModelEx: PartialEq,
156{
157 fn eq(&self, other: &HasOne<E>) -> bool {
158 other == self
159 }
160}
161
162impl<E> Hash for HasOne<E>
163where
164 E: EntityTrait,
165 E::ModelEx: Hash,
166{
167 fn hash<H: Hasher>(&self, state: &mut H) {
168 std::mem::discriminant(self).hash(state);
169 match self {
170 Self::Loaded(model) => model.hash(state),
171 Self::Unloaded => {}
172 Self::NotFound => {}
173 }
174 }
175}
176
177#[cfg(feature = "with-json")]
178impl<E> serde::Serialize for HasOne<E>
179where
180 E: EntityTrait,
181 E::ModelEx: serde::Serialize,
182{
183 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
184 where
185 S: serde::Serializer,
186 {
187 match self {
188 HasOne::Unloaded => None,
189 HasOne::NotFound => None,
190 HasOne::Loaded(model) => Some(model),
191 }
192 .serialize(serializer)
193 }
194}
195
196#[cfg(feature = "with-json")]
197impl<'de, E> serde::Deserialize<'de> for HasOne<E>
198where
199 E: EntityTrait,
200 E::ModelEx: serde::Deserialize<'de>,
201{
202 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
203 where
204 D: serde::Deserializer<'de>,
205 {
206 match <Option<E::ModelEx>>::deserialize(deserializer)? {
207 Some(model) => Ok(HasOne::Loaded(Box::new(model))),
208 None => Ok(HasOne::Unloaded),
209 }
210 }
211}