toasty_core/schema/diff/
columns.rs1use super::Context;
2use crate::schema::db::Column;
3
4use hashbrown::{HashMap, HashSet};
5use std::ops::Deref;
6
7pub struct Columns<'a> {
25 items: Vec<ColumnsItem<'a>>,
26}
27
28impl<'a> Columns<'a> {
29 pub fn from(cx: &Context<'a>, previous: &'a [Column], next: &'a [Column]) -> Self {
35 fn has_diff(previous: &Column, next: &Column) -> bool {
36 previous.name != next.name
37 || previous.storage_ty != next.storage_ty
38 || previous.nullable != next.nullable
39 || previous.primary_key != next.primary_key
40 || previous.auto_increment != next.auto_increment
41 || previous.versionable != next.versionable
42 }
43
44 let mut items = vec![];
45 let mut add_ids: HashSet<_> = next.iter().map(|next| next.id).collect();
46
47 let next_map =
48 HashMap::<&str, &'a Column>::from_iter(next.iter().map(|to| (to.name.as_str(), to)));
49
50 for previous in previous {
51 let next = if let Some(next_id) = cx.rename_hints().get_column(previous.id) {
52 cx.next().column(next_id)
53 } else if let Some(next) = next_map.get(previous.name.as_str()) {
54 next
55 } else {
56 items.push(ColumnsItem::DropColumn(previous));
57 continue;
58 };
59
60 add_ids.remove(&next.id);
61
62 if has_diff(previous, next) {
63 items.push(ColumnsItem::AlterColumn { previous, next });
64 }
65 }
66
67 for column_id in add_ids {
68 items.push(ColumnsItem::AddColumn(cx.next().column(column_id)));
69 }
70
71 Self { items }
72 }
73
74 pub const fn is_empty(&self) -> bool {
76 self.items.is_empty()
77 }
78}
79
80impl<'a> Deref for Columns<'a> {
81 type Target = Vec<ColumnsItem<'a>>;
82
83 fn deref(&self) -> &Self::Target {
84 &self.items
85 }
86}
87
88pub enum ColumnsItem<'a> {
90 AddColumn(&'a Column),
92 DropColumn(&'a Column),
94 AlterColumn {
96 previous: &'a Column,
98 next: &'a Column,
100 },
101}