1use serde::{Deserialize, Serialize};
4
5use super::{
6 Attribute, Documentation, EnhancedDocumentation, FieldAttributes, FieldType, FieldValidation,
7 Ident, Span, TypeModifier, ValidationRule, ValidationType,
8};
9
10#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
12pub struct Field {
13 pub name: Ident,
15 pub field_type: FieldType,
17 pub modifier: TypeModifier,
19 pub attributes: Vec<Attribute>,
21 pub documentation: Option<Documentation>,
23 pub validation: FieldValidation,
25 pub span: Span,
27}
28
29impl Field {
30 pub fn new(
32 name: Ident,
33 field_type: FieldType,
34 modifier: TypeModifier,
35 attributes: Vec<Attribute>,
36 span: Span,
37 ) -> Self {
38 Self {
39 name,
40 field_type,
41 modifier,
42 attributes,
43 documentation: None,
44 validation: FieldValidation::new(),
45 span,
46 }
47 }
48
49 pub fn name(&self) -> &str {
51 self.name.as_str()
52 }
53
54 pub fn is_optional(&self) -> bool {
56 self.modifier.is_optional()
57 }
58
59 pub fn is_list(&self) -> bool {
61 self.modifier.is_list()
62 }
63
64 pub fn has_attribute(&self, name: &str) -> bool {
66 self.attributes.iter().any(|a| a.is(name))
67 }
68
69 pub fn get_attribute(&self, name: &str) -> Option<&Attribute> {
71 self.attributes.iter().find(|a| a.is(name))
72 }
73
74 pub fn is_id(&self) -> bool {
76 self.has_attribute("id")
77 }
78
79 pub fn is_unique(&self) -> bool {
81 self.has_attribute("unique")
82 }
83
84 pub fn is_relation(&self) -> bool {
86 self.field_type.is_relation() || self.has_attribute("relation")
87 }
88
89 pub fn extract_attributes(&self) -> FieldAttributes {
91 let mut attrs = FieldAttributes::default();
92
93 for attr in &self.attributes {
94 match attr.name() {
95 "id" => attrs.is_id = true,
96 "auto" => attrs.is_auto = true,
97 "unique" => attrs.is_unique = true,
98 "index" => attrs.is_indexed = true,
99 "updated_at" => attrs.is_updated_at = true,
100 "omit" => attrs.is_omit = true,
101 "default" => {
102 attrs.default = attr.first_arg().cloned();
103 }
104 "map" => {
105 if let Some(val) = attr.first_arg() {
106 attrs.map = val.as_string().map(String::from);
107 }
108 }
109 "db" => {
110 if let Some(val) = attr.first_arg() {
112 if let super::AttributeValue::Function(name, args) = val {
113 attrs.native_type =
114 Some(super::NativeType::new(name.clone(), args.clone()));
115 } else if let Some(name) = val.as_ident() {
116 attrs.native_type = Some(super::NativeType::new(name, vec![]));
117 }
118 }
119 }
120 "relation" => {
121 let mut rel = super::RelationAttribute {
123 name: None,
124 fields: vec![],
125 references: vec![],
126 on_delete: None,
127 on_update: None,
128 map: None,
129 };
130
131 if let Some(val) = attr.first_arg() {
133 rel.name = val.as_string().map(String::from);
134 }
135
136 if let Some(super::AttributeValue::FieldRefList(fields)) =
138 attr.get_arg("fields")
139 {
140 rel.fields = fields.clone();
141 }
142 if let Some(super::AttributeValue::FieldRefList(refs)) =
143 attr.get_arg("references")
144 {
145 rel.references = refs.clone();
146 }
147 if let Some(val) = attr.get_arg("onDelete") {
148 if let Some(action) = val.as_ident() {
149 rel.on_delete = super::ReferentialAction::from_str(action);
150 }
151 }
152 if let Some(val) = attr.get_arg("onUpdate") {
153 if let Some(action) = val.as_ident() {
154 rel.on_update = super::ReferentialAction::from_str(action);
155 }
156 }
157 if let Some(val) = attr.get_arg("map") {
158 rel.map = val.as_string().map(String::from);
159 }
160
161 attrs.relation = Some(rel);
162 }
163 _ => {}
164 }
165 }
166
167 attrs
168 }
169
170 pub fn with_documentation(mut self, doc: Documentation) -> Self {
172 self.documentation = Some(doc);
173 self
174 }
175
176 pub fn with_enhanced_documentation(mut self, doc: EnhancedDocumentation) -> Self {
178 self.documentation = Some(Documentation::new(&doc.text, doc.span));
179 for rule in doc.validation.rules {
181 self.validation.add_rule(rule);
182 }
183 self
184 }
185
186 pub fn with_validation(mut self, validation: FieldValidation) -> Self {
188 self.validation = validation;
189 self
190 }
191
192 pub fn add_validation_rule(&mut self, rule: ValidationRule) {
194 self.validation.add_rule(rule);
195 }
196
197 pub fn has_validation(&self) -> bool {
199 !self.validation.is_empty()
200 }
201
202 pub fn validation_rules(&self) -> &[ValidationRule] {
204 &self.validation.rules
205 }
206
207 pub fn is_validated_required(&self) -> bool {
209 self.validation.is_required()
210 }
211
212 pub fn extract_validation_from_attributes(&mut self) {
219 for attr in &self.attributes {
220 let attr_name = attr.name();
221
222 if let Some(validator_name) = attr_name.strip_prefix("validate.") {
224 if let Some(rule) = self.parse_validate_attribute(validator_name, attr) {
225 self.validation.add_rule(rule);
226 }
227 } else if attr_name == "validate" {
228 for arg in &attr.args {
230 if let Some(rule) = self.parse_validate_arg(arg) {
231 self.validation.add_rule(rule);
232 }
233 }
234 }
235 }
236 }
237
238 fn parse_validate_attribute(
240 &self,
241 validator_name: &str,
242 attr: &Attribute,
243 ) -> Option<ValidationRule> {
244 let span = attr.span;
245
246 let rule_type = match validator_name {
248 "email" => ValidationType::Email,
250 "url" => ValidationType::Url,
251 "uuid" => ValidationType::Uuid,
252 "cuid" => ValidationType::Cuid,
253 "cuid2" => ValidationType::Cuid2,
254 "nanoid" | "nanoId" | "NanoId" => ValidationType::NanoId,
255 "ulid" => ValidationType::Ulid,
256 "alpha" => ValidationType::Alpha,
257 "alphanumeric" => ValidationType::Alphanumeric,
258 "lowercase" => ValidationType::Lowercase,
259 "uppercase" => ValidationType::Uppercase,
260 "trim" => ValidationType::Trim,
261 "noWhitespace" => ValidationType::NoWhitespace,
262 "ip" => ValidationType::Ip,
263 "ipv4" => ValidationType::Ipv4,
264 "ipv6" => ValidationType::Ipv6,
265 "creditCard" => ValidationType::CreditCard,
266 "phone" => ValidationType::Phone,
267 "slug" => ValidationType::Slug,
268 "hex" => ValidationType::Hex,
269 "base64" => ValidationType::Base64,
270 "json" => ValidationType::Json,
271
272 "positive" => ValidationType::Positive,
274 "negative" => ValidationType::Negative,
275 "nonNegative" => ValidationType::NonNegative,
276 "nonPositive" => ValidationType::NonPositive,
277 "integer" => ValidationType::Integer,
278 "finite" => ValidationType::Finite,
279
280 "unique" => ValidationType::Unique,
282 "nonEmpty" => ValidationType::NonEmpty,
283
284 "past" => ValidationType::Past,
286 "future" => ValidationType::Future,
287 "pastOrPresent" => ValidationType::PastOrPresent,
288 "futureOrPresent" => ValidationType::FutureOrPresent,
289
290 "required" => ValidationType::Required,
292 "notEmpty" => ValidationType::NotEmpty,
293
294 "minLength" => {
296 let n = attr.first_arg()?.as_int()? as usize;
297 ValidationType::MinLength(n)
298 }
299 "maxLength" => {
300 let n = attr.first_arg()?.as_int()? as usize;
301 ValidationType::MaxLength(n)
302 }
303 "length" => {
304 let args = &attr.args;
305 if args.len() >= 2 {
306 let min = args[0].value.as_int()? as usize;
307 let max = args[1].value.as_int()? as usize;
308 ValidationType::Length { min, max }
309 } else {
310 return None;
311 }
312 }
313 "min" => {
314 let n = attr
315 .first_arg()?
316 .as_float()
317 .or_else(|| attr.first_arg()?.as_int().map(|i| i as f64))?;
318 ValidationType::Min(n)
319 }
320 "max" => {
321 let n = attr
322 .first_arg()?
323 .as_float()
324 .or_else(|| attr.first_arg()?.as_int().map(|i| i as f64))?;
325 ValidationType::Max(n)
326 }
327 "range" => {
328 let args = &attr.args;
329 if args.len() >= 2 {
330 let min = args[0]
331 .value
332 .as_float()
333 .or_else(|| args[0].value.as_int().map(|i| i as f64))?;
334 let max = args[1]
335 .value
336 .as_float()
337 .or_else(|| args[1].value.as_int().map(|i| i as f64))?;
338 ValidationType::Range { min, max }
339 } else {
340 return None;
341 }
342 }
343 "regex" => {
344 let pattern = attr.first_arg()?.as_string()?.to_string();
345 ValidationType::Regex(pattern)
346 }
347 "startsWith" => {
348 let prefix = attr.first_arg()?.as_string()?.to_string();
349 ValidationType::StartsWith(prefix)
350 }
351 "endsWith" => {
352 let suffix = attr.first_arg()?.as_string()?.to_string();
353 ValidationType::EndsWith(suffix)
354 }
355 "contains" => {
356 let substring = attr.first_arg()?.as_string()?.to_string();
357 ValidationType::Contains(substring)
358 }
359 "minItems" => {
360 let n = attr.first_arg()?.as_int()? as usize;
361 ValidationType::MinItems(n)
362 }
363 "maxItems" => {
364 let n = attr.first_arg()?.as_int()? as usize;
365 ValidationType::MaxItems(n)
366 }
367 "items" => {
368 let args = &attr.args;
369 if args.len() >= 2 {
370 let min = args[0].value.as_int()? as usize;
371 let max = args[1].value.as_int()? as usize;
372 ValidationType::Items { min, max }
373 } else {
374 return None;
375 }
376 }
377 "multipleOf" => {
378 let n = attr
379 .first_arg()?
380 .as_float()
381 .or_else(|| attr.first_arg()?.as_int().map(|i| i as f64))?;
382 ValidationType::MultipleOf(n)
383 }
384 "after" => {
385 let date = attr.first_arg()?.as_string()?.to_string();
386 ValidationType::After(date)
387 }
388 "before" => {
389 let date = attr.first_arg()?.as_string()?.to_string();
390 ValidationType::Before(date)
391 }
392 "custom" => {
393 let name = attr.first_arg()?.as_string()?.to_string();
394 ValidationType::Custom(name)
395 }
396 _ => return None,
397 };
398
399 Some(ValidationRule::new(rule_type, span))
400 }
401
402 fn parse_validate_arg(&self, arg: &super::AttributeArg) -> Option<ValidationRule> {
404 let span = arg.span;
405
406 match &arg.value {
407 super::AttributeValue::Ident(name) => {
408 let rule_type = match name.as_str() {
410 "email" => ValidationType::Email,
411 "url" => ValidationType::Url,
412 "uuid" => ValidationType::Uuid,
413 "cuid" => ValidationType::Cuid,
414 "cuid2" => ValidationType::Cuid2,
415 "nanoid" | "nanoId" | "NanoId" => ValidationType::NanoId,
416 "ulid" => ValidationType::Ulid,
417 "alpha" => ValidationType::Alpha,
418 "alphanumeric" => ValidationType::Alphanumeric,
419 "lowercase" => ValidationType::Lowercase,
420 "uppercase" => ValidationType::Uppercase,
421 "trim" => ValidationType::Trim,
422 "noWhitespace" => ValidationType::NoWhitespace,
423 "ip" => ValidationType::Ip,
424 "ipv4" => ValidationType::Ipv4,
425 "ipv6" => ValidationType::Ipv6,
426 "creditCard" => ValidationType::CreditCard,
427 "phone" => ValidationType::Phone,
428 "slug" => ValidationType::Slug,
429 "hex" => ValidationType::Hex,
430 "base64" => ValidationType::Base64,
431 "json" => ValidationType::Json,
432 "positive" => ValidationType::Positive,
433 "negative" => ValidationType::Negative,
434 "nonNegative" => ValidationType::NonNegative,
435 "nonPositive" => ValidationType::NonPositive,
436 "integer" => ValidationType::Integer,
437 "finite" => ValidationType::Finite,
438 "unique" => ValidationType::Unique,
439 "nonEmpty" => ValidationType::NonEmpty,
440 "past" => ValidationType::Past,
441 "future" => ValidationType::Future,
442 "pastOrPresent" => ValidationType::PastOrPresent,
443 "futureOrPresent" => ValidationType::FutureOrPresent,
444 "required" => ValidationType::Required,
445 "notEmpty" => ValidationType::NotEmpty,
446 _ => return None,
447 };
448 Some(ValidationRule::new(rule_type, span))
449 }
450 super::AttributeValue::Function(name, args) => {
451 let rule_type = match name.as_str() {
453 "minLength" => {
454 let n = args.first()?.as_int()? as usize;
455 ValidationType::MinLength(n)
456 }
457 "maxLength" => {
458 let n = args.first()?.as_int()? as usize;
459 ValidationType::MaxLength(n)
460 }
461 "min" => {
462 let n = args
463 .first()?
464 .as_float()
465 .or_else(|| args.first()?.as_int().map(|i| i as f64))?;
466 ValidationType::Min(n)
467 }
468 "max" => {
469 let n = args
470 .first()?
471 .as_float()
472 .or_else(|| args.first()?.as_int().map(|i| i as f64))?;
473 ValidationType::Max(n)
474 }
475 "range" => {
476 if args.len() >= 2 {
477 let min = args[0]
478 .as_float()
479 .or_else(|| args[0].as_int().map(|i| i as f64))?;
480 let max = args[1]
481 .as_float()
482 .or_else(|| args[1].as_int().map(|i| i as f64))?;
483 ValidationType::Range { min, max }
484 } else {
485 return None;
486 }
487 }
488 "regex" => {
489 let pattern = args.first()?.as_string()?.to_string();
490 ValidationType::Regex(pattern)
491 }
492 "custom" => {
493 let validator_name = args.first()?.as_string()?.to_string();
494 ValidationType::Custom(validator_name)
495 }
496 _ => return None,
497 };
498 Some(ValidationRule::new(rule_type, span))
499 }
500 _ => None,
501 }
502 }
503}
504
505impl std::fmt::Display for Field {
506 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
507 write!(f, "{}", self.name)?;
508
509 match self.modifier {
511 TypeModifier::Required => write!(f, " {}", self.field_type)?,
512 TypeModifier::Optional => write!(f, " {}?", self.field_type)?,
513 TypeModifier::List => write!(f, " {}[]", self.field_type)?,
514 TypeModifier::OptionalList => write!(f, " {}[]?", self.field_type)?,
515 }
516
517 for attr in &self.attributes {
519 write!(f, " @{}", attr.name)?;
520 if !attr.args.is_empty() {
521 write!(f, "(...)")?;
522 }
523 }
524
525 Ok(())
526 }
527}
528
529#[cfg(test)]
530mod tests {
531 use super::*;
532 use crate::ast::{AttributeArg, AttributeValue, ReferentialAction, ScalarType};
533
534 fn make_span() -> Span {
535 Span::new(0, 10)
536 }
537
538 fn make_field(name: &str, field_type: FieldType, modifier: TypeModifier) -> Field {
539 Field::new(
540 Ident::new(name, make_span()),
541 field_type,
542 modifier,
543 vec![],
544 make_span(),
545 )
546 }
547
548 fn make_attribute(name: &str) -> Attribute {
549 Attribute::simple(Ident::new(name, make_span()), make_span())
550 }
551
552 fn make_attribute_with_arg(name: &str, value: AttributeValue) -> Attribute {
553 Attribute::new(
554 Ident::new(name, make_span()),
555 vec![AttributeArg::positional(value, make_span())],
556 make_span(),
557 )
558 }
559
560 #[test]
563 fn test_field_new() {
564 let field = Field::new(
565 Ident::new("id", make_span()),
566 FieldType::Scalar(ScalarType::Int),
567 TypeModifier::Required,
568 vec![],
569 make_span(),
570 );
571
572 assert_eq!(field.name(), "id");
573 assert!(field.field_type.is_scalar());
574 assert_eq!(field.modifier, TypeModifier::Required);
575 assert!(field.attributes.is_empty());
576 assert!(field.documentation.is_none());
577 }
578
579 #[test]
580 fn test_field_with_attributes() {
581 let field = Field::new(
582 Ident::new("email", make_span()),
583 FieldType::Scalar(ScalarType::String),
584 TypeModifier::Required,
585 vec![make_attribute("unique")],
586 make_span(),
587 );
588
589 assert_eq!(field.attributes.len(), 1);
590 }
591
592 #[test]
593 fn test_field_with_documentation() {
594 let field = make_field(
595 "name",
596 FieldType::Scalar(ScalarType::String),
597 TypeModifier::Optional,
598 )
599 .with_documentation(Documentation::new("User's display name", make_span()));
600
601 assert!(field.documentation.is_some());
602 assert_eq!(field.documentation.unwrap().text, "User's display name");
603 }
604
605 #[test]
608 fn test_field_name() {
609 let field = make_field(
610 "created_at",
611 FieldType::Scalar(ScalarType::DateTime),
612 TypeModifier::Required,
613 );
614 assert_eq!(field.name(), "created_at");
615 }
616
617 #[test]
620 fn test_field_is_optional_required() {
621 let field = make_field(
622 "id",
623 FieldType::Scalar(ScalarType::Int),
624 TypeModifier::Required,
625 );
626 assert!(!field.is_optional());
627 }
628
629 #[test]
630 fn test_field_is_optional_true() {
631 let field = make_field(
632 "bio",
633 FieldType::Scalar(ScalarType::String),
634 TypeModifier::Optional,
635 );
636 assert!(field.is_optional());
637 }
638
639 #[test]
640 fn test_field_is_list_false() {
641 let field = make_field(
642 "name",
643 FieldType::Scalar(ScalarType::String),
644 TypeModifier::Required,
645 );
646 assert!(!field.is_list());
647 }
648
649 #[test]
650 fn test_field_is_list_true() {
651 let field = make_field(
652 "tags",
653 FieldType::Scalar(ScalarType::String),
654 TypeModifier::List,
655 );
656 assert!(field.is_list());
657 }
658
659 #[test]
660 fn test_field_optional_list() {
661 let field = make_field(
662 "metadata",
663 FieldType::Scalar(ScalarType::Json),
664 TypeModifier::OptionalList,
665 );
666 assert!(field.is_optional());
667 assert!(field.is_list());
668 }
669
670 #[test]
673 fn test_field_has_attribute_true() {
674 let mut field = make_field(
675 "id",
676 FieldType::Scalar(ScalarType::Int),
677 TypeModifier::Required,
678 );
679 field.attributes.push(make_attribute("id"));
680 field.attributes.push(make_attribute("auto"));
681
682 assert!(field.has_attribute("id"));
683 assert!(field.has_attribute("auto"));
684 }
685
686 #[test]
687 fn test_field_has_attribute_false() {
688 let field = make_field(
689 "name",
690 FieldType::Scalar(ScalarType::String),
691 TypeModifier::Required,
692 );
693 assert!(!field.has_attribute("unique"));
694 }
695
696 #[test]
697 fn test_field_get_attribute() {
698 let mut field = make_field(
699 "email",
700 FieldType::Scalar(ScalarType::String),
701 TypeModifier::Required,
702 );
703 field.attributes.push(make_attribute("unique"));
704
705 let attr = field.get_attribute("unique");
706 assert!(attr.is_some());
707 assert!(attr.unwrap().is("unique"));
708
709 assert!(field.get_attribute("id").is_none());
710 }
711
712 #[test]
713 fn test_field_is_id_true() {
714 let mut field = make_field(
715 "id",
716 FieldType::Scalar(ScalarType::Int),
717 TypeModifier::Required,
718 );
719 field.attributes.push(make_attribute("id"));
720 assert!(field.is_id());
721 }
722
723 #[test]
724 fn test_field_is_id_false() {
725 let field = make_field(
726 "email",
727 FieldType::Scalar(ScalarType::String),
728 TypeModifier::Required,
729 );
730 assert!(!field.is_id());
731 }
732
733 #[test]
734 fn test_field_is_unique_true() {
735 let mut field = make_field(
736 "email",
737 FieldType::Scalar(ScalarType::String),
738 TypeModifier::Required,
739 );
740 field.attributes.push(make_attribute("unique"));
741 assert!(field.is_unique());
742 }
743
744 #[test]
745 fn test_field_is_unique_false() {
746 let field = make_field(
747 "name",
748 FieldType::Scalar(ScalarType::String),
749 TypeModifier::Required,
750 );
751 assert!(!field.is_unique());
752 }
753
754 #[test]
757 fn test_field_is_relation_by_type() {
758 let field = make_field(
759 "author",
760 FieldType::Model("User".into()),
761 TypeModifier::Required,
762 );
763 assert!(field.is_relation());
764 }
765
766 #[test]
767 fn test_field_is_relation_by_attribute() {
768 let mut field = make_field(
769 "author_id",
770 FieldType::Scalar(ScalarType::Int),
771 TypeModifier::Required,
772 );
773 field.attributes.push(make_attribute("relation"));
774 assert!(field.is_relation());
775 }
776
777 #[test]
778 fn test_field_is_relation_list() {
779 let field = make_field("posts", FieldType::Model("Post".into()), TypeModifier::List);
780 assert!(field.is_relation());
781 assert!(field.is_list());
782 }
783
784 #[test]
787 fn test_extract_attributes_empty() {
788 let field = make_field(
789 "name",
790 FieldType::Scalar(ScalarType::String),
791 TypeModifier::Required,
792 );
793 let attrs = field.extract_attributes();
794
795 assert!(!attrs.is_id);
796 assert!(!attrs.is_auto);
797 assert!(!attrs.is_unique);
798 assert!(!attrs.is_indexed);
799 assert!(!attrs.is_updated_at);
800 assert!(!attrs.is_omit);
801 assert!(attrs.default.is_none());
802 assert!(attrs.map.is_none());
803 assert!(attrs.native_type.is_none());
804 assert!(attrs.relation.is_none());
805 }
806
807 #[test]
808 fn test_extract_attributes_id_and_auto() {
809 let mut field = make_field(
810 "id",
811 FieldType::Scalar(ScalarType::Int),
812 TypeModifier::Required,
813 );
814 field.attributes.push(make_attribute("id"));
815 field.attributes.push(make_attribute("auto"));
816
817 let attrs = field.extract_attributes();
818 assert!(attrs.is_id);
819 assert!(attrs.is_auto);
820 }
821
822 #[test]
823 fn test_extract_attributes_unique() {
824 let mut field = make_field(
825 "email",
826 FieldType::Scalar(ScalarType::String),
827 TypeModifier::Required,
828 );
829 field.attributes.push(make_attribute("unique"));
830
831 let attrs = field.extract_attributes();
832 assert!(attrs.is_unique);
833 }
834
835 #[test]
836 fn test_extract_attributes_index() {
837 let mut field = make_field(
838 "name",
839 FieldType::Scalar(ScalarType::String),
840 TypeModifier::Required,
841 );
842 field.attributes.push(make_attribute("index"));
843
844 let attrs = field.extract_attributes();
845 assert!(attrs.is_indexed);
846 }
847
848 #[test]
849 fn test_extract_attributes_updated_at() {
850 let mut field = make_field(
851 "updated_at",
852 FieldType::Scalar(ScalarType::DateTime),
853 TypeModifier::Required,
854 );
855 field.attributes.push(make_attribute("updated_at"));
856
857 let attrs = field.extract_attributes();
858 assert!(attrs.is_updated_at);
859 }
860
861 #[test]
862 fn test_extract_attributes_omit() {
863 let mut field = make_field(
864 "password_hash",
865 FieldType::Scalar(ScalarType::String),
866 TypeModifier::Required,
867 );
868 field.attributes.push(make_attribute("omit"));
869
870 let attrs = field.extract_attributes();
871 assert!(attrs.is_omit);
872 }
873
874 #[test]
875 fn test_extract_attributes_default_int() {
876 let mut field = make_field(
877 "count",
878 FieldType::Scalar(ScalarType::Int),
879 TypeModifier::Required,
880 );
881 field
882 .attributes
883 .push(make_attribute_with_arg("default", AttributeValue::Int(0)));
884
885 let attrs = field.extract_attributes();
886 assert!(attrs.default.is_some());
887 assert_eq!(attrs.default.as_ref().unwrap().as_int(), Some(0));
888 }
889
890 #[test]
891 fn test_extract_attributes_default_function() {
892 let mut field = make_field(
893 "created_at",
894 FieldType::Scalar(ScalarType::DateTime),
895 TypeModifier::Required,
896 );
897 field.attributes.push(make_attribute_with_arg(
898 "default",
899 AttributeValue::Function("now".into(), vec![]),
900 ));
901
902 let attrs = field.extract_attributes();
903 assert!(attrs.default.is_some());
904 if let AttributeValue::Function(name, _) = attrs.default.as_ref().unwrap() {
905 assert_eq!(name.as_str(), "now");
906 } else {
907 panic!("Expected Function");
908 }
909 }
910
911 #[test]
912 fn test_extract_attributes_map() {
913 let mut field = make_field(
914 "email",
915 FieldType::Scalar(ScalarType::String),
916 TypeModifier::Required,
917 );
918 field.attributes.push(make_attribute_with_arg(
919 "map",
920 AttributeValue::String("email_address".into()),
921 ));
922
923 let attrs = field.extract_attributes();
924 assert_eq!(attrs.map, Some("email_address".to_string()));
925 }
926
927 #[test]
928 fn test_extract_attributes_native_type_ident() {
929 let mut field = make_field(
930 "data",
931 FieldType::Scalar(ScalarType::String),
932 TypeModifier::Required,
933 );
934 field.attributes.push(make_attribute_with_arg(
935 "db",
936 AttributeValue::Ident("Text".into()),
937 ));
938
939 let attrs = field.extract_attributes();
940 assert!(attrs.native_type.is_some());
941 let nt = attrs.native_type.unwrap();
942 assert_eq!(nt.name.as_str(), "Text");
943 assert!(nt.args.is_empty());
944 }
945
946 #[test]
947 fn test_extract_attributes_native_type_function() {
948 let mut field = make_field(
949 "name",
950 FieldType::Scalar(ScalarType::String),
951 TypeModifier::Required,
952 );
953 field.attributes.push(make_attribute_with_arg(
954 "db",
955 AttributeValue::Function("VarChar".into(), vec![AttributeValue::Int(255)]),
956 ));
957
958 let attrs = field.extract_attributes();
959 assert!(attrs.native_type.is_some());
960 let nt = attrs.native_type.unwrap();
961 assert_eq!(nt.name.as_str(), "VarChar");
962 assert_eq!(nt.args.len(), 1);
963 }
964
965 #[test]
966 fn test_extract_attributes_relation() {
967 let mut field = make_field(
968 "author",
969 FieldType::Model("User".into()),
970 TypeModifier::Required,
971 );
972 field.attributes.push(Attribute::new(
973 Ident::new("relation", make_span()),
974 vec![
975 AttributeArg::named(
976 Ident::new("fields", make_span()),
977 AttributeValue::FieldRefList(vec!["author_id".into()]),
978 make_span(),
979 ),
980 AttributeArg::named(
981 Ident::new("references", make_span()),
982 AttributeValue::FieldRefList(vec!["id".into()]),
983 make_span(),
984 ),
985 AttributeArg::named(
986 Ident::new("onDelete", make_span()),
987 AttributeValue::Ident("Cascade".into()),
988 make_span(),
989 ),
990 AttributeArg::named(
991 Ident::new("onUpdate", make_span()),
992 AttributeValue::Ident("Restrict".into()),
993 make_span(),
994 ),
995 ],
996 make_span(),
997 ));
998
999 let attrs = field.extract_attributes();
1000 assert!(attrs.relation.is_some());
1001
1002 let rel = attrs.relation.unwrap();
1003 assert_eq!(rel.fields, vec!["author_id".to_string()]);
1004 assert_eq!(rel.references, vec!["id".to_string()]);
1005 assert_eq!(rel.on_delete, Some(ReferentialAction::Cascade));
1006 assert_eq!(rel.on_update, Some(ReferentialAction::Restrict));
1007 }
1008
1009 #[test]
1010 fn test_extract_attributes_relation_with_name() {
1011 let mut field = make_field(
1012 "author",
1013 FieldType::Model("User".into()),
1014 TypeModifier::Required,
1015 );
1016 field.attributes.push(Attribute::new(
1017 Ident::new("relation", make_span()),
1018 vec![AttributeArg::positional(
1019 AttributeValue::String("PostAuthor".into()),
1020 make_span(),
1021 )],
1022 make_span(),
1023 ));
1024
1025 let attrs = field.extract_attributes();
1026 assert!(attrs.relation.is_some());
1027 assert_eq!(attrs.relation.unwrap().name, Some("PostAuthor".to_string()));
1028 }
1029
1030 #[test]
1033 fn test_field_display_required() {
1034 let field = make_field(
1035 "id",
1036 FieldType::Scalar(ScalarType::Int),
1037 TypeModifier::Required,
1038 );
1039 assert_eq!(format!("{}", field), "id Int");
1040 }
1041
1042 #[test]
1043 fn test_field_display_optional() {
1044 let field = make_field(
1045 "bio",
1046 FieldType::Scalar(ScalarType::String),
1047 TypeModifier::Optional,
1048 );
1049 assert_eq!(format!("{}", field), "bio String?");
1050 }
1051
1052 #[test]
1053 fn test_field_display_list() {
1054 let field = make_field(
1055 "tags",
1056 FieldType::Scalar(ScalarType::String),
1057 TypeModifier::List,
1058 );
1059 assert_eq!(format!("{}", field), "tags String[]");
1060 }
1061
1062 #[test]
1063 fn test_field_display_optional_list() {
1064 let field = make_field(
1065 "data",
1066 FieldType::Scalar(ScalarType::Json),
1067 TypeModifier::OptionalList,
1068 );
1069 assert_eq!(format!("{}", field), "data Json[]?");
1070 }
1071
1072 #[test]
1073 fn test_field_display_with_simple_attribute() {
1074 let mut field = make_field(
1075 "id",
1076 FieldType::Scalar(ScalarType::Int),
1077 TypeModifier::Required,
1078 );
1079 field.attributes.push(make_attribute("id"));
1080 assert!(format!("{}", field).contains("@id"));
1081 }
1082
1083 #[test]
1084 fn test_field_display_with_attribute_args() {
1085 let mut field = make_field(
1086 "count",
1087 FieldType::Scalar(ScalarType::Int),
1088 TypeModifier::Required,
1089 );
1090 field
1091 .attributes
1092 .push(make_attribute_with_arg("default", AttributeValue::Int(0)));
1093 assert!(format!("{}", field).contains("@default(...)"));
1094 }
1095
1096 #[test]
1097 fn test_field_display_relation() {
1098 let field = make_field(
1099 "author",
1100 FieldType::Model("User".into()),
1101 TypeModifier::Required,
1102 );
1103 assert_eq!(format!("{}", field), "author User");
1104 }
1105
1106 #[test]
1107 fn test_field_display_enum() {
1108 let field = make_field(
1109 "role",
1110 FieldType::Enum("Role".into()),
1111 TypeModifier::Required,
1112 );
1113 assert_eq!(format!("{}", field), "role Role");
1114 }
1115
1116 #[test]
1119 fn test_field_equality() {
1120 let field1 = make_field(
1121 "id",
1122 FieldType::Scalar(ScalarType::Int),
1123 TypeModifier::Required,
1124 );
1125 let field2 = make_field(
1126 "id",
1127 FieldType::Scalar(ScalarType::Int),
1128 TypeModifier::Required,
1129 );
1130 assert_eq!(field1, field2);
1131 }
1132
1133 #[test]
1134 fn test_field_inequality_name() {
1135 let field1 = make_field(
1136 "id",
1137 FieldType::Scalar(ScalarType::Int),
1138 TypeModifier::Required,
1139 );
1140 let field2 = make_field(
1141 "user_id",
1142 FieldType::Scalar(ScalarType::Int),
1143 TypeModifier::Required,
1144 );
1145 assert_ne!(field1, field2);
1146 }
1147
1148 #[test]
1149 fn test_field_inequality_type() {
1150 let field1 = make_field(
1151 "id",
1152 FieldType::Scalar(ScalarType::Int),
1153 TypeModifier::Required,
1154 );
1155 let field2 = make_field(
1156 "id",
1157 FieldType::Scalar(ScalarType::String),
1158 TypeModifier::Required,
1159 );
1160 assert_ne!(field1, field2);
1161 }
1162
1163 #[test]
1164 fn test_field_inequality_modifier() {
1165 let field1 = make_field(
1166 "name",
1167 FieldType::Scalar(ScalarType::String),
1168 TypeModifier::Required,
1169 );
1170 let field2 = make_field(
1171 "name",
1172 FieldType::Scalar(ScalarType::String),
1173 TypeModifier::Optional,
1174 );
1175 assert_ne!(field1, field2);
1176 }
1177
1178 #[test]
1181 fn test_field_with_validation() {
1182 let validation = FieldValidation::new();
1183 let field = make_field(
1184 "email",
1185 FieldType::Scalar(ScalarType::String),
1186 TypeModifier::Required,
1187 )
1188 .with_validation(validation);
1189
1190 assert!(!field.has_validation());
1191 }
1192
1193 #[test]
1194 fn test_field_add_validation_rule() {
1195 let mut field = make_field(
1196 "email",
1197 FieldType::Scalar(ScalarType::String),
1198 TypeModifier::Required,
1199 );
1200
1201 field.add_validation_rule(ValidationRule::new(ValidationType::Email, make_span()));
1202 assert!(field.has_validation());
1203 assert_eq!(field.validation_rules().len(), 1);
1204 }
1205
1206 #[test]
1207 fn test_field_validation_required() {
1208 let mut field = make_field(
1209 "name",
1210 FieldType::Scalar(ScalarType::String),
1211 TypeModifier::Optional,
1212 );
1213
1214 assert!(!field.is_validated_required());
1215 field.add_validation_rule(ValidationRule::new(ValidationType::Required, make_span()));
1216 assert!(field.is_validated_required());
1217 }
1218
1219 #[test]
1220 fn test_extract_validation_email() {
1221 let mut field = make_field(
1222 "email",
1223 FieldType::Scalar(ScalarType::String),
1224 TypeModifier::Required,
1225 );
1226 field.attributes.push(Attribute::simple(
1227 Ident::new("validate.email", make_span()),
1228 make_span(),
1229 ));
1230
1231 field.extract_validation_from_attributes();
1232 assert!(field.has_validation());
1233 assert_eq!(field.validation_rules().len(), 1);
1234 }
1235
1236 #[test]
1237 fn test_extract_validation_url() {
1238 let mut field = make_field(
1239 "website",
1240 FieldType::Scalar(ScalarType::String),
1241 TypeModifier::Optional,
1242 );
1243 field.attributes.push(Attribute::simple(
1244 Ident::new("validate.url", make_span()),
1245 make_span(),
1246 ));
1247
1248 field.extract_validation_from_attributes();
1249 assert!(field.has_validation());
1250 }
1251
1252 #[test]
1253 fn test_extract_validation_uuid() {
1254 let mut field = make_field(
1255 "id",
1256 FieldType::Scalar(ScalarType::String),
1257 TypeModifier::Required,
1258 );
1259 field.attributes.push(Attribute::simple(
1260 Ident::new("validate.uuid", make_span()),
1261 make_span(),
1262 ));
1263
1264 field.extract_validation_from_attributes();
1265 assert!(field.has_validation());
1266 }
1267
1268 #[test]
1269 fn test_extract_validation_min_length() {
1270 let mut field = make_field(
1271 "name",
1272 FieldType::Scalar(ScalarType::String),
1273 TypeModifier::Required,
1274 );
1275 field.attributes.push(Attribute::new(
1276 Ident::new("validate.minLength", make_span()),
1277 vec![AttributeArg::positional(
1278 AttributeValue::Int(3),
1279 make_span(),
1280 )],
1281 make_span(),
1282 ));
1283
1284 field.extract_validation_from_attributes();
1285 assert!(field.has_validation());
1286 }
1287
1288 #[test]
1289 fn test_extract_validation_max_length() {
1290 let mut field = make_field(
1291 "bio",
1292 FieldType::Scalar(ScalarType::String),
1293 TypeModifier::Optional,
1294 );
1295 field.attributes.push(Attribute::new(
1296 Ident::new("validate.maxLength", make_span()),
1297 vec![AttributeArg::positional(
1298 AttributeValue::Int(500),
1299 make_span(),
1300 )],
1301 make_span(),
1302 ));
1303
1304 field.extract_validation_from_attributes();
1305 assert!(field.has_validation());
1306 }
1307
1308 #[test]
1309 fn test_extract_validation_min() {
1310 let mut field = make_field(
1311 "age",
1312 FieldType::Scalar(ScalarType::Int),
1313 TypeModifier::Required,
1314 );
1315 field.attributes.push(Attribute::new(
1316 Ident::new("validate.min", make_span()),
1317 vec![AttributeArg::positional(
1318 AttributeValue::Int(0),
1319 make_span(),
1320 )],
1321 make_span(),
1322 ));
1323
1324 field.extract_validation_from_attributes();
1325 assert!(field.has_validation());
1326 }
1327
1328 #[test]
1329 fn test_extract_validation_max() {
1330 let mut field = make_field(
1331 "percentage",
1332 FieldType::Scalar(ScalarType::Float),
1333 TypeModifier::Required,
1334 );
1335 field.attributes.push(Attribute::new(
1336 Ident::new("validate.max", make_span()),
1337 vec![AttributeArg::positional(
1338 AttributeValue::Float(100.0),
1339 make_span(),
1340 )],
1341 make_span(),
1342 ));
1343
1344 field.extract_validation_from_attributes();
1345 assert!(field.has_validation());
1346 }
1347
1348 #[test]
1349 fn test_extract_validation_range() {
1350 let mut field = make_field(
1351 "rating",
1352 FieldType::Scalar(ScalarType::Int),
1353 TypeModifier::Required,
1354 );
1355 field.attributes.push(Attribute::new(
1356 Ident::new("validate.range", make_span()),
1357 vec![
1358 AttributeArg::positional(AttributeValue::Int(1), make_span()),
1359 AttributeArg::positional(AttributeValue::Int(5), make_span()),
1360 ],
1361 make_span(),
1362 ));
1363
1364 field.extract_validation_from_attributes();
1365 assert!(field.has_validation());
1366 }
1367
1368 #[test]
1369 fn test_extract_validation_regex() {
1370 let mut field = make_field(
1371 "phone",
1372 FieldType::Scalar(ScalarType::String),
1373 TypeModifier::Required,
1374 );
1375 field.attributes.push(Attribute::new(
1376 Ident::new("validate.regex", make_span()),
1377 vec![AttributeArg::positional(
1378 AttributeValue::String("^\\+[0-9]+$".into()),
1379 make_span(),
1380 )],
1381 make_span(),
1382 ));
1383
1384 field.extract_validation_from_attributes();
1385 assert!(field.has_validation());
1386 }
1387
1388 #[test]
1389 fn test_extract_validation_positive() {
1390 let mut field = make_field(
1391 "amount",
1392 FieldType::Scalar(ScalarType::Float),
1393 TypeModifier::Required,
1394 );
1395 field.attributes.push(Attribute::simple(
1396 Ident::new("validate.positive", make_span()),
1397 make_span(),
1398 ));
1399
1400 field.extract_validation_from_attributes();
1401 assert!(field.has_validation());
1402 }
1403
1404 #[test]
1405 fn test_extract_validation_negative() {
1406 let mut field = make_field(
1407 "debt",
1408 FieldType::Scalar(ScalarType::Float),
1409 TypeModifier::Required,
1410 );
1411 field.attributes.push(Attribute::simple(
1412 Ident::new("validate.negative", make_span()),
1413 make_span(),
1414 ));
1415
1416 field.extract_validation_from_attributes();
1417 assert!(field.has_validation());
1418 }
1419
1420 #[test]
1421 fn test_extract_validation_nonNegative() {
1422 let mut field = make_field(
1423 "count",
1424 FieldType::Scalar(ScalarType::Int),
1425 TypeModifier::Required,
1426 );
1427 field.attributes.push(Attribute::simple(
1428 Ident::new("validate.nonNegative", make_span()),
1429 make_span(),
1430 ));
1431
1432 field.extract_validation_from_attributes();
1433 assert!(field.has_validation());
1434 }
1435
1436 #[test]
1437 fn test_extract_validation_alpha() {
1438 let mut field = make_field(
1439 "code",
1440 FieldType::Scalar(ScalarType::String),
1441 TypeModifier::Required,
1442 );
1443 field.attributes.push(Attribute::simple(
1444 Ident::new("validate.alpha", make_span()),
1445 make_span(),
1446 ));
1447
1448 field.extract_validation_from_attributes();
1449 assert!(field.has_validation());
1450 }
1451
1452 #[test]
1453 fn test_extract_validation_alphanumeric() {
1454 let mut field = make_field(
1455 "username",
1456 FieldType::Scalar(ScalarType::String),
1457 TypeModifier::Required,
1458 );
1459 field.attributes.push(Attribute::simple(
1460 Ident::new("validate.alphanumeric", make_span()),
1461 make_span(),
1462 ));
1463
1464 field.extract_validation_from_attributes();
1465 assert!(field.has_validation());
1466 }
1467
1468 #[test]
1469 fn test_extract_validation_lowercase() {
1470 let mut field = make_field(
1471 "slug",
1472 FieldType::Scalar(ScalarType::String),
1473 TypeModifier::Required,
1474 );
1475 field.attributes.push(Attribute::simple(
1476 Ident::new("validate.lowercase", make_span()),
1477 make_span(),
1478 ));
1479
1480 field.extract_validation_from_attributes();
1481 assert!(field.has_validation());
1482 }
1483
1484 #[test]
1485 fn test_extract_validation_uppercase() {
1486 let mut field = make_field(
1487 "country_code",
1488 FieldType::Scalar(ScalarType::String),
1489 TypeModifier::Required,
1490 );
1491 field.attributes.push(Attribute::simple(
1492 Ident::new("validate.uppercase", make_span()),
1493 make_span(),
1494 ));
1495
1496 field.extract_validation_from_attributes();
1497 assert!(field.has_validation());
1498 }
1499
1500 #[test]
1501 fn test_extract_validation_trim() {
1502 let mut field = make_field(
1503 "input",
1504 FieldType::Scalar(ScalarType::String),
1505 TypeModifier::Required,
1506 );
1507 field.attributes.push(Attribute::simple(
1508 Ident::new("validate.trim", make_span()),
1509 make_span(),
1510 ));
1511
1512 field.extract_validation_from_attributes();
1513 assert!(field.has_validation());
1514 }
1515
1516 #[test]
1517 fn test_extract_validation_ip() {
1518 let mut field = make_field(
1519 "ip_address",
1520 FieldType::Scalar(ScalarType::String),
1521 TypeModifier::Required,
1522 );
1523 field.attributes.push(Attribute::simple(
1524 Ident::new("validate.ip", make_span()),
1525 make_span(),
1526 ));
1527
1528 field.extract_validation_from_attributes();
1529 assert!(field.has_validation());
1530 }
1531
1532 #[test]
1533 fn test_extract_validation_ipv4() {
1534 let mut field = make_field(
1535 "ipv4",
1536 FieldType::Scalar(ScalarType::String),
1537 TypeModifier::Required,
1538 );
1539 field.attributes.push(Attribute::simple(
1540 Ident::new("validate.ipv4", make_span()),
1541 make_span(),
1542 ));
1543
1544 field.extract_validation_from_attributes();
1545 assert!(field.has_validation());
1546 }
1547
1548 #[test]
1549 fn test_extract_validation_ipv6() {
1550 let mut field = make_field(
1551 "ipv6",
1552 FieldType::Scalar(ScalarType::String),
1553 TypeModifier::Required,
1554 );
1555 field.attributes.push(Attribute::simple(
1556 Ident::new("validate.ipv6", make_span()),
1557 make_span(),
1558 ));
1559
1560 field.extract_validation_from_attributes();
1561 assert!(field.has_validation());
1562 }
1563
1564 #[test]
1565 fn test_extract_validation_slug() {
1566 let mut field = make_field(
1567 "url_slug",
1568 FieldType::Scalar(ScalarType::String),
1569 TypeModifier::Required,
1570 );
1571 field.attributes.push(Attribute::simple(
1572 Ident::new("validate.slug", make_span()),
1573 make_span(),
1574 ));
1575
1576 field.extract_validation_from_attributes();
1577 assert!(field.has_validation());
1578 }
1579
1580 #[test]
1581 fn test_extract_validation_hex() {
1582 let mut field = make_field(
1583 "color",
1584 FieldType::Scalar(ScalarType::String),
1585 TypeModifier::Required,
1586 );
1587 field.attributes.push(Attribute::simple(
1588 Ident::new("validate.hex", make_span()),
1589 make_span(),
1590 ));
1591
1592 field.extract_validation_from_attributes();
1593 assert!(field.has_validation());
1594 }
1595
1596 #[test]
1597 fn test_extract_validation_base64() {
1598 let mut field = make_field(
1599 "encoded",
1600 FieldType::Scalar(ScalarType::String),
1601 TypeModifier::Required,
1602 );
1603 field.attributes.push(Attribute::simple(
1604 Ident::new("validate.base64", make_span()),
1605 make_span(),
1606 ));
1607
1608 field.extract_validation_from_attributes();
1609 assert!(field.has_validation());
1610 }
1611
1612 #[test]
1613 fn test_extract_validation_json() {
1614 let mut field = make_field(
1615 "json_str",
1616 FieldType::Scalar(ScalarType::String),
1617 TypeModifier::Required,
1618 );
1619 field.attributes.push(Attribute::simple(
1620 Ident::new("validate.json", make_span()),
1621 make_span(),
1622 ));
1623
1624 field.extract_validation_from_attributes();
1625 assert!(field.has_validation());
1626 }
1627
1628 #[test]
1629 fn test_extract_validation_integer() {
1630 let mut field = make_field(
1631 "whole",
1632 FieldType::Scalar(ScalarType::Float),
1633 TypeModifier::Required,
1634 );
1635 field.attributes.push(Attribute::simple(
1636 Ident::new("validate.integer", make_span()),
1637 make_span(),
1638 ));
1639
1640 field.extract_validation_from_attributes();
1641 assert!(field.has_validation());
1642 }
1643
1644 #[test]
1645 fn test_extract_validation_finite() {
1646 let mut field = make_field(
1647 "value",
1648 FieldType::Scalar(ScalarType::Float),
1649 TypeModifier::Required,
1650 );
1651 field.attributes.push(Attribute::simple(
1652 Ident::new("validate.finite", make_span()),
1653 make_span(),
1654 ));
1655
1656 field.extract_validation_from_attributes();
1657 assert!(field.has_validation());
1658 }
1659
1660 #[test]
1661 fn test_extract_validation_unique_array() {
1662 let mut field = make_field(
1663 "tags",
1664 FieldType::Scalar(ScalarType::String),
1665 TypeModifier::List,
1666 );
1667 field.attributes.push(Attribute::simple(
1668 Ident::new("validate.unique", make_span()),
1669 make_span(),
1670 ));
1671
1672 field.extract_validation_from_attributes();
1673 assert!(field.has_validation());
1674 }
1675
1676 #[test]
1677 fn test_extract_validation_nonEmpty() {
1678 let mut field = make_field(
1679 "required_tags",
1680 FieldType::Scalar(ScalarType::String),
1681 TypeModifier::List,
1682 );
1683 field.attributes.push(Attribute::simple(
1684 Ident::new("validate.nonEmpty", make_span()),
1685 make_span(),
1686 ));
1687
1688 field.extract_validation_from_attributes();
1689 assert!(field.has_validation());
1690 }
1691
1692 #[test]
1693 fn test_extract_validation_past() {
1694 let mut field = make_field(
1695 "birth_date",
1696 FieldType::Scalar(ScalarType::DateTime),
1697 TypeModifier::Required,
1698 );
1699 field.attributes.push(Attribute::simple(
1700 Ident::new("validate.past", make_span()),
1701 make_span(),
1702 ));
1703
1704 field.extract_validation_from_attributes();
1705 assert!(field.has_validation());
1706 }
1707
1708 #[test]
1709 fn test_extract_validation_future() {
1710 let mut field = make_field(
1711 "expiry_date",
1712 FieldType::Scalar(ScalarType::DateTime),
1713 TypeModifier::Required,
1714 );
1715 field.attributes.push(Attribute::simple(
1716 Ident::new("validate.future", make_span()),
1717 make_span(),
1718 ));
1719
1720 field.extract_validation_from_attributes();
1721 assert!(field.has_validation());
1722 }
1723
1724 #[test]
1725 fn test_extract_validation_min_items() {
1726 let mut field = make_field(
1727 "items",
1728 FieldType::Scalar(ScalarType::String),
1729 TypeModifier::List,
1730 );
1731 field.attributes.push(Attribute::new(
1732 Ident::new("validate.minItems", make_span()),
1733 vec![AttributeArg::positional(
1734 AttributeValue::Int(1),
1735 make_span(),
1736 )],
1737 make_span(),
1738 ));
1739
1740 field.extract_validation_from_attributes();
1741 assert!(field.has_validation());
1742 }
1743
1744 #[test]
1745 fn test_extract_validation_max_items() {
1746 let mut field = make_field(
1747 "items",
1748 FieldType::Scalar(ScalarType::String),
1749 TypeModifier::List,
1750 );
1751 field.attributes.push(Attribute::new(
1752 Ident::new("validate.maxItems", make_span()),
1753 vec![AttributeArg::positional(
1754 AttributeValue::Int(10),
1755 make_span(),
1756 )],
1757 make_span(),
1758 ));
1759
1760 field.extract_validation_from_attributes();
1761 assert!(field.has_validation());
1762 }
1763
1764 #[test]
1765 fn test_extract_validation_multiple_of() {
1766 let mut field = make_field(
1767 "amount",
1768 FieldType::Scalar(ScalarType::Float),
1769 TypeModifier::Required,
1770 );
1771 field.attributes.push(Attribute::new(
1772 Ident::new("validate.multipleOf", make_span()),
1773 vec![AttributeArg::positional(
1774 AttributeValue::Float(0.01),
1775 make_span(),
1776 )],
1777 make_span(),
1778 ));
1779
1780 field.extract_validation_from_attributes();
1781 assert!(field.has_validation());
1782 }
1783
1784 #[test]
1785 fn test_extract_validation_starts_with() {
1786 let mut field = make_field(
1787 "prefix_field",
1788 FieldType::Scalar(ScalarType::String),
1789 TypeModifier::Required,
1790 );
1791 field.attributes.push(Attribute::new(
1792 Ident::new("validate.startsWith", make_span()),
1793 vec![AttributeArg::positional(
1794 AttributeValue::String("PREFIX_".into()),
1795 make_span(),
1796 )],
1797 make_span(),
1798 ));
1799
1800 field.extract_validation_from_attributes();
1801 assert!(field.has_validation());
1802 }
1803
1804 #[test]
1805 fn test_extract_validation_ends_with() {
1806 let mut field = make_field(
1807 "suffix_field",
1808 FieldType::Scalar(ScalarType::String),
1809 TypeModifier::Required,
1810 );
1811 field.attributes.push(Attribute::new(
1812 Ident::new("validate.endsWith", make_span()),
1813 vec![AttributeArg::positional(
1814 AttributeValue::String(".json".into()),
1815 make_span(),
1816 )],
1817 make_span(),
1818 ));
1819
1820 field.extract_validation_from_attributes();
1821 assert!(field.has_validation());
1822 }
1823
1824 #[test]
1825 fn test_extract_validation_contains() {
1826 let mut field = make_field(
1827 "text",
1828 FieldType::Scalar(ScalarType::String),
1829 TypeModifier::Required,
1830 );
1831 field.attributes.push(Attribute::new(
1832 Ident::new("validate.contains", make_span()),
1833 vec![AttributeArg::positional(
1834 AttributeValue::String("keyword".into()),
1835 make_span(),
1836 )],
1837 make_span(),
1838 ));
1839
1840 field.extract_validation_from_attributes();
1841 assert!(field.has_validation());
1842 }
1843
1844 #[test]
1845 fn test_extract_validation_after() {
1846 let mut field = make_field(
1847 "start_date",
1848 FieldType::Scalar(ScalarType::DateTime),
1849 TypeModifier::Required,
1850 );
1851 field.attributes.push(Attribute::new(
1852 Ident::new("validate.after", make_span()),
1853 vec![AttributeArg::positional(
1854 AttributeValue::String("2024-01-01".into()),
1855 make_span(),
1856 )],
1857 make_span(),
1858 ));
1859
1860 field.extract_validation_from_attributes();
1861 assert!(field.has_validation());
1862 }
1863
1864 #[test]
1865 fn test_extract_validation_before() {
1866 let mut field = make_field(
1867 "end_date",
1868 FieldType::Scalar(ScalarType::DateTime),
1869 TypeModifier::Required,
1870 );
1871 field.attributes.push(Attribute::new(
1872 Ident::new("validate.before", make_span()),
1873 vec![AttributeArg::positional(
1874 AttributeValue::String("2025-12-31".into()),
1875 make_span(),
1876 )],
1877 make_span(),
1878 ));
1879
1880 field.extract_validation_from_attributes();
1881 assert!(field.has_validation());
1882 }
1883
1884 #[test]
1885 fn test_extract_validation_custom() {
1886 let mut field = make_field(
1887 "password",
1888 FieldType::Scalar(ScalarType::String),
1889 TypeModifier::Required,
1890 );
1891 field.attributes.push(Attribute::new(
1892 Ident::new("validate.custom", make_span()),
1893 vec![AttributeArg::positional(
1894 AttributeValue::String("strongPassword".into()),
1895 make_span(),
1896 )],
1897 make_span(),
1898 ));
1899
1900 field.extract_validation_from_attributes();
1901 assert!(field.has_validation());
1902 }
1903
1904 #[test]
1905 fn test_extract_validation_length() {
1906 let mut field = make_field(
1907 "bio",
1908 FieldType::Scalar(ScalarType::String),
1909 TypeModifier::Required,
1910 );
1911 field.attributes.push(Attribute::new(
1912 Ident::new("validate.length", make_span()),
1913 vec![
1914 AttributeArg::positional(AttributeValue::Int(10), make_span()),
1915 AttributeArg::positional(AttributeValue::Int(500), make_span()),
1916 ],
1917 make_span(),
1918 ));
1919
1920 field.extract_validation_from_attributes();
1921 assert!(field.has_validation());
1922 }
1923
1924 #[test]
1925 fn test_extract_validation_cuid() {
1926 let mut field = make_field(
1927 "cuid_field",
1928 FieldType::Scalar(ScalarType::String),
1929 TypeModifier::Required,
1930 );
1931 field.attributes.push(Attribute::simple(
1932 Ident::new("validate.cuid", make_span()),
1933 make_span(),
1934 ));
1935
1936 field.extract_validation_from_attributes();
1937 assert!(field.has_validation());
1938 }
1939
1940 #[test]
1941 fn test_extract_validation_cuid2() {
1942 let mut field = make_field(
1943 "cuid2_field",
1944 FieldType::Scalar(ScalarType::String),
1945 TypeModifier::Required,
1946 );
1947 field.attributes.push(Attribute::simple(
1948 Ident::new("validate.cuid2", make_span()),
1949 make_span(),
1950 ));
1951
1952 field.extract_validation_from_attributes();
1953 assert!(field.has_validation());
1954 }
1955
1956 #[test]
1957 fn test_extract_validation_nanoid() {
1958 let mut field = make_field(
1959 "nanoid_field",
1960 FieldType::Scalar(ScalarType::String),
1961 TypeModifier::Required,
1962 );
1963 field.attributes.push(Attribute::simple(
1964 Ident::new("validate.nanoid", make_span()),
1965 make_span(),
1966 ));
1967
1968 field.extract_validation_from_attributes();
1969 assert!(field.has_validation());
1970 }
1971
1972 #[test]
1973 fn test_extract_validation_ulid() {
1974 let mut field = make_field(
1975 "ulid_field",
1976 FieldType::Scalar(ScalarType::String),
1977 TypeModifier::Required,
1978 );
1979 field.attributes.push(Attribute::simple(
1980 Ident::new("validate.ulid", make_span()),
1981 make_span(),
1982 ));
1983
1984 field.extract_validation_from_attributes();
1985 assert!(field.has_validation());
1986 }
1987
1988 #[test]
1989 fn test_extract_validation_noWhitespace() {
1990 let mut field = make_field(
1991 "username",
1992 FieldType::Scalar(ScalarType::String),
1993 TypeModifier::Required,
1994 );
1995 field.attributes.push(Attribute::simple(
1996 Ident::new("validate.noWhitespace", make_span()),
1997 make_span(),
1998 ));
1999
2000 field.extract_validation_from_attributes();
2001 assert!(field.has_validation());
2002 }
2003
2004 #[test]
2005 fn test_extract_validation_creditCard() {
2006 let mut field = make_field(
2007 "card_number",
2008 FieldType::Scalar(ScalarType::String),
2009 TypeModifier::Required,
2010 );
2011 field.attributes.push(Attribute::simple(
2012 Ident::new("validate.creditCard", make_span()),
2013 make_span(),
2014 ));
2015
2016 field.extract_validation_from_attributes();
2017 assert!(field.has_validation());
2018 }
2019
2020 #[test]
2021 fn test_extract_validation_phone() {
2022 let mut field = make_field(
2023 "phone_number",
2024 FieldType::Scalar(ScalarType::String),
2025 TypeModifier::Required,
2026 );
2027 field.attributes.push(Attribute::simple(
2028 Ident::new("validate.phone", make_span()),
2029 make_span(),
2030 ));
2031
2032 field.extract_validation_from_attributes();
2033 assert!(field.has_validation());
2034 }
2035
2036 #[test]
2037 fn test_extract_validation_nonPositive() {
2038 let mut field = make_field(
2039 "debt",
2040 FieldType::Scalar(ScalarType::Float),
2041 TypeModifier::Required,
2042 );
2043 field.attributes.push(Attribute::simple(
2044 Ident::new("validate.nonPositive", make_span()),
2045 make_span(),
2046 ));
2047
2048 field.extract_validation_from_attributes();
2049 assert!(field.has_validation());
2050 }
2051
2052 #[test]
2053 fn test_extract_validation_pastOrPresent() {
2054 let mut field = make_field(
2055 "login_date",
2056 FieldType::Scalar(ScalarType::DateTime),
2057 TypeModifier::Required,
2058 );
2059 field.attributes.push(Attribute::simple(
2060 Ident::new("validate.pastOrPresent", make_span()),
2061 make_span(),
2062 ));
2063
2064 field.extract_validation_from_attributes();
2065 assert!(field.has_validation());
2066 }
2067
2068 #[test]
2069 fn test_extract_validation_futureOrPresent() {
2070 let mut field = make_field(
2071 "schedule_date",
2072 FieldType::Scalar(ScalarType::DateTime),
2073 TypeModifier::Required,
2074 );
2075 field.attributes.push(Attribute::simple(
2076 Ident::new("validate.futureOrPresent", make_span()),
2077 make_span(),
2078 ));
2079
2080 field.extract_validation_from_attributes();
2081 assert!(field.has_validation());
2082 }
2083
2084 #[test]
2085 fn test_extract_validation_required() {
2086 let mut field = make_field(
2087 "important",
2088 FieldType::Scalar(ScalarType::String),
2089 TypeModifier::Optional,
2090 );
2091 field.attributes.push(Attribute::simple(
2092 Ident::new("validate.required", make_span()),
2093 make_span(),
2094 ));
2095
2096 field.extract_validation_from_attributes();
2097 assert!(field.has_validation());
2098 assert!(field.is_validated_required());
2099 }
2100
2101 #[test]
2102 fn test_extract_validation_notEmpty() {
2103 let mut field = make_field(
2104 "content",
2105 FieldType::Scalar(ScalarType::String),
2106 TypeModifier::Required,
2107 );
2108 field.attributes.push(Attribute::simple(
2109 Ident::new("validate.notEmpty", make_span()),
2110 make_span(),
2111 ));
2112
2113 field.extract_validation_from_attributes();
2114 assert!(field.has_validation());
2115 }
2116
2117 #[test]
2118 fn test_extract_validation_unknown_validator() {
2119 let mut field = make_field(
2120 "field",
2121 FieldType::Scalar(ScalarType::String),
2122 TypeModifier::Required,
2123 );
2124 field.attributes.push(Attribute::simple(
2125 Ident::new("validate.unknownValidator", make_span()),
2126 make_span(),
2127 ));
2128
2129 field.extract_validation_from_attributes();
2130 assert!(!field.has_validation());
2132 }
2133
2134 #[test]
2135 fn test_extract_validation_items() {
2136 let mut field = make_field(
2137 "tags",
2138 FieldType::Scalar(ScalarType::String),
2139 TypeModifier::List,
2140 );
2141 field.attributes.push(Attribute::new(
2142 Ident::new("validate.items", make_span()),
2143 vec![
2144 AttributeArg::positional(AttributeValue::Int(1), make_span()),
2145 AttributeArg::positional(AttributeValue::Int(10), make_span()),
2146 ],
2147 make_span(),
2148 ));
2149
2150 field.extract_validation_from_attributes();
2151 assert!(field.has_validation());
2152 }
2153
2154 #[test]
2157 fn test_extract_validate_attribute_with_ident() {
2158 let mut field = make_field(
2159 "email",
2160 FieldType::Scalar(ScalarType::String),
2161 TypeModifier::Required,
2162 );
2163 field.attributes.push(Attribute::new(
2164 Ident::new("validate", make_span()),
2165 vec![AttributeArg::positional(
2166 AttributeValue::Ident("email".into()),
2167 make_span(),
2168 )],
2169 make_span(),
2170 ));
2171
2172 field.extract_validation_from_attributes();
2173 assert!(field.has_validation());
2174 assert_eq!(field.validation_rules().len(), 1);
2175 }
2176
2177 #[test]
2178 fn test_extract_validate_attribute_with_function() {
2179 let mut field = make_field(
2180 "name",
2181 FieldType::Scalar(ScalarType::String),
2182 TypeModifier::Required,
2183 );
2184 field.attributes.push(Attribute::new(
2185 Ident::new("validate", make_span()),
2186 vec![AttributeArg::positional(
2187 AttributeValue::Function("minLength".into(), vec![AttributeValue::Int(3)]),
2188 make_span(),
2189 )],
2190 make_span(),
2191 ));
2192
2193 field.extract_validation_from_attributes();
2194 assert!(field.has_validation());
2195 assert_eq!(field.validation_rules().len(), 1);
2196 }
2197
2198 #[test]
2199 fn test_extract_validate_multiple_validators() {
2200 let mut field = make_field(
2201 "email",
2202 FieldType::Scalar(ScalarType::String),
2203 TypeModifier::Required,
2204 );
2205 field.attributes.push(Attribute::new(
2206 Ident::new("validate", make_span()),
2207 vec![
2208 AttributeArg::positional(AttributeValue::Ident("email".into()), make_span()),
2209 AttributeArg::positional(
2210 AttributeValue::Function("maxLength".into(), vec![AttributeValue::Int(255)]),
2211 make_span(),
2212 ),
2213 ],
2214 make_span(),
2215 ));
2216
2217 field.extract_validation_from_attributes();
2218 assert!(field.has_validation());
2219 assert_eq!(field.validation_rules().len(), 2);
2220 }
2221}