reinhardt_forms/
formset.rs1use crate::form::Form;
2use std::collections::HashMap;
3
4pub struct FormSet {
6 forms: Vec<Form>,
7 prefix: String,
8 can_delete: bool,
9 can_order: bool,
10 extra: usize,
11 max_num: Option<usize>,
12 min_num: usize,
13 errors: Vec<String>,
14}
15
16impl FormSet {
17 pub fn new(prefix: String) -> Self {
29 Self {
30 forms: vec![],
31 prefix,
32 can_delete: false,
33 can_order: false,
34 extra: 1,
35 max_num: Some(1000),
36 min_num: 0,
37 errors: vec![],
38 }
39 }
40
41 pub fn prefix(&self) -> &str {
42 &self.prefix
43 }
44
45 pub fn can_delete(&self) -> bool {
46 self.can_delete
47 }
48 pub fn with_extra(mut self, extra: usize) -> Self {
49 self.extra = extra;
50 self
51 }
52 pub fn with_can_delete(mut self, can_delete: bool) -> Self {
53 self.can_delete = can_delete;
54 self
55 }
56 pub fn with_can_order(mut self, can_order: bool) -> Self {
57 self.can_order = can_order;
58 self
59 }
60 pub fn with_max_num(mut self, max_num: Option<usize>) -> Self {
61 self.max_num = max_num;
62 self
63 }
64 pub fn with_min_num(mut self, min_num: usize) -> Self {
65 self.min_num = min_num;
66 self
67 }
68 pub fn add_form(&mut self, form: Form) -> Result<(), String> {
91 if let Some(max) = self.max_num
92 && self.forms.len() >= max
93 {
94 return Err(format!(
95 "Cannot add form: maximum number of forms ({}) reached",
96 max
97 ));
98 }
99 self.forms.push(form);
100 Ok(())
101 }
102 pub fn forms(&self) -> &[Form] {
103 &self.forms
104 }
105 pub fn forms_mut(&mut self) -> &mut Vec<Form> {
106 &mut self.forms
107 }
108 pub fn form_count(&self) -> usize {
109 self.forms.len()
110 }
111 pub fn total_form_count(&self) -> usize {
112 self.forms.len() + self.extra
113 }
114 pub fn is_valid(&mut self) -> bool {
127 self.errors.clear();
128
129 let mut all_valid = true;
131 for form in &mut self.forms {
132 if !form.is_valid() {
133 all_valid = false;
134 }
135 }
136
137 if self.forms.len() < self.min_num {
139 self.errors
140 .push(format!("Please submit at least {} forms", self.min_num));
141 all_valid = false;
142 }
143
144 if let Some(max) = self.max_num
146 && self.forms.len() > max
147 {
148 self.errors
149 .push(format!("Please submit no more than {} forms", max));
150 all_valid = false;
151 }
152
153 all_valid && self.errors.is_empty()
154 }
155 pub fn errors(&self) -> &[String] {
156 &self.errors
157 }
158 pub fn cleaned_data(&self) -> Vec<&HashMap<String, serde_json::Value>> {
159 self.forms.iter().map(|f| f.cleaned_data()).collect()
160 }
161 pub fn management_form_data(&self) -> HashMap<String, String> {
173 let mut data = HashMap::new();
174 data.insert(
175 format!("{}-TOTAL_FORMS", self.prefix),
176 self.total_form_count().to_string(),
177 );
178 data.insert(
179 format!("{}-INITIAL_FORMS", self.prefix),
180 self.forms.len().to_string(),
181 );
182 data.insert(
183 format!("{}-MIN_NUM_FORMS", self.prefix),
184 self.min_num.to_string(),
185 );
186 if let Some(max) = self.max_num {
187 data.insert(format!("{}-MAX_NUM_FORMS", self.prefix), max.to_string());
188 }
189 data
190 }
191 pub fn process_data(&mut self, data: &HashMap<String, HashMap<String, serde_json::Value>>) {
212 self.forms.clear();
213
214 for (key, form_data) in data {
216 if key.starts_with(&self.prefix) {
217 if let Some(max) = self.max_num
219 && self.forms.len() >= max
220 {
221 break;
222 }
223 let mut form = Form::new();
224 form.bind(form_data.clone());
225 self.forms.push(form);
226 }
227 }
228 }
229}
230
231impl Default for FormSet {
232 fn default() -> Self {
233 Self::new("form".to_string())
234 }
235}
236
237#[cfg(test)]
238mod tests {
239 use super::*;
240 use crate::fields::CharField;
241
242 #[test]
243 fn test_formset_basic() {
244 let mut formset = FormSet::new("person".to_string());
245
246 let mut form1 = Form::new();
247 form1.add_field(Box::new(CharField::new("name".to_string())));
248
249 let mut form2 = Form::new();
250 form2.add_field(Box::new(CharField::new("name".to_string())));
251
252 formset.add_form(form1).unwrap();
253 formset.add_form(form2).unwrap();
254
255 assert_eq!(formset.form_count(), 2);
256 }
257
258 #[test]
259 fn test_formset_min_num_validation() {
260 let mut formset = FormSet::new("person".to_string()).with_min_num(2);
261
262 let mut form1 = Form::new();
263 form1.add_field(Box::new(CharField::new("name".to_string())));
264 formset.add_form(form1).unwrap();
265
266 assert!(!formset.is_valid());
267 assert!(!formset.errors().is_empty());
268 }
269
270 #[test]
271 fn test_formset_max_num_enforced_on_add() {
272 let mut formset = FormSet::new("person".to_string()).with_max_num(Some(2));
273
274 let mut form1 = Form::new();
275 form1.add_field(Box::new(CharField::new("name".to_string())));
276 assert!(formset.add_form(form1).is_ok());
277
278 let mut form2 = Form::new();
279 form2.add_field(Box::new(CharField::new("name".to_string())));
280 assert!(formset.add_form(form2).is_ok());
281
282 let mut form3 = Form::new();
284 form3.add_field(Box::new(CharField::new("name".to_string())));
285 assert!(formset.add_form(form3).is_err());
286
287 assert_eq!(formset.form_count(), 2);
288 }
289
290 #[test]
291 fn test_forms_formset_management_data() {
292 let formset = FormSet::new("person".to_string())
293 .with_extra(3)
294 .with_min_num(1)
295 .with_max_num(Some(10));
296
297 let mgmt_data = formset.management_form_data();
298
299 assert_eq!(mgmt_data.get("person-TOTAL_FORMS"), Some(&"3".to_string()));
300 assert_eq!(
301 mgmt_data.get("person-INITIAL_FORMS"),
302 Some(&"0".to_string())
303 );
304 assert_eq!(
305 mgmt_data.get("person-MIN_NUM_FORMS"),
306 Some(&"1".to_string())
307 );
308 assert_eq!(
309 mgmt_data.get("person-MAX_NUM_FORMS"),
310 Some(&"10".to_string())
311 );
312 }
313}