1use sntl_schema::schema::{Column, Schema, Table};
2
3#[derive(Debug, Clone, PartialEq, Eq)]
6pub enum Change {
7 AddTable(Table),
8 DropTable {
9 name: String,
10 },
11 AddColumn {
12 table: String,
13 column: Column,
14 },
15 DropColumn {
16 table: String,
17 column: String,
18 },
19 AlterColumnType {
20 table: String,
21 column: String,
22 from: String,
23 to: String,
24 },
25 AlterColumnNullable {
26 table: String,
27 column: String,
28 to: bool,
29 },
30 AlterColumnDefault {
31 table: String,
32 column: String,
33 to: Option<String>,
34 },
35 AddPrimaryKey {
36 table: String,
37 columns: Vec<String>,
38 },
39 DropPrimaryKey {
40 table: String,
41 },
42 AddUnique {
43 table: String,
44 columns: Vec<String>,
45 },
46 DropUnique {
47 table: String,
48 columns: Vec<String>,
49 },
50}
51
52pub fn compare(cache: &Schema, live: &Schema) -> Vec<Change> {
59 let mut out = Vec::new();
60
61 for t in &cache.tables {
62 if live.find_table(&t.name).is_none() {
63 out.push(Change::AddTable(t.clone()));
64 }
65 }
66 for t in &live.tables {
67 if cache.find_table(&t.name).is_none() {
68 out.push(Change::DropTable {
69 name: t.name.clone(),
70 });
71 }
72 }
73 for cache_t in &cache.tables {
74 let Some(live_t) = live.find_table(&cache_t.name) else {
75 continue;
76 };
77 diff_columns(cache_t, live_t, &mut out);
78 diff_pk(cache_t, live_t, &mut out);
79 diff_unique(cache_t, live_t, &mut out);
80 }
81
82 out
83}
84
85fn diff_columns(cache_t: &Table, live_t: &Table, out: &mut Vec<Change>) {
86 for c in &cache_t.columns {
87 if live_t.columns.iter().any(|lc| lc.name == c.name) {
88 continue;
89 }
90 out.push(Change::AddColumn {
91 table: cache_t.name.clone(),
92 column: c.clone(),
93 });
94 }
95 for c in &live_t.columns {
96 if cache_t.columns.iter().any(|cc| cc.name == c.name) {
97 continue;
98 }
99 out.push(Change::DropColumn {
100 table: cache_t.name.clone(),
101 column: c.name.clone(),
102 });
103 }
104 for cc in &cache_t.columns {
105 let Some(lc) = live_t.columns.iter().find(|lc| lc.name == cc.name) else {
106 continue;
107 };
108 if cc.pg_type.pg_type != lc.pg_type.pg_type {
109 out.push(Change::AlterColumnType {
110 table: cache_t.name.clone(),
111 column: cc.name.clone(),
112 from: lc.pg_type.pg_type.clone(),
113 to: cc.pg_type.pg_type.clone(),
114 });
115 }
116 if cc.nullable != lc.nullable {
117 out.push(Change::AlterColumnNullable {
118 table: cache_t.name.clone(),
119 column: cc.name.clone(),
120 to: cc.nullable,
121 });
122 }
123 if cc.default != lc.default {
124 out.push(Change::AlterColumnDefault {
125 table: cache_t.name.clone(),
126 column: cc.name.clone(),
127 to: cc.default.clone(),
128 });
129 }
130 }
131}
132
133fn diff_pk(cache_t: &Table, live_t: &Table, out: &mut Vec<Change>) {
134 let cache_pk: Vec<String> = cache_t
135 .columns
136 .iter()
137 .filter(|c| c.primary_key)
138 .map(|c| c.name.clone())
139 .collect();
140 let live_pk: Vec<String> = live_t
141 .columns
142 .iter()
143 .filter(|c| c.primary_key)
144 .map(|c| c.name.clone())
145 .collect();
146 match (cache_pk.is_empty(), live_pk.is_empty()) {
147 (false, true) => out.push(Change::AddPrimaryKey {
148 table: cache_t.name.clone(),
149 columns: cache_pk,
150 }),
151 (true, false) => out.push(Change::DropPrimaryKey {
152 table: cache_t.name.clone(),
153 }),
154 (false, false) if cache_pk != live_pk => {
155 out.push(Change::DropPrimaryKey {
156 table: cache_t.name.clone(),
157 });
158 out.push(Change::AddPrimaryKey {
159 table: cache_t.name.clone(),
160 columns: cache_pk,
161 });
162 }
163 _ => {}
164 }
165}
166
167fn diff_unique(cache_t: &Table, live_t: &Table, out: &mut Vec<Change>) {
168 for cc in &cache_t.columns {
169 let lc = live_t.columns.iter().find(|lc| lc.name == cc.name);
170 match (cc.unique, lc.map(|lc| lc.unique)) {
171 (true, Some(false)) | (true, None) => {
172 out.push(Change::AddUnique {
173 table: cache_t.name.clone(),
174 columns: vec![cc.name.clone()],
175 });
176 }
177 (false, Some(true)) => {
178 out.push(Change::DropUnique {
179 table: cache_t.name.clone(),
180 columns: vec![cc.name.clone()],
181 });
182 }
183 _ => {}
184 }
185 }
186}