Skip to content

Commit 7643f97

Browse files
committed
address review notes
1 parent 0224bfe commit 7643f97

File tree

4 files changed

+67
-77
lines changed

4 files changed

+67
-77
lines changed

pkg/migrations/dbactions.go

Lines changed: 32 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010

1111
"github.com/lib/pq"
1212
"github.com/xataio/pgroll/pkg/db"
13+
"github.com/xataio/pgroll/pkg/schema"
1314
)
1415

1516
// DBAction is an interface for common database actions
@@ -842,75 +843,46 @@ func (a *setReplicaIdentityAction) Execute(ctx context.Context) error {
842843
}
843844

844845
type alterReferencesAction struct {
845-
conn db.DB
846-
table string
847-
column string
846+
conn db.DB
847+
referencedBy map[string][]*schema.ReferencedBy
848+
table string
849+
column string
848850
}
849851

850-
func NewAlterReferencesAction(conn db.DB, table, column string) *alterReferencesAction {
852+
func NewAlterReferencesAction(conn db.DB, referencedBy map[string][]*schema.ReferencedBy, table, column string) *alterReferencesAction {
851853
return &alterReferencesAction{
852-
conn: conn,
853-
table: table,
854-
column: column,
854+
conn: conn,
855+
referencedBy: referencedBy,
856+
table: table,
857+
column: column,
855858
}
856859
}
857860

858861
func (a *alterReferencesAction) Execute(ctx context.Context) error {
859-
definitions, err := a.constraintDefinitions(ctx)
860-
if err != nil {
861-
return err
862-
}
863-
for _, def := range definitions {
864-
// Drop the existing constraint
865-
_, err := a.conn.ExecContext(ctx, fmt.Sprintf("ALTER TABLE %s DROP CONSTRAINT %s",
866-
pq.QuoteIdentifier(def.table),
867-
pq.QuoteIdentifier(def.name),
868-
))
869-
if err != nil {
870-
return fmt.Errorf("dropping constraint %s on %s: %w", def.name, def.table, err)
871-
}
872-
873-
// Recreate the constraint with the table and new column
874-
newDef := strings.ReplaceAll(def.def, a.column, pq.QuoteIdentifier(TemporaryName(a.column)))
875-
newDef = strings.ReplaceAll(newDef, a.table, pq.QuoteIdentifier(a.table))
876-
_, err = a.conn.ExecContext(ctx, fmt.Sprintf("ALTER TABLE %s ADD CONSTRAINT %s %s",
877-
pq.QuoteIdentifier(def.table),
878-
pq.QuoteIdentifier(def.name),
879-
newDef,
880-
))
881-
if err != nil {
882-
return fmt.Errorf("altering references for %s.%s: %w", a.table, a.column, err)
883-
}
884-
}
885-
return nil
886-
}
887-
888-
type constraintDefinition struct {
889-
name string
890-
table string
891-
def string
892-
}
862+
for table, constraints := range a.referencedBy {
863+
for _, constraint := range constraints {
864+
// Drop the existing constraint
865+
_, err := a.conn.ExecContext(ctx, fmt.Sprintf("ALTER TABLE %s DROP CONSTRAINT %s",
866+
pq.QuoteIdentifier(table),
867+
pq.QuoteIdentifier(constraint.Name),
868+
))
869+
if err != nil {
870+
return fmt.Errorf("dropping constraint %s on %s: %w", constraint.Name, table, err)
871+
}
893872

894-
func (a *alterReferencesAction) constraintDefinitions(ctx context.Context) ([]constraintDefinition, error) {
895-
rows, err := a.conn.QueryContext(ctx, fmt.Sprintf(`
896-
SELECT conname, r.conrelid::regclass, pg_catalog.pg_get_constraintdef(r.oid, true) as condef
897-
FROM pg_catalog.pg_constraint r
898-
WHERE confrelid = %s::regclass AND r.contype = 'f'`,
899-
pq.QuoteIdentifier(a.table),
900-
))
901-
// No FK constraint for table
902-
if err != nil {
903-
return nil, nil
904-
}
905-
defer rows.Close()
873+
// Recreate the constraint with the table and new column
874+
newDef := strings.ReplaceAll(constraint.Definition, a.column, pq.QuoteIdentifier(TemporaryName(a.column)))
875+
newDef = strings.ReplaceAll(newDef, a.table, pq.QuoteIdentifier(a.table))
876+
_, err = a.conn.ExecContext(ctx, fmt.Sprintf("ALTER TABLE %s ADD CONSTRAINT %s %s",
877+
pq.QuoteIdentifier(table),
878+
pq.QuoteIdentifier(constraint.Name),
879+
newDef,
880+
))
881+
if err != nil {
882+
return fmt.Errorf("altering references for %s.%s: %w", a.table, a.column, err)
883+
}
906884

907-
defs := make([]constraintDefinition, 0)
908-
for rows.Next() {
909-
var def constraintDefinition
910-
if err := rows.Scan(&def.name, &def.table, &def.def); err != nil {
911-
return nil, fmt.Errorf("scanning referencing constraints for %s.%s: %w", a.table, a.column, err)
912885
}
913-
defs = append(defs, def)
914886
}
915-
return defs, rows.Err()
887+
return nil
916888
}

pkg/migrations/op_alter_column.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ func (o *OpAlterColumn) Complete(l Logger, conn db.DB, s *schema.Schema) ([]DBAc
118118

119119
return append(dbActions, []DBAction{
120120
NewAlterSequenceOwnerAction(conn, o.Table, o.Column, TemporaryName(o.Column)),
121-
NewAlterReferencesAction(conn, o.Table, o.Column),
121+
NewAlterReferencesAction(conn, table.ReferencedBy, o.Table, o.Column),
122122
NewDropColumnAction(conn, o.Table, o.Column),
123123
NewDropFunctionAction(conn,
124124
backfill.TriggerFunctionName(o.Table, o.Column),

pkg/migrations/op_alter_column_test.go

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -726,7 +726,7 @@ func TestAlterPrimaryKeyColumns(t *testing.T) {
726726
Name: "02_alter_column",
727727
Operations: migrations.Operations{
728728
&migrations.OpAlterColumn{
729-
Table: "people",
729+
Table: "events",
730730
Column: "id",
731731
Type: ptr("bigint"),
732732
Up: "CAST(id AS bigint)",
@@ -740,29 +740,32 @@ func TestAlterPrimaryKeyColumns(t *testing.T) {
740740
ValidatedForeignKeyMustExist(t, db, schema, "people", "person_manages_event_fk")
741741

742742
bigint := "31474836471" // A value larger than int can hold
743-
integer := "100"
744743

745744
// Inserting a row with integer id into the old schema should succeed
746745
MustInsert(t, db, schema, "01_create_table", "events", map[string]string{
746+
"id": "1",
747747
"name": "pgroll v1 release party",
748748
})
749749
MustInsert(t, db, schema, "01_create_table", "people", map[string]string{
750-
"id": integer,
750+
"id": "1",
751751
"name": "alice",
752752
"manages": "1",
753753
})
754754
// Inserting a row with integer bigint id into the old schema should fail
755-
MustNotInsert(t, db, schema, "01_create_table", "people", map[string]string{
756-
"id": bigint,
757-
"name": "alice",
758-
"manages": "1",
755+
MustNotInsert(t, db, schema, "01_create_table", "events", map[string]string{
756+
"id": bigint,
757+
"name": "pgroll v2 release party",
759758
}, testutils.NumericValueOutOfRangeErrorCode)
760759

761760
// Inserting a row with bigint id into the new schema should succeed
761+
MustInsert(t, db, schema, "02_alter_column", "events", map[string]string{
762+
"id": bigint,
763+
"name": "pgroll v2 release party",
764+
})
762765
MustInsert(t, db, schema, "02_alter_column", "people", map[string]string{
763-
"id": bigint,
764-
"name": "alice",
765-
"manages": "1",
766+
"id": "2",
767+
"name": "bob",
768+
"manages": bigint,
766769
})
767770
// Inserting a row into the `people` table with a `manages` field that
768771
// violates the FK constraint fails
@@ -781,16 +784,15 @@ func TestAlterPrimaryKeyColumns(t *testing.T) {
781784
ValidatedForeignKeyMustExist(t, db, schema, "people", "person_manages_event_fk")
782785

783786
// Inserting a row with integer bigint into the new schema should succeed
784-
MustInsert(t, db, schema, "02_alter_column", "people", map[string]string{
785-
"id": "31474836472",
786-
"name": "bob",
787-
"manages": "1",
787+
MustInsert(t, db, schema, "02_alter_column", "events", map[string]string{
788+
"id": "31474836472",
789+
"name": "pgroll v3 release party",
788790
})
789791
// Inserting a row into the `people` table with a `manages` field that
790792
// violates the FK constraint fails
791793
MustNotInsert(t, db, schema, "02_alter_column", "people", map[string]string{
792-
"id": "31474836474",
793-
"name": "alice",
794+
"id": "3",
795+
"name": "carol",
794796
"manages": "2",
795797
}, testutils.FKViolationErrorCode)
796798
},

pkg/schema/schema.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,26 @@ type Table struct {
6262
// ExcludeConstraints is a map of all exclude constraints defined on the table
6363
ExcludeConstraints map[string]*ExcludeConstraint `json:"excludeConstraints"`
6464

65+
// ReferencedBy is a map of table names that reference this table by foreign key
66+
// The key is the name of the referencing table, and the value is the name and
67+
// the definition of the foreign key constraint
68+
ReferencedBy map[string][]*ReferencedBy `json:"referencedBy"`
69+
6570
// Whether or not the table has been deleted in the virtual schema
6671
Deleted bool `json:"-"`
6772
}
6873

74+
type ReferencedBy struct {
75+
// Name is the name of the foreign key constraint
76+
Name string `json:"name"`
77+
78+
// Table is the name of the table that is referenced
79+
Table string `json:"table"`
80+
81+
// Definition is the definition of the foreign key constraint
82+
Definition string `json:"definition"`
83+
}
84+
6985
// Column represents a column in a table
7086
type Column struct {
7187
// Name is the actual name in postgres

0 commit comments

Comments
 (0)