1use crate::imr::Annotation;
4
5#[derive(Copy, Clone, Default, Debug)]
7pub struct Annotations {
8 pub auto_create_time: bool,
10
11 pub auto_update_time: bool,
13
14 pub auto_increment: bool,
16
17 pub choices: bool,
19
20 pub default: bool,
22
23 pub index: bool,
30
31 pub max_length: bool,
33
34 pub not_null: bool,
36
37 pub primary_key: bool,
39
40 pub unique: bool,
42
43 pub foreign_key: bool,
45}
46
47impl Annotations {
48 #[rustfmt::skip]
53 pub const fn check(self) -> Result<(), &'static str> {
54 use Annotations as A;
56
57 let msg = match self {
58 A { auto_create_time: true, auto_increment: true, .. } => "AutoCreateTime and AutoIncrement are mutually exclusive",
59 A { auto_create_time: true, choices: true, .. } => "AutoCreateTime and Choices are mutually exclusive",
60 A { auto_create_time: true, default: true, .. } => "AutoCreateTime and DefaultValue are mutually exclusive",
61 A { auto_create_time: true, max_length: true, .. } => "AutoCreateTime and MaxLength are mutually exclusive",
62 A { auto_create_time: true, primary_key: true, .. } => "AutoCreateTime and PrimaryKey are mutually exclusive",
63 A { auto_create_time: true, unique: true, .. } => "AutoCreateTime and Unique are mutually exclusive",
64 A { auto_update_time: true, auto_increment: true, .. } => "AutoUpdateTime and AutoIncrement are mutually exclusive",
65 A { auto_update_time: true, choices: true, .. } => "AutoUpdateTime and Choices are mutually exclusive",
66 A { auto_update_time: true, max_length: true, .. } => "AutoUpdateTime and MaxLength are mutually exclusive",
67 A { auto_update_time: true, primary_key: true, .. } => "AutoUpdateTime and PrimaryKey are mutually exclusive",
68 A { auto_update_time: true, unique: true, .. } => "AutoUpdateTime and Unique are mutually exclusive",
69 A { auto_increment: true, choices: true, .. } => "AutoIncrement and Choices are mutually exclusive",
70 A { auto_increment: true, max_length: true, .. } => "AutoIncrement and MaxLength are mutually exclusive",
71 A { choices: true, max_length: true, .. } => "Choices and MaxLength are mutually exclusive",
72 A { choices: true, primary_key: true, .. } => "Choices and PrimaryKey are mutually exclusive",
73 A { choices: true, unique: true, .. } => "Choices and Unique are mutually exclusive",
74 A { default: true, auto_update_time: true, .. } => "DefaultValue and AutoUpdateTime are mutually exclusive",
75 A { default: true, auto_increment: true, .. } => "DefaultValue and AutoIncrement are mutually exclusive",
76 A { default: true, primary_key: true, .. } => "DefaultValue and PrimaryKey are mutually exclusive",
77 A { default: true, unique: true, .. } => "DefaultValue and Unique are mutually exclusive",
78 A { index: true, primary_key: true, .. } => "An unnamed Index and PrimaryKey are mutually exclusive; name the index to span the column as part of a composite index",
79 A { not_null: true, primary_key: true, .. } => "NotNull and PrimaryKey are mutually exclusive",
80
81 A { auto_increment: true, primary_key: false, .. } => "AutoIncrement requires PrimaryKey",
82
83 A { auto_update_time: true, not_null: true, auto_create_time: false, default: false, ..} => "AutoUpdateTime in combination with NotNull requires ether DefaultValue or AutoCreateTime",
84
85 _ => "",
86 };
87
88 if !msg.is_empty() {
90 Err(msg)
91 } else {
92 Ok(())
93 }
94 }
95}
96
97impl From<&[Annotation]> for Annotations {
98 fn from(annotations: &[Annotation]) -> Self {
99 let mut result = Annotations::default();
100 for annotation in annotations {
101 match annotation {
102 Annotation::AutoCreateTime => result.auto_create_time = true,
103 Annotation::AutoUpdateTime => result.auto_update_time = true,
104 Annotation::AutoIncrement => result.auto_increment = true,
105 Annotation::Choices(_) => result.choices = true,
106 Annotation::DefaultValue(_) => result.default = true,
107 Annotation::Index(index) => result.index |= index.is_none(),
109 Annotation::MaxLength(_) => result.max_length = true,
110 Annotation::NotNull => result.not_null = true,
111 Annotation::PrimaryKey => result.primary_key = true,
112 Annotation::Unique => result.unique = true,
113 Annotation::ForeignKey(_) => result.foreign_key = true,
114 }
115 }
116 result
117 }
118}
119
120#[cfg(test)]
121mod test_index_on_primary_key {
122 use crate::imr::{Annotation, IndexValue};
123 use crate::lints::Annotations;
124
125 fn check(annotations: &[Annotation]) -> Result<(), &'static str> {
126 Annotations::from(annotations).check()
127 }
128
129 #[test]
130 fn unnamed_index_on_primary_key_is_redundant() {
131 assert!(check(&[Annotation::PrimaryKey, Annotation::Index(None)]).is_err());
132 }
133
134 #[test]
135 fn named_index_on_primary_key_is_allowed() {
136 assert!(check(&[
140 Annotation::PrimaryKey,
141 Annotation::Index(Some(IndexValue {
142 name: "collection_uuid".to_string(),
143 priority: Some(2),
144 })),
145 ])
146 .is_ok());
147 }
148
149 #[test]
150 fn an_unnamed_index_is_still_caught_next_to_a_named_one() {
151 assert!(check(&[
152 Annotation::PrimaryKey,
153 Annotation::Index(Some(IndexValue {
154 name: "collection_uuid".to_string(),
155 priority: None,
156 })),
157 Annotation::Index(None),
158 ])
159 .is_err());
160 }
161}