toasty_core/schema/db/
diff.rs

1use std::collections::HashMap;
2
3use crate::schema::db::{ColumnId, IndexId, Schema, TableId};
4
5/// Hints that tell the diff algorithm which schema items were renamed.
6///
7/// Without rename hints, a renamed table/column/index appears as a drop
8/// followed by a create. Adding a hint maps the old ID to the new ID so
9/// the diff produces an alter instead.
10///
11/// # Examples
12///
13/// ```ignore
14/// use toasty_core::schema::db::{RenameHints, TableId};
15///
16/// let mut hints = RenameHints::new();
17/// hints.add_table_hint(TableId(0), TableId(1));
18/// assert_eq!(hints.get_table(TableId(0)), Some(TableId(1)));
19/// assert_eq!(hints.get_table(TableId(2)), None);
20/// ```
21#[derive(Default)]
22pub struct RenameHints {
23    tables: HashMap<TableId, TableId>,
24    columns: HashMap<ColumnId, ColumnId>,
25    indices: HashMap<IndexId, IndexId>,
26}
27
28impl RenameHints {
29    /// Creates an empty set of rename hints.
30    pub fn new() -> Self {
31        Self::default()
32    }
33
34    /// Records that the table previously identified by `from` is now identified by `to`.
35    pub fn add_table_hint(&mut self, from: TableId, to: TableId) {
36        self.tables.insert(from, to);
37    }
38
39    /// Records that the column previously identified by `from` is now identified by `to`.
40    pub fn add_column_hint(&mut self, from: ColumnId, to: ColumnId) {
41        self.columns.insert(from, to);
42    }
43
44    /// Records that the index previously identified by `from` is now identified by `to`.
45    pub fn add_index_hint(&mut self, from: IndexId, to: IndexId) {
46        self.indices.insert(from, to);
47    }
48
49    /// Returns the new [`TableId`] if a rename hint exists for `from`.
50    pub fn get_table(&self, from: TableId) -> Option<TableId> {
51        self.tables.get(&from).copied()
52    }
53
54    /// Returns the new [`ColumnId`] if a rename hint exists for `from`.
55    pub fn get_column(&self, from: ColumnId) -> Option<ColumnId> {
56        self.columns.get(&from).copied()
57    }
58
59    /// Returns the new [`IndexId`] if a rename hint exists for `from`.
60    pub fn get_index(&self, from: IndexId) -> Option<IndexId> {
61        self.indices.get(&from).copied()
62    }
63}
64
65/// Shared context passed to all diff computations.
66///
67/// Holds references to both the previous and next [`Schema`] versions and
68/// the [`RenameHints`] that guide rename detection.
69///
70/// # Examples
71///
72/// ```ignore
73/// use toasty_core::schema::db::{DiffContext, RenameHints, Schema};
74///
75/// let previous = Schema::default();
76/// let next = Schema::default();
77/// let hints = RenameHints::new();
78/// let cx = DiffContext::new(&previous, &next, &hints);
79/// assert!(cx.previous().tables.is_empty());
80/// ```
81pub struct DiffContext<'a> {
82    previous: &'a Schema,
83    next: &'a Schema,
84
85    rename_hints: &'a RenameHints,
86}
87
88impl<'a> DiffContext<'a> {
89    /// Creates a new diff context from the previous schema, the next schema,
90    /// and the rename hints that map old IDs to new IDs.
91    pub fn new(previous: &'a Schema, next: &'a Schema, rename_hints: &'a RenameHints) -> Self {
92        Self {
93            previous,
94            next,
95            rename_hints,
96        }
97    }
98
99    /// Returns the rename hints for this diff.
100    pub fn rename_hints(&self) -> &'a RenameHints {
101        self.rename_hints
102    }
103
104    /// Returns the schema before the change.
105    pub fn previous(&self) -> &'a Schema {
106        self.previous
107    }
108
109    /// Returns the schema after the change.
110    pub fn next(&self) -> &'a Schema {
111        self.next
112    }
113}