1use indexmap::IndexMap;
10use serde::{Deserialize, Serialize};
11
12#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct FormData {
15 pub fields: IndexMap<String, FieldValue>,
17}
18
19#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
21#[serde(untagged)]
22pub enum FieldValue {
23 Number(f64),
25 Boolean(bool),
27 Text(String),
29 Null,
31 Array(Vec<IndexMap<String, FieldValue>>),
33}
34
35#[derive(Debug, Clone, Serialize, Deserialize)]
37pub struct FormSchema {
38 pub fields: IndexMap<String, FieldSchema>,
40}
41
42#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
44#[serde(rename_all = "lowercase")]
45pub enum FieldType {
46 Text,
48 Numeric,
50 Boolean,
52 Static,
54}
55
56#[derive(Debug, Clone, Serialize, Deserialize)]
58pub struct FieldSchema {
59 pub som_path: String,
61 pub field_type: FieldType,
63 pub required: bool,
65 pub repeatable: bool,
67 pub max_occurrences: Option<u32>,
69 #[serde(skip_serializing_if = "Option::is_none")]
71 pub calculate: Option<String>,
72 #[serde(skip_serializing_if = "Option::is_none")]
74 pub validate: Option<String>,
75}
76
77#[cfg(test)]
78mod tests {
79 use super::*;
80
81 #[test]
82 fn field_value_json_roundtrip() {
83 let val = FieldValue::Number(42.5);
84 let json = serde_json::to_string(&val).unwrap();
85 assert_eq!(json, "42.5");
86
87 let val = FieldValue::Boolean(true);
88 let json = serde_json::to_string(&val).unwrap();
89 assert_eq!(json, "true");
90
91 let val = FieldValue::Text("hello".to_string());
92 let json = serde_json::to_string(&val).unwrap();
93 assert_eq!(json, "\"hello\"");
94
95 let val = FieldValue::Null;
96 let json = serde_json::to_string(&val).unwrap();
97 assert_eq!(json, "null");
98 }
99
100 #[test]
101 fn form_data_json_roundtrip() {
102 let mut fields = IndexMap::new();
103 fields.insert("name".to_string(), FieldValue::Text("Acme".to_string()));
104 fields.insert("amount".to_string(), FieldValue::Number(100.0));
105 let data = FormData { fields };
106
107 let json = serde_json::to_string_pretty(&data).unwrap();
108 let parsed: FormData = serde_json::from_str(&json).unwrap();
109 assert_eq!(parsed.fields.len(), 2);
110 }
111
112 #[test]
113 fn field_schema_omits_none_scripts() {
114 let schema = FieldSchema {
115 som_path: "form1.Name".to_string(),
116 field_type: FieldType::Text,
117 required: true,
118 repeatable: false,
119 max_occurrences: Some(1),
120 calculate: None,
121 validate: None,
122 };
123 let json = serde_json::to_string(&schema).unwrap();
124 assert!(!json.contains("calculate"));
125 assert!(!json.contains("validate"));
126 }
127}