From 62e9a64340e07827e1c5bd1bcb58e9919a85c524 Mon Sep 17 00:00:00 2001 From: "Rodrigo Rodriguez (Pragmatismo)" Date: Sat, 4 Apr 2026 11:11:22 -0300 Subject: [PATCH] fix: Remove duplicate code in table_migration.rs - Removed duplicate DbColumn struct, PROTECTED_COLUMNS const, and sync_table_schema fn - File now has single clean implementation with column drop protection --- src/basic/keywords/table_migration.rs | 145 -------------------------- 1 file changed, 145 deletions(-) diff --git a/src/basic/keywords/table_migration.rs b/src/basic/keywords/table_migration.rs index 22eb0608..c6c595a3 100644 --- a/src/basic/keywords/table_migration.rs +++ b/src/basic/keywords/table_migration.rs @@ -172,151 +172,6 @@ pub fn sync_table_schema( Ok(result) } -/// Column metadata from database -#[derive(Debug, Clone)] -pub struct DbColumn { - pub name: String, - pub data_type: String, - pub is_nullable: bool, -} - -/// Columns that should never be dropped automatically -const PROTECTED_COLUMNS: &[&str] = &[ - "id", - "bot_id", - "org_id", - "user_id", - "created_at", - "updated_at", - "deleted_at", - "is_deleted", - "version", - "tenant_id", -]; - -/// Compare and sync table schema with definition -pub fn sync_table_schema( - table: &TableDefinition, - existing_columns: &[DbColumn], - create_sql: &str, - conn: &mut diesel::PgConnection, -) -> Result> { - let mut result = MigrationResult::default(); - - // If no columns exist, create the table - if existing_columns.is_empty() { - info!("Creating new table: {}", table.name); - sql_query(create_sql) - .execute(conn) - .map_err(|e| format!("Failed to create table {}: {}", table.name, e))?; - result.tables_created += 1; - return Ok(result); - } - - let table_name = sanitize_identifier(&table.name); - let defined_col_names: std::collections::HashSet = - table.fields.iter().map(|f| f.name.clone()).collect(); - let existing_col_names: std::collections::HashSet = - existing_columns.iter().map(|c| c.name.clone()).collect(); - - // Add missing columns - let mut missing_columns: Vec<&FieldDefinition> = Vec::new(); - for field in &table.fields { - if !existing_col_names.contains(&field.name) { - missing_columns.push(field); - } - } - - if !missing_columns.is_empty() { - info!( - "Table {} is missing {} columns, adding them", - table.name, - missing_columns.len() - ); - - for field in &missing_columns { - let sql_type = map_type_to_sql(field, "postgres"); - let column_sql = format!( - "ALTER TABLE {} ADD COLUMN IF NOT EXISTS {} {}", - &table_name, - sanitize_identifier(&field.name), - sql_type - ); - - info!( - "Adding column: {}.{} ({})", - table.name, field.name, sql_type - ); - match sql_query(&column_sql).execute(conn) { - Ok(_) => { - result.columns_added += 1; - info!("Successfully added column {}.{}", table.name, field.name); - } - Err(e) => { - let err_str = e.to_string(); - if !err_str.contains("already exists") && !err_str.contains("duplicate column") - { - let error_msg = - format!("Failed to add column {}.{}: {}", table.name, field.name, e); - error!("{}", error_msg); - result.errors.push(error_msg); - } else { - info!( - "Column {}.{} already exists, skipping", - table.name, field.name - ); - } - } - } - } - result.tables_altered += 1; - } - - // Drop columns that were removed from definition (with protection) - let mut orphaned_columns: Vec<&DbColumn> = Vec::new(); - for col in existing_columns { - if !defined_col_names.contains(&col.name) && !PROTECTED_COLUMNS.contains(&col.name.as_str()) - { - orphaned_columns.push(col); - } - } - - if !orphaned_columns.is_empty() { - warn!( - "Table {} has {} orphaned columns not in definition:", - table.name, - orphaned_columns.len() - ); - - for col in &orphaned_columns { - info!("Dropping orphaned column: {}.{}", table.name, col.name); - let drop_sql = format!( - "ALTER TABLE {} DROP COLUMN IF EXISTS {}", - &table_name, - sanitize_identifier(&col.name) - ); - - match sql_query(&drop_sql).execute(conn) { - Ok(_) => { - result.columns_dropped += 1; - info!("Successfully dropped column {}.{}", table.name, col.name); - } - Err(e) => { - let error_msg = - format!("Failed to drop column {}.{}: {}", table.name, col.name, e); - error!("{}", error_msg); - result.errors.push(error_msg); - } - } - } - if result.columns_dropped > 0 { - result.tables_altered += 1; - } - } - - Ok(result) -} - /// Get existing columns from a table pub fn get_table_columns( table_name: &str,