toasty_core/schema/diff/
index.rs1use super::Context;
2use crate::schema::db;
3
4use hashbrown::{HashMap, HashSet};
5
6pub enum Index<'a> {
10 Create(&'a db::Index),
12 Drop(&'a db::Index),
14 Alter {
16 previous: &'a db::Index,
18 next: &'a db::Index,
20 },
21}
22
23impl<'a> Index<'a> {
24 pub fn diff(cx: &Context<'a>, previous: &'a [db::Index], next: &'a [db::Index]) -> Vec<Self> {
43 fn has_diff(cx: &Context<'_>, previous: &db::Index, next: &db::Index) -> bool {
44 if previous.name != next.name
45 || previous.columns.len() != next.columns.len()
46 || previous.unique != next.unique
47 || previous.primary_key != next.primary_key
48 {
49 return true;
50 }
51
52 for (previous_col, next_col) in previous.columns.iter().zip(next.columns.iter()) {
53 if previous_col.op != next_col.op || previous_col.scope != next_col.scope {
54 return true;
55 }
56
57 let columns_match =
58 if let Some(renamed_to) = cx.rename_hints().get_column(previous_col.column) {
59 renamed_to == next_col.column
60 } else {
61 let previous_column = cx.previous().column(previous_col.column);
62 let next_column = cx.next().column(next_col.column);
63 previous_column.name == next_column.name
64 };
65
66 if !columns_match {
67 return true;
68 }
69 }
70
71 false
72 }
73
74 let mut changes = vec![];
75 let mut create_ids: HashSet<_> = next.iter().map(|to| to.id).collect();
76
77 let next_map =
78 HashMap::<&str, &'a db::Index>::from_iter(next.iter().map(|to| (to.name.as_str(), to)));
79
80 for previous in previous {
81 let next = if let Some(next_id) = cx.rename_hints().get_index(previous.id) {
82 cx.next().index(next_id)
83 } else if let Some(next) = next_map.get(previous.name.as_str()) {
84 next
85 } else {
86 changes.push(Self::Drop(previous));
87 continue;
88 };
89
90 create_ids.remove(&next.id);
91
92 if has_diff(cx, previous, next) {
93 changes.push(Self::Alter { previous, next });
94 }
95 }
96
97 for index_id in create_ids {
98 changes.push(Self::Create(cx.next().index(index_id)));
99 }
100
101 changes
102 }
103}