1use super::types::{ChoiceInfo, FieldType};
4use super::validators::FieldValidator;
5use serde::{Deserialize, Serialize};
6use std::collections::HashMap;
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct FieldInfo {
11 #[serde(rename = "type")]
13 pub field_type: FieldType,
14 pub required: bool,
16 #[serde(skip_serializing_if = "Option::is_none")]
18 pub read_only: Option<bool>,
19 #[serde(skip_serializing_if = "Option::is_none")]
21 pub label: Option<String>,
22 #[serde(skip_serializing_if = "Option::is_none")]
24 pub help_text: Option<String>,
25 #[serde(skip_serializing_if = "Option::is_none")]
27 pub min_length: Option<usize>,
28 #[serde(skip_serializing_if = "Option::is_none")]
30 pub max_length: Option<usize>,
31 #[serde(skip_serializing_if = "Option::is_none")]
33 pub min_value: Option<f64>,
34 #[serde(skip_serializing_if = "Option::is_none")]
36 pub max_value: Option<f64>,
37 #[serde(skip_serializing_if = "Option::is_none")]
39 pub choices: Option<Vec<ChoiceInfo>>,
40 #[serde(skip_serializing_if = "Option::is_none")]
42 pub child: Option<Box<FieldInfo>>,
43 #[serde(skip_serializing_if = "Option::is_none")]
45 pub children: Option<HashMap<String, FieldInfo>>,
46 #[serde(skip_serializing_if = "Option::is_none")]
48 pub validators: Option<Vec<FieldValidator>>,
49 #[serde(skip_serializing_if = "Option::is_none")]
51 pub default_value: Option<serde_json::Value>,
52}
53
54pub struct FieldInfoBuilder {
56 field_type: FieldType,
57 required: bool,
58 read_only: Option<bool>,
59 label: Option<String>,
60 help_text: Option<String>,
61 min_length: Option<usize>,
62 max_length: Option<usize>,
63 min_value: Option<f64>,
64 max_value: Option<f64>,
65 choices: Option<Vec<ChoiceInfo>>,
66 child: Option<Box<FieldInfo>>,
67 children: Option<HashMap<String, FieldInfo>>,
68 validators: Option<Vec<FieldValidator>>,
69 default_value: Option<serde_json::Value>,
70}
71
72impl FieldInfoBuilder {
73 pub fn new(field_type: FieldType) -> Self {
86 Self {
87 field_type,
88 required: false,
89 read_only: None,
90 label: None,
91 help_text: None,
92 min_length: None,
93 max_length: None,
94 min_value: None,
95 max_value: None,
96 choices: None,
97 child: None,
98 children: None,
99 validators: None,
100 default_value: None,
101 }
102 }
103 pub fn required(mut self, required: bool) -> Self {
116 self.required = required;
117 self
118 }
119 pub fn read_only(mut self, read_only: bool) -> Self {
132 self.read_only = Some(read_only);
133 self
134 }
135 pub fn label(mut self, label: impl Into<String>) -> Self {
148 self.label = Some(label.into());
149 self
150 }
151 pub fn help_text(mut self, help_text: impl Into<String>) -> Self {
164 self.help_text = Some(help_text.into());
165 self
166 }
167 pub fn min_length(mut self, min_length: usize) -> Self {
180 self.min_length = Some(min_length);
181 self
182 }
183 pub fn max_length(mut self, max_length: usize) -> Self {
196 self.max_length = Some(max_length);
197 self
198 }
199 pub fn min_value(mut self, min_value: f64) -> Self {
212 self.min_value = Some(min_value);
213 self
214 }
215 pub fn max_value(mut self, max_value: f64) -> Self {
228 self.max_value = Some(max_value);
229 self
230 }
231 pub fn choices(mut self, choices: Vec<ChoiceInfo>) -> Self {
255 self.choices = Some(choices);
256 self
257 }
258 pub fn child(mut self, child: FieldInfo) -> Self {
277 self.child = Some(Box::new(child));
278 self
279 }
280 pub fn children(mut self, children: HashMap<String, FieldInfo>) -> Self {
306 self.children = Some(children);
307 self
308 }
309
310 pub fn add_validator(mut self, validator: FieldValidator) -> Self {
333 if let Some(ref mut validators) = self.validators {
334 validators.push(validator);
335 } else {
336 self.validators = Some(vec![validator]);
337 }
338 self
339 }
340
341 pub fn validators(mut self, validators: Vec<FieldValidator>) -> Self {
369 self.validators = Some(validators);
370 self
371 }
372
373 pub fn default_value(mut self, default_value: serde_json::Value) -> Self {
389 self.default_value = Some(default_value);
390 self
391 }
392 pub fn build(self) -> FieldInfo {
413 FieldInfo {
414 field_type: self.field_type,
415 required: self.required,
416 read_only: self.read_only,
417 label: self.label,
418 help_text: self.help_text,
419 min_length: self.min_length,
420 max_length: self.max_length,
421 min_value: self.min_value,
422 max_value: self.max_value,
423 choices: self.choices,
424 child: self.child,
425 children: self.children,
426 validators: self.validators,
427 default_value: self.default_value,
428 }
429 }
430}
431
432#[cfg(test)]
433mod tests {
434 use super::*;
435 use crate::metadata::FieldValidator;
436
437 #[tokio::test]
438 async fn test_field_info_builder() {
439 let field = FieldInfoBuilder::new(FieldType::String)
440 .required(true)
441 .label("Username")
442 .help_text("Enter your username")
443 .min_length(3)
444 .max_length(50)
445 .build();
446
447 assert_eq!(field.field_type, FieldType::String);
448 assert!(field.required);
449 assert_eq!(field.label, Some("Username".to_string()));
450 assert_eq!(field.help_text, Some("Enter your username".to_string()));
451 assert_eq!(field.min_length, Some(3));
452 assert_eq!(field.max_length, Some(50));
453 }
454
455 #[tokio::test]
456 async fn test_choice_field() {
457 let choices = vec![
458 ChoiceInfo {
459 value: "active".to_string(),
460 display_name: "Active".to_string(),
461 },
462 ChoiceInfo {
463 value: "inactive".to_string(),
464 display_name: "Inactive".to_string(),
465 },
466 ];
467
468 let field = FieldInfoBuilder::new(FieldType::Choice)
469 .required(true)
470 .label("Status")
471 .choices(choices.clone())
472 .build();
473
474 assert_eq!(field.field_type, FieldType::Choice);
475 assert!(field.required);
476 assert_eq!(field.choices.as_ref().unwrap().len(), 2);
477 }
478
479 #[test]
481 fn test_list_field_with_child() {
482 let child_field = FieldInfoBuilder::new(FieldType::Integer)
483 .required(true)
484 .read_only(false)
485 .build();
486
487 let list_field = FieldInfoBuilder::new(FieldType::List)
488 .required(true)
489 .read_only(false)
490 .label("List field")
491 .child(child_field)
492 .build();
493
494 assert_eq!(list_field.field_type, FieldType::List);
495 assert!(list_field.child.is_some());
496 let child = list_field.child.as_ref().unwrap();
497 assert_eq!(child.field_type, FieldType::Integer);
498 }
499
500 #[test]
503 fn test_hidden_fields_not_included() {
504 let mut fields = HashMap::new();
505
506 fields.insert(
508 "integer_field".to_string(),
509 FieldInfoBuilder::new(FieldType::Integer)
510 .required(true)
511 .max_value(10.0)
512 .build(),
513 );
514
515 assert!(fields.contains_key("integer_field"));
518 assert!(!fields.contains_key("hidden_field"));
519 assert_eq!(fields.len(), 1);
520 }
521
522 #[test]
523 fn test_field_with_single_validator() {
524 let validator = FieldValidator {
525 validator_type: "email".to_string(),
526 options: None,
527 message: Some("Invalid email format".to_string()),
528 };
529
530 let field = FieldInfoBuilder::new(FieldType::Email)
531 .required(true)
532 .add_validator(validator)
533 .build();
534
535 assert!(field.validators.is_some());
536 let validators = field.validators.as_ref().unwrap();
537 assert_eq!(validators.len(), 1);
538 assert_eq!(validators[0].validator_type, "email");
539 assert_eq!(
540 validators[0].message,
541 Some("Invalid email format".to_string())
542 );
543 }
544
545 #[test]
546 fn test_field_with_multiple_validators() {
547 let validators = vec![
548 FieldValidator {
549 validator_type: "min_length".to_string(),
550 options: Some(serde_json::json!({"min": 3})),
551 message: Some("Too short".to_string()),
552 },
553 FieldValidator {
554 validator_type: "max_length".to_string(),
555 options: Some(serde_json::json!({"max": 50})),
556 message: Some("Too long".to_string()),
557 },
558 FieldValidator {
559 validator_type: "regex".to_string(),
560 options: Some(serde_json::json!({"pattern": "^[a-zA-Z0-9_]+$"})),
561 message: Some("Invalid characters".to_string()),
562 },
563 ];
564
565 let field = FieldInfoBuilder::new(FieldType::String)
566 .validators(validators)
567 .build();
568
569 assert!(field.validators.is_some());
570 let field_validators = field.validators.as_ref().unwrap();
571 assert_eq!(field_validators.len(), 3);
572 assert_eq!(field_validators[0].validator_type, "min_length");
573 assert_eq!(field_validators[1].validator_type, "max_length");
574 assert_eq!(field_validators[2].validator_type, "regex");
575 }
576
577 #[test]
578 fn test_field_without_validators() {
579 let field = FieldInfoBuilder::new(FieldType::String)
580 .required(true)
581 .label("Username")
582 .build();
583
584 assert!(field.validators.is_none());
585 }
586
587 #[test]
588 fn test_field_with_default_value_string() {
589 let field = FieldInfoBuilder::new(FieldType::String)
590 .required(false)
591 .default_value(serde_json::json!("default text"))
592 .build();
593
594 assert!(field.default_value.is_some());
595 assert_eq!(field.default_value, Some(serde_json::json!("default text")));
596 }
597
598 #[test]
599 fn test_field_with_default_value_number() {
600 let field = FieldInfoBuilder::new(FieldType::Integer)
601 .required(false)
602 .default_value(serde_json::json!(42))
603 .build();
604
605 assert!(field.default_value.is_some());
606 assert_eq!(field.default_value, Some(serde_json::json!(42)));
607 }
608
609 #[test]
610 fn test_field_with_default_value_boolean() {
611 let field = FieldInfoBuilder::new(FieldType::Boolean)
612 .required(false)
613 .default_value(serde_json::json!(true))
614 .build();
615
616 assert!(field.default_value.is_some());
617 assert_eq!(field.default_value, Some(serde_json::json!(true)));
618 }
619
620 #[test]
621 fn test_field_with_default_value_object() {
622 let default_obj = serde_json::json!({
623 "name": "John Doe",
624 "age": 30
625 });
626
627 let field = FieldInfoBuilder::new(FieldType::NestedObject)
628 .required(false)
629 .default_value(default_obj.clone())
630 .build();
631
632 assert!(field.default_value.is_some());
633 assert_eq!(field.default_value, Some(default_obj));
634 }
635
636 #[test]
637 fn test_field_with_default_value_array() {
638 let default_array = serde_json::json!(["item1", "item2", "item3"]);
639
640 let field = FieldInfoBuilder::new(FieldType::List)
641 .required(false)
642 .default_value(default_array.clone())
643 .build();
644
645 assert!(field.default_value.is_some());
646 assert_eq!(field.default_value, Some(default_array));
647 }
648
649 #[test]
650 fn test_field_without_default_value() {
651 let field = FieldInfoBuilder::new(FieldType::String)
652 .required(true)
653 .label("Username")
654 .build();
655
656 assert!(field.default_value.is_none());
657 }
658
659 #[test]
660 fn test_default_value_serialization() {
661 let field = FieldInfoBuilder::new(FieldType::String)
662 .default_value(serde_json::json!("default"))
663 .build();
664
665 let json = serde_json::to_string(&field).unwrap();
666 assert!(json.contains("default_value"));
667 assert!(json.contains("default"));
668 }
669
670 #[test]
671 fn test_default_value_not_serialized_when_none() {
672 let field = FieldInfoBuilder::new(FieldType::String).build();
673
674 let json = serde_json::to_string(&field).unwrap();
675 assert!(!json.contains("default_value"));
676 }
677}