1use sea_orm_migration::prelude::*;
2
3pub struct Schema;
4
5impl Schema {
6 pub async fn create<F>(manager: &SchemaManager<'_>, table_name: &str, callback: F) -> Result<(), DbErr>
7 where
8 F: FnOnce(&mut Blueprint),
9 {
10 let mut blueprint = Blueprint::new(table_name);
11 callback(&mut blueprint);
12
13 manager.create_table(blueprint.table).await?;
15
16 for index in blueprint.indices {
18 manager.create_index(index).await?;
19 }
20
21 Ok(())
22 }
23
24 pub async fn drop(manager: &SchemaManager<'_>, table_name: &str) -> Result<(), DbErr> {
25 manager.drop_table(
26 Table::drop()
27 .table(Alias::new(table_name))
28 .to_owned()
29 ).await
30 }
31}
32
33pub struct Blueprint {
34 pub table_name: String,
35 pub table: TableCreateStatement,
36 pub indices: Vec<IndexCreateStatement>,
37}
38
39impl Blueprint {
40 pub fn new(table_name: &str) -> Self {
41 let mut table = Table::create();
42 table.table(Alias::new(table_name)).if_not_exists();
43 Self {
44 table_name: table_name.to_string(),
45 table,
46 indices: Vec::new(),
47 }
48 }
49
50 pub fn id(&mut self) -> &mut Self {
51 self.table.col(
52 ColumnDef::new(Alias::new("id"))
53 .integer()
54 .not_null()
55 .auto_increment()
56 .primary_key()
57 );
58 self
59 }
60
61 pub fn string<'a>(&'a mut self, name: &str) -> ColumnBuilder<'a> {
62 let mut col_def = ColumnDef::new(Alias::new(name));
63 col_def.string();
64 ColumnBuilder::new(self, name, col_def)
65 }
66
67 pub fn text<'a>(&'a mut self, name: &str) -> ColumnBuilder<'a> {
68 let mut col_def = ColumnDef::new(Alias::new(name));
69 col_def.text();
70 ColumnBuilder::new(self, name, col_def)
71 }
72
73 pub fn integer<'a>(&'a mut self, name: &str) -> ColumnBuilder<'a> {
74 let mut col_def = ColumnDef::new(Alias::new(name));
75 col_def.integer();
76 ColumnBuilder::new(self, name, col_def)
77 }
78
79 pub fn big_integer<'a>(&'a mut self, name: &str) -> ColumnBuilder<'a> {
80 let mut col_def = ColumnDef::new(Alias::new(name));
81 col_def.big_integer();
82 ColumnBuilder::new(self, name, col_def)
83 }
84
85 pub fn float<'a>(&'a mut self, name: &str) -> ColumnBuilder<'a> {
86 let mut col_def = ColumnDef::new(Alias::new(name));
87 col_def.float();
88 ColumnBuilder::new(self, name, col_def)
89 }
90
91 pub fn double<'a>(&'a mut self, name: &str) -> ColumnBuilder<'a> {
92 let mut col_def = ColumnDef::new(Alias::new(name));
93 col_def.double();
94 ColumnBuilder::new(self, name, col_def)
95 }
96
97 pub fn decimal<'a>(&'a mut self, name: &str) -> ColumnBuilder<'a> {
98 let mut col_def = ColumnDef::new(Alias::new(name));
99 col_def.decimal();
100 ColumnBuilder::new(self, name, col_def)
101 }
102
103 pub fn char<'a>(&'a mut self, name: &str) -> ColumnBuilder<'a> {
104 let mut col_def = ColumnDef::new(Alias::new(name));
105 col_def.char();
106 ColumnBuilder::new(self, name, col_def)
107 }
108
109 pub fn boolean<'a>(&'a mut self, name: &str) -> ColumnBuilder<'a> {
110 let mut col_def = ColumnDef::new(Alias::new(name));
111 col_def.boolean();
112 ColumnBuilder::new(self, name, col_def)
113 }
114
115 pub fn date_time<'a>(&'a mut self, name: &str) -> ColumnBuilder<'a> {
116 let mut col_def = ColumnDef::new(Alias::new(name));
117 col_def.date_time();
118 ColumnBuilder::new(self, name, col_def)
119 }
120
121 pub fn timestamp<'a>(&'a mut self, name: &str) -> ColumnBuilder<'a> {
122 let mut col_def = ColumnDef::new(Alias::new(name));
123 col_def.timestamp();
124 ColumnBuilder::new(self, name, col_def)
125 }
126
127 pub fn uuid<'a>(&'a mut self, name: &str) -> ColumnBuilder<'a> {
128 let mut col_def = ColumnDef::new(Alias::new(name));
129 col_def.uuid();
130 ColumnBuilder::new(self, name, col_def)
131 }
132
133 pub fn json<'a>(&'a mut self, name: &str) -> ColumnBuilder<'a> {
134 let mut col_def = ColumnDef::new(Alias::new(name));
135 col_def.json();
136 ColumnBuilder::new(self, name, col_def)
137 }
138
139 pub fn json_binary<'a>(&'a mut self, name: &str) -> ColumnBuilder<'a> {
140 let mut col_def = ColumnDef::new(Alias::new(name));
141 col_def.json_binary();
142 ColumnBuilder::new(self, name, col_def)
143 }
144
145 pub fn binary<'a>(&'a mut self, name: &str) -> ColumnBuilder<'a> {
146 let mut col_def = ColumnDef::new(Alias::new(name));
147 col_def.binary();
148 ColumnBuilder::new(self, name, col_def)
149 }
150
151 pub fn timestamps(&mut self) -> &mut Self {
152 self.table.col(
153 ColumnDef::new(Alias::new("created_at"))
154 .date_time()
155 .not_null()
156 .default(Expr::current_timestamp())
157 );
158 self.table.col(
159 ColumnDef::new(Alias::new("updated_at"))
160 .date_time()
161 .not_null()
162 .default(Expr::current_timestamp())
163 );
164 self
165 }
166
167 pub fn foreign<'a>(&'a mut self, from_col: &str) -> ForeignKeyBuilder<'a> {
168 ForeignKeyBuilder::new(self, from_col)
169 }
170}
171
172pub struct ColumnBuilder<'a> {
173 blueprint: &'a mut Blueprint,
174 col_name: String,
175 col_def: Option<ColumnDef>,
176 is_indexed: bool,
177}
178
179impl<'a> ColumnBuilder<'a> {
180 pub fn new(blueprint: &'a mut Blueprint, col_name: &str, col_def: ColumnDef) -> Self {
181 Self {
182 blueprint,
183 col_name: col_name.to_string(),
184 col_def: Some(col_def),
185 is_indexed: false,
186 }
187 }
188
189 pub fn not_null(mut self) -> Self {
190 if let Some(ref mut col) = self.col_def {
191 col.not_null();
192 }
193 self
194 }
195
196 pub fn nullable(mut self) -> Self {
197 if let Some(ref mut col) = self.col_def {
198 col.null();
199 }
200 self
201 }
202
203 pub fn unique(mut self) -> Self {
204 if let Some(ref mut col) = self.col_def {
205 col.unique_key();
206 }
207 self
208 }
209
210 pub fn primary_key(mut self) -> Self {
211 if let Some(ref mut col) = self.col_def {
212 col.primary_key();
213 }
214 self
215 }
216
217 pub fn default<T>(mut self, value: T) -> Self
218 where
219 T: Into<SimpleExpr>,
220 {
221 if let Some(ref mut col) = self.col_def {
222 col.default(value);
223 }
224 self
225 }
226
227 pub fn index(mut self) -> Self {
228 self.is_indexed = true;
229 self
230 }
231}
232
233impl<'a> Drop for ColumnBuilder<'a> {
234 fn drop(&mut self) {
235 if let Some(mut col) = self.col_def.take() {
236 self.blueprint.table.col(&mut col);
237 if self.is_indexed {
238 let index_name = format!("{}_{}_index", self.blueprint.table_name, self.col_name);
239 let index_stmt = Index::create()
240 .name(&index_name)
241 .table(Alias::new(&self.blueprint.table_name))
242 .col(Alias::new(&self.col_name))
243 .to_owned();
244 self.blueprint.indices.push(index_stmt);
245 }
246 }
247 }
248}
249
250pub struct ForeignKeyBuilder<'a> {
251 blueprint: &'a mut Blueprint,
252 from_col: String,
253 to_col: Option<String>,
254 to_table: Option<String>,
255 on_delete: Option<ForeignKeyAction>,
256 on_update: Option<ForeignKeyAction>,
257}
258
259impl<'a> ForeignKeyBuilder<'a> {
260 pub fn new(blueprint: &'a mut Blueprint, from_col: &str) -> Self {
261 Self {
262 blueprint,
263 from_col: from_col.to_string(),
264 to_col: None,
265 to_table: None,
266 on_delete: None,
267 on_update: None,
268 }
269 }
270
271 pub fn references(mut self, to_col: &str) -> Self {
272 self.to_col = Some(to_col.to_string());
273 self
274 }
275
276 pub fn on(mut self, to_table: &str) -> Self {
277 self.to_table = Some(to_table.to_string());
278 self
279 }
280
281 pub fn on_delete(mut self, action: &str) -> Self {
282 let act = match action.to_lowercase().as_str() {
283 "cascade" => ForeignKeyAction::Cascade,
284 "restrict" => ForeignKeyAction::Restrict,
285 "set null" | "set_null" => ForeignKeyAction::SetNull,
286 "no action" | "no_action" => ForeignKeyAction::NoAction,
287 _ => ForeignKeyAction::Cascade,
288 };
289 self.on_delete = Some(act);
290 self
291 }
292
293 pub fn on_update(mut self, action: &str) -> Self {
294 let act = match action.to_lowercase().as_str() {
295 "cascade" => ForeignKeyAction::Cascade,
296 "restrict" => ForeignKeyAction::Restrict,
297 "set null" | "set_null" => ForeignKeyAction::SetNull,
298 "no action" | "no_action" => ForeignKeyAction::NoAction,
299 _ => ForeignKeyAction::Cascade,
300 };
301 self.on_update = Some(act);
302 self
303 }
304}
305
306impl<'a> Drop for ForeignKeyBuilder<'a> {
307 fn drop(&mut self) {
308 if let (Some(to_table), Some(to_col)) = (&self.to_table, &self.to_col) {
309 let mut fk = ForeignKey::create();
310
311 let fk_name = format!(
312 "fk_{}_{}_{}_{}",
313 self.blueprint.table_name, self.from_col, to_table, to_col
314 );
315
316 fk.name(&fk_name)
317 .from(Alias::new(&self.blueprint.table_name), Alias::new(&self.from_col))
318 .to(Alias::new(to_table), Alias::new(to_col));
319
320 if let Some(action) = self.on_delete {
321 fk.on_delete(action);
322 }
323 if let Some(action) = self.on_update {
324 fk.on_update(action);
325 }
326
327 self.blueprint.table.foreign_key(&mut fk);
328 }
329 }
330}