Skip to content

Commit d656387

Browse files
Update schema during create table validation (#455)
Update the schema during `create_table` operation validation so that validation of subsequent operations in the same migration can see the new table. This means that migrations that add a new table and then perform some other operation, like adding a column, on that table can be validated because the new table is visible to the `add_column` operation during it's validation phase. This means that the following migration is now able to validate: ```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 } } } ] } ``` Previously, the new table would not have been visible to the `add_column` operation and its validation would have failed. In order to make this work the schema needs to be re-read from the target database in between validation and migration start, as the previous assumption that validation would not make changes to the in-memory schema representation no longer holds. Part of #239
1 parent 68578f2 commit d656387

File tree

3 files changed

+32
-12
lines changed

3 files changed

+32
-12
lines changed

pkg/migrations/op_add_column_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1524,6 +1524,7 @@ func TestAddColumnToATableCreatedInTheSameMigration(t *testing.T) {
15241524
Name: "age",
15251525
Type: "integer",
15261526
Nullable: ptr(false),
1527+
Default: ptr("18"),
15271528
Check: &migrations.CheckConstraint{
15281529
Name: "age_check",
15291530
Constraint: "age >= 18",
@@ -1559,7 +1560,7 @@ func TestAddColumnToATableCreatedInTheSameMigration(t *testing.T) {
15591560
}, testutils.CheckViolationErrorCode)
15601561
},
15611562
},
1562-
}, roll.WithSkipValidation(true)) // TODO: remove once this migration can be validated
1563+
})
15631564
}
15641565

15651566
func TestAddColumnInvalidNameLength(t *testing.T) {

pkg/migrations/op_create_table.go

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -47,17 +47,8 @@ func (o *OpCreateTable) Start(ctx context.Context, conn db.DB, latestSchema stri
4747
}
4848
}
4949

50-
columns := make(map[string]schema.Column, len(o.Columns))
51-
for _, col := range o.Columns {
52-
columns[col.Name] = schema.Column{
53-
Name: col.Name,
54-
}
55-
}
56-
57-
s.AddTable(o.Name, schema.Table{
58-
Name: tempName,
59-
Columns: columns,
60-
})
50+
// Update the in-memory schema representation with the new table
51+
o.updateSchema(s)
6152

6253
return nil, nil
6354
}
@@ -117,9 +108,30 @@ func (o *OpCreateTable) Validate(ctx context.Context, s *schema.Schema) error {
117108
}
118109
}
119110

111+
// Update the schema to ensure that the new table is visible to validation of
112+
// subsequent operations.
113+
o.updateSchema(s)
114+
120115
return nil
121116
}
122117

118+
// updateSchema updates the in-memory schema representation with the details of
119+
// the new table.
120+
func (o *OpCreateTable) updateSchema(s *schema.Schema) *schema.Schema {
121+
columns := make(map[string]schema.Column, len(o.Columns))
122+
for _, col := range o.Columns {
123+
columns[col.Name] = schema.Column{
124+
Name: col.Name,
125+
}
126+
}
127+
s.AddTable(o.Name, schema.Table{
128+
Name: TemporaryName(o.Name),
129+
Columns: columns,
130+
})
131+
132+
return s
133+
}
134+
123135
func columnsToSQL(cols []Column, tr SQLTransformer) (string, error) {
124136
var sql string
125137
var primaryKeys []string

pkg/roll/execute.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,13 @@ func (m *Roll) StartDDLOperations(ctx context.Context, migration *migrations.Mig
7575
}
7676
latestSchema := VersionedSchemaName(m.schema, *latestVersion)
7777

78+
// Reread the latest schema as validation may have updated the schema object
79+
// in memory.
80+
newSchema, err = m.state.ReadSchema(ctx, m.schema)
81+
if err != nil {
82+
return nil, fmt.Errorf("unable to read schema: %w", err)
83+
}
84+
7885
// execute operations
7986
var tablesToBackfill []*schema.Table
8087
for _, op := range migration.Operations {

0 commit comments

Comments
 (0)