feat(migration): add fallback for column type conversion failures
* implement renaming of old column and adding new column on conversion failure * update templates and tests to support new behavior
This commit is contained in:
@@ -442,12 +442,14 @@ func (w *MigrationWriter) generateAlterTableScripts(schema *models.Schema, model
|
||||
} else if !columnsEqual(modelCol, currentCol) {
|
||||
// Column exists but properties changed
|
||||
if !columnTypesEqual(modelCol, currentCol) {
|
||||
sql, err := w.executor.ExecuteAlterColumnType(AlterColumnTypeData{
|
||||
SchemaName: schema.Name,
|
||||
TableName: modelTable.Name,
|
||||
ColumnName: modelCol.Name,
|
||||
NewType: effectiveAlterColumnSQLType(modelCol),
|
||||
UsingExpr: buildAlterColumnUsingExpression(modelCol.Name, effectiveAlterColumnSQLType(modelCol)),
|
||||
newType := effectiveAlterColumnSQLType(modelCol)
|
||||
sql, err := w.executor.ExecuteAlterColumnTypeWithFallback(AlterColumnTypeWithFallbackData{
|
||||
SchemaName: schema.Name,
|
||||
TableName: modelTable.Name,
|
||||
ColumnName: modelCol.Name,
|
||||
NewType: newType,
|
||||
UsingExpr: buildAlterColumnUsingExpression(modelCol.Name, newType),
|
||||
OldColumnName: renamedColumnName(modelCol.Name, effectiveAlterColumnSQLType(currentCol)),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -962,6 +964,32 @@ func (w *MigrationWriter) generateAuditScripts(schema *models.Schema, auditConfi
|
||||
|
||||
// Helper functions for comparing database objects
|
||||
|
||||
// renamedColumnName builds the fallback column name used when an in-place
|
||||
// type conversion fails: "<column>_<oldtype>", with the old type sanitized
|
||||
// to a valid identifier fragment (e.g. "varchar(50)" -> "varchar_50").
|
||||
func renamedColumnName(columnName, oldType string) string {
|
||||
sanitized := strings.Map(func(r rune) rune {
|
||||
switch {
|
||||
case r >= 'a' && r <= 'z', r >= '0' && r <= '9':
|
||||
return r
|
||||
case r >= 'A' && r <= 'Z':
|
||||
return r + ('a' - 'A')
|
||||
default:
|
||||
return '_'
|
||||
}
|
||||
}, oldType)
|
||||
|
||||
for strings.Contains(sanitized, "__") {
|
||||
sanitized = strings.ReplaceAll(sanitized, "__", "_")
|
||||
}
|
||||
sanitized = strings.Trim(sanitized, "_")
|
||||
|
||||
if sanitized == "" {
|
||||
return columnName + "_old"
|
||||
}
|
||||
return columnName + "_" + sanitized
|
||||
}
|
||||
|
||||
// columnsEqual checks if two columns have the same definition
|
||||
func columnsEqual(col1, col2 *models.Column) bool {
|
||||
if col1 == nil || col2 == nil {
|
||||
|
||||
Reference in New Issue
Block a user