Skip to content

Commit 1650210

Browse files
Allow adding indexes to columns created in the same migration (#454)
Allow the `create_index` operation to add an index to a column that was created by an operation earlier in the same migration. The following migration would previously have failed to start: ```json { "name": "43_multiple_ops", "operations": [ { "create_table": { "name": "players", "columns": [ { "name": "id", "type": "serial", "pk": true }, { "name": "name", "type": "varchar(255)", "check": { "name": "name_length_check", "constraint": "length(name) > 2" } } ] } }, { "add_column": { "table": "players", "column": { "name": "rating", "type": "integer", "comment": "hello world", "check": { "name": "rating_check", "constraint": "rating > 0 AND rating < 100" }, "nullable": false } } }, { "create_index": { "name": "idx_player_rating", "table": "players", "columns": [ "rating" ] } } ] } ``` As of this PR the migration can be started. The above migration does not validate yet, but it can be started successfully with the `--skip-validation` flag to the `start` command. Part of #239
1 parent 5a49929 commit 1650210

File tree

3 files changed

+71
-3
lines changed

3 files changed

+71
-3
lines changed

pkg/migrations/op_create_index.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ func (o *OpCreateIndex) Start(ctx context.Context, conn db.DB, latestSchema stri
3131
stmt += fmt.Sprintf(" USING %s", string(*o.Method))
3232
}
3333

34-
stmt += fmt.Sprintf(" (%s)", strings.Join(quoteColumnNames(o.Columns), ", "))
34+
stmt += fmt.Sprintf(" (%s)", strings.Join(
35+
quoteColumnNames(table.PhysicalColumnNamesFor(o.Columns...)), ", "),
36+
)
3537

3638
if o.StorageParameters != nil {
3739
stmt += fmt.Sprintf(" WITH (%s)", *o.StorageParameters)

pkg/migrations/op_create_index_test.go

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ func TestCreateIndexOnMultipleColumns(t *testing.T) {
315315
}})
316316
}
317317

318-
func TestCreateIndexOnTableCreatedInSameMigration(t *testing.T) {
318+
func TestCreateIndexOnObjectsCreatedInSameMigration(t *testing.T) {
319319
t.Parallel()
320320

321321
ExecuteTests(t, TestCases{
@@ -361,5 +361,61 @@ func TestCreateIndexOnTableCreatedInSameMigration(t *testing.T) {
361361
IndexMustExist(t, db, schema, "users", "idx_users_name")
362362
},
363363
},
364-
}, roll.WithSkipValidation(true)) // TODO: Remove once this migration passes validation
364+
{
365+
name: "create index on newly created column",
366+
migrations: []migrations.Migration{
367+
{
368+
Name: "01_add_table",
369+
Operations: migrations.Operations{
370+
&migrations.OpCreateTable{
371+
Name: "users",
372+
Columns: []migrations.Column{
373+
{
374+
Name: "id",
375+
Type: "serial",
376+
Pk: ptr(true),
377+
},
378+
{
379+
Name: "name",
380+
Type: "varchar(255)",
381+
Nullable: ptr(false),
382+
},
383+
},
384+
},
385+
},
386+
},
387+
{
388+
Name: "02_add_column_and_index",
389+
Operations: migrations.Operations{
390+
&migrations.OpAddColumn{
391+
Table: "users",
392+
Column: migrations.Column{
393+
Name: "age",
394+
Type: "integer",
395+
Nullable: ptr(true),
396+
},
397+
Up: "18",
398+
},
399+
&migrations.OpCreateIndex{
400+
Name: "idx_users_age",
401+
Table: "users",
402+
Columns: []string{"age"},
403+
},
404+
},
405+
},
406+
},
407+
afterStart: func(t *testing.T, db *sql.DB, schema string) {
408+
// The index has been created on the underlying table.
409+
IndexMustExist(t, db, schema, "users", "idx_users_age")
410+
},
411+
afterRollback: func(t *testing.T, db *sql.DB, schema string) {
412+
// The index has been dropped from the the underlying table.
413+
IndexMustNotExist(t, db, schema, "users", "idx_users_age")
414+
},
415+
afterComplete: func(t *testing.T, db *sql.DB, schema string) {
416+
// The index has been created on the underlying table.
417+
IndexMustExist(t, db, schema, "users", "idx_users_age")
418+
},
419+
},
420+
}, roll.WithSkipValidation(true)) // TODO: Remove once these migrations pass validation
365421
}

pkg/schema/schema.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,16 @@ func (t *Table) RenameColumn(from, to string) {
253253
delete(t.Columns, from)
254254
}
255255

256+
// PhysicalColumnNames returns the physical column names for the given virtual
257+
// column names
258+
func (t *Table) PhysicalColumnNamesFor(columnNames ...string) []string {
259+
physicalNames := make([]string, 0, len(columnNames))
260+
for _, cn := range columnNames {
261+
physicalNames = append(physicalNames, t.GetColumn(cn).Name)
262+
}
263+
return physicalNames
264+
}
265+
256266
// Make the Schema struct implement the driver.Valuer interface. This method
257267
// simply returns the JSON-encoded representation of the struct.
258268
func (s Schema) Value() (driver.Value, error) {

0 commit comments

Comments
 (0)