reinhardt_forms/fields/
integer_field.rs1use crate::field::{FieldError, FieldResult, FormField, Widget};
4
5#[derive(Debug, Clone)]
7pub struct IntegerField {
8 pub name: String,
10 pub label: Option<String>,
12 pub required: bool,
14 pub help_text: Option<String>,
16 pub widget: Widget,
18 pub initial: Option<serde_json::Value>,
20 pub max_value: Option<i64>,
22 pub min_value: Option<i64>,
24}
25
26impl IntegerField {
27 pub fn new(name: String) -> Self {
40 Self {
41 name,
42 label: None,
43 required: false,
44 help_text: None,
45 widget: Widget::NumberInput,
46 initial: None,
47 max_value: None,
48 min_value: None,
49 }
50 }
51 pub fn required(mut self) -> Self {
62 self.required = true;
63 self
64 }
65 pub fn with_min_value(mut self, min_value: i64) -> Self {
76 self.min_value = Some(min_value);
77 self
78 }
79 pub fn with_max_value(mut self, max_value: i64) -> Self {
90 self.max_value = Some(max_value);
91 self
92 }
93
94 pub fn with_label(mut self, label: impl Into<String>) -> Self {
105 self.label = Some(label.into());
106 self
107 }
108
109 pub fn with_help_text(mut self, help_text: impl Into<String>) -> Self {
120 self.help_text = Some(help_text.into());
121 self
122 }
123
124 pub fn with_initial(mut self, initial: i64) -> Self {
135 self.initial = Some(serde_json::json!(initial));
136 self
137 }
138}
139
140impl FormField for IntegerField {
143 fn name(&self) -> &str {
144 &self.name
145 }
146
147 fn label(&self) -> Option<&str> {
148 self.label.as_deref()
149 }
150
151 fn required(&self) -> bool {
152 self.required
153 }
154
155 fn help_text(&self) -> Option<&str> {
156 self.help_text.as_deref()
157 }
158
159 fn widget(&self) -> &Widget {
160 &self.widget
161 }
162
163 fn initial(&self) -> Option<&serde_json::Value> {
164 self.initial.as_ref()
165 }
166
167 fn clean(&self, value: Option<&serde_json::Value>) -> FieldResult<serde_json::Value> {
168 match value {
169 None if self.required => Err(FieldError::Required(self.name.clone())),
170 None => Ok(serde_json::Value::Null),
171 Some(v) => {
172 let num = if let Some(n) = v.as_i64() {
174 n
175 } else if let Some(s) = v.as_str() {
176 let s = s.trim();
178
179 if s.is_empty() {
181 if self.required {
182 return Err(FieldError::Required(self.name.clone()));
183 }
184 return Ok(serde_json::Value::Null);
185 }
186
187 s.parse::<i64>()
189 .map_err(|_| FieldError::Validation("Enter a whole number".to_string()))?
190 } else {
191 return Err(FieldError::Validation(
192 "Expected integer or string".to_string(),
193 ));
194 };
195
196 if let Some(max) = self.max_value
198 && num > max
199 {
200 return Err(FieldError::Validation(format!(
201 "Ensure this value is less than or equal to {}",
202 max
203 )));
204 }
205
206 if let Some(min) = self.min_value
207 && num < min
208 {
209 return Err(FieldError::Validation(format!(
210 "Ensure this value is greater than or equal to {}",
211 min
212 )));
213 }
214
215 Ok(serde_json::Value::Number(num.into()))
216 }
217 }
218 }
219}