sw4rm_rs/shared/
schema.rs

1use std::collections::HashMap;
2use serde::{Deserialize, Serialize};
3use serde_json::Value;
4
5use crate::{
6    Spec,
7    reference::*,
8    shared::{
9        ExternalDocumentation,
10        StringOrDiscriminator,
11        XML,
12    },
13};
14
15/// Schema Object
16///
17/// The Schema Object allows the definition of input and output data types. These types can be
18/// objects, but also primitives and arrays. This object is an extended subset of the JSON Schema
19/// Specification Wright Draft 00.
20///
21/// For more information about the properties, see JSON Schema Core and JSON Schema Validation.
22/// Unless stated otherwise, the property definitions follow the JSON Schema.
23#[derive(Debug, Serialize, Deserialize, Default, Clone, PartialEq)]
24#[serde(default, rename_all = "camelCase")]
25pub struct Schema {
26    // MARK: Common Fields
27
28    #[serde(skip_serializing_if = "Option::is_none")]
29    pub format: Option<String>,
30    #[serde(skip_serializing_if = "Option::is_none")]
31    pub title: Option<String>,
32    #[serde(skip_serializing_if = "Option::is_none")]
33    pub description: Option<String>,
34    #[serde(skip_serializing_if = "Option::is_none")]
35    pub default: Option<Value>,
36    #[serde(skip_serializing_if = "Option::is_none")]
37    pub multiple_of: Option<u64>,
38    #[serde(skip_serializing_if = "Option::is_none")]
39    pub maximum: Option<i64>,
40    #[serde(skip_serializing_if = "Option::is_none")]
41    pub exclusive_maximum: Option<i64>,
42    #[serde(skip_serializing_if = "Option::is_none")]
43    pub minimum: Option<i64>,
44    #[serde(skip_serializing_if = "Option::is_none")]
45    pub exclusive_minimum: Option<i64>,
46    #[serde(skip_serializing_if = "Option::is_none")]
47    pub max_length: Option<u64>,
48    #[serde(skip_serializing_if = "Option::is_none")]
49    pub min_length: Option<u64>,
50    #[serde(skip_serializing_if = "Option::is_none")]
51    pub pattern: Option<String>,
52    #[serde(skip_serializing_if = "Option::is_none")]
53    pub max_items: Option<u64>,
54    #[serde(skip_serializing_if = "Option::is_none")]
55    pub min_items: Option<u64>,
56    #[serde(skip_serializing_if = "Option::is_none")]
57    pub unique_items: Option<bool>,
58    #[serde(skip_serializing_if = "Option::is_none")]
59    pub max_properties: Option<u64>,
60    #[serde(skip_serializing_if = "Option::is_none")]
61    pub min_properties: Option<u64>,
62    #[serde(skip_serializing_if = "Vec::is_empty")]
63    pub required: Vec<String>,
64    #[serde(rename = "enum", skip_serializing_if = "Vec::is_empty")]
65    pub enum_values: Vec<Value>,
66    #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
67    pub schema_type: Option<SchemaType>,
68    #[serde(skip_serializing_if = "Option::is_none")]
69    pub items: Option<RefOr<Box<Self>>>,
70    #[serde(skip_serializing_if = "Vec::is_empty")]
71    pub all_of: Vec<RefOr<Box<Self>>>,
72    #[serde(skip_serializing_if = "HashMap::is_empty")]
73    pub properties: HashMap<String, RefOr<Box<Self>>>,
74    #[serde(skip_serializing_if = "Option::is_none")]
75    pub additional_properties: Option<RefOr<Box<Self>>>,
76    #[serde(skip_serializing_if = "Option::is_none")]
77    pub discriminator: Option<StringOrDiscriminator>,
78    #[serde(skip_serializing_if = "Option::is_none")]
79    pub read_only: Option<bool>,
80    #[serde(skip_serializing_if = "Option::is_none")]
81    pub xml: Option<XML>,
82    #[serde(skip_serializing_if = "Option::is_none")]
83    pub external_docs: Option<ExternalDocumentation>,
84    #[serde(skip_serializing_if = "Option::is_none")]
85    pub example: Option<Value>,
86
87    /// Allows extensions to the Swagger Schema. The field name MUST begin with x-, for example,
88    /// x-internal-id. The value can be null, a primitive, an array or an object. See Vendor
89    /// Extensions for further details.
90    #[serde(flatten, skip_serializing_if = "HashMap::is_empty")]
91    pub x_fields: HashMap<String, Value>,
92
93    // MARK: OpenAPI v3 Fields
94
95    #[serde(skip_serializing_if = "Vec::is_empty")]
96    pub one_of: Vec<RefOr<Box<Self>>>,
97    #[serde(skip_serializing_if = "Vec::is_empty")]
98    pub any_of: Vec<RefOr<Box<Self>>>,
99    #[serde(skip_serializing_if = "Option::is_none")]
100    pub not: Option<RefOr<Box<Self>>>,
101    #[serde(skip_serializing_if = "Option::is_none")]
102    pub nullable: Option<bool>,
103    #[serde(skip_serializing_if = "Option::is_none")]
104    pub write_only: Option<bool>,
105    #[serde(skip_serializing_if = "Option::is_none")]
106    pub deprecated: Option<bool>,
107}
108
109impl Resolvable for Schema {
110    fn resolve(spec: &Spec, path: &String) -> Result<Self, ResolveError> {
111        let path = path.clone();
112        let reference: Reference = path.clone().try_into().unwrap();
113
114        match reference.kind {
115            ReferenceType::Schema | ReferenceType::Definitions => {
116                if spec.semver_check("=2") {
117                    spec.definitions.get(&reference.name)
118                        .ok_or_else(|| ResolveError::UnknownPathError(path))
119                        .and_then(|t| t.resolve(spec))
120                } else {
121                    spec.components
122                        .as_ref()
123                        .ok_or_else(|| ResolveError::UnknownPathError(path.clone()))
124                        .and_then(|c| c.schemas.get(&reference.name).ok_or_else(|| ResolveError::UnknownPathError(path)))
125                        .and_then(|p| p.resolve(spec))
126                }
127            },
128            _ => Err(ResolveError::UnknownPathError(path)),
129        }
130    }
131}
132
133#[derive(Debug, Serialize, Deserialize, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
134#[serde(rename_all = "camelCase")]
135pub enum SchemaType {
136    Array,
137    Boolean,
138    File,
139    Integer,
140    Number,
141    Object,
142    String,
143}
144impl Default for SchemaType {
145    fn default() -> Self { Self::Object }
146}