1use json::{object, JsonValue};
2#[derive(Clone, Debug)]
3pub enum Fields {
4 String,
5 StringPass,
6 StringKey,
7 StringTel,
8 StringIdent,
9 StringEmail,
10 StringColor,
11 StringCode,
12 StringBarcode,
13 StringQrcode,
14 Radio,
15 Select,
16 TableList,
17 TableTree,
18 Int,
19 Switch,
20 Dict,
21 Text,
22 TextEditor,
23 TextUrl,
24 Json,
25 Array,
26 Object,
27 Float,
28 DateTime,
29 Year,
30}
31impl Fields {
32 pub fn name(&mut self, name: &str) -> Field {
33 Field::new(self.clone(), name)
34 }
35 pub fn str(self) -> &'static str {
36 match self {
37 Fields::String
38 | Fields::StringPass
39 | Fields::StringKey
40 | Fields::StringTel
41 | Fields::StringIdent
42 | Fields::StringEmail
43 | Fields::StringColor
44 | Fields::StringCode
45 | Fields::StringBarcode
46 | Fields::StringQrcode => "string",
47 Fields::Radio => "radio",
48 Fields::Select => "select",
49 Fields::TableList => "table",
50 Fields::TableTree => "tree",
51 Fields::Int => "int",
52 Fields::Switch => "bool",
53 Fields::Dict => "string",
54 Fields::Text | Fields::TextEditor | Fields::TextUrl => "text",
55 Fields::Json => "json",
56 Fields::Array => "array",
57 Fields::Object => "object",
58 Fields::Float => "float",
59 Fields::DateTime => "datetime",
60 Fields::Year => "year",
61 }
62 }
63}
64#[derive(Debug)]
65pub struct Field {
66 mode: Fields,
67 require: bool,
69 field: String,
70 title: String,
71 def: JsonValue,
73 length: usize,
75 dec: usize,
77 option: Vec<&'static str>,
79 show: bool,
81 describe: String,
82 example: JsonValue,
84 api: String,
86 table_name: String,
88 multiple: bool,
90}
91
92impl Field {
93 pub fn new(mode: Fields, name: &str) -> Field {
94 Self {
95 mode,
96 require: true,
97 field: name.to_string(),
98 title: "".to_string(),
99 def: JsonValue::Null,
100 length: 0,
101 dec: 0,
102 option: vec![],
103 show: true,
104 describe: "".to_string(),
105 example: JsonValue::Null,
106 api: "".to_string(),
107 table_name: "".to_string(),
108 multiple: false,
109 }
110 }
111 pub fn title(mut self, name: &str) -> Field {
112 self.title = name.to_string();
113 self
114 }
115 pub fn def(mut self, name: JsonValue) -> Field {
117 self.def = name;
118 self
119 }
120 pub fn require(mut self, require: bool) -> Field {
121 self.require = require;
122 self
123 }
124 pub fn show(mut self, show: bool) -> Field {
125 self.show = show;
126 self
127 }
128 pub fn example(mut self, example: JsonValue) -> Field {
129 self.example = example;
130 self
131 }
132 pub fn length(mut self, length: usize) -> Field {
133 self.length = length;
134 self
135 }
136 pub fn describe(mut self, describe: &str) -> Field {
137 self.describe = describe.to_string();
138 self
139 }
140 pub fn option(mut self, option: Vec<&'static str>) -> Field {
141 self.option = option;
142 self
143 }
144 pub fn table(mut self, table: &str, api: &str, fields: Vec<&'static str>) -> Field {
146 self.api = api.to_string();
147 self.table_name = table.to_string();
148 self.option = fields;
149 self
150 }
151 pub fn multiple(mut self, multiple: bool, count: usize) -> Field {
152 self.multiple = multiple;
153 if count == 0 {
154 self.length = 1
155 } else {
156 self.length = count;
157 }
158 self
159 }
160 pub fn dec(mut self, dec: usize) -> Field {
161 self.dec = dec;
162 self
163 }
164 pub fn sql(self) -> JsonValue {
165 object! {}
166 }
167 pub fn swagger(self) -> JsonValue {
168 object! {
169 "type": self.mode.str(),
170 "example": self.example,
171 }
172 }
173 pub fn field(self) -> JsonValue {
174 let example = if self.example.is_empty() {
175 self.def.clone()
176 } else {
177 self.example
178 };
179 let mut field = object! {
180 "require"=> self.require,
181 "field"=> self.field,
182 "title"=> self.title,
183 "show"=> self.show,
184 "describe"=> self.describe,
185 "example"=> example
186 };
187 match self.mode {
188 Fields::String
189 | Fields::StringPass
190 | Fields::StringKey
191 | Fields::StringTel
192 | Fields::StringIdent
193 | Fields::StringEmail
194 | Fields::StringColor
195 | Fields::StringCode
196 | Fields::StringBarcode
197 | Fields::StringQrcode => {
198 field["length"] = self.length.into();
199 field["def"] = self.def;
200 }
201 Fields::Radio => {
202 field["option"] = self.option.into();
203 field["def"] = self.def;
204 }
205 Fields::Select => {
206 field["option"] = self.option.into();
207 field["def"] = self.def;
208 }
209 Fields::TableList | Fields::TableTree | Fields::Dict => {
210 field["option"] = self.option.into();
211 field["def"] = self.def;
212 field["api"] = self.api.into();
213 field["table"] = self.table_name.into();
214 field["multiple"] = self.multiple.into();
215 field["length"] = self.length.into();
216 }
217 Fields::Int => {
218 field["length"] = self.length.into();
219 field["def"] = self.def;
220 }
221 Fields::Switch => {
222 field["def"] = self.def;
223 }
224 Fields::Text
225 | Fields::TextEditor
226 | Fields::TextUrl
227 | Fields::Json
228 | Fields::Array
229 | Fields::Object => {
230 field["length"] = self.length.into();
231 field["def"] = self.def;
232 }
233 Fields::Float => {
234 field["length"] = self.length.into();
235 field["dec"] = self.dec.into();
236 field["def"] = self.def;
237 }
238 Fields::DateTime => {
239 field["def"] = self.def;
240 }
241 Fields::Year => {
242 field["def"] = self.def;
243 }
244 };
245 field
246 }
247}
248#[cfg(test)]
249mod tests {
250 use super::*;
251 use json::JsonValue;
252
253 #[test]
254 fn fields_str_string_variants() {
255 assert_eq!(Fields::String.str(), "string");
256 assert_eq!(Fields::StringPass.str(), "string");
257 assert_eq!(Fields::StringKey.str(), "string");
258 assert_eq!(Fields::StringTel.str(), "string");
259 assert_eq!(Fields::StringIdent.str(), "string");
260 assert_eq!(Fields::StringEmail.str(), "string");
261 assert_eq!(Fields::StringColor.str(), "string");
262 assert_eq!(Fields::StringCode.str(), "string");
263 assert_eq!(Fields::StringBarcode.str(), "string");
264 assert_eq!(Fields::StringQrcode.str(), "string");
265 }
266
267 #[test]
268 fn fields_str_other_variants() {
269 assert_eq!(Fields::Radio.str(), "radio");
270 assert_eq!(Fields::Select.str(), "select");
271 assert_eq!(Fields::TableList.str(), "table");
272 assert_eq!(Fields::TableTree.str(), "tree");
273 assert_eq!(Fields::Int.str(), "int");
274 assert_eq!(Fields::Switch.str(), "bool");
275 assert_eq!(Fields::Dict.str(), "string");
276 assert_eq!(Fields::Text.str(), "text");
277 assert_eq!(Fields::TextEditor.str(), "text");
278 assert_eq!(Fields::TextUrl.str(), "text");
279 assert_eq!(Fields::Json.str(), "json");
280 assert_eq!(Fields::Array.str(), "array");
281 assert_eq!(Fields::Object.str(), "object");
282 assert_eq!(Fields::Float.str(), "float");
283 assert_eq!(Fields::DateTime.str(), "datetime");
284 assert_eq!(Fields::Year.str(), "year");
285 }
286
287 #[test]
288 fn fields_name_creates_field() {
289 let f = Fields::Int.name("age");
290 assert_eq!(f.field, "age");
291 assert!(matches!(f.mode, Fields::Int));
292 }
293
294 #[test]
295 fn field_new_defaults() {
296 let f = Field::new(Fields::String, "name");
297 assert!(matches!(f.mode, Fields::String));
298 assert!(f.require);
299 assert!(f.show);
300 assert_eq!(f.field, "name");
301 assert_eq!(f.title, "");
302 assert!(f.def.is_null());
303 assert_eq!(f.length, 0);
304 assert_eq!(f.dec, 0);
305 assert!(f.option.is_empty());
306 assert_eq!(f.describe, "");
307 assert!(f.example.is_null());
308 assert_eq!(f.api, "");
309 assert_eq!(f.table_name, "");
310 assert!(!f.multiple);
311 }
312
313 #[test]
314 fn field_title() {
315 let res = Fields::String.name("x").title("My Title").field();
316 assert_eq!(res["title"], "My Title");
317 }
318
319 #[test]
320 fn field_def() {
321 let res = Fields::String.name("x").def("default_val".into()).field();
322 assert_eq!(res["def"], "default_val");
323 }
324
325 #[test]
326 fn field_require_false() {
327 let res = Fields::String.name("x").require(false).field();
328 assert_eq!(res["require"], false);
329 }
330
331 #[test]
332 fn field_show_false() {
333 let res = Fields::String.name("x").show(false).field();
334 assert_eq!(res["show"], false);
335 }
336
337 #[test]
338 fn field_example_set() {
339 let res = Fields::String.name("x").example("ex".into()).field();
340 assert_eq!(res["example"], "ex");
341 }
342
343 #[test]
344 fn field_length() {
345 let res = Fields::String.name("x").length(50).field();
346 assert_eq!(res["length"], 50);
347 }
348
349 #[test]
350 fn field_describe() {
351 let res = Fields::String.name("x").describe("desc text").field();
352 assert_eq!(res["describe"], "desc text");
353 }
354
355 #[test]
356 fn field_option() {
357 let res = Fields::Radio.name("x").option(vec!["a", "b"]).field();
358 assert_eq!(res["option"][0], "a");
359 assert_eq!(res["option"][1], "b");
360 }
361
362 #[test]
363 fn field_table() {
364 let res = Fields::TableList
365 .name("x")
366 .table("my_table", "/api/list", vec!["col1", "col2"])
367 .field();
368 assert_eq!(res["table"], "my_table");
369 assert_eq!(res["api"], "/api/list");
370 assert_eq!(res["option"][0], "col1");
371 assert_eq!(res["option"][1], "col2");
372 }
373
374 #[test]
375 fn field_multiple_count_zero() {
376 let f = Field::new(Fields::TableList, "x").multiple(true, 0);
377 assert!(f.multiple);
378 assert_eq!(f.length, 1);
379 }
380
381 #[test]
382 fn field_multiple_count_nonzero() {
383 let f = Field::new(Fields::TableList, "x").multiple(true, 5);
384 assert!(f.multiple);
385 assert_eq!(f.length, 5);
386 }
387
388 #[test]
389 fn field_dec() {
390 let res = Fields::Float.name("x").dec(4).field();
391 assert_eq!(res["dec"], 4);
392 }
393
394 #[test]
395 fn field_sql_returns_empty_object() {
396 let res = Fields::String.name("x").sql();
397 assert!(res.is_object());
398 assert_eq!(res.len(), 0);
399 }
400
401 #[test]
402 fn field_swagger_returns_type_and_example() {
403 let res = Fields::Int.name("x").example(42.into()).swagger();
404 assert_eq!(res["type"], "int");
405 assert_eq!(res["example"], 42);
406 }
407
408 #[test]
409 fn field_output_string_variants() {
410 let variants = [
411 Fields::String,
412 Fields::StringPass,
413 Fields::StringKey,
414 Fields::StringTel,
415 Fields::StringIdent,
416 Fields::StringEmail,
417 Fields::StringColor,
418 Fields::StringCode,
419 Fields::StringBarcode,
420 Fields::StringQrcode,
421 ];
422 for mut v in variants {
423 let res = v.name("s").length(100).def("d".into()).field();
424 assert_eq!(res["length"], 100);
425 assert_eq!(res["def"], "d");
426 }
427 }
428
429 #[test]
430 fn field_output_radio() {
431 let res = Fields::Radio
432 .name("r")
433 .option(vec!["yes", "no"])
434 .def("yes".into())
435 .field();
436 assert_eq!(res["option"][0], "yes");
437 assert_eq!(res["option"][1], "no");
438 assert_eq!(res["def"], "yes");
439 assert!(res["length"].is_null());
440 }
441
442 #[test]
443 fn field_output_select() {
444 let res = Fields::Select
445 .name("s")
446 .option(vec!["a", "b", "c"])
447 .def("a".into())
448 .field();
449 assert_eq!(res["option"].len(), 3);
450 assert_eq!(res["def"], "a");
451 assert!(res["length"].is_null());
452 }
453
454 #[test]
455 fn field_output_table_list() {
456 let res = Fields::TableList
457 .name("t")
458 .table("tbl", "/api", vec!["f1"])
459 .multiple(true, 3)
460 .def("x".into())
461 .field();
462 assert_eq!(res["option"][0], "f1");
463 assert_eq!(res["def"], "x");
464 assert_eq!(res["api"], "/api");
465 assert_eq!(res["table"], "tbl");
466 assert_eq!(res["multiple"], true);
467 assert_eq!(res["length"], 3);
468 }
469
470 #[test]
471 fn field_output_table_tree() {
472 let res = Fields::TableTree
473 .name("t")
474 .table("tree_tbl", "/tree", vec!["c1", "c2"])
475 .multiple(false, 0)
476 .def(JsonValue::Null)
477 .field();
478 assert_eq!(res["table"], "tree_tbl");
479 assert_eq!(res["api"], "/tree");
480 assert_eq!(res["multiple"], false);
481 assert_eq!(res["length"], 1);
482 }
483
484 #[test]
485 fn field_output_dict() {
486 let res = Fields::Dict
487 .name("d")
488 .table("dict_tbl", "/dict", vec!["k"])
489 .def("v".into())
490 .field();
491 assert_eq!(res["table"], "dict_tbl");
492 assert_eq!(res["api"], "/dict");
493 assert_eq!(res["def"], "v");
494 assert!(!res["multiple"].is_null());
495 }
496
497 #[test]
498 fn field_output_int() {
499 let res = Fields::Int.name("i").length(11).def(0.into()).field();
500 assert_eq!(res["length"], 11);
501 assert_eq!(res["def"], 0);
502 }
503
504 #[test]
505 fn field_output_switch() {
506 let res = Fields::Switch.name("sw").def(true.into()).field();
507 assert_eq!(res["def"], true);
508 assert!(res["length"].is_null());
509 }
510
511 #[test]
512 fn field_output_text_variants() {
513 let variants = [
514 Fields::Text,
515 Fields::TextEditor,
516 Fields::TextUrl,
517 Fields::Json,
518 Fields::Array,
519 Fields::Object,
520 ];
521 for mut v in variants {
522 let res = v.name("t").length(5000).def("body".into()).field();
523 assert_eq!(res["length"], 5000);
524 assert_eq!(res["def"], "body");
525 }
526 }
527
528 #[test]
529 fn field_output_float() {
530 let res = Fields::Float
531 .name("f")
532 .length(10)
533 .dec(2)
534 .def(1.5.into())
535 .field();
536 assert_eq!(res["length"], 10);
537 assert_eq!(res["dec"], 2);
538 assert_eq!(res["def"], 1.5);
539 }
540
541 #[test]
542 fn field_output_datetime() {
543 let res = Fields::DateTime.name("dt").def("2026-01-01".into()).field();
544 assert_eq!(res["def"], "2026-01-01");
545 assert!(res["length"].is_null());
546 }
547
548 #[test]
549 fn field_output_year() {
550 let res = Fields::Year.name("y").def(2026.into()).field();
551 assert_eq!(res["def"], 2026);
552 assert!(res["length"].is_null());
553 }
554
555 #[test]
556 fn field_example_fallback_to_def() {
557 let res = Fields::String.name("x").def("fallback".into()).field();
558 assert_eq!(res["example"], "fallback");
559 }
560
561 #[test]
562 fn field_example_explicit_overrides_def() {
563 let res = Fields::String
564 .name("x")
565 .def("default".into())
566 .example("explicit".into())
567 .field();
568 assert_eq!(res["example"], "explicit");
569 }
570}