vertigo_forms/form/data/
form_export.rs

1use std::{collections::HashMap, rc::Rc};
2use vertigo::DropFileItem;
3
4use crate::{image_as_uri, nonify};
5
6pub enum FieldExport {
7    Bool(bool),
8    String(String),
9    List(String),
10    Dict(i64),
11    Multi(Vec<i64>),
12    Image((Option<Rc<String>>, Option<DropFileItem>)),
13}
14
15/// After form is submitted, it generates an export from every field. This can be used to construct a new model.
16#[derive(Clone)]
17pub struct FormExport(Rc<HashMap<String, FieldExport>>);
18
19impl FormExport {
20    pub fn new(map: HashMap<String, FieldExport>) -> Self {
21        Self(Rc::new(map))
22    }
23
24    pub fn get<'a>(&'a self, key: &str) -> Option<&'a FieldExport> {
25        self.0.get(key)
26    }
27
28    /// Get value from string input.
29    pub fn get_string(&self, key: &str) -> String {
30        self.get_string_opt(key).unwrap_or_default()
31    }
32
33    /// Get value from string input or None if empty.
34    pub fn get_string_opt(&self, key: &str) -> Option<String> {
35        self.get(key).and_then(|export| {
36            if let FieldExport::String(val) = export {
37                nonify(val.clone())
38            } else {
39                None
40            }
41        })
42    }
43
44    // Get optional value from list field (string-based).
45    pub fn list<T: From<String>>(&self, key: &str) -> Option<T> {
46        self.get(key).and_then(|export| {
47            if let FieldExport::List(val) = export {
48                nonify(val.clone()).map(Into::into)
49            } else {
50                None
51            }
52        })
53    }
54    // Get value from list field (string-based) or default.
55    pub fn list_or_default<T: Default + From<String>>(&self, key: &str) -> T {
56        self.list(key).unwrap_or_default()
57    }
58
59    // Get value from dict field (i64-based).
60    pub fn dict_or_default<T: From<i64>>(&self, key: &str) -> T {
61        self.get(key)
62            .map(|export| {
63                if let FieldExport::Dict(val) = export {
64                    *val
65                } else {
66                    Default::default()
67                }
68            })
69            .unwrap_or_default()
70            .into()
71    }
72
73    // Get values from multi field (i64-based).
74    pub fn multi<T: From<i64>>(&self, key: &str) -> Vec<T> {
75        self.get(key)
76            .map(|export| {
77                if let FieldExport::Multi(val) = export {
78                    val.iter().cloned().map(Into::into).collect()
79                } else {
80                    Default::default()
81                }
82            })
83            .unwrap_or_default()
84    }
85
86    /// Get value from bool input (i. e. checkbox) or false.
87    pub fn get_bool(&self, key: &str) -> bool {
88        self.get_bool_opt(key).unwrap_or_default()
89    }
90
91    /// Get value from bool input (i. e. checkbox) or None.
92    pub fn get_bool_opt(&self, key: &str) -> Option<bool> {
93        self.get(key).and_then(|export| {
94            if let FieldExport::Bool(val) = export {
95                Some(*val)
96            } else {
97                None
98            }
99        })
100    }
101
102    // Get new image (base64) or original value from image field.
103    pub fn image_url(&self, key: &str) -> String {
104        self.image_url_opt(key).unwrap_or_default()
105    }
106
107    // Get new image (base64) or original value from image field or none.
108    pub fn image_url_opt(&self, key: &str) -> Option<String> {
109        if let Some(export) = self.get(key) {
110            match export {
111                FieldExport::Image((orig_link, dfi)) => dfi
112                    .as_ref()
113                    .map(image_as_uri)
114                    .or_else(|| orig_link.as_ref().map(|ol| ol.to_string())),
115                _ => None,
116            }
117        } else {
118            None
119        }
120    }
121
122    // Get new image (base64)
123    pub fn image_item_opt(&self, key: &str) -> Option<DropFileItem> {
124        if let Some(export) = self.get(key) {
125            match export {
126                FieldExport::Image((_orig_link, dfi)) => dfi.clone(),
127                _ => None,
128            }
129        } else {
130            None
131        }
132    }
133
134    // Get original image url
135    pub fn image_orig_url_opt(&self, key: &str) -> Option<Rc<String>> {
136        if let Some(export) = self.get(key) {
137            match export {
138                FieldExport::Image((orig_link, _dfi)) => orig_link.clone(),
139                _ => None,
140            }
141        } else {
142            None
143        }
144    }
145}