1use std::fmt;
2
3use bon::bon;
4use thiserror::Error;
5
6use crate::{
7 ast::{CreateDomain, CreateExtension, CreateIndex, CreateTable, CreateType, Statement},
8 dialect::{Generic, PostgreSQL, SQLite},
9 sealed::Sealed,
10};
11
12pub mod generic;
13
14#[derive(Error, Debug)]
15pub struct DiffError {
16 kind: DiffErrorKind,
17 statement_a: Option<Box<Statement>>,
18 statement_b: Option<Box<Statement>>,
19}
20
21impl fmt::Display for DiffError {
22 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23 write!(
24 f,
25 "Oops, we couldn't diff that: {reason}",
26 reason = self.kind
27 )?;
28 if let Some(statement_a) = &self.statement_a {
29 write!(f, "\n\nStatement A:\n{statement_a}")?;
30 }
31 if let Some(statement_b) = &self.statement_b {
32 write!(f, "\n\nStatement B:\n{statement_b}")?;
33 }
34 Ok(())
35 }
36}
37
38#[bon]
39impl DiffError {
40 #[builder]
41 pub(crate) fn new(
42 kind: DiffErrorKind,
43 #[builder(into)] statement_a: Option<Statement>,
44 #[builder(into)] statement_b: Option<Statement>,
45 ) -> Self {
46 Self {
47 kind,
48 statement_a: statement_a.map(Box::new),
49 statement_b: statement_b.map(Box::new),
50 }
51 }
52}
53
54#[derive(Error, Debug)]
55#[non_exhaustive]
56pub enum DiffErrorKind {
57 #[error("can't drop unnamed index")]
58 DropUnnamedIndex,
59 #[error("can't compare unnamed index")]
60 CompareUnnamedIndex,
61 #[error("removing enum labels is not supported")]
62 RemoveEnumLabel,
63 #[error("not yet supported")]
64 NotImplemented,
65}
66
67pub type Result<T, E = DiffError> = std::result::Result<T, E>;
68
69pub trait TreeDiffer: StatementDiffer + Sealed {
70 fn diff_tree(&self, a: &[Statement], b: &[Statement]) -> Result<Option<Vec<Statement>>> {
71 generic::tree::tree_diff(self, a, b)
72 }
73
74 fn find_and_compare_create_table(
75 &self,
76 sa: &Statement,
77 a: &CreateTable,
78 b: &[Statement],
79 ) -> Result<Option<Vec<Statement>>> {
80 generic::tree::find_and_compare_create_table(self, sa, a, b)
81 }
82
83 fn find_and_compare_create_index(
84 &self,
85 sa: &Statement,
86 a: &CreateIndex,
87 b: &[Statement],
88 ) -> Result<Option<Vec<Statement>>> {
89 generic::tree::find_and_compare_create_index(self, sa, a, b)
90 }
91
92 fn find_and_compare_create_type(
93 &self,
94 sa: &Statement,
95 a: &CreateType,
96 b: &[Statement],
97 ) -> Result<Option<Vec<Statement>>> {
98 generic::tree::find_and_compare_create_type(self, sa, a, b)
99 }
100
101 fn find_and_compare_create_extension(
102 &self,
103 sa: &Statement,
104 a: &CreateExtension,
105 b: &[Statement],
106 ) -> Result<Option<Vec<Statement>>> {
107 generic::tree::find_and_compare_create_extension(self, sa, a, b)
108 }
109
110 fn find_and_compare_create_domain(
111 &self,
112 sa: &Statement,
113 a: &CreateDomain,
114 b: &[Statement],
115 ) -> Result<Option<Vec<Statement>>> {
116 generic::tree::find_and_compare_create_domain(self, sa, a, b)
117 }
118}
119
120impl TreeDiffer for Generic {}
121
122impl TreeDiffer for PostgreSQL {}
123
124impl TreeDiffer for SQLite {}
125
126pub trait StatementDiffer: fmt::Debug + Default + Clone + Sized + Sealed {
127 fn diff(&self, sa: &Statement, sb: &Statement) -> Result<Option<Vec<Statement>>> {
128 generic::statement::diff(self, sa, sb)
129 }
130
131 fn compare_create_table(
132 &self,
133 a: &CreateTable,
134 b: &CreateTable,
135 ) -> Result<Option<Vec<Statement>>> {
136 generic::statement::compare_create_table(a, b)
137 }
138
139 fn compare_create_index(
140 &self,
141 a: &CreateIndex,
142 b: &CreateIndex,
143 ) -> Result<Option<Vec<Statement>>> {
144 generic::statement::compare_create_index(a, b)
145 }
146
147 fn compare_create_type(
148 &self,
149 a: &CreateType,
150 b: &CreateType,
151 ) -> Result<Option<Vec<Statement>>> {
152 generic::statement::compare_create_type(a, b)
153 }
154
155 fn compare_create_domain(
156 &self,
157 a: &CreateDomain,
158 b: &CreateDomain,
159 ) -> Result<Option<Vec<Statement>>> {
160 generic::statement::compare_create_domain(a, b)
161 }
162}
163
164impl StatementDiffer for Generic {}
165
166impl StatementDiffer for PostgreSQL {}
167
168impl StatementDiffer for SQLite {}