Skip to content

Commit e3d27d0

Browse files
authored
Merge pull request #115 from dev-five-git/fix-casting-issue
Fix enum casting issue
2 parents 61a6479 + dfa7e5f commit e3d27d0

3 files changed

Lines changed: 41 additions & 26 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"changes":{"crates/vespertide-core/Cargo.toml":"Patch","crates/vespertide-macro/Cargo.toml":"Patch","crates/vespertide-cli/Cargo.toml":"Patch","crates/vespertide-loader/Cargo.toml":"Patch","crates/vespertide-naming/Cargo.toml":"Patch","crates/vespertide-query/Cargo.toml":"Patch","crates/vespertide-config/Cargo.toml":"Patch","crates/vespertide-exporter/Cargo.toml":"Patch","crates/vespertide/Cargo.toml":"Patch","crates/vespertide-planner/Cargo.toml":"Patch"},"note":"Fix enum casting issue","date":"2026-02-24T01:47:44.397924100Z"}

crates/vespertide-query/src/sql/modify_column_type.rs

Lines changed: 39 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -124,56 +124,62 @@ pub fn build_modify_column_type(
124124
.map(|c| &c.r#type);
125125

126126
// Check if this is an enum-to-enum migration that needs special handling (PostgreSQL only)
127+
// Covers both: enum value changes (same name) and enum name changes (different name)
127128
let needs_enum_migration = if *backend == DatabaseBackend::Postgres {
128129
matches!(
129130
(old_type, new_type),
130131
(
131132
Some(ColumnType::Complex(ComplexColumnType::Enum { name: old_name, values: old_values })),
132133
ColumnType::Complex(ComplexColumnType::Enum { name: new_name, values: new_values })
133-
) if old_name == new_name && old_values != new_values
134+
) if old_name != new_name || old_values != new_values
134135
)
135136
} else {
136137
false
137138
};
138-
139139
if needs_enum_migration {
140-
// Use the safe temp type + USING + RENAME approach for enum value changes
140+
// PostgreSQL enum-to-enum migration with USING clause for safe casting
141141
if let (
142142
Some(ColumnType::Complex(ComplexColumnType::Enum {
143-
name: enum_name, ..
143+
name: old_enum_name,
144+
..
144145
})),
145146
ColumnType::Complex(ComplexColumnType::Enum {
146-
values: new_values, ..
147+
name: new_enum_name,
148+
values: new_values,
147149
}),
148150
) = (old_type, new_type)
149151
{
150-
// Use table-prefixed enum type names
151-
let type_name = super::helpers::build_enum_type_name(table, enum_name);
152-
let temp_type_name = format!("{}_new", type_name);
153-
152+
let old_type_name = super::helpers::build_enum_type_name(table, old_enum_name);
153+
let new_type_name = super::helpers::build_enum_type_name(table, new_enum_name);
154+
let names_differ = old_enum_name != new_enum_name;
155+
156+
// For same-name changes: create temp type, then rename back
157+
// For different-name changes: create final type directly, no rename needed
158+
let (target_type_name, needs_rename) = if names_differ {
159+
(new_type_name, false)
160+
} else {
161+
(format!("{}_new", old_type_name), true)
162+
};
154163
// 0. INSERT fill_with UPDATEs before any type changes (rows still have old enum type)
155164
if let Some(fw) = fill_with {
156165
queries.extend(build_fill_with_updates(table, column, fw));
157166
}
158-
159167
// Check if column has a DEFAULT value that needs to be handled
160168
let column_default = current_schema
161169
.iter()
162170
.find(|t| t.name == table)
163171
.and_then(|t| t.columns.iter().find(|c| c.name == column))
164172
.and_then(|c| c.default.clone());
165-
166-
// 1. CREATE TYPE {table}_{enum}_new AS ENUM (new values)
167-
let create_temp_values = new_values.to_sql_values().join(", ");
173+
// 1. CREATE TYPE target_type AS ENUM (new values)
174+
let create_values = new_values.to_sql_values().join(", ");
168175
queries.push(BuiltQuery::Raw(super::types::RawSql::per_backend(
169176
format!(
170177
"CREATE TYPE \"{}\" AS ENUM ({})",
171-
temp_type_name, create_temp_values
178+
target_type_name, create_values
172179
),
173180
String::new(),
174181
String::new(),
175182
)));
176-
177183
// 2. DROP DEFAULT if exists (must be done before type change)
178184
if column_default.is_some() {
179185
queries.push(BuiltQuery::Raw(super::types::RawSql::per_backend(
@@ -186,26 +192,34 @@ pub fn build_modify_column_type(
186192
)));
187193
}
188194

189-
// 3. ALTER TABLE ... ALTER COLUMN ... TYPE {table}_{enum}_new USING {column}::text::{table}_{enum}_new
190-
queries.push(BuiltQuery::Raw(super::types::RawSql::per_backend(format!("ALTER TABLE \"{}\" ALTER COLUMN \"{}\" TYPE \"{}\" USING \"{}\"::text::\"{}\"", table, column, temp_type_name, column, temp_type_name), String::new(), String::new())));
191-
192-
// 4. DROP TYPE {table}_{enum}
195+
// 3. ALTER TABLE ... ALTER COLUMN ... TYPE target_type USING col::text::target_type
193196
queries.push(BuiltQuery::Raw(super::types::RawSql::per_backend(
194-
format!("DROP TYPE \"{}\"", type_name),
197+
format!(
198+
"ALTER TABLE \"{}\" ALTER COLUMN \"{}\" TYPE \"{}\" USING \"{}\"::text::\"{}\"",
199+
table, column, target_type_name, column, target_type_name
200+
),
195201
String::new(),
196202
String::new(),
197203
)));
198204

199-
// 5. ALTER TYPE {table}_{enum}_new RENAME TO {table}_{enum}
205+
// 4. DROP old enum type
200206
queries.push(BuiltQuery::Raw(super::types::RawSql::per_backend(
201-
format!(
202-
"ALTER TYPE \"{}\" RENAME TO \"{}\"",
203-
temp_type_name, type_name
204-
),
207+
format!("DROP TYPE \"{}\"", old_type_name),
205208
String::new(),
206209
String::new(),
207210
)));
208211

212+
// 5. RENAME temp to final (only for same-name value changes)
213+
if needs_rename {
214+
queries.push(BuiltQuery::Raw(super::types::RawSql::per_backend(
215+
format!(
216+
"ALTER TYPE \"{}\" RENAME TO \"{}\"",
217+
target_type_name, old_type_name
218+
),
219+
String::new(),
220+
String::new(),
221+
)));
222+
}
209223
// 6. Restore DEFAULT if it existed
210224
if let Some(default_value) = column_default {
211225
// Use normalize_enum_default to properly quote enum values

crates/vespertide-query/src/sql/snapshots/vespertide_query__sql__modify_column_type__tests__modify_enum_types@modify_enum_types_enum_name_changed_postgres.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@ source: crates/vespertide-query/src/sql/modify_column_type.rs
33
expression: sql
44
---
55
CREATE TYPE "users_new_status" AS ENUM ('active', 'inactive');
6-
ALTER TABLE "users" ALTER COLUMN "status" TYPE users_new_status;
6+
ALTER TABLE "users" ALTER COLUMN "status" TYPE "users_new_status" USING "status"::text::"users_new_status";
77
DROP TYPE "users_old_status"

0 commit comments

Comments
 (0)