1use std::borrow::Cow;
73
74use poem_openapi::{
75 registry::MetaSchemaRef,
76 types::{ParseFromJSON, ParseResult, ToJSON, Type},
77};
78#[cfg(feature = "sea-orm")]
79use sea_orm::ActiveValue;
80
81#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
84pub enum PatchValue<T> {
85 Set(T),
87 #[default]
89 Unchanged,
90}
91
92impl<T> PatchValue<T> {
93 #[cfg(feature = "sea-orm")]
96 pub fn update(self, old: T) -> ActiveValue<T>
97 where
98 T: Into<sea_orm::Value>,
99 {
100 match self {
101 Self::Set(x) => ActiveValue::Set(x),
102 Self::Unchanged => ActiveValue::Unchanged(old),
103 }
104 }
105
106 pub fn get_new<'a>(&'a self, old: &'a T) -> &'a T {
109 match self {
110 Self::Set(x) => x,
111 Self::Unchanged => old,
112 }
113 }
114
115 pub fn map<U>(self, f: impl FnOnce(T) -> U) -> PatchValue<U> {
117 match self {
118 PatchValue::Set(x) => PatchValue::Set(f(x)),
119 PatchValue::Unchanged => PatchValue::Unchanged,
120 }
121 }
122}
123
124impl<T> ParseFromJSON for PatchValue<T>
125where
126 T: ParseFromJSON,
127{
128 fn parse_from_json(
129 value: Option<poem_openapi::__private::serde_json::Value>,
130 ) -> ParseResult<Self> {
131 match Option::<T>::parse_from_json(value) {
132 Ok(Some(x)) => Ok(Self::Set(x)),
133 Ok(None) => Ok(Self::Unchanged),
134 Err(x) => Err(x.propagate()),
135 }
136 }
137}
138
139impl<T> ToJSON for PatchValue<T>
140where
141 T: ToJSON,
142{
143 fn to_json(&self) -> Option<poem_openapi::__private::serde_json::Value> {
144 match self {
145 Self::Set(x) => Some(x),
146 Self::Unchanged => None,
147 }
148 .to_json()
149 }
150}
151
152impl<T> Type for PatchValue<T>
153where
154 T: Type,
155{
156 const IS_REQUIRED: bool = false; type RawValueType = T::RawValueType;
159
160 type RawElementValueType = T::RawElementValueType;
161
162 fn name() -> Cow<'static, str> {
163 format!("optional<{}>", T::name()).into()
164 }
165
166 fn schema_ref() -> MetaSchemaRef {
167 T::schema_ref()
168 }
169
170 fn as_raw_value(&self) -> Option<&Self::RawValueType> {
171 match self {
172 Self::Set(value) => value.as_raw_value(),
173 Self::Unchanged => None,
174 }
175 }
176
177 fn raw_element_iter<'a>(
178 &'a self,
179 ) -> Box<dyn Iterator<Item = &'a Self::RawElementValueType> + 'a> {
180 match self {
181 Self::Set(value) => value.raw_element_iter(),
182 Self::Unchanged => Box::new(std::iter::empty()),
183 }
184 }
185}
186
187#[cfg(feature = "serde")]
188impl<T> serde::Serialize for PatchValue<T>
189where
190 T: serde::Serialize,
191{
192 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
193 where
194 S: serde::Serializer,
195 {
196 match self {
197 PatchValue::Set(x) => Some(x),
198 PatchValue::Unchanged => None,
199 }
200 .serialize(serializer)
201 }
202}
203
204#[cfg(feature = "serde")]
205impl<'de, T> serde::Deserialize<'de> for PatchValue<T>
206where
207 T: serde::Deserialize<'de>,
208{
209 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
210 where
211 D: serde::Deserializer<'de>,
212 {
213 match Option::<T>::deserialize(deserializer) {
214 Ok(Some(x)) => Ok(Self::Set(x)),
215 Ok(None) => Ok(Self::Unchanged),
216 Err(err) => Err(err),
217 }
218 }
219}
220
221#[cfg(test)]
222mod tests {
223 use serde::{Deserialize, Serialize};
224
225 use super::{PatchValue::*, *};
226
227 #[test]
228 fn serialize() {
229 assert_eq!(
230 serde_json::to_string(&Test { value: Unchanged }).unwrap(),
231 r#"{"value":null}"#
232 );
233 assert_eq!(
234 serde_json::to_string(&Test { value: Set(42) }).unwrap(),
235 r#"{"value":42}"#
236 );
237 }
238
239 #[test]
240 fn deserialize() {
241 assert_eq!(
242 serde_json::from_str::<Test>(r#"{}"#).unwrap(),
243 Test { value: Unchanged }
244 );
245 assert_eq!(
246 serde_json::from_str::<Test>(r#"{"value":null}"#).unwrap(),
247 Test { value: Unchanged }
248 );
249 assert_eq!(
250 serde_json::from_str::<Test>(r#"{"value":42}"#).unwrap(),
251 Test { value: Set(42) }
252 );
253 }
254
255 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
256 struct Test {
257 value: PatchValue<i32>,
258 }
259}