reinhardt_forms/fields/
integer_field.rs1use crate::field::{FieldError, FieldResult, FormField, Widget};
4
5#[derive(Debug, Clone)]
7pub struct IntegerField {
8 pub name: String,
9 pub label: Option<String>,
10 pub required: bool,
11 pub help_text: Option<String>,
12 pub widget: Widget,
13 pub initial: Option<serde_json::Value>,
14 pub max_value: Option<i64>,
15 pub min_value: Option<i64>,
16}
17
18impl IntegerField {
19 pub fn new(name: String) -> Self {
32 Self {
33 name,
34 label: None,
35 required: false,
36 help_text: None,
37 widget: Widget::NumberInput,
38 initial: None,
39 max_value: None,
40 min_value: None,
41 }
42 }
43 pub fn required(mut self) -> Self {
54 self.required = true;
55 self
56 }
57 pub fn with_min_value(mut self, min_value: i64) -> Self {
68 self.min_value = Some(min_value);
69 self
70 }
71 pub fn with_max_value(mut self, max_value: i64) -> Self {
82 self.max_value = Some(max_value);
83 self
84 }
85
86 pub fn with_label(mut self, label: impl Into<String>) -> Self {
97 self.label = Some(label.into());
98 self
99 }
100
101 pub fn with_help_text(mut self, help_text: impl Into<String>) -> Self {
112 self.help_text = Some(help_text.into());
113 self
114 }
115
116 pub fn with_initial(mut self, initial: i64) -> Self {
127 self.initial = Some(serde_json::json!(initial));
128 self
129 }
130}
131
132impl FormField for IntegerField {
135 fn name(&self) -> &str {
136 &self.name
137 }
138
139 fn label(&self) -> Option<&str> {
140 self.label.as_deref()
141 }
142
143 fn required(&self) -> bool {
144 self.required
145 }
146
147 fn help_text(&self) -> Option<&str> {
148 self.help_text.as_deref()
149 }
150
151 fn widget(&self) -> &Widget {
152 &self.widget
153 }
154
155 fn initial(&self) -> Option<&serde_json::Value> {
156 self.initial.as_ref()
157 }
158
159 fn clean(&self, value: Option<&serde_json::Value>) -> FieldResult<serde_json::Value> {
160 match value {
161 None if self.required => Err(FieldError::Required(self.name.clone())),
162 None => Ok(serde_json::Value::Null),
163 Some(v) => {
164 let num = if let Some(n) = v.as_i64() {
166 n
167 } else if let Some(s) = v.as_str() {
168 let s = s.trim();
170
171 if s.is_empty() {
173 if self.required {
174 return Err(FieldError::Required(self.name.clone()));
175 }
176 return Ok(serde_json::Value::Null);
177 }
178
179 s.parse::<i64>()
181 .map_err(|_| FieldError::Validation("Enter a whole number".to_string()))?
182 } else {
183 return Err(FieldError::Validation(
184 "Expected integer or string".to_string(),
185 ));
186 };
187
188 if let Some(max) = self.max_value
190 && num > max
191 {
192 return Err(FieldError::Validation(format!(
193 "Ensure this value is less than or equal to {}",
194 max
195 )));
196 }
197
198 if let Some(min) = self.min_value
199 && num < min
200 {
201 return Err(FieldError::Validation(format!(
202 "Ensure this value is greater than or equal to {}",
203 min
204 )));
205 }
206
207 Ok(serde_json::Value::Number(num.into()))
208 }
209 }
210 }
211}