1pub mod add_column;
2pub mod add_constraint;
3pub mod create_table;
4pub mod data_migration;
5pub mod delete_column;
6pub mod delete_table;
7pub(crate) mod fill_with;
8pub mod helpers;
9pub mod modify_column_comment;
10pub mod modify_column_default;
11pub mod modify_column_nullable;
12pub mod modify_column_type;
13pub mod raw_sql;
14pub mod remap_enum_values;
15pub mod remove_constraint;
16pub mod rename_column;
17pub mod rename_table;
18pub mod replace_constraint;
19pub mod types;
20
21pub use helpers::{quote_ident, quote_idents};
22pub use types::{BuiltQuery, DatabaseBackend, RawSql};
23
24use crate::error::QueryError;
25use vespertide_core::{MigrationAction, TableConstraint, TableDef};
26
27use self::{
28 add_column::build_add_column, add_constraint::build_add_constraint,
29 create_table::build_create_table, data_migration::build_data_migration,
30 delete_column::build_delete_column, delete_table::build_delete_table,
31 modify_column_comment::build_modify_column_comment,
32 modify_column_default::build_modify_column_default,
33 modify_column_nullable::build_modify_column_nullable,
34 remap_enum_values::build_remap_enum_values, remove_constraint::build_remove_constraint,
35 rename_column::build_rename_column, rename_table::build_rename_table,
36 replace_constraint::build_replace_constraint,
37};
38
39pub fn build_action_queries(
44 backend: DatabaseBackend,
45 action: &MigrationAction,
46 current_schema: &[TableDef],
47) -> Result<Vec<BuiltQuery>, QueryError> {
48 build_action_queries_with_pending(backend, action, current_schema, &[])
49}
50
51#[expect(
57 clippy::too_many_lines,
58 reason = "flat 16-variant MigrationAction dispatcher kept inline so the variant→builder mapping stays auditable; extracting individual arms scatters the routing logic"
59)]
60pub fn build_action_queries_with_pending(
61 backend: DatabaseBackend,
62 action: &MigrationAction,
63 current_schema: &[TableDef],
64 pending_constraints: &[TableConstraint],
65) -> Result<Vec<BuiltQuery>, QueryError> {
66 match action {
67 MigrationAction::CreateTable {
68 table,
69 columns,
70 constraints,
71 } => build_create_table(backend, table, columns, constraints),
72
73 MigrationAction::DeleteTable { table } => Ok(vec![build_delete_table(table)]),
74
75 MigrationAction::AddColumn {
76 table,
77 column,
78 fill_with,
79 } => build_add_column(
80 backend,
81 table,
82 column,
83 fill_with.as_deref(),
84 current_schema,
85 pending_constraints,
86 ),
87
88 MigrationAction::RenameColumn { table, from, to } => {
89 Ok(vec![build_rename_column(table, from, to)])
90 }
91
92 MigrationAction::DeleteColumn { table, column } => {
93 let column_type =
95 helpers::find_column_in_schema(current_schema, table, column).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_modify_column_comment(
162 backend,
163 table,
164 column,
165 new_comment.as_deref(),
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::DataMigration { sql, .. } => Ok(build_data_migration(sql)),
174
175 MigrationAction::AddConstraint { .. }
176 | MigrationAction::RemoveConstraint { .. }
177 | MigrationAction::ReplaceConstraint { .. } => {
178 build_constraint_action_queries(backend, action, current_schema, pending_constraints)
179 }
180
181 MigrationAction::RemapEnumValues {
182 table,
183 column,
184 mapping,
185 } => build_remap_enum_values(backend, table.as_str(), column.as_str(), mapping),
186
187 _ => unreachable!("MigrationAction is #[non_exhaustive]; all variants are matched above"),
188 }
189}
190
191fn build_constraint_action_queries(
192 backend: DatabaseBackend,
193 action: &MigrationAction,
194 current_schema: &[TableDef],
195 pending_constraints: &[TableConstraint],
196) -> Result<Vec<BuiltQuery>, QueryError> {
197 match action {
198 MigrationAction::AddConstraint { table, constraint } => build_add_constraint(
199 backend,
200 table,
201 constraint,
202 current_schema,
203 pending_constraints,
204 ),
205 MigrationAction::RemoveConstraint { table, constraint } => build_remove_constraint(
206 backend,
207 table,
208 constraint,
209 current_schema,
210 pending_constraints,
211 ),
212 MigrationAction::ReplaceConstraint { table, from, to } => build_replace_constraint(
213 backend,
214 table,
215 from,
216 to,
217 current_schema,
218 pending_constraints,
219 ),
220 _ => unreachable!("only constraint actions are dispatched here"),
221 }
222}
223
224#[cfg(test)]
225mod tests;