Skip to content

Commit 0afae1d

Browse files
committed
Expose foreign key constraint options
1 parent bbdb2f8 commit 0afae1d

File tree

5 files changed

+51
-42
lines changed

5 files changed

+51
-42
lines changed

docs/operations/create_constraint.mdx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ Required fields: `name`, `table`, `type`, `up`, `down`.
2222
"table": "name of referenced table",
2323
"columns": "[names of referenced columns]",
2424
"on_delete": "ON DELETE behaviour, can be CASCADE, SET NULL, RESTRICT, or NO ACTION. Default is NO ACTION",
25+
"on_delete_set_columns": ["list of FKs to set", "in on delete operation on SET NULL or SET DEFAULT"],
26+
"on_update": "ON UPDATE behaviour, can be CASCADE, SET NULL, RESTRICT, or NO ACTION. Default is NO ACTION",
27+
"match_type": "match type, can be SIMPLE or FULL. Default is SIMPLE"
2528
},
2629
"up": {
2730
"column1": "up SQL expressions for each column covered by the constraint",

docs/operations/create_table.mdx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ Each `column` is defined as:
4242
"table": "name of referenced table",
4343
"column": "name of referenced column",
4444
"on_delete": "ON DELETE behaviour, can be CASCADE, SET NULL, SET DEFAULT, RESTRICT, or NO ACTION. Default is NO ACTION",
45+
"on_update": "ON UPDATE behaviour, can be CASCADE, SET NULL, RESTRICT, or NO ACTION. Default is NO ACTION",
46+
"match_type": "match type, can be SIMPLE or FULL. Default is SIMPLE"
4547
}
4648
},
4749
```

pkg/migrations/op_add_column.go

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -314,16 +314,14 @@ func (w ColumnSQLWriter) Write(col Column) (string, error) {
314314
}
315315

316316
if col.References != nil {
317-
onDelete := string(ForeignKeyActionNOACTION)
318-
if col.References.OnDelete != "" {
319-
onDelete = strings.ToUpper(string(col.References.OnDelete))
320-
}
321-
322-
sql += fmt.Sprintf(" CONSTRAINT %s REFERENCES %s(%s) ON DELETE %s",
323-
pq.QuoteIdentifier(col.References.Name),
324-
pq.QuoteIdentifier(col.References.Table),
325-
pq.QuoteIdentifier(col.References.Column),
326-
onDelete)
317+
writer := &ConstraintSQLWriter{Name: col.References.Name}
318+
sql += " " + writer.WriteForeignKey(
319+
col.References.Table,
320+
[]string{col.References.Column},
321+
col.References.OnDelete,
322+
col.References.OnUpdate,
323+
nil,
324+
col.References.MatchType)
327325
}
328326
if col.Check != nil {
329327
sql += fmt.Sprintf(" CONSTRAINT %s CHECK (%s)",

pkg/migrations/op_create_constraint.go

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,7 @@ func (o *OpCreateConstraint) Start(ctx context.Context, conn db.DB, latestSchema
6868

6969
switch o.Type {
7070
case OpCreateConstraintTypeUnique:
71-
temporaryColumnNames := make([]string, len(o.Columns))
72-
for i, col := range o.Columns {
73-
temporaryColumnNames[i] = TemporaryName(col)
74-
}
75-
return table, createUniqueIndexConcurrently(ctx, conn, s.Name, o.Name, o.Table, temporaryColumnNames)
71+
return table, createUniqueIndexConcurrently(ctx, conn, s.Name, o.Name, o.Table, temporaryNames(o.Columns))
7672
case OpCreateConstraintTypeCheck:
7773
return table, o.addCheckConstraint(ctx, conn)
7874
case OpCreateConstraintTypeForeignKey:
@@ -248,24 +244,35 @@ func (o *OpCreateConstraint) addCheckConstraint(ctx context.Context, conn db.DB)
248244
}
249245

250246
func (o *OpCreateConstraint) addForeignKeyConstraint(ctx context.Context, conn db.DB) error {
251-
onDelete := "NO ACTION"
252-
if o.References.OnDelete != "" {
253-
onDelete = strings.ToUpper(string(o.References.OnDelete))
247+
sql := fmt.Sprintf("ALTER TABLE %s ADD ", pq.QuoteIdentifier(o.Table))
248+
249+
writer := &ConstraintSQLWriter{
250+
Name: o.Name,
251+
Columns: temoraryNames(o.Columns),
252+
SkipValidation: true,
254253
}
254+
sql += writer.WriteForeignKey(
255+
o.References.Table,
256+
o.References.Columns,
257+
o.References.OnDelete,
258+
o.References.OnUpdate,
259+
o.References.OnDeleteSetColumns,
260+
o.References.MatchType,
261+
)
255262

256-
_, err := conn.ExecContext(ctx,
257-
fmt.Sprintf("ALTER TABLE %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s) ON DELETE %s NOT VALID",
258-
pq.QuoteIdentifier(o.Table),
259-
pq.QuoteIdentifier(o.Name),
260-
strings.Join(quotedTemporaryNames(o.Columns), ","),
261-
pq.QuoteIdentifier(o.References.Table),
262-
strings.Join(quoteColumnNames(o.References.Columns), ","),
263-
onDelete,
264-
))
263+
_, err := conn.ExecContext(ctx, sql)
265264

266265
return err
267266
}
268267

268+
func temporaryNames(columns []string) []string {
269+
names := make([]string, len(columns))
270+
for i, col := range columns {
271+
names[i] = TemporaryName(col)
272+
}
273+
return names
274+
}
275+
269276
func quotedTemporaryNames(columns []string) []string {
270277
names := make([]string, len(columns))
271278
for i, col := range columns {

pkg/migrations/op_set_fk.go

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ package migrations
55
import (
66
"context"
77
"fmt"
8-
"strings"
98

109
"github.com/lib/pq"
1110

@@ -89,20 +88,20 @@ func (o *OpSetForeignKey) addForeignKeyConstraint(ctx context.Context, conn db.D
8988
referencedTable := s.GetTable(o.References.Table)
9089
referencedColumn := referencedTable.GetColumn(o.References.Column)
9190

92-
onDelete := "NO ACTION"
93-
if o.References.OnDelete != "" {
94-
onDelete = strings.ToUpper(string(o.References.OnDelete))
91+
sql := fmt.Sprintf("ALTER TABLE %s ADD ", pq.QuoteIdentifier(table.Name))
92+
writer := &ConstraintSQLWriter{
93+
Name: o.References.Name,
94+
Columns: []string{column.Name},
95+
SkipValidation: true,
9596
}
96-
97-
_, err := conn.ExecContext(ctx,
98-
fmt.Sprintf("ALTER TABLE %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s) ON DELETE %s NOT VALID",
99-
pq.QuoteIdentifier(table.Name),
100-
pq.QuoteIdentifier(o.References.Name),
101-
pq.QuoteIdentifier(column.Name),
102-
pq.QuoteIdentifier(referencedTable.Name),
103-
pq.QuoteIdentifier(referencedColumn.Name),
104-
onDelete,
105-
))
106-
97+
sql += writer.WriteForeignKey(
98+
referencedTable.Name,
99+
[]string{referencedColumn.Name},
100+
o.References.OnDelete,
101+
o.References.OnUpdate,
102+
nil,
103+
o.References.MatchType)
104+
105+
_, err := conn.ExecContext(ctx, sql)
107106
return err
108107
}

0 commit comments

Comments
 (0)