salvo_oapi/openapi/schema/
one_of.rs1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3
4use crate::{Discriminator, PropMap, RefOr, Schema, SchemaType};
5
6#[non_exhaustive]
13#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
14pub struct OneOf {
15 #[serde(rename = "oneOf")]
17 pub items: Vec<RefOr<Schema>>,
18
19 #[serde(
24 rename = "type",
25 default = "SchemaType::any",
26 skip_serializing_if = "SchemaType::is_any_value"
27 )]
28 pub schema_type: SchemaType,
29
30 #[serde(skip_serializing_if = "Option::is_none")]
32 pub title: Option<String>,
33
34 #[serde(skip_serializing_if = "Option::is_none")]
36 pub description: Option<String>,
37
38 #[serde(rename = "default", skip_serializing_if = "Option::is_none")]
40 pub default_value: Option<Value>,
41
42 #[serde(skip_serializing_if = "Vec::is_empty", default)]
44 pub examples: Vec<Value>,
45
46 #[serde(skip_serializing_if = "Option::is_none")]
49 pub discriminator: Option<Discriminator>,
50
51 #[serde(skip_serializing_if = "PropMap::is_empty", flatten)]
53 pub extensions: PropMap<String, serde_json::Value>,
54}
55
56impl Default for OneOf {
57 fn default() -> Self {
58 Self {
59 items: Default::default(),
60 schema_type: SchemaType::AnyValue,
61 title: Default::default(),
62 description: Default::default(),
63 default_value: Default::default(),
64 examples: Default::default(),
65 discriminator: Default::default(),
66 extensions: Default::default(),
67 }
68 }
69}
70
71impl OneOf {
72 pub fn new() -> Self {
74 Default::default()
75 }
76
77 pub fn with_capacity(capacity: usize) -> Self {
90 Self {
91 items: Vec::with_capacity(capacity),
92 ..Default::default()
93 }
94 }
95 pub fn item<I: Into<RefOr<Schema>>>(mut self, component: I) -> Self {
99 self.items.push(component.into());
100
101 self
102 }
103
104 pub fn schema_type<T: Into<SchemaType>>(mut self, schema_type: T) -> Self {
107 self.schema_type = schema_type.into();
108 self
109 }
110
111 pub fn title(mut self, title: impl Into<String>) -> Self {
113 self.title = Some(title.into());
114 self
115 }
116
117 pub fn description(mut self, description: impl Into<String>) -> Self {
119 self.description = Some(description.into());
120 self
121 }
122
123 pub fn default_value(mut self, default: Value) -> Self {
125 self.default_value = Some(default);
126 self
127 }
128
129 pub fn add_example<V: Into<Value>>(mut self, example: V) -> Self {
131 self.examples.push(example.into());
132 self
133 }
134
135 pub fn discriminator(mut self, discriminator: Discriminator) -> Self {
137 self.discriminator = Some(discriminator);
138 self
139 }
140
141 pub fn add_extension<K: Into<String>>(mut self, key: K, value: serde_json::Value) -> Self {
143 self.extensions.insert(key.into(), value);
144 self
145 }
146}
147
148impl From<OneOf> for Schema {
149 fn from(one_of: OneOf) -> Self {
150 Self::OneOf(one_of)
151 }
152}
153
154impl From<OneOf> for RefOr<Schema> {
155 fn from(one_of: OneOf) -> Self {
156 Self::Type(Schema::OneOf(one_of))
157 }
158}
159
160#[cfg(test)]
161mod tests {
162 use assert_json_diff::assert_json_eq;
163 use serde_json::json;
164
165 use super::*;
166
167 #[test]
168 fn test_build_one_of() {
169 let one_of = OneOf::with_capacity(5)
170 .title("title")
171 .description("description")
172 .default_value(Value::String("default".to_string()))
173 .add_example(Value::String("example1".to_string()))
174 .add_example(Value::String("example2".to_string()))
175 .discriminator(Discriminator::new("discriminator".to_string()));
176
177 assert_eq!(one_of.items.len(), 0);
178 assert_eq!(one_of.items.capacity(), 5);
179 assert_json_eq!(
180 one_of,
181 json!({
182 "oneOf": [],
183 "title": "title",
184 "description": "description",
185 "default": "default",
186 "examples": ["example1", "example2"],
187 "discriminator": {
188 "propertyName": "discriminator"
189 }
190 })
191 )
192 }
193
194 #[test]
195 fn test_schema_from_one_of() {
196 let one_of = OneOf::new();
197 let schema = Schema::from(one_of);
198 assert_json_eq!(
199 schema,
200 json!({
201 "oneOf": []
202 })
203 )
204 }
205
206 #[test]
207 fn test_refor_schema_from_one_of() {
208 let one_of = OneOf::new();
209 let ref_or: RefOr<Schema> = RefOr::from(one_of);
210 assert_json_eq!(
211 ref_or,
212 json!({
213 "oneOf": []
214 })
215 )
216 }
217
218 #[test]
219 fn test_oneof_with_extensions() {
220 let expected = json!("value");
221 let json_value = OneOf::new().add_extension("x-some-extension", expected.clone());
222
223 let value = serde_json::to_value(&json_value).unwrap();
224 assert_eq!(value.get("x-some-extension"), Some(&expected));
225 }
226}