Skip to content

Commit f672053

Browse files
authored
Add new DBAction: RenameDuplicatedColumnAction (#883)
This PR transforms `RenameDuplicatedColumn` to a `DBAction`. It consists of multiple `DBAction`s. It might be more elegant if it returned a list of `DBActions` instead. But for now, it is good enough for the upcoming extraction of the cleanup phase from complete and rollback. Related to #742
1 parent 192f4eb commit f672053

File tree

5 files changed

+41
-33
lines changed

5 files changed

+41
-33
lines changed

pkg/migrations/op_alter_column.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ func (o *OpAlterColumn) Complete(ctx context.Context, l Logger, conn db.DB, s *s
134134
if column == nil {
135135
return ColumnDoesNotExistError{Table: o.Table, Name: o.Column}
136136
}
137-
if err := RenameDuplicatedColumn(ctx, conn, table, column); err != nil {
137+
if err := NewRenameDuplicatedColumnAction(conn, table, column.Name).Execute(ctx); err != nil {
138138
return err
139139
}
140140

pkg/migrations/op_create_constraint.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ func (o *OpCreateConstraint) Complete(ctx context.Context, l Logger, conn db.DB,
168168
if column == nil {
169169
return ColumnDoesNotExistError{Table: o.Table, Name: col}
170170
}
171-
if err := RenameDuplicatedColumn(ctx, conn, table, column); err != nil {
171+
if err := NewRenameDuplicatedColumnAction(conn, table, column.Name).Execute(ctx); err != nil {
172172
return err
173173
}
174174
}

pkg/migrations/op_drop_constraint.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ func (o *OpDropConstraint) Complete(ctx context.Context, l Logger, conn db.DB, s
111111
}
112112

113113
// Rename the new column to the old column name
114-
if err := RenameDuplicatedColumn(ctx, conn, table, column); err != nil {
114+
if err := NewRenameDuplicatedColumnAction(conn, table, column.Name).Execute(ctx); err != nil {
115115
return err
116116
}
117117

pkg/migrations/op_drop_multicolumn_constraint.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ func (o *OpDropMultiColumnConstraint) Complete(ctx context.Context, l Logger, co
127127

128128
// Rename the new column to the old column name
129129
column := table.GetColumn(columnName)
130-
if err := RenameDuplicatedColumn(ctx, conn, table, column); err != nil {
130+
if err := NewRenameDuplicatedColumnAction(conn, table, column.Name).Execute(ctx); err != nil {
131131
return err
132132
}
133133
}

pkg/migrations/rename.go

Lines changed: 37 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -17,71 +17,79 @@ import (
1717
// * Renames a duplicated column to its original name
1818
// * Renames any foreign keys on the duplicated column to their original name.
1919
// * Validates and renames any temporary `CHECK` constraints on the duplicated column.
20-
func RenameDuplicatedColumn(ctx context.Context, conn db.DB, table *schema.Table, column *schema.Column) error {
20+
type renameDuplicatedColumnAction struct {
21+
conn db.DB
22+
table *schema.Table
23+
from string
24+
to string
25+
}
26+
27+
func NewRenameDuplicatedColumnAction(conn db.DB, table *schema.Table, column string) *renameDuplicatedColumnAction {
28+
return &renameDuplicatedColumnAction{
29+
conn: conn,
30+
table: table,
31+
from: TemporaryName(column),
32+
to: column,
33+
}
34+
}
35+
36+
func (a *renameDuplicatedColumnAction) Execute(ctx context.Context) error {
2137
const (
22-
cSetNotNullSQL = `ALTER TABLE IF EXISTS %s ALTER COLUMN %s SET NOT NULL`
23-
cDropConstraintSQL = `ALTER TABLE IF EXISTS %s DROP CONSTRAINT IF EXISTS %s`
2438
cCreateUniqueConstraintSQL = `ALTER TABLE IF EXISTS %s ADD CONSTRAINT %s UNIQUE USING INDEX %s`
2539
cRenameIndexSQL = `ALTER INDEX IF EXISTS %s RENAME TO %s`
2640
)
2741

28-
err := NewRenameColumnAction(conn, table.Name, TemporaryName(column.Name), column.Name).Execute(ctx)
42+
err := NewRenameColumnAction(a.conn, a.table.Name, a.from, a.to).Execute(ctx)
2943
if err != nil {
30-
return fmt.Errorf("failed to rename duplicated column %q: %w", column.Name, err)
44+
return fmt.Errorf("failed to rename duplicated column %q: %w", a.to, err)
3145
}
3246

3347
// Rename any foreign keys on the duplicated column from their temporary name
3448
// to their original name
35-
for _, fk := range table.ForeignKeys {
49+
for _, fk := range a.table.ForeignKeys {
3650
if !IsDuplicatedName(fk.Name) {
3751
continue
3852
}
3953

40-
if slices.Contains(fk.Columns, TemporaryName(column.Name)) {
41-
err = NewRenameConstraintAction(conn, table.Name, fk.Name, StripDuplicationPrefix(fk.Name)).Execute(ctx)
54+
if slices.Contains(fk.Columns, a.from) {
55+
err = NewRenameConstraintAction(a.conn, a.table.Name, fk.Name, StripDuplicationPrefix(fk.Name)).Execute(ctx)
4256
if err != nil {
4357
return fmt.Errorf("failed to rename foreign key constraint %q: %w", fk.Name, err)
4458
}
45-
delete(table.ForeignKeys, fk.Name)
59+
delete(a.table.ForeignKeys, fk.Name)
4660
}
4761
}
4862

4963
// Validate and rename any temporary `CHECK` constraints on the duplicated
5064
// column.
51-
for _, cc := range table.CheckConstraints {
65+
for _, cc := range a.table.CheckConstraints {
5266
if !IsDuplicatedName(cc.Name) {
5367
continue
5468
}
5569

56-
if slices.Contains(cc.Columns, TemporaryName(column.Name)) {
57-
err := NewValidateConstraintAction(conn, table.Name, cc.Name).Execute(ctx)
70+
if slices.Contains(cc.Columns, a.from) {
71+
err := NewValidateConstraintAction(a.conn, a.table.Name, cc.Name).Execute(ctx)
5872
if err != nil {
5973
return fmt.Errorf("failed to validate check constraint %q: %w", cc.Name, err)
6074
}
6175

62-
err = NewRenameConstraintAction(conn, table.Name, cc.Name, StripDuplicationPrefix(cc.Name)).Execute(ctx)
76+
err = NewRenameConstraintAction(a.conn, a.table.Name, cc.Name, StripDuplicationPrefix(cc.Name)).Execute(ctx)
6377
if err != nil {
6478
return fmt.Errorf("failed to rename check constraint %q: %w", cc.Name, err)
6579
}
66-
delete(table.CheckConstraints, cc.Name)
80+
delete(a.table.CheckConstraints, cc.Name)
6781

6882
// If the constraint is a `NOT NULL` constraint, convert the duplicated
6983
// unchecked `NOT NULL` constraint into a `NOT NULL` attribute on the
7084
// column.
7185
if IsNotNullConstraintName(StripDuplicationPrefix(cc.Name)) {
7286
// Apply `NOT NULL` attribute to the column. This uses the validated constraint
73-
setNotNullSQL := fmt.Sprintf(cSetNotNullSQL,
74-
pq.QuoteIdentifier(table.Name),
75-
pq.QuoteIdentifier(column.Name),
76-
)
77-
78-
_, err = conn.ExecContext(ctx, setNotNullSQL)
79-
if err != nil {
87+
if err := NewSetNotNullAction(a.conn, a.table.Name, a.to).Execute(ctx); err != nil {
8088
return fmt.Errorf("failed to set column not null: %w", err)
8189
}
8290

8391
// Drop the constraint
84-
err = NewDropConstraintAction(conn, table.Name, NotNullConstraintName(column.Name)).Execute(ctx)
92+
err = NewDropConstraintAction(a.conn, a.table.Name, NotNullConstraintName(a.to)).Execute(ctx)
8593
if err != nil {
8694
return fmt.Errorf("failed to drop not null constraint: %w", err)
8795
}
@@ -91,8 +99,8 @@ func RenameDuplicatedColumn(ctx context.Context, conn db.DB, table *schema.Table
9199

92100
// Rename any indexes on the duplicated column and use unique indexes to
93101
// create `UNIQUE` constraints.
94-
for _, idx := range table.Indexes {
95-
if !IsDuplicatedName(idx.Name) || !slices.Contains(idx.Columns, TemporaryName(column.Name)) {
102+
for _, idx := range a.table.Indexes {
103+
if !IsDuplicatedName(idx.Name) || !slices.Contains(idx.Columns, a.from) {
96104
continue
97105
}
98106

@@ -102,23 +110,23 @@ func RenameDuplicatedColumn(ctx context.Context, conn db.DB, table *schema.Table
102110
pq.QuoteIdentifier(StripDuplicationPrefix(idx.Name)),
103111
)
104112

105-
_, err = conn.ExecContext(ctx, renameIndexSQL)
113+
_, err = a.conn.ExecContext(ctx, renameIndexSQL)
106114
if err != nil {
107115
return fmt.Errorf("failed to rename index %q: %w", idx.Name, err)
108116
}
109117

110118
// Index no longer exists, remove it from the table
111-
delete(table.Indexes, idx.Name)
119+
delete(a.table.Indexes, idx.Name)
112120

113-
if _, ok := table.UniqueConstraints[StripDuplicationPrefix(idx.Name)]; idx.Unique && ok {
121+
if _, ok := a.table.UniqueConstraints[StripDuplicationPrefix(idx.Name)]; idx.Unique && ok {
114122
// Create a unique constraint using the unique index
115123
createUniqueConstraintSQL := fmt.Sprintf(cCreateUniqueConstraintSQL,
116-
pq.QuoteIdentifier(table.Name),
124+
pq.QuoteIdentifier(a.table.Name),
117125
pq.QuoteIdentifier(StripDuplicationPrefix(idx.Name)),
118126
pq.QuoteIdentifier(StripDuplicationPrefix(idx.Name)),
119127
)
120128

121-
_, err = conn.ExecContext(ctx, createUniqueConstraintSQL)
129+
_, err = a.conn.ExecContext(ctx, createUniqueConstraintSQL)
122130
if err != nil {
123131
return fmt.Errorf("failed to create unique constraint from index %q: %w", idx.Name, err)
124132
}

0 commit comments

Comments
 (0)