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 fn test_attribute_value_float() {
315 let val = AttributeValue::Float(3.14);
316 assert_eq!(val.as_int(), None);
317 assert_eq!(val.as_string(), None);
318 }
319
320 #[test]
321 fn test_attribute_value_boolean_true() {
322 let val = AttributeValue::Boolean(true);
323 assert_eq!(val.as_bool(), Some(true));
324 assert_eq!(val.as_int(), None);
325 }
326
327 #[test]
328 fn test_attribute_value_boolean_false() {
329 let val = AttributeValue::Boolean(false);
330 assert_eq!(val.as_bool(), Some(false));
331 }
332
333 #[test]
334 fn test_attribute_value_ident() {
335 let val = AttributeValue::Ident("MyEnum".into());
336 assert_eq!(val.as_ident(), Some("MyEnum"));
337 assert_eq!(val.as_string(), None);
338 }
339
340 #[test]
341 fn test_attribute_value_function() {
342 let val = AttributeValue::Function("now".into(), vec![]);
343 assert_eq!(val.as_string(), None);
344 assert_eq!(val.as_int(), None);
345
346 if let AttributeValue::Function(name, args) = val {
348 assert_eq!(name.as_str(), "now");
349 assert!(args.is_empty());
350 } else {
351 panic!("Expected Function variant");
352 }
353 }
354
355 #[test]
356 fn test_attribute_value_function_with_args() {
357 let val = AttributeValue::Function("uuid".into(), vec![AttributeValue::Int(4)]);
358
359 if let AttributeValue::Function(name, args) = val {
360 assert_eq!(name.as_str(), "uuid");
361 assert_eq!(args.len(), 1);
362 } else {
363 panic!("Expected Function variant");
364 }
365 }
366
367 #[test]
368 fn test_attribute_value_array() {
369 let val = AttributeValue::Array(vec![
370 AttributeValue::String("a".into()),
371 AttributeValue::String("b".into()),
372 ]);
373
374 if let AttributeValue::Array(items) = val {
375 assert_eq!(items.len(), 2);
376 } else {
377 panic!("Expected Array variant");
378 }
379 }
380
381 #[test]
382 fn test_attribute_value_field_ref() {
383 let val = AttributeValue::FieldRef("user_id".into());
384 assert_eq!(val.as_ident(), None);
385
386 if let AttributeValue::FieldRef(name) = val {
387 assert_eq!(name.as_str(), "user_id");
388 } else {
389 panic!("Expected FieldRef variant");
390 }
391 }
392
393 #[test]
394 fn test_attribute_value_field_ref_list() {
395 let val = AttributeValue::FieldRefList(vec!["id".into(), "name".into()]);
396
397 if let AttributeValue::FieldRefList(fields) = val {
398 assert_eq!(fields.len(), 2);
399 assert_eq!(fields[0].as_str(), "id");
400 assert_eq!(fields[1].as_str(), "name");
401 } else {
402 panic!("Expected FieldRefList variant");
403 }
404 }
405
406 #[test]
407 fn test_attribute_value_equality() {
408 let val1 = AttributeValue::Int(42);
409 let val2 = AttributeValue::Int(42);
410 let val3 = AttributeValue::Int(43);
411
412 assert_eq!(val1, val2);
413 assert_ne!(val1, val3);
414 }
415
416 #[test]
419 fn test_attribute_arg_positional() {
420 let arg = AttributeArg::positional(AttributeValue::Int(42), Span::new(0, 2));
421
422 assert!(arg.is_positional());
423 assert!(arg.name.is_none());
424 assert_eq!(arg.value.as_int(), Some(42));
425 }
426
427 #[test]
428 fn test_attribute_arg_named() {
429 let arg = AttributeArg::named(
430 Ident::new("length", Span::new(0, 6)),
431 AttributeValue::Int(255),
432 Span::new(0, 10),
433 );
434
435 assert!(!arg.is_positional());
436 assert!(arg.name.is_some());
437 assert_eq!(arg.name.as_ref().unwrap().as_str(), "length");
438 assert_eq!(arg.value.as_int(), Some(255));
439 }
440
441 #[test]
442 fn test_attribute_arg_equality() {
443 let arg1 = AttributeArg::positional(AttributeValue::Int(42), Span::new(0, 2));
444 let arg2 = AttributeArg::positional(AttributeValue::Int(42), Span::new(0, 2));
445 let arg3 = AttributeArg::positional(AttributeValue::Int(43), Span::new(0, 2));
446
447 assert_eq!(arg1, arg2);
448 assert_ne!(arg1, arg3);
449 }
450
451 #[test]
454 fn test_attribute_new() {
455 let attr = Attribute::new(
456 Ident::new("default", Span::new(0, 7)),
457 vec![AttributeArg::positional(
458 AttributeValue::Int(0),
459 Span::new(8, 9),
460 )],
461 Span::new(0, 10),
462 );
463
464 assert_eq!(attr.name(), "default");
465 assert_eq!(attr.args.len(), 1);
466 }
467
468 #[test]
469 fn test_attribute_simple() {
470 let attr = Attribute::simple(Ident::new("id", Span::new(0, 2)), Span::new(0, 3));
471
472 assert_eq!(attr.name(), "id");
473 assert!(attr.args.is_empty());
474 }
475
476 #[test]
477 fn test_attribute_is() {
478 let attr = Attribute::simple(Ident::new("unique", Span::new(0, 6)), Span::new(0, 7));
479
480 assert!(attr.is("unique"));
481 assert!(!attr.is("id"));
482 assert!(!attr.is("UNIQUE")); }
484
485 #[test]
486 fn test_attribute_first_arg() {
487 let attr = Attribute::new(
488 Ident::new("default", Span::new(0, 7)),
489 vec![
490 AttributeArg::positional(AttributeValue::Int(42), Span::new(8, 10)),
491 AttributeArg::positional(AttributeValue::String("extra".into()), Span::new(12, 19)),
492 ],
493 Span::new(0, 20),
494 );
495
496 assert_eq!(attr.first_arg().unwrap().as_int(), Some(42));
497 }
498
499 #[test]
500 fn test_attribute_first_arg_none() {
501 let attr = Attribute::simple(Ident::new("id", Span::new(0, 2)), Span::new(0, 3));
502 assert!(attr.first_arg().is_none());
503 }
504
505 #[test]
506 fn test_attribute_get_arg() {
507 let attr = Attribute::new(
508 Ident::new("relation", Span::new(0, 8)),
509 vec![
510 AttributeArg::named(
511 Ident::new("fields", Span::new(9, 15)),
512 AttributeValue::FieldRefList(vec!["user_id".into()]),
513 Span::new(9, 30),
514 ),
515 AttributeArg::named(
516 Ident::new("references", Span::new(32, 42)),
517 AttributeValue::FieldRefList(vec!["id".into()]),
518 Span::new(32, 50),
519 ),
520 ],
521 Span::new(0, 51),
522 );
523
524 let fields = attr.get_arg("fields").unwrap();
525 if let AttributeValue::FieldRefList(f) = fields {
526 assert_eq!(f[0].as_str(), "user_id");
527 } else {
528 panic!("Expected FieldRefList");
529 }
530
531 assert!(attr.get_arg("onDelete").is_none());
532 }
533
534 #[test]
535 fn test_attribute_is_field_attribute() {
536 let id_attr = Attribute::simple(Ident::new("id", Span::new(0, 2)), Span::new(0, 3));
537 let auto_attr = Attribute::simple(Ident::new("auto", Span::new(0, 4)), Span::new(0, 5));
538 let unique_attr = Attribute::simple(Ident::new("unique", Span::new(0, 6)), Span::new(0, 7));
539 let index_attr = Attribute::simple(Ident::new("index", Span::new(0, 5)), Span::new(0, 6));
540 let default_attr =
541 Attribute::simple(Ident::new("default", Span::new(0, 7)), Span::new(0, 8));
542 let updated_at_attr =
543 Attribute::simple(Ident::new("updated_at", Span::new(0, 10)), Span::new(0, 11));
544 let omit_attr = Attribute::simple(Ident::new("omit", Span::new(0, 4)), Span::new(0, 5));
545 let map_attr = Attribute::simple(Ident::new("map", Span::new(0, 3)), Span::new(0, 4));
546 let db_attr = Attribute::simple(Ident::new("db", Span::new(0, 2)), Span::new(0, 3));
547 let relation_attr =
548 Attribute::simple(Ident::new("relation", Span::new(0, 8)), Span::new(0, 9));
549 let unknown_attr =
550 Attribute::simple(Ident::new("unknown", Span::new(0, 7)), Span::new(0, 8));
551
552 assert!(id_attr.is_field_attribute());
553 assert!(auto_attr.is_field_attribute());
554 assert!(unique_attr.is_field_attribute());
555 assert!(index_attr.is_field_attribute());
556 assert!(default_attr.is_field_attribute());
557 assert!(updated_at_attr.is_field_attribute());
558 assert!(omit_attr.is_field_attribute());
559 assert!(map_attr.is_field_attribute());
560 assert!(db_attr.is_field_attribute());
561 assert!(relation_attr.is_field_attribute());
562 assert!(!unknown_attr.is_field_attribute());
563 }
564
565 #[test]
566 fn test_attribute_is_model_attribute() {
567 let map_attr = Attribute::simple(Ident::new("map", Span::new(0, 3)), Span::new(0, 4));
568 let index_attr = Attribute::simple(Ident::new("index", Span::new(0, 5)), Span::new(0, 6));
569 let unique_attr = Attribute::simple(Ident::new("unique", Span::new(0, 6)), Span::new(0, 7));
570 let id_attr = Attribute::simple(Ident::new("id", Span::new(0, 2)), Span::new(0, 3));
571 let search_attr = Attribute::simple(Ident::new("search", Span::new(0, 6)), Span::new(0, 7));
572 let sql_attr = Attribute::simple(Ident::new("sql", Span::new(0, 3)), Span::new(0, 4));
573 let unknown_attr =
574 Attribute::simple(Ident::new("unknown", Span::new(0, 7)), Span::new(0, 8));
575
576 assert!(map_attr.is_model_attribute());
577 assert!(index_attr.is_model_attribute());
578 assert!(unique_attr.is_model_attribute());
579 assert!(id_attr.is_model_attribute());
580 assert!(search_attr.is_model_attribute());
581 assert!(sql_attr.is_model_attribute());
582 assert!(!unknown_attr.is_model_attribute());
583 }
584
585 #[test]
588 fn test_field_attributes_default() {
589 let attrs = FieldAttributes::default();
590
591 assert!(!attrs.is_id);
592 assert!(!attrs.is_auto);
593 assert!(!attrs.is_unique);
594 assert!(!attrs.is_indexed);
595 assert!(!attrs.is_updated_at);
596 assert!(!attrs.is_omit);
597 assert!(attrs.default.is_none());
598 assert!(attrs.map.is_none());
599 assert!(attrs.native_type.is_none());
600 assert!(attrs.relation.is_none());
601 }
602
603 #[test]
604 fn test_field_attributes_with_values() {
605 let attrs = FieldAttributes {
606 is_id: true,
607 is_auto: true,
608 is_unique: false,
609 is_indexed: false,
610 is_updated_at: false,
611 is_omit: false,
612 default: Some(AttributeValue::Function("auto".into(), vec![])),
613 map: Some("user_id".to_string()),
614 native_type: None,
615 relation: None,
616 };
617
618 assert!(attrs.is_id);
619 assert!(attrs.is_auto);
620 assert!(attrs.default.is_some());
621 assert_eq!(attrs.map, Some("user_id".to_string()));
622 }
623
624 #[test]
627 fn test_native_type_new() {
628 let nt = NativeType::new("VarChar", vec![AttributeValue::Int(255)]);
629
630 assert_eq!(nt.name.as_str(), "VarChar");
631 assert_eq!(nt.args.len(), 1);
632 assert_eq!(nt.args[0].as_int(), Some(255));
633 }
634
635 #[test]
636 fn test_native_type_no_args() {
637 let nt = NativeType::new("Text", vec![]);
638
639 assert_eq!(nt.name.as_str(), "Text");
640 assert!(nt.args.is_empty());
641 }
642
643 #[test]
644 fn test_native_type_multiple_args() {
645 let nt = NativeType::new(
646 "Decimal",
647 vec![AttributeValue::Int(10), AttributeValue::Int(2)],
648 );
649
650 assert_eq!(nt.name.as_str(), "Decimal");
651 assert_eq!(nt.args.len(), 2);
652 }
653
654 #[test]
655 fn test_native_type_equality() {
656 let nt1 = NativeType::new("VarChar", vec![AttributeValue::Int(255)]);
657 let nt2 = NativeType::new("VarChar", vec![AttributeValue::Int(255)]);
658 let nt3 = NativeType::new("VarChar", vec![AttributeValue::Int(100)]);
659
660 assert_eq!(nt1, nt2);
661 assert_ne!(nt1, nt3);
662 }
663
664 #[test]
667 fn test_relation_attribute() {
668 let rel = RelationAttribute {
669 name: Some("UserPosts".to_string()),
670 fields: vec!["author_id".into()],
671 references: vec!["id".into()],
672 on_delete: Some(ReferentialAction::Cascade),
673 on_update: Some(ReferentialAction::Cascade),
674 };
675
676 assert_eq!(rel.name, Some("UserPosts".to_string()));
677 assert_eq!(rel.fields[0].as_str(), "author_id");
678 assert_eq!(rel.references[0].as_str(), "id");
679 assert_eq!(rel.on_delete, Some(ReferentialAction::Cascade));
680 }
681
682 #[test]
683 fn test_relation_attribute_minimal() {
684 let rel = RelationAttribute {
685 name: None,
686 fields: vec![],
687 references: vec![],
688 on_delete: None,
689 on_update: None,
690 };
691
692 assert!(rel.name.is_none());
693 assert!(rel.fields.is_empty());
694 }
695
696 #[test]
699 fn test_referential_action_from_str_cascade() {
700 assert_eq!(
701 ReferentialAction::from_str("Cascade"),
702 Some(ReferentialAction::Cascade)
703 );
704 }
705
706 #[test]
707 fn test_referential_action_from_str_restrict() {
708 assert_eq!(
709 ReferentialAction::from_str("Restrict"),
710 Some(ReferentialAction::Restrict)
711 );
712 }
713
714 #[test]
715 fn test_referential_action_from_str_no_action() {
716 assert_eq!(
717 ReferentialAction::from_str("NoAction"),
718 Some(ReferentialAction::NoAction)
719 );
720 }
721
722 #[test]
723 fn test_referential_action_from_str_set_null() {
724 assert_eq!(
725 ReferentialAction::from_str("SetNull"),
726 Some(ReferentialAction::SetNull)
727 );
728 }
729
730 #[test]
731 fn test_referential_action_from_str_set_default() {
732 assert_eq!(
733 ReferentialAction::from_str("SetDefault"),
734 Some(ReferentialAction::SetDefault)
735 );
736 }
737
738 #[test]
739 fn test_referential_action_from_str_unknown() {
740 assert_eq!(ReferentialAction::from_str("Unknown"), None);
741 assert_eq!(ReferentialAction::from_str("cascade"), None); assert_eq!(ReferentialAction::from_str(""), None);
743 }
744
745 #[test]
746 fn test_referential_action_as_str() {
747 assert_eq!(ReferentialAction::Cascade.as_str(), "CASCADE");
748 assert_eq!(ReferentialAction::Restrict.as_str(), "RESTRICT");
749 assert_eq!(ReferentialAction::NoAction.as_str(), "NO ACTION");
750 assert_eq!(ReferentialAction::SetNull.as_str(), "SET NULL");
751 assert_eq!(ReferentialAction::SetDefault.as_str(), "SET DEFAULT");
752 }
753
754 #[test]
755 fn test_referential_action_equality() {
756 assert_eq!(ReferentialAction::Cascade, ReferentialAction::Cascade);
757 assert_ne!(ReferentialAction::Cascade, ReferentialAction::Restrict);
758 }
759
760 #[test]
761 fn test_referential_action_copy() {
762 let action = ReferentialAction::Cascade;
763 let copy = action;
764 assert_eq!(action, copy);
765 }
766}