1use std::fmt;
2use std::sync::Arc;
3
4impl fmt::Debug for dyn crate::validator::Validator {
5 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
6 write!(f, "Validator")
7 }
8}
9
10impl fmt::Debug for dyn crate::validator::AsyncValidator {
11 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
12 write!(f, "AsyncValidator")
13 }
14}
15
16pub trait Widget: Send + Sync {
18 fn render_input(&self, name: &str, value: Option<&str>) -> String;
20 fn render_display(&self, value: Option<&str>) -> String;
22}
23
24impl fmt::Debug for dyn Widget {
25 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26 write!(f, "Widget")
27 }
28}
29
30pub enum FieldType {
31 Text,
32 TextArea,
33 Email,
34 Password,
35 Number,
36 Float,
37 Boolean,
38 Date,
39 DateTime,
40 Select(Vec<(String, String)>),
41 ForeignKey {
42 adapter: Box<dyn crate::adapter::DataAdapter>,
43 value_field: String,
44 label_field: String,
45 limit: Option<u64>,
46 order_by: Option<String>,
47 },
48 ManyToMany {
49 adapter: Box<dyn crate::adapter::ManyToManyAdapter>,
50 },
51 File {
52 storage: Arc<dyn crate::storage::FileStorage>,
53 accept: Vec<String>, },
55 Image {
56 storage: Arc<dyn crate::storage::FileStorage>,
57 },
59 Json,
60 Custom(Box<dyn Widget>),
61}
62
63impl std::fmt::Debug for FieldType {
64 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
65 match self {
66 FieldType::Text => write!(f, "Text"),
67 FieldType::TextArea => write!(f, "TextArea"),
68 FieldType::Email => write!(f, "Email"),
69 FieldType::Password => write!(f, "Password"),
70 FieldType::Number => write!(f, "Number"),
71 FieldType::Float => write!(f, "Float"),
72 FieldType::Boolean => write!(f, "Boolean"),
73 FieldType::Date => write!(f, "Date"),
74 FieldType::DateTime => write!(f, "DateTime"),
75 FieldType::Select(opts) => write!(f, "Select({} options)", opts.len()),
76 FieldType::ForeignKey { value_field, label_field, limit, order_by, .. } => {
77 write!(f, "ForeignKey {{ value_field: {value_field:?}, label_field: {label_field:?}, limit: {limit:?}, order_by: {order_by:?} }}")
78 }
79 FieldType::ManyToMany { .. } => write!(f, "ManyToMany(..)"),
80 FieldType::File { accept, .. } => write!(f, "File(accept: {:?})", accept),
81 FieldType::Image { .. } => write!(f, "Image"),
82 FieldType::Json => write!(f, "Json"),
83 FieldType::Custom(_) => write!(f, "Custom(..)"),
84 }
85 }
86}
87
88#[derive(Debug)]
89pub struct Field {
90 pub name: String,
91 pub label: String,
92 pub field_type: FieldType,
93 pub readonly: bool,
94 pub hidden: bool,
95 pub list_only: bool,
96 pub form_only: bool,
97 pub required: bool,
98 pub help_text: Option<String>,
99 pub validators: Vec<Box<dyn crate::validator::Validator>>,
100 pub async_validators: Vec<Box<dyn crate::validator::AsyncValidator>>,
101}
102
103pub(crate) fn default_label(name: &str) -> String {
105 let mut chars = name.replace('_', " ").chars().collect::<Vec<_>>();
106 if let Some(c) = chars.first_mut() {
107 *c = c.to_uppercase().next().unwrap_or(*c);
108 }
109 chars.into_iter().collect()
110}
111
112impl Field {
113 pub(crate) fn new(name: &str, field_type: FieldType) -> Self {
114 Self {
115 label: default_label(name),
116 name: name.to_string(),
117 field_type,
118 readonly: false,
119 hidden: false,
120 list_only: false,
121 form_only: false,
122 required: false,
123 help_text: None,
124 validators: Vec::new(),
125 async_validators: Vec::new(),
126 }
127 }
128
129 pub fn text(name: &str) -> Self { Self::new(name, FieldType::Text) }
130 pub fn textarea(name: &str) -> Self { Self::new(name, FieldType::TextArea) }
131 pub fn email(name: &str) -> Self {
132 let mut f = Self::new(name, FieldType::Email);
133 f.validators.push(Box::new(crate::validator::EmailFormat));
134 f
135 }
136 pub fn password(name: &str) -> Self { Self::new(name, FieldType::Password) }
137 pub fn number(name: &str) -> Self { Self::new(name, FieldType::Number) }
138 pub fn float(name: &str) -> Self { Self::new(name, FieldType::Float) }
139 pub fn boolean(name: &str) -> Self { Self::new(name, FieldType::Boolean) }
140 pub fn date(name: &str) -> Self { Self::new(name, FieldType::Date) }
141 pub fn datetime(name: &str) -> Self { Self::new(name, FieldType::DateTime) }
142 pub fn json(name: &str) -> Self { Self::new(name, FieldType::Json) }
143
144 pub fn select(name: &str, options: Vec<(String, String)>) -> Self {
145 Self::new(name, FieldType::Select(options))
146 }
147
148 pub fn foreign_key(
149 name: &str,
150 label: &str,
151 adapter: Box<dyn crate::adapter::DataAdapter>,
152 value_field: &str,
153 label_field: &str,
154 ) -> Self {
155 let mut f = Self::new(name, FieldType::ForeignKey {
156 adapter,
157 value_field: value_field.to_string(),
158 label_field: label_field.to_string(),
159 limit: None,
160 order_by: None,
161 });
162 f.label = label.to_string();
163 f
164 }
165
166 pub fn custom(name: &str, widget: Box<dyn Widget>) -> Self {
167 Self::new(name, FieldType::Custom(widget))
168 }
169
170 pub fn many_to_many(name: &str, adapter: Box<dyn crate::adapter::ManyToManyAdapter>) -> Self {
171 Self::new(name, FieldType::ManyToMany { adapter })
172 }
173
174 pub fn file(name: &str, storage: Arc<dyn crate::storage::FileStorage>) -> Self {
175 Self::new(name, FieldType::File { storage, accept: vec![] })
176 }
177
178 pub fn image(name: &str, storage: Arc<dyn crate::storage::FileStorage>) -> Self {
179 Self::new(name, FieldType::Image { storage })
180 }
181
182 pub fn accept(mut self, types: Vec<String>) -> Self {
185 if let FieldType::File { ref mut accept, .. } = self.field_type {
186 *accept = types;
187 }
188 self
189 }
190
191 pub fn label(mut self, label: &str) -> Self { self.label = label.to_string(); self }
193 pub fn readonly(mut self) -> Self { self.readonly = true; self }
194 pub fn hidden(mut self) -> Self { self.hidden = true; self }
195 pub fn list_only(mut self) -> Self { self.list_only = true; self }
196 pub fn form_only(mut self) -> Self { self.form_only = true; self }
197 pub fn required(mut self) -> Self {
198 self.required = true;
199 self.validators.push(Box::new(crate::validator::Required));
200 self
201 }
202 pub fn help_text(mut self, text: &str) -> Self { self.help_text = Some(text.to_string()); self }
203
204 pub fn validator(mut self, v: Box<dyn crate::validator::Validator>) -> Self {
206 self.validators.push(v);
207 self
208 }
209
210 pub fn async_validator(mut self, v: Box<dyn crate::validator::AsyncValidator>) -> Self {
212 self.async_validators.push(v);
213 self
214 }
215
216 pub fn min_length(mut self, n: usize) -> Self {
217 self.validators.push(Box::new(crate::validator::MinLength(n)));
218 self
219 }
220
221 pub fn max_length(mut self, n: usize) -> Self {
222 self.validators.push(Box::new(crate::validator::MaxLength(n)));
223 self
224 }
225
226 pub fn min_value(mut self, n: f64) -> Self {
227 self.validators.push(Box::new(crate::validator::MinValue(n)));
228 self
229 }
230
231 pub fn max_value(mut self, n: f64) -> Self {
232 self.validators.push(Box::new(crate::validator::MaxValue(n)));
233 self
234 }
235
236 pub fn regex(mut self, pattern: &str) -> Self {
237 self.validators.push(Box::new(crate::validator::RegexValidator::new(pattern)));
238 self
239 }
240
241 pub fn unique(mut self, adapter: Box<dyn crate::adapter::DataAdapter>, col: &str) -> Self {
242 self.async_validators.push(Box::new(crate::validator::Unique::new(adapter, col)));
243 self
244 }
245
246 pub fn fk_limit(mut self, n: u64) -> Self {
247 if let FieldType::ForeignKey { ref mut limit, .. } = self.field_type {
248 *limit = Some(n);
249 }
250 self
251 }
252
253 pub fn fk_order_by(mut self, field: &str) -> Self {
254 if let FieldType::ForeignKey { ref mut order_by, .. } = self.field_type {
255 *order_by = Some(field.to_string());
256 }
257 self
258 }
259}