1use crate::table::{Table, TableMeta};
15use crate::DatabaseChange;
16
17use crate::backend::{SqlGenerator, SqlVariant};
18use crate::connectors::SqlRunner;
19
20use std::rc::Rc;
21
22pub struct Migration {
24 #[doc(hidden)]
25 pub schema: Option<String>,
26 #[doc(hidden)]
27 pub changes: Vec<DatabaseChange>,
28}
29
30impl Migration {
31 pub fn new() -> Migration {
32 Migration {
33 schema: None,
34 changes: Vec::new(),
35 }
36 }
37
38 pub fn schema<S: Into<String>>(self, schema: S) -> Migration {
40 Self {
41 schema: Some(schema.into()),
42 ..self
43 }
44 }
45
46 pub fn make<T: SqlGenerator>(&self) -> String {
52 use DatabaseChange::*;
53
54 let mut changes = self.changes.clone();
56 let schema = self.schema.as_ref().map(|s| s.as_str());
57
58 changes.iter_mut().fold(String::new(), |mut sql, change| {
59 match change {
60 &mut CreateTable(ref mut t, ref mut cb)
61 | &mut CreateTableIfNotExists(ref mut t, ref mut cb) => {
62 cb(t); let sql_changes = t.make::<T>(false, schema);
64
65 let name = t.meta.name().clone();
66 sql.push_str(&match change {
67 CreateTable(_, _) => T::create_table(&name, schema),
68 CreateTableIfNotExists(_, _) => {
69 T::create_table_if_not_exists(&name, schema)
70 }
71 _ => unreachable!(),
72 });
73 sql.push_str(" (");
74 let l = sql_changes.columns.len();
75 for (i, slice) in sql_changes.columns.iter().enumerate() {
76 sql.push_str(slice);
77
78 if i < l - 1 {
79 sql.push_str(", ");
80 }
81 }
82
83 let l = sql_changes.constraints.len();
84 for (i, slice) in sql_changes.constraints.iter().enumerate() {
85 if sql_changes.columns.len() > 0 && i == 0 {
86 sql.push_str(", ")
87 }
88
89 sql.push_str(slice);
90
91 if i < l - 1 {
92 sql.push_str(", ")
93 }
94 }
95
96 if let Some(ref primary_key) = sql_changes.primary_key {
97 sql.push_str(", ");
98 sql.push_str(primary_key);
99 };
100
101 let l = sql_changes.foreign_keys.len();
102 for (i, slice) in sql_changes.foreign_keys.iter().enumerate() {
103 if sql_changes.columns.len() > 0 && i == 0 {
104 sql.push_str(", ")
105 }
106
107 sql.push_str(slice);
108
109 if i < l - 1 {
110 sql.push_str(", ")
111 }
112 }
113
114 sql.push_str(")");
115
116 if sql_changes.indices.len() > 0 {
118 sql.push_str(";");
119 sql.push_str(&sql_changes.indices.join(";"));
120 }
121 }
122 &mut DropTable(ref name) => sql.push_str(&T::drop_table(name, schema)),
123 &mut DropTableIfExists(ref name) => {
124 sql.push_str(&T::drop_table_if_exists(name, schema))
125 }
126 &mut RenameTable(ref old, ref new) => {
127 sql.push_str(&T::rename_table(old, new, schema))
128 }
129 &mut ChangeTable(ref mut t, ref mut cb) => {
130 cb(t);
131 let sql_changes = t.make::<T>(true, schema);
132
133 sql.push_str(&T::alter_table(&t.meta.name(), schema));
134 sql.push_str(" ");
135
136 let l = sql_changes.columns.len();
137 for (i, slice) in sql_changes.columns.iter().enumerate() {
138 sql.push_str(slice);
139
140 if i < l - 1 {
141 sql.push_str(", ");
142 }
143 }
144
145 let l = sql_changes.foreign_keys.len();
146 for (i, slice) in sql_changes.foreign_keys.iter().enumerate() {
147 if sql_changes.columns.len() > 0 && i == 0 {
148 sql.push_str(", ")
149 }
150
151 sql.push_str("ADD ");
152 sql.push_str(slice);
153
154 if i < l - 1 {
155 sql.push_str(", ")
156 }
157 }
158
159 if let Some(ref primary_key) = sql_changes.primary_key {
160 sql.push_str(", ");
161 sql.push_str("ADD ");
162 sql.push_str(primary_key);
163 };
164
165 if sql_changes.indices.len() > 0 {
167 sql.push_str(";");
168 sql.push_str(&sql_changes.indices.join(";"));
169 }
170 }
171
172 &mut CustomLine(ref line) => sql.push_str(line.as_str()),
173 }
174
175 sql.push_str(";");
176 sql
177 })
178 }
179
180 pub fn make_from(&self, variant: SqlVariant) -> String {
187 variant.run_for(self)
188 }
189
190 pub fn inject_custom<S: Into<String>>(&mut self, sql: S) {
199 self.changes.push(DatabaseChange::CustomLine(sql.into()));
200 }
201
202 pub fn revert<T: SqlGenerator>(&self) -> String {
207 unimplemented!()
208 }
209
210 pub fn execute<S: SqlGenerator, T: SqlRunner>(&self, runner: &mut T) {
213 runner.execute(self.make::<S>());
214 }
215
216 pub fn create_table<S: Into<String>, F: 'static>(&mut self, name: S, cb: F) -> &mut TableMeta
218 where
219 F: Fn(&mut Table),
220 {
221 self.changes
222 .push(DatabaseChange::CreateTable(Table::new(name), Rc::new(cb)));
223
224 match self.changes.last_mut().unwrap() {
225 &mut DatabaseChange::CreateTable(ref mut t, _) => &mut t.meta,
226 _ => unreachable!(),
227 }
228 }
229
230 pub fn create_table_if_not_exists<S: Into<String>, F: 'static>(
232 &mut self,
233 name: S,
234 cb: F,
235 ) -> &mut TableMeta
236 where
237 F: Fn(&mut Table),
238 {
239 self.changes.push(DatabaseChange::CreateTableIfNotExists(
240 Table::new(name),
241 Rc::new(cb),
242 ));
243
244 match self.changes.last_mut().unwrap() {
245 &mut DatabaseChange::CreateTableIfNotExists(ref mut t, _) => &mut t.meta,
246 _ => unreachable!(),
247 }
248 }
249
250 pub fn change_table<S: Into<String>, F: 'static>(&mut self, name: S, cb: F)
252 where
253 F: Fn(&mut Table),
254 {
255 let t = Table::new(name);
256 let c = DatabaseChange::ChangeTable(t, Rc::new(cb));
257 self.changes.push(c);
258 }
259
260 pub fn rename_table<S: Into<String>>(&mut self, old: S, new: S) {
262 self.changes
263 .push(DatabaseChange::RenameTable(old.into(), new.into()));
264 }
265
266 pub fn drop_table<S: Into<String>>(&mut self, name: S) {
268 self.changes.push(DatabaseChange::DropTable(name.into()));
269 }
270
271 pub fn drop_table_if_exists<S: Into<String>>(&mut self, name: S) {
273 self.changes
274 .push(DatabaseChange::DropTableIfExists(name.into()));
275 }
276}