1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
pub mod action;
mod compare;
mod crud;
mod inner;
use super::schema::Schema;
use crate::prelude::*;
use action::{depends, Action};
pub use compare::*;
use crud::*;
use inner::*;
#[derive(Debug)]
pub(crate) struct Actions<'table> {
name: &'table ObjectName,
actions: Vec<Action<'table>>,
}
impl<'table> Actions<'table> {
pub fn new(schema: &'table Schema, target: &'table Table) -> Result<Self> {
let table = schema.get_table(&target.name);
let mut out = Self {
name: &target.name,
actions: vec![],
};
out.init(Inner { table, target })?;
Ok(out)
}
fn init(&mut self, inner: Inner<'table>) -> Result<()> {
if inner.table.is_none() {
let action = Action::create_table(inner.target);
self.actions.push(action);
return Ok(());
}
let columns = inner.columns();
let constraints = inner.constraints();
if move_required(&columns, &constraints) {
self.perform_move(&inner, columns, constraints);
} else {
let table_name = &inner.target.name;
for col in columns.delete {
let action = Action::drop_col(table_name, col);
self.actions.push(action);
}
for cons in constraints.delete {
let action = Action::drop_cons(table_name, cons)?;
self.actions.push(action);
}
for cons in &constraints.update {
let action = Action::drop_cons(table_name, cons)?;
self.actions.push(action);
}
for col in columns.create {
let action = Action::create_column(table_name, col);
self.actions.push(action);
}
for cons in &constraints.create {
let action = Action::create_cons(table_name, cons);
self.actions.push(action);
}
for cons in &constraints.update {
let action = Action::create_cons(table_name, cons);
self.actions.push(action);
}
}
Ok(())
}
fn perform_move(
&mut self,
inner: &Inner<'table>,
cols: ColCRUD<'table>,
cons: ConsCRUD<'table>,
) {
let move_action = Action::move_to(inner.table.unwrap(), &cols, &cons);
self.actions.push(move_action);
let table_name = &inner.target.name;
for &col in &cols.create {
let action = Action::create_column(table_name, col);
self.actions.push(action);
}
for &cons in &cons.create {
if depends(cons, &cols.create) && !matches!(*DIALECT, SQLite) {
let action = Action::create_cons(table_name, cons);
self.actions.push(action);
}
}
}
pub fn as_migrations(self) -> Result<Vec<Migration>> {
let mut migrations = vec![];
let mut migr = Migration::new(self.name.clone());
for action in self.actions {
if action.is_fallible() && !migr.is_empty() {
migrations.push(migr);
migr = Migration::new(self.name.clone())
}
migr.push_up(action)?;
}
migrations.push(migr);
Ok(migrations)
}
}
pub(crate) fn move_required<'table>(cols: &ColCRUD<'table>, cons: &ConsCRUD<'table>) -> bool {
let sqlite_conditions = DIALECT.requires_move()
&& !(cols.update.is_empty()
&& cols.delete.is_empty()
&& cons.delete.is_empty()
&& cons.create.is_empty()
&& cons.update.is_empty());
sqlite_conditions || !cols.update.is_empty()
}