feat(migration): add support for altering column nullability
* Implement ExecuteAlterColumnNullability function * Create alter_column_nullability template * Add test for altering column nullability behavior
This commit is contained in:
@@ -497,6 +497,29 @@ func (w *MigrationWriter) generateAlterTableScripts(schema *models.Schema, model
|
||||
}
|
||||
scripts = append(scripts, script)
|
||||
}
|
||||
|
||||
// Check nullability changes
|
||||
if modelCol.NotNull != currentCol.NotNull {
|
||||
sql, err := w.executor.ExecuteAlterColumnNullability(AlterColumnNullabilityData{
|
||||
SchemaName: schema.Name,
|
||||
TableName: modelTable.Name,
|
||||
ColumnName: modelCol.Name,
|
||||
NotNull: modelCol.NotNull,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
script := MigrationScript{
|
||||
ObjectName: fmt.Sprintf("%s.%s.%s", schema.Name, modelTable.Name, modelCol.Name),
|
||||
ObjectType: "alter column nullability",
|
||||
Schema: schema.Name,
|
||||
Priority: 145,
|
||||
Sequence: len(scripts),
|
||||
Body: sql,
|
||||
}
|
||||
scripts = append(scripts, script)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -136,6 +136,44 @@ func TestWriteMigration_AltersColumnTypeWhenActualTypeDiffers(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestWriteMigration_AltersColumnNullabilityWhenNotNullDiffers(t *testing.T) {
|
||||
current := models.InitDatabase("testdb")
|
||||
currentSchema := models.InitSchema("public")
|
||||
currentTable := models.InitTable("service_instance", "public")
|
||||
currentType := models.InitColumn("rid_service_instance_type", "service_instance", "public")
|
||||
currentType.Type = "text"
|
||||
currentType.NotNull = true
|
||||
currentTable.Columns["rid_service_instance_type"] = currentType
|
||||
currentSchema.Tables = append(currentSchema.Tables, currentTable)
|
||||
current.Schemas = append(current.Schemas, currentSchema)
|
||||
|
||||
model := models.InitDatabase("testdb")
|
||||
modelSchema := models.InitSchema("public")
|
||||
modelTable := models.InitTable("service_instance", "public")
|
||||
modelType := models.InitColumn("rid_service_instance_type", "service_instance", "public")
|
||||
modelType.Type = "text"
|
||||
modelType.NotNull = false
|
||||
modelTable.Columns["rid_service_instance_type"] = modelType
|
||||
modelSchema.Tables = append(modelSchema.Tables, modelTable)
|
||||
model.Schemas = append(model.Schemas, modelSchema)
|
||||
|
||||
var buf bytes.Buffer
|
||||
writer, err := NewMigrationWriter(&writers.WriterOptions{})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create writer: %v", err)
|
||||
}
|
||||
writer.writer = &buf
|
||||
|
||||
if err := writer.WriteMigration(model, current); err != nil {
|
||||
t.Fatalf("WriteMigration failed: %v", err)
|
||||
}
|
||||
|
||||
output := buf.String()
|
||||
if !strings.Contains(output, "ALTER COLUMN rid_service_instance_type DROP NOT NULL") {
|
||||
t.Fatalf("expected migration to drop NOT NULL on existing column, got:\n%s", output)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWriteMigration_UsesStorageTypeForSerialAlterStatements(t *testing.T) {
|
||||
current := models.InitDatabase("testdb")
|
||||
currentSchema := models.InitSchema("public")
|
||||
|
||||
@@ -116,6 +116,14 @@ type AlterColumnDefaultData struct {
|
||||
DefaultValue string
|
||||
}
|
||||
|
||||
// AlterColumnNullabilityData contains data for alter column nullability template
|
||||
type AlterColumnNullabilityData struct {
|
||||
SchemaName string
|
||||
TableName string
|
||||
ColumnName string
|
||||
NotNull bool
|
||||
}
|
||||
|
||||
// CreatePrimaryKeyData contains data for create primary key template
|
||||
type CreatePrimaryKeyData struct {
|
||||
SchemaName string
|
||||
@@ -331,6 +339,16 @@ func (te *TemplateExecutor) ExecuteAlterColumnDefault(data AlterColumnDefaultDat
|
||||
return buf.String(), nil
|
||||
}
|
||||
|
||||
// ExecuteAlterColumnNullability executes the alter column nullability template
|
||||
func (te *TemplateExecutor) ExecuteAlterColumnNullability(data AlterColumnNullabilityData) (string, error) {
|
||||
var buf bytes.Buffer
|
||||
err := te.templates.ExecuteTemplate(&buf, "alter_column_nullability.tmpl", data)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to execute alter_column_nullability template: %w", err)
|
||||
}
|
||||
return buf.String(), nil
|
||||
}
|
||||
|
||||
// ExecuteCreatePrimaryKey executes the create primary key template
|
||||
func (te *TemplateExecutor) ExecuteCreatePrimaryKey(data CreatePrimaryKeyData) (string, error) {
|
||||
var buf bytes.Buffer
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
{{- if .NotNull -}}
|
||||
ALTER TABLE {{qual_table .SchemaName .TableName}}
|
||||
ALTER COLUMN {{quote_ident .ColumnName}} SET NOT NULL;
|
||||
{{- else -}}
|
||||
ALTER TABLE {{qual_table .SchemaName .TableName}}
|
||||
ALTER COLUMN {{quote_ident .ColumnName}} DROP NOT NULL;
|
||||
{{- end -}}
|
||||
Reference in New Issue
Block a user