Skip to content

Commit

Permalink
sql/internal/sqlx: support diffing triggers (#2380)
Browse files Browse the repository at this point in the history
  • Loading branch information
a8m authored Dec 17, 2023
1 parent 947dc16 commit f5a6b53
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 6 deletions.
3 changes: 3 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ issues:
- path: sql/migrate/lex.go
linters:
- revive
- path: sql/internal/sqlx/diff.go
linters:
- revive

linters-settings:
goheader:
Expand Down
6 changes: 6 additions & 0 deletions cmd/atlas/internal/cmdlog/cmdlog.go
Original file line number Diff line number Diff line change
Expand Up @@ -709,9 +709,15 @@ func sqlInspect(report *SchemaInspect, indent ...string) (string, error) {
}
for _, t := range s.Tables {
changes = append(changes, &schema.AddTable{T: t})
for _, r := range t.Triggers {
changes = append(changes, &schema.AddTrigger{T: r})
}
}
for _, v := range s.Views {
changes = append(changes, &schema.AddView{V: v})
for _, r := range v.Triggers {
changes = append(changes, &schema.AddTrigger{T: r})
}
}
for _, f := range s.Funcs {
changes = append(changes, &schema.AddFunc{F: f})
Expand Down
38 changes: 32 additions & 6 deletions sql/internal/sqlx/diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,13 @@ type (
// from one schema state to the other.
ProcFuncsDiff(from, to *schema.Schema, opts *schema.DiffOptions) ([]schema.Change, error)
}

// TriggerDiffer is an optional interface allows DiffDriver to diff triggers.
TriggerDiffer interface {
// TriggerDiff returns a changeset for migrating triggers from
// one state to the other. For example, changing action time.
TriggerDiff(from, to *schema.Trigger) ([]schema.Change, error)
}
)

// RealmDiff implements the schema.Differ for Realm objects and returns a list of changes
Expand Down Expand Up @@ -144,9 +151,15 @@ func (d *Diff) RealmDiff(from, to *schema.Realm, options ...schema.DiffOption) (
}
for _, t := range s1.Tables {
changes = opts.AddOrSkip(changes, &schema.AddTable{T: t})
for _, r := range t.Triggers {
changes = opts.AddOrSkip(changes, &schema.AddTrigger{T: r})
}
}
for _, v := range s1.Views {
changes = opts.AddOrSkip(changes, &schema.AddView{V: v})
for _, r := range v.Triggers {
changes = opts.AddOrSkip(changes, &schema.AddTrigger{T: r})
}
}
}
return d.mayAnnotate(changes, opts)
Expand Down Expand Up @@ -186,20 +199,24 @@ func (d *Diff) schemaDiff(from, to *schema.Schema, opts *schema.DiffOptions) ([]
for _, t1 := range from.Tables {
switch t2, err := d.findTable(to, t1.Name); {
case schema.IsNotExistError(err):
// Triggers should be dropped either by the driver or the database.
changes = opts.AddOrSkip(changes, &schema.DropTable{T: t1})
case err != nil:
return nil, err
default:
change, err := d.tableDiff(t1, t2, opts)
if err != nil {
if change, err := d.tableDiff(t1, t2, opts); err != nil {
return nil, err
}
if len(change) > 0 {
} else if len(change) > 0 {
changes = opts.AddOrSkip(changes, &schema.ModifyTable{
T: t2,
Changes: change,
})
}
if change, err := d.triggerDiff(t1, t2, t1.Triggers, t2.Triggers, opts); err != nil {
return nil, err
} else {
changes = append(changes, change...)
}
}
}
// Add tables.
Expand All @@ -220,10 +237,14 @@ func (d *Diff) schemaDiff(from, to *schema.Schema, opts *schema.DiffOptions) ([]
changes = opts.AddOrSkip(changes, &schema.DropView{V: v1})
continue
}
change := d.indexDiffV(v1, v2, opts)
if d.viewDefChanged(v1, v2) || d.ViewAttrChanged(v1, v2) || len(change) > 0 {
if change := d.indexDiffV(v1, v2, opts); d.viewDefChanged(v1, v2) || d.ViewAttrChanged(v1, v2) || len(change) > 0 {
changes = opts.AddOrSkip(changes, &schema.ModifyView{From: v1, To: v2, Changes: change})
}
if change, err := d.triggerDiff(v1, v2, v1.Triggers, v2.Triggers, opts); err != nil {
return nil, err
} else {
changes = append(changes, change...)
}
}
// Add views.
for _, v1 := range to.Views {
Expand Down Expand Up @@ -253,6 +274,11 @@ func (d *Diff) TableDiff(from, to *schema.Table, options ...schema.DiffOption) (
if err != nil {
return nil, err
}
if change, err := d.triggerDiff(from, to, from.Triggers, to.Triggers, opts); err != nil {
return nil, err
} else {
changes = append(changes, change...)
}
return d.mayAnnotate(changes, opts)
}

Expand Down
6 changes: 6 additions & 0 deletions sql/internal/sqlx/sqlx_oss.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,9 @@ import (
func sortViewChanges(changes []schema.Change) ([]schema.Change, error) {
return changes, nil // unimplemented.
}

func (*Diff) triggerDiff(_, _ interface {
Trigger(string) (*schema.Trigger, bool)
}, _, _ []*schema.Trigger, _ *schema.DiffOptions) ([]schema.Change, error) {
return nil, nil // unimplemented.
}
20 changes: 20 additions & 0 deletions sql/schema/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,16 @@ func (t *Table) ForeignKey(symbol string) (*ForeignKey, bool) {
return nil, false
}

// Trigger returns the first trigger that matches the given name.
func (t *Table) Trigger(name string) (*Trigger, bool) {
for _, r := range t.Triggers {
if r.Name == name {
return r, true
}
}
return nil, false
}

// Materialized reports if the view is materialized.
func (v *View) Materialized() bool {
for _, a := range v.Attrs {
Expand Down Expand Up @@ -347,6 +357,16 @@ func (v *View) Index(name string) (*Index, bool) {
return nil, false
}

// Trigger returns the first trigger that matches the given name.
func (v *View) Trigger(name string) (*Trigger, bool) {
for _, r := range v.Triggers {
if r.Name == name {
return r, true
}
}
return nil, false
}

// AsTable returns a table that represents the view.
func (v *View) AsTable() *Table {
return NewTable(v.Name).
Expand Down

0 comments on commit f5a6b53

Please sign in to comment.