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 && let Some(action) = val.as_ident()
149 {
150 rel.on_delete = super::ReferentialAction::from_str(action);
151 }
152 if let Some(val) = attr.get_arg("onUpdate")
153 && let Some(action) = val.as_ident()
154 {
155 rel.on_update = super::ReferentialAction::from_str(action);
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)]
530#[allow(non_snake_case)]
533mod tests {
534 use super::*;
535 use crate::ast::{AttributeArg, AttributeValue, ReferentialAction, ScalarType};
536
537 fn make_span() -> Span {
538 Span::new(0, 10)
539 }
540
541 fn make_field(name: &str, field_type: FieldType, modifier: TypeModifier) -> Field {
542 Field::new(
543 Ident::new(name, make_span()),
544 field_type,
545 modifier,
546 vec![],
547 make_span(),
548 )
549 }
550
551 fn make_attribute(name: &str) -> Attribute {
552 Attribute::simple(Ident::new(name, make_span()), make_span())
553 }
554
555 fn make_attribute_with_arg(name: &str, value: AttributeValue) -> Attribute {
556 Attribute::new(
557 Ident::new(name, make_span()),
558 vec![AttributeArg::positional(value, make_span())],
559 make_span(),
560 )
561 }
562
563 #[test]
566 fn test_field_new() {
567 let field = Field::new(
568 Ident::new("id", make_span()),
569 FieldType::Scalar(ScalarType::Int),
570 TypeModifier::Required,
571 vec![],
572 make_span(),
573 );
574
575 assert_eq!(field.name(), "id");
576 assert!(field.field_type.is_scalar());
577 assert_eq!(field.modifier, TypeModifier::Required);
578 assert!(field.attributes.is_empty());
579 assert!(field.documentation.is_none());
580 }
581
582 #[test]
583 fn test_field_with_attributes() {
584 let field = Field::new(
585 Ident::new("email", make_span()),
586 FieldType::Scalar(ScalarType::String),
587 TypeModifier::Required,
588 vec![make_attribute("unique")],
589 make_span(),
590 );
591
592 assert_eq!(field.attributes.len(), 1);
593 }
594
595 #[test]
596 fn test_field_with_documentation() {
597 let field = make_field(
598 "name",
599 FieldType::Scalar(ScalarType::String),
600 TypeModifier::Optional,
601 )
602 .with_documentation(Documentation::new("User's display name", make_span()));
603
604 assert!(field.documentation.is_some());
605 assert_eq!(field.documentation.unwrap().text, "User's display name");
606 }
607
608 #[test]
611 fn test_field_name() {
612 let field = make_field(
613 "created_at",
614 FieldType::Scalar(ScalarType::DateTime),
615 TypeModifier::Required,
616 );
617 assert_eq!(field.name(), "created_at");
618 }
619
620 #[test]
623 fn test_field_is_optional_required() {
624 let field = make_field(
625 "id",
626 FieldType::Scalar(ScalarType::Int),
627 TypeModifier::Required,
628 );
629 assert!(!field.is_optional());
630 }
631
632 #[test]
633 fn test_field_is_optional_true() {
634 let field = make_field(
635 "bio",
636 FieldType::Scalar(ScalarType::String),
637 TypeModifier::Optional,
638 );
639 assert!(field.is_optional());
640 }
641
642 #[test]
643 fn test_field_is_list_false() {
644 let field = make_field(
645 "name",
646 FieldType::Scalar(ScalarType::String),
647 TypeModifier::Required,
648 );
649 assert!(!field.is_list());
650 }
651
652 #[test]
653 fn test_field_is_list_true() {
654 let field = make_field(
655 "tags",
656 FieldType::Scalar(ScalarType::String),
657 TypeModifier::List,
658 );
659 assert!(field.is_list());
660 }
661
662 #[test]
663 fn test_field_optional_list() {
664 let field = make_field(
665 "metadata",
666 FieldType::Scalar(ScalarType::Json),
667 TypeModifier::OptionalList,
668 );
669 assert!(field.is_optional());
670 assert!(field.is_list());
671 }
672
673 #[test]
676 fn test_field_has_attribute_true() {
677 let mut field = make_field(
678 "id",
679 FieldType::Scalar(ScalarType::Int),
680 TypeModifier::Required,
681 );
682 field.attributes.push(make_attribute("id"));
683 field.attributes.push(make_attribute("auto"));
684
685 assert!(field.has_attribute("id"));
686 assert!(field.has_attribute("auto"));
687 }
688
689 #[test]
690 fn test_field_has_attribute_false() {
691 let field = make_field(
692 "name",
693 FieldType::Scalar(ScalarType::String),
694 TypeModifier::Required,
695 );
696 assert!(!field.has_attribute("unique"));
697 }
698
699 #[test]
700 fn test_field_get_attribute() {
701 let mut field = make_field(
702 "email",
703 FieldType::Scalar(ScalarType::String),
704 TypeModifier::Required,
705 );
706 field.attributes.push(make_attribute("unique"));
707
708 let attr = field.get_attribute("unique");
709 assert!(attr.is_some());
710 assert!(attr.unwrap().is("unique"));
711
712 assert!(field.get_attribute("id").is_none());
713 }
714
715 #[test]
716 fn test_field_is_id_true() {
717 let mut field = make_field(
718 "id",
719 FieldType::Scalar(ScalarType::Int),
720 TypeModifier::Required,
721 );
722 field.attributes.push(make_attribute("id"));
723 assert!(field.is_id());
724 }
725
726 #[test]
727 fn test_field_is_id_false() {
728 let field = make_field(
729 "email",
730 FieldType::Scalar(ScalarType::String),
731 TypeModifier::Required,
732 );
733 assert!(!field.is_id());
734 }
735
736 #[test]
737 fn test_field_is_unique_true() {
738 let mut field = make_field(
739 "email",
740 FieldType::Scalar(ScalarType::String),
741 TypeModifier::Required,
742 );
743 field.attributes.push(make_attribute("unique"));
744 assert!(field.is_unique());
745 }
746
747 #[test]
748 fn test_field_is_unique_false() {
749 let field = make_field(
750 "name",
751 FieldType::Scalar(ScalarType::String),
752 TypeModifier::Required,
753 );
754 assert!(!field.is_unique());
755 }
756
757 #[test]
760 fn test_field_is_relation_by_type() {
761 let field = make_field(
762 "author",
763 FieldType::Model("User".into()),
764 TypeModifier::Required,
765 );
766 assert!(field.is_relation());
767 }
768
769 #[test]
770 fn test_field_is_relation_by_attribute() {
771 let mut field = make_field(
772 "author_id",
773 FieldType::Scalar(ScalarType::Int),
774 TypeModifier::Required,
775 );
776 field.attributes.push(make_attribute("relation"));
777 assert!(field.is_relation());
778 }
779
780 #[test]
781 fn test_field_is_relation_list() {
782 let field = make_field("posts", FieldType::Model("Post".into()), TypeModifier::List);
783 assert!(field.is_relation());
784 assert!(field.is_list());
785 }
786
787 #[test]
790 fn test_extract_attributes_empty() {
791 let field = make_field(
792 "name",
793 FieldType::Scalar(ScalarType::String),
794 TypeModifier::Required,
795 );
796 let attrs = field.extract_attributes();
797
798 assert!(!attrs.is_id);
799 assert!(!attrs.is_auto);
800 assert!(!attrs.is_unique);
801 assert!(!attrs.is_indexed);
802 assert!(!attrs.is_updated_at);
803 assert!(!attrs.is_omit);
804 assert!(attrs.default.is_none());
805 assert!(attrs.map.is_none());
806 assert!(attrs.native_type.is_none());
807 assert!(attrs.relation.is_none());
808 }
809
810 #[test]
811 fn test_extract_attributes_id_and_auto() {
812 let mut field = make_field(
813 "id",
814 FieldType::Scalar(ScalarType::Int),
815 TypeModifier::Required,
816 );
817 field.attributes.push(make_attribute("id"));
818 field.attributes.push(make_attribute("auto"));
819
820 let attrs = field.extract_attributes();
821 assert!(attrs.is_id);
822 assert!(attrs.is_auto);
823 }
824
825 #[test]
826 fn test_extract_attributes_unique() {
827 let mut field = make_field(
828 "email",
829 FieldType::Scalar(ScalarType::String),
830 TypeModifier::Required,
831 );
832 field.attributes.push(make_attribute("unique"));
833
834 let attrs = field.extract_attributes();
835 assert!(attrs.is_unique);
836 }
837
838 #[test]
839 fn test_extract_attributes_index() {
840 let mut field = make_field(
841 "name",
842 FieldType::Scalar(ScalarType::String),
843 TypeModifier::Required,
844 );
845 field.attributes.push(make_attribute("index"));
846
847 let attrs = field.extract_attributes();
848 assert!(attrs.is_indexed);
849 }
850
851 #[test]
852 fn test_extract_attributes_updated_at() {
853 let mut field = make_field(
854 "updated_at",
855 FieldType::Scalar(ScalarType::DateTime),
856 TypeModifier::Required,
857 );
858 field.attributes.push(make_attribute("updated_at"));
859
860 let attrs = field.extract_attributes();
861 assert!(attrs.is_updated_at);
862 }
863
864 #[test]
865 fn test_extract_attributes_omit() {
866 let mut field = make_field(
867 "password_hash",
868 FieldType::Scalar(ScalarType::String),
869 TypeModifier::Required,
870 );
871 field.attributes.push(make_attribute("omit"));
872
873 let attrs = field.extract_attributes();
874 assert!(attrs.is_omit);
875 }
876
877 #[test]
878 fn test_extract_attributes_default_int() {
879 let mut field = make_field(
880 "count",
881 FieldType::Scalar(ScalarType::Int),
882 TypeModifier::Required,
883 );
884 field
885 .attributes
886 .push(make_attribute_with_arg("default", AttributeValue::Int(0)));
887
888 let attrs = field.extract_attributes();
889 assert!(attrs.default.is_some());
890 assert_eq!(attrs.default.as_ref().unwrap().as_int(), Some(0));
891 }
892
893 #[test]
894 fn test_extract_attributes_default_function() {
895 let mut field = make_field(
896 "created_at",
897 FieldType::Scalar(ScalarType::DateTime),
898 TypeModifier::Required,
899 );
900 field.attributes.push(make_attribute_with_arg(
901 "default",
902 AttributeValue::Function("now".into(), vec![]),
903 ));
904
905 let attrs = field.extract_attributes();
906 assert!(attrs.default.is_some());
907 if let AttributeValue::Function(name, _) = attrs.default.as_ref().unwrap() {
908 assert_eq!(name.as_str(), "now");
909 } else {
910 panic!("Expected Function");
911 }
912 }
913
914 #[test]
915 fn test_extract_attributes_map() {
916 let mut field = make_field(
917 "email",
918 FieldType::Scalar(ScalarType::String),
919 TypeModifier::Required,
920 );
921 field.attributes.push(make_attribute_with_arg(
922 "map",
923 AttributeValue::String("email_address".into()),
924 ));
925
926 let attrs = field.extract_attributes();
927 assert_eq!(attrs.map, Some("email_address".to_string()));
928 }
929
930 #[test]
931 fn test_extract_attributes_native_type_ident() {
932 let mut field = make_field(
933 "data",
934 FieldType::Scalar(ScalarType::String),
935 TypeModifier::Required,
936 );
937 field.attributes.push(make_attribute_with_arg(
938 "db",
939 AttributeValue::Ident("Text".into()),
940 ));
941
942 let attrs = field.extract_attributes();
943 assert!(attrs.native_type.is_some());
944 let nt = attrs.native_type.unwrap();
945 assert_eq!(nt.name.as_str(), "Text");
946 assert!(nt.args.is_empty());
947 }
948
949 #[test]
950 fn test_extract_attributes_native_type_function() {
951 let mut field = make_field(
952 "name",
953 FieldType::Scalar(ScalarType::String),
954 TypeModifier::Required,
955 );
956 field.attributes.push(make_attribute_with_arg(
957 "db",
958 AttributeValue::Function("VarChar".into(), vec![AttributeValue::Int(255)]),
959 ));
960
961 let attrs = field.extract_attributes();
962 assert!(attrs.native_type.is_some());
963 let nt = attrs.native_type.unwrap();
964 assert_eq!(nt.name.as_str(), "VarChar");
965 assert_eq!(nt.args.len(), 1);
966 }
967
968 #[test]
969 fn test_extract_attributes_relation() {
970 let mut field = make_field(
971 "author",
972 FieldType::Model("User".into()),
973 TypeModifier::Required,
974 );
975 field.attributes.push(Attribute::new(
976 Ident::new("relation", make_span()),
977 vec![
978 AttributeArg::named(
979 Ident::new("fields", make_span()),
980 AttributeValue::FieldRefList(vec!["author_id".into()]),
981 make_span(),
982 ),
983 AttributeArg::named(
984 Ident::new("references", make_span()),
985 AttributeValue::FieldRefList(vec!["id".into()]),
986 make_span(),
987 ),
988 AttributeArg::named(
989 Ident::new("onDelete", make_span()),
990 AttributeValue::Ident("Cascade".into()),
991 make_span(),
992 ),
993 AttributeArg::named(
994 Ident::new("onUpdate", make_span()),
995 AttributeValue::Ident("Restrict".into()),
996 make_span(),
997 ),
998 ],
999 make_span(),
1000 ));
1001
1002 let attrs = field.extract_attributes();
1003 assert!(attrs.relation.is_some());
1004
1005 let rel = attrs.relation.unwrap();
1006 assert_eq!(rel.fields, vec!["author_id".to_string()]);
1007 assert_eq!(rel.references, vec!["id".to_string()]);
1008 assert_eq!(rel.on_delete, Some(ReferentialAction::Cascade));
1009 assert_eq!(rel.on_update, Some(ReferentialAction::Restrict));
1010 }
1011
1012 #[test]
1013 fn test_extract_attributes_relation_with_name() {
1014 let mut field = make_field(
1015 "author",
1016 FieldType::Model("User".into()),
1017 TypeModifier::Required,
1018 );
1019 field.attributes.push(Attribute::new(
1020 Ident::new("relation", make_span()),
1021 vec![AttributeArg::positional(
1022 AttributeValue::String("PostAuthor".into()),
1023 make_span(),
1024 )],
1025 make_span(),
1026 ));
1027
1028 let attrs = field.extract_attributes();
1029 assert!(attrs.relation.is_some());
1030 assert_eq!(attrs.relation.unwrap().name, Some("PostAuthor".to_string()));
1031 }
1032
1033 #[test]
1036 fn test_field_display_required() {
1037 let field = make_field(
1038 "id",
1039 FieldType::Scalar(ScalarType::Int),
1040 TypeModifier::Required,
1041 );
1042 assert_eq!(format!("{}", field), "id Int");
1043 }
1044
1045 #[test]
1046 fn test_field_display_optional() {
1047 let field = make_field(
1048 "bio",
1049 FieldType::Scalar(ScalarType::String),
1050 TypeModifier::Optional,
1051 );
1052 assert_eq!(format!("{}", field), "bio String?");
1053 }
1054
1055 #[test]
1056 fn test_field_display_list() {
1057 let field = make_field(
1058 "tags",
1059 FieldType::Scalar(ScalarType::String),
1060 TypeModifier::List,
1061 );
1062 assert_eq!(format!("{}", field), "tags String[]");
1063 }
1064
1065 #[test]
1066 fn test_field_display_optional_list() {
1067 let field = make_field(
1068 "data",
1069 FieldType::Scalar(ScalarType::Json),
1070 TypeModifier::OptionalList,
1071 );
1072 assert_eq!(format!("{}", field), "data Json[]?");
1073 }
1074
1075 #[test]
1076 fn test_field_display_with_simple_attribute() {
1077 let mut field = make_field(
1078 "id",
1079 FieldType::Scalar(ScalarType::Int),
1080 TypeModifier::Required,
1081 );
1082 field.attributes.push(make_attribute("id"));
1083 assert!(format!("{}", field).contains("@id"));
1084 }
1085
1086 #[test]
1087 fn test_field_display_with_attribute_args() {
1088 let mut field = make_field(
1089 "count",
1090 FieldType::Scalar(ScalarType::Int),
1091 TypeModifier::Required,
1092 );
1093 field
1094 .attributes
1095 .push(make_attribute_with_arg("default", AttributeValue::Int(0)));
1096 assert!(format!("{}", field).contains("@default(...)"));
1097 }
1098
1099 #[test]
1100 fn test_field_display_relation() {
1101 let field = make_field(
1102 "author",
1103 FieldType::Model("User".into()),
1104 TypeModifier::Required,
1105 );
1106 assert_eq!(format!("{}", field), "author User");
1107 }
1108
1109 #[test]
1110 fn test_field_display_enum() {
1111 let field = make_field(
1112 "role",
1113 FieldType::Enum("Role".into()),
1114 TypeModifier::Required,
1115 );
1116 assert_eq!(format!("{}", field), "role Role");
1117 }
1118
1119 #[test]
1122 fn test_field_equality() {
1123 let field1 = make_field(
1124 "id",
1125 FieldType::Scalar(ScalarType::Int),
1126 TypeModifier::Required,
1127 );
1128 let field2 = make_field(
1129 "id",
1130 FieldType::Scalar(ScalarType::Int),
1131 TypeModifier::Required,
1132 );
1133 assert_eq!(field1, field2);
1134 }
1135
1136 #[test]
1137 fn test_field_inequality_name() {
1138 let field1 = make_field(
1139 "id",
1140 FieldType::Scalar(ScalarType::Int),
1141 TypeModifier::Required,
1142 );
1143 let field2 = make_field(
1144 "user_id",
1145 FieldType::Scalar(ScalarType::Int),
1146 TypeModifier::Required,
1147 );
1148 assert_ne!(field1, field2);
1149 }
1150
1151 #[test]
1152 fn test_field_inequality_type() {
1153 let field1 = make_field(
1154 "id",
1155 FieldType::Scalar(ScalarType::Int),
1156 TypeModifier::Required,
1157 );
1158 let field2 = make_field(
1159 "id",
1160 FieldType::Scalar(ScalarType::String),
1161 TypeModifier::Required,
1162 );
1163 assert_ne!(field1, field2);
1164 }
1165
1166 #[test]
1167 fn test_field_inequality_modifier() {
1168 let field1 = make_field(
1169 "name",
1170 FieldType::Scalar(ScalarType::String),
1171 TypeModifier::Required,
1172 );
1173 let field2 = make_field(
1174 "name",
1175 FieldType::Scalar(ScalarType::String),
1176 TypeModifier::Optional,
1177 );
1178 assert_ne!(field1, field2);
1179 }
1180
1181 #[test]
1184 fn test_field_with_validation() {
1185 let validation = FieldValidation::new();
1186 let field = make_field(
1187 "email",
1188 FieldType::Scalar(ScalarType::String),
1189 TypeModifier::Required,
1190 )
1191 .with_validation(validation);
1192
1193 assert!(!field.has_validation());
1194 }
1195
1196 #[test]
1197 fn test_field_add_validation_rule() {
1198 let mut field = make_field(
1199 "email",
1200 FieldType::Scalar(ScalarType::String),
1201 TypeModifier::Required,
1202 );
1203
1204 field.add_validation_rule(ValidationRule::new(ValidationType::Email, make_span()));
1205 assert!(field.has_validation());
1206 assert_eq!(field.validation_rules().len(), 1);
1207 }
1208
1209 #[test]
1210 fn test_field_validation_required() {
1211 let mut field = make_field(
1212 "name",
1213 FieldType::Scalar(ScalarType::String),
1214 TypeModifier::Optional,
1215 );
1216
1217 assert!(!field.is_validated_required());
1218 field.add_validation_rule(ValidationRule::new(ValidationType::Required, make_span()));
1219 assert!(field.is_validated_required());
1220 }
1221
1222 #[test]
1223 fn test_extract_validation_email() {
1224 let mut field = make_field(
1225 "email",
1226 FieldType::Scalar(ScalarType::String),
1227 TypeModifier::Required,
1228 );
1229 field.attributes.push(Attribute::simple(
1230 Ident::new("validate.email", make_span()),
1231 make_span(),
1232 ));
1233
1234 field.extract_validation_from_attributes();
1235 assert!(field.has_validation());
1236 assert_eq!(field.validation_rules().len(), 1);
1237 }
1238
1239 #[test]
1240 fn test_extract_validation_url() {
1241 let mut field = make_field(
1242 "website",
1243 FieldType::Scalar(ScalarType::String),
1244 TypeModifier::Optional,
1245 );
1246 field.attributes.push(Attribute::simple(
1247 Ident::new("validate.url", make_span()),
1248 make_span(),
1249 ));
1250
1251 field.extract_validation_from_attributes();
1252 assert!(field.has_validation());
1253 }
1254
1255 #[test]
1256 fn test_extract_validation_uuid() {
1257 let mut field = make_field(
1258 "id",
1259 FieldType::Scalar(ScalarType::String),
1260 TypeModifier::Required,
1261 );
1262 field.attributes.push(Attribute::simple(
1263 Ident::new("validate.uuid", make_span()),
1264 make_span(),
1265 ));
1266
1267 field.extract_validation_from_attributes();
1268 assert!(field.has_validation());
1269 }
1270
1271 #[test]
1272 fn test_extract_validation_min_length() {
1273 let mut field = make_field(
1274 "name",
1275 FieldType::Scalar(ScalarType::String),
1276 TypeModifier::Required,
1277 );
1278 field.attributes.push(Attribute::new(
1279 Ident::new("validate.minLength", make_span()),
1280 vec![AttributeArg::positional(
1281 AttributeValue::Int(3),
1282 make_span(),
1283 )],
1284 make_span(),
1285 ));
1286
1287 field.extract_validation_from_attributes();
1288 assert!(field.has_validation());
1289 }
1290
1291 #[test]
1292 fn test_extract_validation_max_length() {
1293 let mut field = make_field(
1294 "bio",
1295 FieldType::Scalar(ScalarType::String),
1296 TypeModifier::Optional,
1297 );
1298 field.attributes.push(Attribute::new(
1299 Ident::new("validate.maxLength", make_span()),
1300 vec![AttributeArg::positional(
1301 AttributeValue::Int(500),
1302 make_span(),
1303 )],
1304 make_span(),
1305 ));
1306
1307 field.extract_validation_from_attributes();
1308 assert!(field.has_validation());
1309 }
1310
1311 #[test]
1312 fn test_extract_validation_min() {
1313 let mut field = make_field(
1314 "age",
1315 FieldType::Scalar(ScalarType::Int),
1316 TypeModifier::Required,
1317 );
1318 field.attributes.push(Attribute::new(
1319 Ident::new("validate.min", make_span()),
1320 vec![AttributeArg::positional(
1321 AttributeValue::Int(0),
1322 make_span(),
1323 )],
1324 make_span(),
1325 ));
1326
1327 field.extract_validation_from_attributes();
1328 assert!(field.has_validation());
1329 }
1330
1331 #[test]
1332 fn test_extract_validation_max() {
1333 let mut field = make_field(
1334 "percentage",
1335 FieldType::Scalar(ScalarType::Float),
1336 TypeModifier::Required,
1337 );
1338 field.attributes.push(Attribute::new(
1339 Ident::new("validate.max", make_span()),
1340 vec![AttributeArg::positional(
1341 AttributeValue::Float(100.0),
1342 make_span(),
1343 )],
1344 make_span(),
1345 ));
1346
1347 field.extract_validation_from_attributes();
1348 assert!(field.has_validation());
1349 }
1350
1351 #[test]
1352 fn test_extract_validation_range() {
1353 let mut field = make_field(
1354 "rating",
1355 FieldType::Scalar(ScalarType::Int),
1356 TypeModifier::Required,
1357 );
1358 field.attributes.push(Attribute::new(
1359 Ident::new("validate.range", make_span()),
1360 vec![
1361 AttributeArg::positional(AttributeValue::Int(1), make_span()),
1362 AttributeArg::positional(AttributeValue::Int(5), make_span()),
1363 ],
1364 make_span(),
1365 ));
1366
1367 field.extract_validation_from_attributes();
1368 assert!(field.has_validation());
1369 }
1370
1371 #[test]
1372 fn test_extract_validation_regex() {
1373 let mut field = make_field(
1374 "phone",
1375 FieldType::Scalar(ScalarType::String),
1376 TypeModifier::Required,
1377 );
1378 field.attributes.push(Attribute::new(
1379 Ident::new("validate.regex", make_span()),
1380 vec![AttributeArg::positional(
1381 AttributeValue::String("^\\+[0-9]+$".into()),
1382 make_span(),
1383 )],
1384 make_span(),
1385 ));
1386
1387 field.extract_validation_from_attributes();
1388 assert!(field.has_validation());
1389 }
1390
1391 #[test]
1392 fn test_extract_validation_positive() {
1393 let mut field = make_field(
1394 "amount",
1395 FieldType::Scalar(ScalarType::Float),
1396 TypeModifier::Required,
1397 );
1398 field.attributes.push(Attribute::simple(
1399 Ident::new("validate.positive", make_span()),
1400 make_span(),
1401 ));
1402
1403 field.extract_validation_from_attributes();
1404 assert!(field.has_validation());
1405 }
1406
1407 #[test]
1408 fn test_extract_validation_negative() {
1409 let mut field = make_field(
1410 "debt",
1411 FieldType::Scalar(ScalarType::Float),
1412 TypeModifier::Required,
1413 );
1414 field.attributes.push(Attribute::simple(
1415 Ident::new("validate.negative", make_span()),
1416 make_span(),
1417 ));
1418
1419 field.extract_validation_from_attributes();
1420 assert!(field.has_validation());
1421 }
1422
1423 #[test]
1424 fn test_extract_validation_nonNegative() {
1425 let mut field = make_field(
1426 "count",
1427 FieldType::Scalar(ScalarType::Int),
1428 TypeModifier::Required,
1429 );
1430 field.attributes.push(Attribute::simple(
1431 Ident::new("validate.nonNegative", make_span()),
1432 make_span(),
1433 ));
1434
1435 field.extract_validation_from_attributes();
1436 assert!(field.has_validation());
1437 }
1438
1439 #[test]
1440 fn test_extract_validation_alpha() {
1441 let mut field = make_field(
1442 "code",
1443 FieldType::Scalar(ScalarType::String),
1444 TypeModifier::Required,
1445 );
1446 field.attributes.push(Attribute::simple(
1447 Ident::new("validate.alpha", make_span()),
1448 make_span(),
1449 ));
1450
1451 field.extract_validation_from_attributes();
1452 assert!(field.has_validation());
1453 }
1454
1455 #[test]
1456 fn test_extract_validation_alphanumeric() {
1457 let mut field = make_field(
1458 "username",
1459 FieldType::Scalar(ScalarType::String),
1460 TypeModifier::Required,
1461 );
1462 field.attributes.push(Attribute::simple(
1463 Ident::new("validate.alphanumeric", make_span()),
1464 make_span(),
1465 ));
1466
1467 field.extract_validation_from_attributes();
1468 assert!(field.has_validation());
1469 }
1470
1471 #[test]
1472 fn test_extract_validation_lowercase() {
1473 let mut field = make_field(
1474 "slug",
1475 FieldType::Scalar(ScalarType::String),
1476 TypeModifier::Required,
1477 );
1478 field.attributes.push(Attribute::simple(
1479 Ident::new("validate.lowercase", make_span()),
1480 make_span(),
1481 ));
1482
1483 field.extract_validation_from_attributes();
1484 assert!(field.has_validation());
1485 }
1486
1487 #[test]
1488 fn test_extract_validation_uppercase() {
1489 let mut field = make_field(
1490 "country_code",
1491 FieldType::Scalar(ScalarType::String),
1492 TypeModifier::Required,
1493 );
1494 field.attributes.push(Attribute::simple(
1495 Ident::new("validate.uppercase", make_span()),
1496 make_span(),
1497 ));
1498
1499 field.extract_validation_from_attributes();
1500 assert!(field.has_validation());
1501 }
1502
1503 #[test]
1504 fn test_extract_validation_trim() {
1505 let mut field = make_field(
1506 "input",
1507 FieldType::Scalar(ScalarType::String),
1508 TypeModifier::Required,
1509 );
1510 field.attributes.push(Attribute::simple(
1511 Ident::new("validate.trim", make_span()),
1512 make_span(),
1513 ));
1514
1515 field.extract_validation_from_attributes();
1516 assert!(field.has_validation());
1517 }
1518
1519 #[test]
1520 fn test_extract_validation_ip() {
1521 let mut field = make_field(
1522 "ip_address",
1523 FieldType::Scalar(ScalarType::String),
1524 TypeModifier::Required,
1525 );
1526 field.attributes.push(Attribute::simple(
1527 Ident::new("validate.ip", make_span()),
1528 make_span(),
1529 ));
1530
1531 field.extract_validation_from_attributes();
1532 assert!(field.has_validation());
1533 }
1534
1535 #[test]
1536 fn test_extract_validation_ipv4() {
1537 let mut field = make_field(
1538 "ipv4",
1539 FieldType::Scalar(ScalarType::String),
1540 TypeModifier::Required,
1541 );
1542 field.attributes.push(Attribute::simple(
1543 Ident::new("validate.ipv4", make_span()),
1544 make_span(),
1545 ));
1546
1547 field.extract_validation_from_attributes();
1548 assert!(field.has_validation());
1549 }
1550
1551 #[test]
1552 fn test_extract_validation_ipv6() {
1553 let mut field = make_field(
1554 "ipv6",
1555 FieldType::Scalar(ScalarType::String),
1556 TypeModifier::Required,
1557 );
1558 field.attributes.push(Attribute::simple(
1559 Ident::new("validate.ipv6", make_span()),
1560 make_span(),
1561 ));
1562
1563 field.extract_validation_from_attributes();
1564 assert!(field.has_validation());
1565 }
1566
1567 #[test]
1568 fn test_extract_validation_slug() {
1569 let mut field = make_field(
1570 "url_slug",
1571 FieldType::Scalar(ScalarType::String),
1572 TypeModifier::Required,
1573 );
1574 field.attributes.push(Attribute::simple(
1575 Ident::new("validate.slug", make_span()),
1576 make_span(),
1577 ));
1578
1579 field.extract_validation_from_attributes();
1580 assert!(field.has_validation());
1581 }
1582
1583 #[test]
1584 fn test_extract_validation_hex() {
1585 let mut field = make_field(
1586 "color",
1587 FieldType::Scalar(ScalarType::String),
1588 TypeModifier::Required,
1589 );
1590 field.attributes.push(Attribute::simple(
1591 Ident::new("validate.hex", make_span()),
1592 make_span(),
1593 ));
1594
1595 field.extract_validation_from_attributes();
1596 assert!(field.has_validation());
1597 }
1598
1599 #[test]
1600 fn test_extract_validation_base64() {
1601 let mut field = make_field(
1602 "encoded",
1603 FieldType::Scalar(ScalarType::String),
1604 TypeModifier::Required,
1605 );
1606 field.attributes.push(Attribute::simple(
1607 Ident::new("validate.base64", make_span()),
1608 make_span(),
1609 ));
1610
1611 field.extract_validation_from_attributes();
1612 assert!(field.has_validation());
1613 }
1614
1615 #[test]
1616 fn test_extract_validation_json() {
1617 let mut field = make_field(
1618 "json_str",
1619 FieldType::Scalar(ScalarType::String),
1620 TypeModifier::Required,
1621 );
1622 field.attributes.push(Attribute::simple(
1623 Ident::new("validate.json", make_span()),
1624 make_span(),
1625 ));
1626
1627 field.extract_validation_from_attributes();
1628 assert!(field.has_validation());
1629 }
1630
1631 #[test]
1632 fn test_extract_validation_integer() {
1633 let mut field = make_field(
1634 "whole",
1635 FieldType::Scalar(ScalarType::Float),
1636 TypeModifier::Required,
1637 );
1638 field.attributes.push(Attribute::simple(
1639 Ident::new("validate.integer", make_span()),
1640 make_span(),
1641 ));
1642
1643 field.extract_validation_from_attributes();
1644 assert!(field.has_validation());
1645 }
1646
1647 #[test]
1648 fn test_extract_validation_finite() {
1649 let mut field = make_field(
1650 "value",
1651 FieldType::Scalar(ScalarType::Float),
1652 TypeModifier::Required,
1653 );
1654 field.attributes.push(Attribute::simple(
1655 Ident::new("validate.finite", make_span()),
1656 make_span(),
1657 ));
1658
1659 field.extract_validation_from_attributes();
1660 assert!(field.has_validation());
1661 }
1662
1663 #[test]
1664 fn test_extract_validation_unique_array() {
1665 let mut field = make_field(
1666 "tags",
1667 FieldType::Scalar(ScalarType::String),
1668 TypeModifier::List,
1669 );
1670 field.attributes.push(Attribute::simple(
1671 Ident::new("validate.unique", make_span()),
1672 make_span(),
1673 ));
1674
1675 field.extract_validation_from_attributes();
1676 assert!(field.has_validation());
1677 }
1678
1679 #[test]
1680 fn test_extract_validation_nonEmpty() {
1681 let mut field = make_field(
1682 "required_tags",
1683 FieldType::Scalar(ScalarType::String),
1684 TypeModifier::List,
1685 );
1686 field.attributes.push(Attribute::simple(
1687 Ident::new("validate.nonEmpty", make_span()),
1688 make_span(),
1689 ));
1690
1691 field.extract_validation_from_attributes();
1692 assert!(field.has_validation());
1693 }
1694
1695 #[test]
1696 fn test_extract_validation_past() {
1697 let mut field = make_field(
1698 "birth_date",
1699 FieldType::Scalar(ScalarType::DateTime),
1700 TypeModifier::Required,
1701 );
1702 field.attributes.push(Attribute::simple(
1703 Ident::new("validate.past", make_span()),
1704 make_span(),
1705 ));
1706
1707 field.extract_validation_from_attributes();
1708 assert!(field.has_validation());
1709 }
1710
1711 #[test]
1712 fn test_extract_validation_future() {
1713 let mut field = make_field(
1714 "expiry_date",
1715 FieldType::Scalar(ScalarType::DateTime),
1716 TypeModifier::Required,
1717 );
1718 field.attributes.push(Attribute::simple(
1719 Ident::new("validate.future", make_span()),
1720 make_span(),
1721 ));
1722
1723 field.extract_validation_from_attributes();
1724 assert!(field.has_validation());
1725 }
1726
1727 #[test]
1728 fn test_extract_validation_min_items() {
1729 let mut field = make_field(
1730 "items",
1731 FieldType::Scalar(ScalarType::String),
1732 TypeModifier::List,
1733 );
1734 field.attributes.push(Attribute::new(
1735 Ident::new("validate.minItems", make_span()),
1736 vec![AttributeArg::positional(
1737 AttributeValue::Int(1),
1738 make_span(),
1739 )],
1740 make_span(),
1741 ));
1742
1743 field.extract_validation_from_attributes();
1744 assert!(field.has_validation());
1745 }
1746
1747 #[test]
1748 fn test_extract_validation_max_items() {
1749 let mut field = make_field(
1750 "items",
1751 FieldType::Scalar(ScalarType::String),
1752 TypeModifier::List,
1753 );
1754 field.attributes.push(Attribute::new(
1755 Ident::new("validate.maxItems", make_span()),
1756 vec![AttributeArg::positional(
1757 AttributeValue::Int(10),
1758 make_span(),
1759 )],
1760 make_span(),
1761 ));
1762
1763 field.extract_validation_from_attributes();
1764 assert!(field.has_validation());
1765 }
1766
1767 #[test]
1768 fn test_extract_validation_multiple_of() {
1769 let mut field = make_field(
1770 "amount",
1771 FieldType::Scalar(ScalarType::Float),
1772 TypeModifier::Required,
1773 );
1774 field.attributes.push(Attribute::new(
1775 Ident::new("validate.multipleOf", make_span()),
1776 vec![AttributeArg::positional(
1777 AttributeValue::Float(0.01),
1778 make_span(),
1779 )],
1780 make_span(),
1781 ));
1782
1783 field.extract_validation_from_attributes();
1784 assert!(field.has_validation());
1785 }
1786
1787 #[test]
1788 fn test_extract_validation_starts_with() {
1789 let mut field = make_field(
1790 "prefix_field",
1791 FieldType::Scalar(ScalarType::String),
1792 TypeModifier::Required,
1793 );
1794 field.attributes.push(Attribute::new(
1795 Ident::new("validate.startsWith", make_span()),
1796 vec![AttributeArg::positional(
1797 AttributeValue::String("PREFIX_".into()),
1798 make_span(),
1799 )],
1800 make_span(),
1801 ));
1802
1803 field.extract_validation_from_attributes();
1804 assert!(field.has_validation());
1805 }
1806
1807 #[test]
1808 fn test_extract_validation_ends_with() {
1809 let mut field = make_field(
1810 "suffix_field",
1811 FieldType::Scalar(ScalarType::String),
1812 TypeModifier::Required,
1813 );
1814 field.attributes.push(Attribute::new(
1815 Ident::new("validate.endsWith", make_span()),
1816 vec![AttributeArg::positional(
1817 AttributeValue::String(".json".into()),
1818 make_span(),
1819 )],
1820 make_span(),
1821 ));
1822
1823 field.extract_validation_from_attributes();
1824 assert!(field.has_validation());
1825 }
1826
1827 #[test]
1828 fn test_extract_validation_contains() {
1829 let mut field = make_field(
1830 "text",
1831 FieldType::Scalar(ScalarType::String),
1832 TypeModifier::Required,
1833 );
1834 field.attributes.push(Attribute::new(
1835 Ident::new("validate.contains", make_span()),
1836 vec![AttributeArg::positional(
1837 AttributeValue::String("keyword".into()),
1838 make_span(),
1839 )],
1840 make_span(),
1841 ));
1842
1843 field.extract_validation_from_attributes();
1844 assert!(field.has_validation());
1845 }
1846
1847 #[test]
1848 fn test_extract_validation_after() {
1849 let mut field = make_field(
1850 "start_date",
1851 FieldType::Scalar(ScalarType::DateTime),
1852 TypeModifier::Required,
1853 );
1854 field.attributes.push(Attribute::new(
1855 Ident::new("validate.after", make_span()),
1856 vec![AttributeArg::positional(
1857 AttributeValue::String("2024-01-01".into()),
1858 make_span(),
1859 )],
1860 make_span(),
1861 ));
1862
1863 field.extract_validation_from_attributes();
1864 assert!(field.has_validation());
1865 }
1866
1867 #[test]
1868 fn test_extract_validation_before() {
1869 let mut field = make_field(
1870 "end_date",
1871 FieldType::Scalar(ScalarType::DateTime),
1872 TypeModifier::Required,
1873 );
1874 field.attributes.push(Attribute::new(
1875 Ident::new("validate.before", make_span()),
1876 vec![AttributeArg::positional(
1877 AttributeValue::String("2025-12-31".into()),
1878 make_span(),
1879 )],
1880 make_span(),
1881 ));
1882
1883 field.extract_validation_from_attributes();
1884 assert!(field.has_validation());
1885 }
1886
1887 #[test]
1888 fn test_extract_validation_custom() {
1889 let mut field = make_field(
1890 "password",
1891 FieldType::Scalar(ScalarType::String),
1892 TypeModifier::Required,
1893 );
1894 field.attributes.push(Attribute::new(
1895 Ident::new("validate.custom", make_span()),
1896 vec![AttributeArg::positional(
1897 AttributeValue::String("strongPassword".into()),
1898 make_span(),
1899 )],
1900 make_span(),
1901 ));
1902
1903 field.extract_validation_from_attributes();
1904 assert!(field.has_validation());
1905 }
1906
1907 #[test]
1908 fn test_extract_validation_length() {
1909 let mut field = make_field(
1910 "bio",
1911 FieldType::Scalar(ScalarType::String),
1912 TypeModifier::Required,
1913 );
1914 field.attributes.push(Attribute::new(
1915 Ident::new("validate.length", make_span()),
1916 vec![
1917 AttributeArg::positional(AttributeValue::Int(10), make_span()),
1918 AttributeArg::positional(AttributeValue::Int(500), make_span()),
1919 ],
1920 make_span(),
1921 ));
1922
1923 field.extract_validation_from_attributes();
1924 assert!(field.has_validation());
1925 }
1926
1927 #[test]
1928 fn test_extract_validation_cuid() {
1929 let mut field = make_field(
1930 "cuid_field",
1931 FieldType::Scalar(ScalarType::String),
1932 TypeModifier::Required,
1933 );
1934 field.attributes.push(Attribute::simple(
1935 Ident::new("validate.cuid", make_span()),
1936 make_span(),
1937 ));
1938
1939 field.extract_validation_from_attributes();
1940 assert!(field.has_validation());
1941 }
1942
1943 #[test]
1944 fn test_extract_validation_cuid2() {
1945 let mut field = make_field(
1946 "cuid2_field",
1947 FieldType::Scalar(ScalarType::String),
1948 TypeModifier::Required,
1949 );
1950 field.attributes.push(Attribute::simple(
1951 Ident::new("validate.cuid2", make_span()),
1952 make_span(),
1953 ));
1954
1955 field.extract_validation_from_attributes();
1956 assert!(field.has_validation());
1957 }
1958
1959 #[test]
1960 fn test_extract_validation_nanoid() {
1961 let mut field = make_field(
1962 "nanoid_field",
1963 FieldType::Scalar(ScalarType::String),
1964 TypeModifier::Required,
1965 );
1966 field.attributes.push(Attribute::simple(
1967 Ident::new("validate.nanoid", make_span()),
1968 make_span(),
1969 ));
1970
1971 field.extract_validation_from_attributes();
1972 assert!(field.has_validation());
1973 }
1974
1975 #[test]
1976 fn test_extract_validation_ulid() {
1977 let mut field = make_field(
1978 "ulid_field",
1979 FieldType::Scalar(ScalarType::String),
1980 TypeModifier::Required,
1981 );
1982 field.attributes.push(Attribute::simple(
1983 Ident::new("validate.ulid", make_span()),
1984 make_span(),
1985 ));
1986
1987 field.extract_validation_from_attributes();
1988 assert!(field.has_validation());
1989 }
1990
1991 #[test]
1992 fn test_extract_validation_noWhitespace() {
1993 let mut field = make_field(
1994 "username",
1995 FieldType::Scalar(ScalarType::String),
1996 TypeModifier::Required,
1997 );
1998 field.attributes.push(Attribute::simple(
1999 Ident::new("validate.noWhitespace", make_span()),
2000 make_span(),
2001 ));
2002
2003 field.extract_validation_from_attributes();
2004 assert!(field.has_validation());
2005 }
2006
2007 #[test]
2008 fn test_extract_validation_creditCard() {
2009 let mut field = make_field(
2010 "card_number",
2011 FieldType::Scalar(ScalarType::String),
2012 TypeModifier::Required,
2013 );
2014 field.attributes.push(Attribute::simple(
2015 Ident::new("validate.creditCard", make_span()),
2016 make_span(),
2017 ));
2018
2019 field.extract_validation_from_attributes();
2020 assert!(field.has_validation());
2021 }
2022
2023 #[test]
2024 fn test_extract_validation_phone() {
2025 let mut field = make_field(
2026 "phone_number",
2027 FieldType::Scalar(ScalarType::String),
2028 TypeModifier::Required,
2029 );
2030 field.attributes.push(Attribute::simple(
2031 Ident::new("validate.phone", make_span()),
2032 make_span(),
2033 ));
2034
2035 field.extract_validation_from_attributes();
2036 assert!(field.has_validation());
2037 }
2038
2039 #[test]
2040 fn test_extract_validation_nonPositive() {
2041 let mut field = make_field(
2042 "debt",
2043 FieldType::Scalar(ScalarType::Float),
2044 TypeModifier::Required,
2045 );
2046 field.attributes.push(Attribute::simple(
2047 Ident::new("validate.nonPositive", make_span()),
2048 make_span(),
2049 ));
2050
2051 field.extract_validation_from_attributes();
2052 assert!(field.has_validation());
2053 }
2054
2055 #[test]
2056 fn test_extract_validation_pastOrPresent() {
2057 let mut field = make_field(
2058 "login_date",
2059 FieldType::Scalar(ScalarType::DateTime),
2060 TypeModifier::Required,
2061 );
2062 field.attributes.push(Attribute::simple(
2063 Ident::new("validate.pastOrPresent", make_span()),
2064 make_span(),
2065 ));
2066
2067 field.extract_validation_from_attributes();
2068 assert!(field.has_validation());
2069 }
2070
2071 #[test]
2072 fn test_extract_validation_futureOrPresent() {
2073 let mut field = make_field(
2074 "schedule_date",
2075 FieldType::Scalar(ScalarType::DateTime),
2076 TypeModifier::Required,
2077 );
2078 field.attributes.push(Attribute::simple(
2079 Ident::new("validate.futureOrPresent", make_span()),
2080 make_span(),
2081 ));
2082
2083 field.extract_validation_from_attributes();
2084 assert!(field.has_validation());
2085 }
2086
2087 #[test]
2088 fn test_extract_validation_required() {
2089 let mut field = make_field(
2090 "important",
2091 FieldType::Scalar(ScalarType::String),
2092 TypeModifier::Optional,
2093 );
2094 field.attributes.push(Attribute::simple(
2095 Ident::new("validate.required", make_span()),
2096 make_span(),
2097 ));
2098
2099 field.extract_validation_from_attributes();
2100 assert!(field.has_validation());
2101 assert!(field.is_validated_required());
2102 }
2103
2104 #[test]
2105 fn test_extract_validation_notEmpty() {
2106 let mut field = make_field(
2107 "content",
2108 FieldType::Scalar(ScalarType::String),
2109 TypeModifier::Required,
2110 );
2111 field.attributes.push(Attribute::simple(
2112 Ident::new("validate.notEmpty", make_span()),
2113 make_span(),
2114 ));
2115
2116 field.extract_validation_from_attributes();
2117 assert!(field.has_validation());
2118 }
2119
2120 #[test]
2121 fn test_extract_validation_unknown_validator() {
2122 let mut field = make_field(
2123 "field",
2124 FieldType::Scalar(ScalarType::String),
2125 TypeModifier::Required,
2126 );
2127 field.attributes.push(Attribute::simple(
2128 Ident::new("validate.unknownValidator", make_span()),
2129 make_span(),
2130 ));
2131
2132 field.extract_validation_from_attributes();
2133 assert!(!field.has_validation());
2135 }
2136
2137 #[test]
2138 fn test_extract_validation_items() {
2139 let mut field = make_field(
2140 "tags",
2141 FieldType::Scalar(ScalarType::String),
2142 TypeModifier::List,
2143 );
2144 field.attributes.push(Attribute::new(
2145 Ident::new("validate.items", make_span()),
2146 vec![
2147 AttributeArg::positional(AttributeValue::Int(1), make_span()),
2148 AttributeArg::positional(AttributeValue::Int(10), make_span()),
2149 ],
2150 make_span(),
2151 ));
2152
2153 field.extract_validation_from_attributes();
2154 assert!(field.has_validation());
2155 }
2156
2157 #[test]
2160 fn test_extract_validate_attribute_with_ident() {
2161 let mut field = make_field(
2162 "email",
2163 FieldType::Scalar(ScalarType::String),
2164 TypeModifier::Required,
2165 );
2166 field.attributes.push(Attribute::new(
2167 Ident::new("validate", make_span()),
2168 vec![AttributeArg::positional(
2169 AttributeValue::Ident("email".into()),
2170 make_span(),
2171 )],
2172 make_span(),
2173 ));
2174
2175 field.extract_validation_from_attributes();
2176 assert!(field.has_validation());
2177 assert_eq!(field.validation_rules().len(), 1);
2178 }
2179
2180 #[test]
2181 fn test_extract_validate_attribute_with_function() {
2182 let mut field = make_field(
2183 "name",
2184 FieldType::Scalar(ScalarType::String),
2185 TypeModifier::Required,
2186 );
2187 field.attributes.push(Attribute::new(
2188 Ident::new("validate", make_span()),
2189 vec![AttributeArg::positional(
2190 AttributeValue::Function("minLength".into(), vec![AttributeValue::Int(3)]),
2191 make_span(),
2192 )],
2193 make_span(),
2194 ));
2195
2196 field.extract_validation_from_attributes();
2197 assert!(field.has_validation());
2198 assert_eq!(field.validation_rules().len(), 1);
2199 }
2200
2201 #[test]
2202 fn test_extract_validate_multiple_validators() {
2203 let mut field = make_field(
2204 "email",
2205 FieldType::Scalar(ScalarType::String),
2206 TypeModifier::Required,
2207 );
2208 field.attributes.push(Attribute::new(
2209 Ident::new("validate", make_span()),
2210 vec![
2211 AttributeArg::positional(AttributeValue::Ident("email".into()), make_span()),
2212 AttributeArg::positional(
2213 AttributeValue::Function("maxLength".into(), vec![AttributeValue::Int(255)]),
2214 make_span(),
2215 ),
2216 ],
2217 make_span(),
2218 ));
2219
2220 field.extract_validation_from_attributes();
2221 assert!(field.has_validation());
2222 assert_eq!(field.validation_rules().len(), 2);
2223 }
2224}