unistructgen_openapi_parser/
validation.rs1use openapiv3::{Schema, SchemaKind, Type};
4use unistructgen_core::FieldConstraints;
5
6pub fn extract_validation_constraints(schema: &Schema) -> FieldConstraints {
8 let mut constraints = FieldConstraints::default();
9
10 match &schema.schema_kind {
11 SchemaKind::Type(Type::String(string_type)) => {
12 if let Some(min_len) = string_type.min_length {
14 constraints.min_length = Some(min_len);
15 }
16 if let Some(max_len) = string_type.max_length {
17 constraints.max_length = Some(max_len);
18 }
19
20 if let Some(pattern) = &string_type.pattern {
22 constraints.pattern = Some(pattern.clone());
23 }
24
25 constraints.format = Some(format!("{:?}", string_type.format));
27 }
28
29 SchemaKind::Type(Type::Number(number_type)) => {
30 if let Some(min) = number_type.minimum {
32 constraints.min_value = Some(min);
33 }
34 if let Some(max) = number_type.maximum {
35 constraints.max_value = Some(max);
36 }
37 }
38
39 SchemaKind::Type(Type::Integer(int_type)) => {
40 if let Some(min) = int_type.minimum {
42 constraints.min_value = Some(min as f64);
43 }
44 if let Some(max) = int_type.maximum {
45 constraints.max_value = Some(max as f64);
46 }
47 }
48
49 SchemaKind::Type(Type::Array(array_type)) => {
50 if let Some(min_items) = array_type.min_items {
52 constraints.min_length = Some(min_items);
53 }
54 if let Some(max_items) = array_type.max_items {
55 constraints.max_length = Some(max_items);
56 }
57 }
58
59 _ => {}
60 }
61
62 constraints
63}
64
65pub fn generate_validator_attribute(constraints: &FieldConstraints) -> Option<String> {
67 let mut attrs = Vec::new();
68
69 if constraints.min_length.is_some() || constraints.max_length.is_some() {
71 let mut length_parts = Vec::new();
72 if let Some(min) = constraints.min_length {
73 length_parts.push(format!("min = {}", min));
74 }
75 if let Some(max) = constraints.max_length {
76 length_parts.push(format!("max = {}", max));
77 }
78 attrs.push(format!("length({})", length_parts.join(", ")));
79 }
80
81 if constraints.min_value.is_some() || constraints.max_value.is_some() {
83 let mut range_parts = Vec::new();
84 if let Some(min) = constraints.min_value {
85 range_parts.push(format!("min = {}", min));
86 }
87 if let Some(max) = constraints.max_value {
88 range_parts.push(format!("max = {}", max));
89 }
90 attrs.push(format!("range({})", range_parts.join(", ")));
91 }
92
93 if let Some(format) = &constraints.format {
95 match format.as_str() {
96 "email" => attrs.push("email".to_string()),
97 "url" | "uri" => attrs.push("url".to_string()),
98 _ => {}
99 }
100 }
101
102 if let Some(pattern) = &constraints.pattern {
104 attrs.push(format!("regex = \"{}\"", pattern));
105 }
106
107 if attrs.is_empty() {
108 None
109 } else {
110 Some(format!("#[validate({})]", attrs.join(", ")))
111 }
112}
113
114#[cfg(test)]
115mod tests {
116 use super::*;
117
118 #[test]
119 fn test_generate_validator_attribute() {
120 let mut constraints = FieldConstraints::default();
121 constraints.min_length = Some(5);
122 constraints.max_length = Some(50);
123
124 let attr = generate_validator_attribute(&constraints);
125 assert_eq!(attr, Some("#[validate(length(min = 5, max = 50))]".to_string()));
126 }
127
128 #[test]
129 fn test_generate_validator_attribute_email() {
130 let mut constraints = FieldConstraints::default();
131 constraints.format = Some("email".to_string());
132
133 let attr = generate_validator_attribute(&constraints);
134 assert_eq!(attr, Some("#[validate(email)]".to_string()));
135 }
136
137 #[test]
138 fn test_generate_validator_attribute_range() {
139 let mut constraints = FieldConstraints::default();
140 constraints.min_value = Some(0.0);
141 constraints.max_value = Some(150.0);
142
143 let attr = generate_validator_attribute(&constraints);
144 assert_eq!(attr, Some("#[validate(range(min = 0, max = 150))]".to_string()));
145 }
146}