1use serde::{Deserialize, Serialize};
4use smol_str::SmolStr;
5
6use super::{Ident, Span};
7
8#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
10pub enum AttributeValue {
11 String(String),
13 Int(i64),
15 Float(f64),
17 Boolean(bool),
19 Ident(SmolStr),
21 Function(SmolStr, Vec<AttributeValue>),
23 Array(Vec<AttributeValue>),
25 FieldRef(SmolStr),
27 FieldRefList(Vec<SmolStr>),
29}
30
31impl AttributeValue {
32 pub fn as_string(&self) -> Option<&str> {
34 match self {
35 Self::String(s) => Some(s),
36 _ => None,
37 }
38 }
39
40 pub fn as_int(&self) -> Option<i64> {
42 match self {
43 Self::Int(i) => Some(*i),
44 _ => None,
45 }
46 }
47
48 pub fn as_float(&self) -> Option<f64> {
50 match self {
51 Self::Float(f) => Some(*f),
52 Self::Int(i) => Some(*i as f64),
53 _ => None,
54 }
55 }
56
57 pub fn as_bool(&self) -> Option<bool> {
59 match self {
60 Self::Boolean(b) => Some(*b),
61 _ => None,
62 }
63 }
64
65 pub fn as_ident(&self) -> Option<&str> {
67 match self {
68 Self::Ident(s) => Some(s),
69 _ => None,
70 }
71 }
72}
73
74#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
76pub struct AttributeArg {
77 pub name: Option<Ident>,
79 pub value: AttributeValue,
81 pub span: Span,
83}
84
85impl AttributeArg {
86 pub fn positional(value: AttributeValue, span: Span) -> Self {
88 Self {
89 name: None,
90 value,
91 span,
92 }
93 }
94
95 pub fn named(name: Ident, value: AttributeValue, span: Span) -> Self {
97 Self {
98 name: Some(name),
99 value,
100 span,
101 }
102 }
103
104 pub fn is_positional(&self) -> bool {
106 self.name.is_none()
107 }
108}
109
110#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
112pub struct Attribute {
113 pub name: Ident,
115 pub args: Vec<AttributeArg>,
117 pub span: Span,
119}
120
121impl Attribute {
122 pub fn new(name: Ident, args: Vec<AttributeArg>, span: Span) -> Self {
124 Self { name, args, span }
125 }
126
127 pub fn simple(name: Ident, span: Span) -> Self {
129 Self {
130 name,
131 args: vec![],
132 span,
133 }
134 }
135
136 pub fn name(&self) -> &str {
138 self.name.as_str()
139 }
140
141 pub fn is(&self, name: &str) -> bool {
143 self.name.as_str() == name
144 }
145
146 pub fn first_arg(&self) -> Option<&AttributeValue> {
148 self.args.first().map(|a| &a.value)
149 }
150
151 pub fn get_arg(&self, name: &str) -> Option<&AttributeValue> {
153 self.args
154 .iter()
155 .find(|a| a.name.as_ref().map(|n| n.as_str()) == Some(name))
156 .map(|a| &a.value)
157 }
158
159 pub fn is_field_attribute(&self) -> bool {
161 matches!(
162 self.name(),
163 "id" | "auto"
164 | "unique"
165 | "index"
166 | "default"
167 | "updated_at"
168 | "omit"
169 | "map"
170 | "db"
171 | "relation"
172 )
173 }
174
175 pub fn is_model_attribute(&self) -> bool {
177 matches!(
178 self.name(),
179 "map" | "index" | "unique" | "id" | "search" | "sql"
180 )
181 }
182}
183
184#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
186pub struct FieldAttributes {
187 pub is_id: bool,
189 pub is_auto: bool,
191 pub is_unique: bool,
193 pub is_indexed: bool,
195 pub is_updated_at: bool,
197 pub is_omit: bool,
199 pub default: Option<AttributeValue>,
201 pub map: Option<String>,
203 pub native_type: Option<NativeType>,
205 pub relation: Option<RelationAttribute>,
207}
208
209#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
211pub struct NativeType {
212 pub name: SmolStr,
214 pub args: Vec<AttributeValue>,
216}
217
218impl NativeType {
219 pub fn new(name: impl Into<SmolStr>, args: Vec<AttributeValue>) -> Self {
221 Self {
222 name: name.into(),
223 args,
224 }
225 }
226}
227
228#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
230pub struct RelationAttribute {
231 pub name: Option<String>,
233 pub fields: Vec<SmolStr>,
235 pub references: Vec<SmolStr>,
237 pub on_delete: Option<ReferentialAction>,
239 pub on_update: Option<ReferentialAction>,
241}
242
243#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
245pub enum ReferentialAction {
246 Cascade,
248 Restrict,
250 NoAction,
252 SetNull,
254 SetDefault,
256}
257
258impl ReferentialAction {
259 #[allow(clippy::should_implement_trait)]
261 pub fn from_str(s: &str) -> Option<Self> {
262 match s {
263 "Cascade" => Some(Self::Cascade),
264 "Restrict" => Some(Self::Restrict),
265 "NoAction" => Some(Self::NoAction),
266 "SetNull" => Some(Self::SetNull),
267 "SetDefault" => Some(Self::SetDefault),
268 _ => None,
269 }
270 }
271
272 pub fn as_str(&self) -> &'static str {
274 match self {
275 Self::Cascade => "CASCADE",
276 Self::Restrict => "RESTRICT",
277 Self::NoAction => "NO ACTION",
278 Self::SetNull => "SET NULL",
279 Self::SetDefault => "SET DEFAULT",
280 }
281 }
282}
283
284#[cfg(test)]
285mod tests {
286 use super::*;
287
288 #[test]
291 fn test_attribute_value_string() {
292 let val = AttributeValue::String("hello".into());
293 assert_eq!(val.as_string(), Some("hello"));
294 assert_eq!(val.as_int(), None);
295 assert_eq!(val.as_bool(), None);
296 assert_eq!(val.as_ident(), None);
297 }
298
299 #[test]
300 fn test_attribute_value_int() {
301 let val = AttributeValue::Int(42);
302 assert_eq!(val.as_int(), Some(42));
303 assert_eq!(val.as_string(), None);
304 assert_eq!(val.as_bool(), None);
305 }
306
307 #[test]
308 fn test_attribute_value_int_negative() {
309 let val = AttributeValue::Int(-100);
310 assert_eq!(val.as_int(), Some(-100));
311 }
312
313 #[test]
314 #[allow(clippy::approx_constant)]
315 fn test_attribute_value_float() {
316 let val = AttributeValue::Float(3.14);
317 assert_eq!(val.as_int(), None);
318 assert_eq!(val.as_string(), None);
319 }
320
321 #[test]
322 fn test_attribute_value_boolean_true() {
323 let val = AttributeValue::Boolean(true);
324 assert_eq!(val.as_bool(), Some(true));
325 assert_eq!(val.as_int(), None);
326 }
327
328 #[test]
329 fn test_attribute_value_boolean_false() {
330 let val = AttributeValue::Boolean(false);
331 assert_eq!(val.as_bool(), Some(false));
332 }
333
334 #[test]
335 fn test_attribute_value_ident() {
336 let val = AttributeValue::Ident("MyEnum".into());
337 assert_eq!(val.as_ident(), Some("MyEnum"));
338 assert_eq!(val.as_string(), None);
339 }
340
341 #[test]
342 fn test_attribute_value_function() {
343 let val = AttributeValue::Function("now".into(), vec![]);
344 assert_eq!(val.as_string(), None);
345 assert_eq!(val.as_int(), None);
346
347 if let AttributeValue::Function(name, args) = val {
349 assert_eq!(name.as_str(), "now");
350 assert!(args.is_empty());
351 } else {
352 panic!("Expected Function variant");
353 }
354 }
355
356 #[test]
357 fn test_attribute_value_function_with_args() {
358 let val = AttributeValue::Function("uuid".into(), vec![AttributeValue::Int(4)]);
359
360 if let AttributeValue::Function(name, args) = val {
361 assert_eq!(name.as_str(), "uuid");
362 assert_eq!(args.len(), 1);
363 } else {
364 panic!("Expected Function variant");
365 }
366 }
367
368 #[test]
369 fn test_attribute_value_array() {
370 let val = AttributeValue::Array(vec![
371 AttributeValue::String("a".into()),
372 AttributeValue::String("b".into()),
373 ]);
374
375 if let AttributeValue::Array(items) = val {
376 assert_eq!(items.len(), 2);
377 } else {
378 panic!("Expected Array variant");
379 }
380 }
381
382 #[test]
383 fn test_attribute_value_field_ref() {
384 let val = AttributeValue::FieldRef("user_id".into());
385 assert_eq!(val.as_ident(), None);
386
387 if let AttributeValue::FieldRef(name) = val {
388 assert_eq!(name.as_str(), "user_id");
389 } else {
390 panic!("Expected FieldRef variant");
391 }
392 }
393
394 #[test]
395 fn test_attribute_value_field_ref_list() {
396 let val = AttributeValue::FieldRefList(vec!["id".into(), "name".into()]);
397
398 if let AttributeValue::FieldRefList(fields) = val {
399 assert_eq!(fields.len(), 2);
400 assert_eq!(fields[0].as_str(), "id");
401 assert_eq!(fields[1].as_str(), "name");
402 } else {
403 panic!("Expected FieldRefList variant");
404 }
405 }
406
407 #[test]
408 fn test_attribute_value_equality() {
409 let val1 = AttributeValue::Int(42);
410 let val2 = AttributeValue::Int(42);
411 let val3 = AttributeValue::Int(43);
412
413 assert_eq!(val1, val2);
414 assert_ne!(val1, val3);
415 }
416
417 #[test]
420 fn test_attribute_arg_positional() {
421 let arg = AttributeArg::positional(AttributeValue::Int(42), Span::new(0, 2));
422
423 assert!(arg.is_positional());
424 assert!(arg.name.is_none());
425 assert_eq!(arg.value.as_int(), Some(42));
426 }
427
428 #[test]
429 fn test_attribute_arg_named() {
430 let arg = AttributeArg::named(
431 Ident::new("length", Span::new(0, 6)),
432 AttributeValue::Int(255),
433 Span::new(0, 10),
434 );
435
436 assert!(!arg.is_positional());
437 assert!(arg.name.is_some());
438 assert_eq!(arg.name.as_ref().unwrap().as_str(), "length");
439 assert_eq!(arg.value.as_int(), Some(255));
440 }
441
442 #[test]
443 fn test_attribute_arg_equality() {
444 let arg1 = AttributeArg::positional(AttributeValue::Int(42), Span::new(0, 2));
445 let arg2 = AttributeArg::positional(AttributeValue::Int(42), Span::new(0, 2));
446 let arg3 = AttributeArg::positional(AttributeValue::Int(43), Span::new(0, 2));
447
448 assert_eq!(arg1, arg2);
449 assert_ne!(arg1, arg3);
450 }
451
452 #[test]
455 fn test_attribute_new() {
456 let attr = Attribute::new(
457 Ident::new("default", Span::new(0, 7)),
458 vec![AttributeArg::positional(
459 AttributeValue::Int(0),
460 Span::new(8, 9),
461 )],
462 Span::new(0, 10),
463 );
464
465 assert_eq!(attr.name(), "default");
466 assert_eq!(attr.args.len(), 1);
467 }
468
469 #[test]
470 fn test_attribute_simple() {
471 let attr = Attribute::simple(Ident::new("id", Span::new(0, 2)), Span::new(0, 3));
472
473 assert_eq!(attr.name(), "id");
474 assert!(attr.args.is_empty());
475 }
476
477 #[test]
478 fn test_attribute_is() {
479 let attr = Attribute::simple(Ident::new("unique", Span::new(0, 6)), Span::new(0, 7));
480
481 assert!(attr.is("unique"));
482 assert!(!attr.is("id"));
483 assert!(!attr.is("UNIQUE")); }
485
486 #[test]
487 fn test_attribute_first_arg() {
488 let attr = Attribute::new(
489 Ident::new("default", Span::new(0, 7)),
490 vec![
491 AttributeArg::positional(AttributeValue::Int(42), Span::new(8, 10)),
492 AttributeArg::positional(AttributeValue::String("extra".into()), Span::new(12, 19)),
493 ],
494 Span::new(0, 20),
495 );
496
497 assert_eq!(attr.first_arg().unwrap().as_int(), Some(42));
498 }
499
500 #[test]
501 fn test_attribute_first_arg_none() {
502 let attr = Attribute::simple(Ident::new("id", Span::new(0, 2)), Span::new(0, 3));
503 assert!(attr.first_arg().is_none());
504 }
505
506 #[test]
507 fn test_attribute_get_arg() {
508 let attr = Attribute::new(
509 Ident::new("relation", Span::new(0, 8)),
510 vec![
511 AttributeArg::named(
512 Ident::new("fields", Span::new(9, 15)),
513 AttributeValue::FieldRefList(vec!["user_id".into()]),
514 Span::new(9, 30),
515 ),
516 AttributeArg::named(
517 Ident::new("references", Span::new(32, 42)),
518 AttributeValue::FieldRefList(vec!["id".into()]),
519 Span::new(32, 50),
520 ),
521 ],
522 Span::new(0, 51),
523 );
524
525 let fields = attr.get_arg("fields").unwrap();
526 if let AttributeValue::FieldRefList(f) = fields {
527 assert_eq!(f[0].as_str(), "user_id");
528 } else {
529 panic!("Expected FieldRefList");
530 }
531
532 assert!(attr.get_arg("onDelete").is_none());
533 }
534
535 #[test]
536 fn test_attribute_is_field_attribute() {
537 let id_attr = Attribute::simple(Ident::new("id", Span::new(0, 2)), Span::new(0, 3));
538 let auto_attr = Attribute::simple(Ident::new("auto", Span::new(0, 4)), Span::new(0, 5));
539 let unique_attr = Attribute::simple(Ident::new("unique", Span::new(0, 6)), Span::new(0, 7));
540 let index_attr = Attribute::simple(Ident::new("index", Span::new(0, 5)), Span::new(0, 6));
541 let default_attr =
542 Attribute::simple(Ident::new("default", Span::new(0, 7)), Span::new(0, 8));
543 let updated_at_attr =
544 Attribute::simple(Ident::new("updated_at", Span::new(0, 10)), Span::new(0, 11));
545 let omit_attr = Attribute::simple(Ident::new("omit", Span::new(0, 4)), Span::new(0, 5));
546 let map_attr = Attribute::simple(Ident::new("map", Span::new(0, 3)), Span::new(0, 4));
547 let db_attr = Attribute::simple(Ident::new("db", Span::new(0, 2)), Span::new(0, 3));
548 let relation_attr =
549 Attribute::simple(Ident::new("relation", Span::new(0, 8)), Span::new(0, 9));
550 let unknown_attr =
551 Attribute::simple(Ident::new("unknown", Span::new(0, 7)), Span::new(0, 8));
552
553 assert!(id_attr.is_field_attribute());
554 assert!(auto_attr.is_field_attribute());
555 assert!(unique_attr.is_field_attribute());
556 assert!(index_attr.is_field_attribute());
557 assert!(default_attr.is_field_attribute());
558 assert!(updated_at_attr.is_field_attribute());
559 assert!(omit_attr.is_field_attribute());
560 assert!(map_attr.is_field_attribute());
561 assert!(db_attr.is_field_attribute());
562 assert!(relation_attr.is_field_attribute());
563 assert!(!unknown_attr.is_field_attribute());
564 }
565
566 #[test]
567 fn test_attribute_is_model_attribute() {
568 let map_attr = Attribute::simple(Ident::new("map", Span::new(0, 3)), Span::new(0, 4));
569 let index_attr = Attribute::simple(Ident::new("index", Span::new(0, 5)), Span::new(0, 6));
570 let unique_attr = Attribute::simple(Ident::new("unique", Span::new(0, 6)), Span::new(0, 7));
571 let id_attr = Attribute::simple(Ident::new("id", Span::new(0, 2)), Span::new(0, 3));
572 let search_attr = Attribute::simple(Ident::new("search", Span::new(0, 6)), Span::new(0, 7));
573 let sql_attr = Attribute::simple(Ident::new("sql", Span::new(0, 3)), Span::new(0, 4));
574 let unknown_attr =
575 Attribute::simple(Ident::new("unknown", Span::new(0, 7)), Span::new(0, 8));
576
577 assert!(map_attr.is_model_attribute());
578 assert!(index_attr.is_model_attribute());
579 assert!(unique_attr.is_model_attribute());
580 assert!(id_attr.is_model_attribute());
581 assert!(search_attr.is_model_attribute());
582 assert!(sql_attr.is_model_attribute());
583 assert!(!unknown_attr.is_model_attribute());
584 }
585
586 #[test]
589 fn test_field_attributes_default() {
590 let attrs = FieldAttributes::default();
591
592 assert!(!attrs.is_id);
593 assert!(!attrs.is_auto);
594 assert!(!attrs.is_unique);
595 assert!(!attrs.is_indexed);
596 assert!(!attrs.is_updated_at);
597 assert!(!attrs.is_omit);
598 assert!(attrs.default.is_none());
599 assert!(attrs.map.is_none());
600 assert!(attrs.native_type.is_none());
601 assert!(attrs.relation.is_none());
602 }
603
604 #[test]
605 fn test_field_attributes_with_values() {
606 let attrs = FieldAttributes {
607 is_id: true,
608 is_auto: true,
609 is_unique: false,
610 is_indexed: false,
611 is_updated_at: false,
612 is_omit: false,
613 default: Some(AttributeValue::Function("auto".into(), vec![])),
614 map: Some("user_id".to_string()),
615 native_type: None,
616 relation: None,
617 };
618
619 assert!(attrs.is_id);
620 assert!(attrs.is_auto);
621 assert!(attrs.default.is_some());
622 assert_eq!(attrs.map, Some("user_id".to_string()));
623 }
624
625 #[test]
628 fn test_native_type_new() {
629 let nt = NativeType::new("VarChar", vec![AttributeValue::Int(255)]);
630
631 assert_eq!(nt.name.as_str(), "VarChar");
632 assert_eq!(nt.args.len(), 1);
633 assert_eq!(nt.args[0].as_int(), Some(255));
634 }
635
636 #[test]
637 fn test_native_type_no_args() {
638 let nt = NativeType::new("Text", vec![]);
639
640 assert_eq!(nt.name.as_str(), "Text");
641 assert!(nt.args.is_empty());
642 }
643
644 #[test]
645 fn test_native_type_multiple_args() {
646 let nt = NativeType::new(
647 "Decimal",
648 vec![AttributeValue::Int(10), AttributeValue::Int(2)],
649 );
650
651 assert_eq!(nt.name.as_str(), "Decimal");
652 assert_eq!(nt.args.len(), 2);
653 }
654
655 #[test]
656 fn test_native_type_equality() {
657 let nt1 = NativeType::new("VarChar", vec![AttributeValue::Int(255)]);
658 let nt2 = NativeType::new("VarChar", vec![AttributeValue::Int(255)]);
659 let nt3 = NativeType::new("VarChar", vec![AttributeValue::Int(100)]);
660
661 assert_eq!(nt1, nt2);
662 assert_ne!(nt1, nt3);
663 }
664
665 #[test]
668 fn test_relation_attribute() {
669 let rel = RelationAttribute {
670 name: Some("UserPosts".to_string()),
671 fields: vec!["author_id".into()],
672 references: vec!["id".into()],
673 on_delete: Some(ReferentialAction::Cascade),
674 on_update: Some(ReferentialAction::Cascade),
675 };
676
677 assert_eq!(rel.name, Some("UserPosts".to_string()));
678 assert_eq!(rel.fields[0].as_str(), "author_id");
679 assert_eq!(rel.references[0].as_str(), "id");
680 assert_eq!(rel.on_delete, Some(ReferentialAction::Cascade));
681 }
682
683 #[test]
684 fn test_relation_attribute_minimal() {
685 let rel = RelationAttribute {
686 name: None,
687 fields: vec![],
688 references: vec![],
689 on_delete: None,
690 on_update: None,
691 };
692
693 assert!(rel.name.is_none());
694 assert!(rel.fields.is_empty());
695 }
696
697 #[test]
700 fn test_referential_action_from_str_cascade() {
701 assert_eq!(
702 ReferentialAction::from_str("Cascade"),
703 Some(ReferentialAction::Cascade)
704 );
705 }
706
707 #[test]
708 fn test_referential_action_from_str_restrict() {
709 assert_eq!(
710 ReferentialAction::from_str("Restrict"),
711 Some(ReferentialAction::Restrict)
712 );
713 }
714
715 #[test]
716 fn test_referential_action_from_str_no_action() {
717 assert_eq!(
718 ReferentialAction::from_str("NoAction"),
719 Some(ReferentialAction::NoAction)
720 );
721 }
722
723 #[test]
724 fn test_referential_action_from_str_set_null() {
725 assert_eq!(
726 ReferentialAction::from_str("SetNull"),
727 Some(ReferentialAction::SetNull)
728 );
729 }
730
731 #[test]
732 fn test_referential_action_from_str_set_default() {
733 assert_eq!(
734 ReferentialAction::from_str("SetDefault"),
735 Some(ReferentialAction::SetDefault)
736 );
737 }
738
739 #[test]
740 fn test_referential_action_from_str_unknown() {
741 assert_eq!(ReferentialAction::from_str("Unknown"), None);
742 assert_eq!(ReferentialAction::from_str("cascade"), None); assert_eq!(ReferentialAction::from_str(""), None);
744 }
745
746 #[test]
747 fn test_referential_action_as_str() {
748 assert_eq!(ReferentialAction::Cascade.as_str(), "CASCADE");
749 assert_eq!(ReferentialAction::Restrict.as_str(), "RESTRICT");
750 assert_eq!(ReferentialAction::NoAction.as_str(), "NO ACTION");
751 assert_eq!(ReferentialAction::SetNull.as_str(), "SET NULL");
752 assert_eq!(ReferentialAction::SetDefault.as_str(), "SET DEFAULT");
753 }
754
755 #[test]
756 fn test_referential_action_equality() {
757 assert_eq!(ReferentialAction::Cascade, ReferentialAction::Cascade);
758 assert_ne!(ReferentialAction::Cascade, ReferentialAction::Restrict);
759 }
760
761 #[test]
762 fn test_referential_action_copy() {
763 let action = ReferentialAction::Cascade;
764 let copy = action;
765 assert_eq!(action, copy);
766 }
767}