Repository: ariga/atlas
Pull request #2676 (2024-04-12 13:52:25)

sql/postgres: support converting types USING expr


Patch:
diff --git a/sql/postgres/inspect.go b/sql/postgres/inspect.go
index 1df32566..73e2d105 100644
--- a/sql/postgres/inspect.go
+++ b/sql/postgres/inspect.go
@@ -960,6 +960,13 @@ type (
 		T string
 	}
 
+	// ConvertUsing describes the USING clause to convert
+	// one type to another.
+	ConvertUsing struct {
+		schema.Clause
+		X string // Conversion expression.
+	}
+
 	// Constraint describes a postgres constraint.
 	// https://postgresql.org/docs/current/catalog-pg-constraint.html
 	Constraint struct {
diff --git a/sql/postgres/migrate.go b/sql/postgres/migrate.go
index f72ce261..14335c44 100644
--- a/sql/postgres/migrate.go
+++ b/sql/postgres/migrate.go
@@ -428,7 +428,7 @@ func (s *state) modifyTable(modify *schema.ModifyTable) error {
 					continue
 				}
 			}
-			alter = append(alter, &schema.ModifyColumn{To: change.To, From: change.From, Change: k})
+			alter = append(alter, &schema.ModifyColumn{To: change.To, From: change.From, Change: k, Extra: change.Extra})
 		case *schema.RenameColumn:
 			// "RENAME COLUMN" cannot be combined with other alterations.
 			b := s.Build("ALTER TABLE").Table(modify.T).P("RENAME COLUMN")
@@ -775,6 +775,9 @@ func (s *state) alterType(b *sqlx.Builder, alter *changeGroup, t *schema.Table,
 	if collate := (schema.Collation{}); sqlx.Has(c.To.Attrs, &collate) {
 		b.P("COLLATE", collate.V)
 	}
+	if using := (ConvertUsing{}); sqlx.Has(c.Extra, &using) {
+		b.P("USING", using.X)
+	}
 	return nil
 }
 
diff --git a/sql/schema/migrate.go b/sql/schema/migrate.go
index f91eafbf..78c7ef24 100644
--- a/sql/schema/migrate.go
+++ b/sql/schema/migrate.go
@@ -225,6 +225,7 @@ type (
 	ModifyColumn struct {
 		From, To *Column
 		Change   ChangeKind
+		Extra    []Clause // Extra clauses and options.
 	}
 
 	// RenameColumn describes a column rename change.


Test patch:
diff --git a/sql/postgres/migrate_test.go b/sql/postgres/migrate_test.go
index 38ede5fd..732bb825 100644
--- a/sql/postgres/migrate_test.go
+++ b/sql/postgres/migrate_test.go
@@ -1395,6 +1395,9 @@ func TestPlanChanges(t *testing.T) {
 							From:   schema.NewColumn("c1").SetType(&SerialType{T: "smallserial"}),
 							To:     schema.NewIntColumn("c1", "integer"),
 							Change: schema.ChangeType,
+							Extra: []schema.Clause{
+								&ConvertUsing{X: "c1::int"},
+							},
 						},
 						&schema.ModifyColumn{
 							From:   schema.NewColumn("c2").SetType(&SerialType{T: "serial", SequenceName: "previous_name"}),
@@ -1409,7 +1412,7 @@ func TestPlanChanges(t *testing.T) {
 				Transactional: true,
 				Changes: []*migrate.Change{
 					{
-						Cmd:     `ALTER TABLE "public"."posts" ALTER COLUMN "c1" DROP DEFAULT, ALTER COLUMN "c1" TYPE integer, ALTER COLUMN "c2" DROP DEFAULT`,
+						Cmd:     `ALTER TABLE "public"."posts" ALTER COLUMN "c1" DROP DEFAULT, ALTER COLUMN "c1" TYPE integer USING c1::int, ALTER COLUMN "c2" DROP DEFAULT`,
 						Reverse: `ALTER TABLE "public"."posts" ALTER COLUMN "c2" SET DEFAULT nextval('"public"."previous_name"'), ALTER COLUMN "c1" SET DEFAULT nextval('"public"."posts_c1_seq"'), ALTER COLUMN "c1" TYPE smallint`,
 					},
 					{