1pub mod add_column;
2pub mod add_constraint;
3pub mod create_table;
4pub mod delete_column;
5pub mod delete_table;
6pub mod helpers;
7pub mod modify_column_comment;
8pub mod modify_column_default;
9pub mod modify_column_nullable;
10pub mod modify_column_type;
11pub mod raw_sql;
12pub mod remap_enum_values;
13pub mod remove_constraint;
14pub mod rename_column;
15pub mod rename_table;
16pub mod replace_constraint;
17pub mod types;
18
19pub use helpers::*;
20pub use types::{BuiltQuery, DatabaseBackend, RawSql};
21
22use crate::error::QueryError;
23use vespertide_core::{MigrationAction, TableConstraint, TableDef};
24
25use self::{
26 add_column::build_add_column, add_constraint::build_add_constraint,
27 create_table::build_create_table, delete_column::build_delete_column,
28 delete_table::build_delete_table, modify_column_comment::build_modify_column_comment,
29 modify_column_default::build_modify_column_default,
30 modify_column_nullable::build_modify_column_nullable,
31 remap_enum_values::build_remap_enum_values, remove_constraint::build_remove_constraint,
32 rename_column::build_rename_column, rename_table::build_rename_table,
33 replace_constraint::build_replace_constraint,
34};
35
36pub fn build_action_queries(
41 backend: DatabaseBackend,
42 action: &MigrationAction,
43 current_schema: &[TableDef],
44) -> Result<Vec<BuiltQuery>, QueryError> {
45 build_action_queries_with_pending(backend, action, current_schema, &[])
46}
47
48#[expect(
54 clippy::too_many_lines,
55 reason = "flat 14-variant MigrationAction dispatcher kept inline so the variant→builder mapping stays auditable; extracting individual arms scatters the routing logic"
56)]
57pub fn build_action_queries_with_pending(
58 backend: DatabaseBackend,
59 action: &MigrationAction,
60 current_schema: &[TableDef],
61 pending_constraints: &[TableConstraint],
62) -> Result<Vec<BuiltQuery>, QueryError> {
63 match action {
64 MigrationAction::CreateTable {
65 table,
66 columns,
67 constraints,
68 } => build_create_table(backend, table, columns, constraints),
69
70 MigrationAction::DeleteTable { table } => Ok(vec![build_delete_table(table)]),
71
72 MigrationAction::AddColumn {
73 table,
74 column,
75 fill_with,
76 } => build_add_column(
77 backend,
78 table,
79 column,
80 fill_with.as_deref(),
81 current_schema,
82 pending_constraints,
83 ),
84
85 MigrationAction::RenameColumn { table, from, to } => {
86 Ok(vec![build_rename_column(table, from, to)])
87 }
88
89 MigrationAction::DeleteColumn { table, column } => {
90 let column_type = current_schema
92 .iter()
93 .find(|t| t.name == *table)
94 .and_then(|t| t.columns.iter().find(|c| c.name == *column))
95 .map(|c| &c.r#type);
96 Ok(build_delete_column(
97 backend,
98 table,
99 column,
100 column_type,
101 current_schema,
102 pending_constraints,
103 ))
104 }
105
106 MigrationAction::ModifyColumnType {
107 table,
108 column,
109 new_type,
110 fill_with,
111 narrowing_strategy,
112 timezone,
113 } => modify_column_type::build_with_narrowing_preprocess(
114 backend,
115 table.as_str(),
116 column.as_str(),
117 new_type,
118 fill_with.as_ref(),
119 narrowing_strategy.as_ref(),
120 timezone.as_deref(),
121 current_schema,
122 pending_constraints,
123 ),
124
125 MigrationAction::ModifyColumnNullable {
126 table,
127 column,
128 nullable,
129 fill_with,
130 delete_null_rows,
131 } => build_modify_column_nullable(
132 backend,
133 table,
134 column,
135 *nullable,
136 fill_with.as_deref(),
137 delete_null_rows.unwrap_or(false),
138 current_schema,
139 pending_constraints,
140 ),
141
142 MigrationAction::ModifyColumnDefault {
143 table,
144 column,
145 new_default,
146 backfill,
147 } => build_modify_column_default(
148 backend,
149 table,
150 column,
151 new_default.as_deref(),
152 backfill.as_deref(),
153 current_schema,
154 pending_constraints,
155 ),
156
157 MigrationAction::ModifyColumnComment {
158 table,
159 column,
160 new_comment,
161 } => build_comment_action_queries(
162 backend,
163 table,
164 column,
165 new_comment.as_ref(),
166 current_schema,
167 ),
168
169 MigrationAction::RenameTable { from, to } => Ok(vec![build_rename_table(from, to)]),
170
171 MigrationAction::RawSql { sql } => Ok(vec![BuiltQuery::Raw(RawSql::uniform(sql.clone()))]),
172
173 MigrationAction::AddConstraint { .. }
174 | MigrationAction::RemoveConstraint { .. }
175 | MigrationAction::ReplaceConstraint { .. } => {
176 build_constraint_action_queries(backend, action, current_schema, pending_constraints)
177 }
178
179 MigrationAction::RemapEnumValues {
180 table,
181 column,
182 mapping,
183 } => build_remap_enum_values(backend, table.as_str(), column.as_str(), mapping),
184
185 _ => unreachable!("MigrationAction is #[non_exhaustive]; all variants are matched above"),
186 }
187}
188
189fn build_comment_action_queries(
190 backend: DatabaseBackend,
191 table: &str,
192 column: &str,
193 new_comment: Option<&String>,
194 current_schema: &[TableDef],
195) -> Result<Vec<BuiltQuery>, QueryError> {
196 build_modify_column_comment(
197 backend,
198 table,
199 column,
200 new_comment.map(String::as_str),
201 current_schema,
202 )
203}
204
205fn build_constraint_action_queries(
206 backend: DatabaseBackend,
207 action: &MigrationAction,
208 current_schema: &[TableDef],
209 pending_constraints: &[TableConstraint],
210) -> Result<Vec<BuiltQuery>, QueryError> {
211 match action {
212 MigrationAction::AddConstraint { table, constraint } => build_add_constraint(
213 backend,
214 table,
215 constraint,
216 current_schema,
217 pending_constraints,
218 ),
219 MigrationAction::RemoveConstraint { table, constraint } => build_remove_constraint(
220 backend,
221 table,
222 constraint,
223 current_schema,
224 pending_constraints,
225 ),
226 MigrationAction::ReplaceConstraint { table, from, to } => build_replace_constraint(
227 backend,
228 table,
229 from,
230 to,
231 current_schema,
232 pending_constraints,
233 ),
234 _ => unreachable!("only constraint actions are dispatched here"),
235 }
236}
237
238#[cfg(test)]
239mod tests;