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