1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub enum Dialect {
6 Postgres,
7 Sqlite,
8 Mysql,
9}
10
11impl std::fmt::Display for Dialect {
12 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13 match self {
14 Dialect::Postgres => write!(f, "postgres"),
15 Dialect::Sqlite => write!(f, "sqlite"),
16 Dialect::Mysql => write!(f, "mysql"),
17 }
18 }
19}
20
21impl std::str::FromStr for Dialect {
22 type Err = String;
23 fn from_str(s: &str) -> Result<Self, Self::Err> {
24 match s.to_lowercase().as_str() {
25 "postgres" | "postgresql" | "pg" => Ok(Dialect::Postgres),
26 "sqlite" => Ok(Dialect::Sqlite),
27 "mysql" | "mariadb" => Ok(Dialect::Mysql),
28 _ => Err(format!("unknown dialect: '{s}'")),
29 }
30 }
31}
32
33#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
35#[serde(rename_all = "lowercase")]
36pub enum Orm {
37 Diesel,
38 Sqlx,
39}
40
41impl std::fmt::Display for Orm {
42 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43 match self {
44 Orm::Diesel => write!(f, "diesel"),
45 Orm::Sqlx => write!(f, "sqlx"),
46 }
47 }
48}
49
50impl std::str::FromStr for Orm {
51 type Err = String;
52 fn from_str(s: &str) -> Result<Self, Self::Err> {
53 match s.to_lowercase().as_str() {
54 "diesel" => Ok(Orm::Diesel),
55 "sqlx" => Ok(Orm::Sqlx),
56 _ => Err(format!("unknown orm: '{s}'")),
57 }
58 }
59}
60
61#[derive(Debug, Clone, PartialEq, Eq, Hash)]
63pub enum ColumnType {
64 Uuid,
66 Varchar,
68 VarcharN(u32),
70 Boolean,
72 DateTime,
74 Json,
76 Int,
78 SmallInt,
80 Text,
82}
83
84#[derive(Debug, Clone, PartialEq, Eq, Hash)]
86pub enum OnDelete {
87 Cascade,
88 SetNull,
89 Restrict,
90 NoAction,
91}
92
93#[derive(Debug, Clone, PartialEq, Eq, Hash)]
95pub struct ForeignKey {
96 pub references_table: String,
97 pub references_column: String,
98 pub on_delete: OnDelete,
99}
100
101#[derive(Debug, Clone, PartialEq, Eq)]
103pub struct ColumnDef {
104 pub name: String,
105 pub col_type: ColumnType,
106 pub nullable: bool,
107 pub primary_key: bool,
108 pub unique: bool,
109 pub default: Option<String>,
110 pub foreign_key: Option<ForeignKey>,
111}
112
113impl ColumnDef {
114 pub fn new(name: &str, col_type: ColumnType) -> Self {
116 Self {
117 name: name.to_string(),
118 col_type,
119 nullable: false,
120 primary_key: false,
121 unique: false,
122 default: None,
123 foreign_key: None,
124 }
125 }
126
127 pub fn nullable(mut self) -> Self {
128 self.nullable = true;
129 self
130 }
131
132 pub fn primary_key(mut self) -> Self {
133 self.primary_key = true;
134 self
135 }
136
137 pub fn unique(mut self) -> Self {
138 self.unique = true;
139 self
140 }
141
142 pub fn default(mut self, val: &str) -> Self {
143 self.default = Some(val.to_string());
144 self
145 }
146
147 pub fn references(mut self, table: &str, column: &str, on_delete: OnDelete) -> Self {
148 self.foreign_key = Some(ForeignKey {
149 references_table: table.to_string(),
150 references_column: column.to_string(),
151 on_delete,
152 });
153 self
154 }
155}
156
157#[derive(Debug, Clone, PartialEq, Eq)]
159pub struct IndexDef {
160 pub name: String,
161 pub columns: Vec<String>,
162 pub unique: bool,
163}
164
165#[derive(Debug, Clone, PartialEq, Eq)]
167pub struct TableDef {
168 pub name: String,
169 pub columns: Vec<ColumnDef>,
170 pub indices: Vec<IndexDef>,
171}
172
173impl TableDef {
174 pub fn new(name: &str) -> Self {
175 Self {
176 name: name.to_string(),
177 columns: Vec::new(),
178 indices: Vec::new(),
179 }
180 }
181
182 pub fn column(mut self, col: ColumnDef) -> Self {
183 self.columns.push(col);
184 self
185 }
186
187 pub fn index(mut self, idx: IndexDef) -> Self {
188 self.indices.push(idx);
189 self
190 }
191
192 pub fn dependencies(&self) -> Vec<&str> {
194 self.columns
195 .iter()
196 .filter_map(|c| {
197 c.foreign_key
198 .as_ref()
199 .map(|fk| fk.references_table.as_str())
200 })
201 .filter(|t| *t != self.name)
202 .collect()
203 }
204
205 pub fn apply_prefix(&mut self, old_prefix: &str, new_prefix: &str) {
207 if self.name.starts_with(old_prefix) {
208 self.name = format!("{}{}", new_prefix, &self.name[old_prefix.len()..]);
209 }
210 for col in &mut self.columns {
211 if let Some(ref mut fk) = col.foreign_key
212 && fk.references_table.starts_with(old_prefix)
213 {
214 fk.references_table =
215 format!("{}{}", new_prefix, &fk.references_table[old_prefix.len()..]);
216 }
217 }
218 for idx in &mut self.indices {
219 if idx.name.starts_with(old_prefix) {
220 idx.name = format!("{}{}", new_prefix, &idx.name[old_prefix.len()..]);
221 }
222 }
223 }
224}