1use std::collections::hash_map::DefaultHasher;
3use std::fmt::{Display, Formatter};
4use std::hash::{Hash, Hasher};
5
6use ordered_float::OrderedFloat;
7use serde::{Deserialize, Serialize};
8use strum::EnumIter;
9
10#[derive(Serialize, Deserialize, Debug, Clone, Hash)]
12#[serde(rename_all = "PascalCase")]
13pub struct InternalModelFormat {
14 pub models: Vec<Model>,
16}
17
18#[derive(Serialize, Deserialize, Debug, Clone)]
20#[serde(rename_all = "PascalCase")]
21pub struct Model {
22 pub name: String,
24
25 pub fields: Vec<Field>,
27
28 #[serde(default)]
30 #[serde(skip_serializing_if = "Option::is_none")]
31 pub source_defined_at: Option<Source>,
32}
33
34impl PartialEq for Model {
35 fn eq(&self, other: &Self) -> bool {
36 self.name == other.name && self.fields == other.fields
37 }
38}
39
40impl Hash for Model {
41 fn hash<H: Hasher>(&self, state: &mut H) {
42 self.fields.hash(state);
43 self.name.hash(state);
44 }
45
46 fn hash_slice<H: Hasher>(data: &[Self], state: &mut H)
47 where
48 Self: Sized,
49 {
50 data.iter().for_each(|x| x.hash(state));
51 }
52}
53
54#[derive(Serialize, Deserialize, Debug, Clone)]
56#[serde(rename_all = "PascalCase")]
57pub struct Field {
58 pub name: String,
60
61 #[serde(rename = "Type")]
63 pub db_type: DbType,
64
65 pub annotations: Vec<Annotation>,
67
68 #[serde(default)]
70 #[serde(skip_serializing_if = "Option::is_none")]
71 pub source_defined_at: Option<Source>,
72}
73
74impl PartialEq for Field {
75 fn eq(&self, other: &Self) -> bool {
76 self.name == other.name
77 && self.db_type == other.db_type
78 && self.annotations == other.annotations
79 }
80}
81
82impl Hash for Field {
83 fn hash<H: Hasher>(&self, state: &mut H) {
84 self.name.hash(state);
85 self.annotations.hash(state);
86 self.db_type.hash(state);
87 }
88
89 fn hash_slice<H: Hasher>(data: &[Self], state: &mut H)
90 where
91 Self: Sized,
92 {
93 data.iter().for_each(|x| x.hash(state));
94 }
95}
96
97#[derive(Serialize, Deserialize, Debug, Clone, Hash)]
100#[serde(rename_all = "PascalCase")]
101pub struct Source {
102 pub file: String,
104 pub line: usize,
106 pub column: usize,
108}
109
110#[allow(missing_docs)]
112#[derive(Serialize, Deserialize, Debug, Copy, Clone, Hash, PartialEq, Eq)]
113#[serde(rename_all = "lowercase")]
114pub enum DbType {
115 VarChar,
116 Binary,
117 Int8,
118 Int16,
119 Int32,
120 Int64,
121 #[serde(rename = "float_number")]
122 Float,
123 #[serde(rename = "double_number")]
124 Double,
125 Boolean,
126 Date,
127 DateTime,
128 Timestamp,
129 Time,
130 Choices,
131 Uuid,
132 MacAddress,
133 IpNetwork,
134 BitVec,
135}
136
137#[non_exhaustive]
139#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash, EnumIter)]
140#[serde(tag = "Type", content = "Value")]
141#[serde(rename_all = "snake_case")]
142pub enum Annotation {
143 AutoCreateTime,
146 AutoUpdateTime,
149 AutoIncrement,
151 Choices(Vec<String>),
153 DefaultValue(DefaultValue),
155 Index(Option<IndexValue>),
157 MaxLength(i32),
159 NotNull,
161 PrimaryKey,
163 Unique,
165 ForeignKey(ForeignKey),
167}
168
169impl Annotation {
170 pub fn eq_shallow(&self, other: &Self) -> bool {
181 match (self, other) {
182 (Annotation::AutoCreateTime, Annotation::AutoCreateTime) => true,
183 (Annotation::AutoCreateTime, _) => false,
184 (Annotation::AutoUpdateTime, Annotation::AutoUpdateTime) => true,
185 (Annotation::AutoUpdateTime, _) => false,
186 (Annotation::AutoIncrement, Annotation::AutoIncrement) => true,
187 (Annotation::AutoIncrement, _) => false,
188 (Annotation::Choices(_), Annotation::Choices(_)) => true,
189 (Annotation::Choices(_), _) => false,
190 (Annotation::DefaultValue(_), Annotation::DefaultValue(_)) => true,
191 (Annotation::DefaultValue(_), _) => false,
192 (Annotation::Index(_), Annotation::Index(_)) => true,
193 (Annotation::Index(_), _) => false,
194 (Annotation::MaxLength(_), Annotation::MaxLength(_)) => true,
195 (Annotation::MaxLength(_), _) => false,
196 (Annotation::NotNull, Annotation::NotNull) => true,
197 (Annotation::NotNull, _) => false,
198 (Annotation::PrimaryKey, Annotation::PrimaryKey) => true,
199 (Annotation::PrimaryKey, _) => false,
200 (Annotation::Unique, Annotation::Unique) => true,
201 (Annotation::Unique, _) => false,
202 (Annotation::ForeignKey(_), Annotation::ForeignKey(_)) => true,
203 (Annotation::ForeignKey(_), _) => false,
204 }
205 }
206
207 pub fn hash_shallow(&self) -> u64 {
218 let mut state = DefaultHasher::new();
219 match self {
220 Annotation::AutoCreateTime => state.write_i8(0),
221 Annotation::AutoUpdateTime => state.write_i8(1),
222 Annotation::AutoIncrement => state.write_i8(2),
223 Annotation::Choices(_) => state.write_i8(3),
224 Annotation::DefaultValue(_) => state.write_i8(4),
225 Annotation::Index(_) => state.write_i8(5),
226 Annotation::MaxLength(_) => state.write_i8(6),
227 Annotation::NotNull => state.write_i8(7),
228 Annotation::PrimaryKey => state.write_i8(8),
229 Annotation::Unique => state.write_i8(9),
230 Annotation::ForeignKey(_) => state.write_i8(10),
231 }
232 state.finish()
233 }
234}
235
236#[cfg(test)]
237mod test {
238
239 use crate::imr::{Annotation, IndexValue};
240
241 #[test]
242 fn test_annotation_hash() {
243 assert_eq!(
244 Annotation::MaxLength(1).hash_shallow(),
245 Annotation::MaxLength(12313).hash_shallow()
246 );
247
248 assert_eq!(
249 Annotation::Index(None).hash_shallow(),
250 Annotation::Index(Some(IndexValue {
251 priority: None,
252 name: "foo".to_string(),
253 }))
254 .hash_shallow()
255 );
256 }
257
258 #[test]
259 fn test_annotation_partial_eq() {
260 assert!(Annotation::MaxLength(1).eq_shallow(&Annotation::MaxLength(2)));
261 assert!(
262 Annotation::Index(None).eq_shallow(&Annotation::Index(Some(IndexValue {
263 priority: None,
264 name: "foo".to_string()
265 })))
266 );
267 }
268}
269
270#[derive(Serialize, Deserialize, Debug, Clone, Hash, PartialEq, Eq, Default)]
272#[serde(rename_all = "PascalCase")]
273pub struct ForeignKey {
274 pub table_name: String,
276 pub column_name: String,
278 pub on_delete: ReferentialAction,
280 pub on_update: ReferentialAction,
282}
283
284#[derive(Serialize, Deserialize, Debug, Clone, Copy, Hash, PartialEq, Eq)]
288#[serde(rename_all = "PascalCase")]
289pub enum ReferentialAction {
290 Restrict,
292 Cascade,
294 SetNull,
296 SetDefault,
298}
299
300impl Default for ReferentialAction {
301 fn default() -> Self {
302 Self::Restrict
303 }
304}
305
306impl Display for ReferentialAction {
307 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
308 match self {
309 ReferentialAction::Restrict => write!(f, "RESTRICT"),
310 ReferentialAction::Cascade => write!(f, "CASCADE"),
311 ReferentialAction::SetNull => write!(f, "SET NULL"),
312 ReferentialAction::SetDefault => write!(f, "SET DEFAULT"),
313 }
314 }
315}
316
317#[derive(Serialize, Deserialize, Debug, Clone, Hash, PartialEq, Eq)]
319#[serde(rename_all = "PascalCase")]
320pub struct IndexValue {
321 pub name: String,
324
325 #[serde(default)]
328 #[serde(skip_serializing_if = "Option::is_none")]
329 pub priority: Option<i32>,
330}
331
332#[derive(Serialize, Deserialize, Debug, Clone, Hash, PartialEq, Eq)]
334#[serde(untagged)]
335pub enum DefaultValue {
336 String(String),
338 Integer(i64),
340 Float(OrderedFloat<f64>),
342 Boolean(bool),
344}
345
346impl Default for DefaultValue {
350 fn default() -> Self {
351 DefaultValue::Boolean(true)
352 }
353}