Skip to content

Commit

Permalink
sql/internal/sqlx: compare check constraint names (#3289)
Browse files Browse the repository at this point in the history
  • Loading branch information
a8m authored Dec 30, 2024
1 parent 43b9a99 commit d739d6d
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 6 deletions.
25 changes: 24 additions & 1 deletion internal/integration/testdata/postgres/table-checks.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ cmpmig 1 migration.v2.sql
atlas migrate diff v2-check --to file://schema.v2.sql --dev-url URL --format '{{ sql . " " }}'
stdout 'The migration directory is synced with the desired state, no changes to be made'

atlas migrate diff v3 --to file://schema.v3.sql --dev-url URL --format '{{ sql . " " }}'
cmpmig 2 migration.v3.sql
atlas migrate diff v3-check --to file://schema.v3.sql --dev-url URL --format '{{ sql . " " }}'
stdout 'The migration directory is synced with the desired state, no changes to be made'

-- schema.sql --
create table t1 (
a int constraint c1 check (a > 0),
Expand Down Expand Up @@ -118,4 +123,22 @@ create table t2 (
-- Modify "t1" table
ALTER TABLE "t1" DROP CONSTRAINT "c1", ADD CONSTRAINT "c1" CHECK (a > 1), DROP CONSTRAINT "c2", ADD CONSTRAINT "c2" CHECK (b > 1);
-- Modify "t2" table
ALTER TABLE "t2" DROP CONSTRAINT "c1", ADD CONSTRAINT "c1" CHECK (a > 1), DROP CONSTRAINT "c4", ADD CONSTRAINT "c4" CHECK (c > 1);
ALTER TABLE "t2" DROP CONSTRAINT "c1", ADD CONSTRAINT "c1" CHECK (a > 1), DROP CONSTRAINT "c4", ADD CONSTRAINT "c4" CHECK (c > 1);
-- schema.v3.sql --
create table t1 (
a int constraint c1 check (a > 1),
b int constraint c2 check (b > 1),
-- Rename constraint.
constraint c4 check (a < b)
);
create table t2 (
a int constraint c1 check (a > 1),
c int constraint c4 check (c > 1),
-- Rename constraint.
constraint c6 check (a < c)
);
-- migration.v3.sql --
-- Modify "t1" table
ALTER TABLE "t1" DROP CONSTRAINT "c3", ADD CONSTRAINT "c4" CHECK (a < b);
-- Modify "t2" table
ALTER TABLE "t2" DROP CONSTRAINT "c5", ADD CONSTRAINT "c6" CHECK (a < c);
46 changes: 41 additions & 5 deletions sql/internal/sqlx/diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package sqlx
import (
"fmt"
"reflect"
"slices"
"sort"
"strconv"
"strings"
Expand Down Expand Up @@ -810,19 +811,54 @@ func CommentDiff(from, to []schema.Attr) schema.Change {
// if the schema.DiffMode is equal to schema.DiffModeNormalized.
func CheckDiffMode(from, to *schema.Table, mode schema.DiffMode, compare ...func(c1, c2 *schema.Check) bool) []schema.Change {
if !mode.Is(schema.DiffModeNormalized) {
return CheckDiff(from, to, compare...)
return checksSimilarDiff(from, to, compare...)
}
return CheckDiff(from, to, func(c1, c2 *schema.Check) bool {
return ChecksDiff(from, to, func(c1, c2 *schema.Check) bool {
if len(compare) == 1 && !compare[0](c1, c2) {
return false
}
return c1.Expr == c2.Expr || MayWrap(c1.Expr) == MayWrap(c2.Expr)
})
}

// CheckDiff computes the change diff between the 2 tables. A compare
// function is provided to check if a Check object was modified.
func CheckDiff(from, to *schema.Table, compare ...func(c1, c2 *schema.Check) bool) []schema.Change {
// ChecksDiff computes the change diff between the 2 tables.
func ChecksDiff(from, to *schema.Table, compare func(c1, c2 *schema.Check) bool) []schema.Change {
var (
changes []schema.Change
fromC, toC = checks(from.Attrs), checks(to.Attrs)
)
for _, c1 := range fromC {
idx := slices.IndexFunc(toC, func(c2 *schema.Check) bool {
return c1.Name == c2.Name
})
if idx == -1 {
changes = append(changes, &schema.DropCheck{
C: c1,
})
} else if c2 := toC[idx]; !compare(c1, c2) {
changes = append(changes, &schema.ModifyCheck{
From: c1,
To: c2,
})
}
}
for _, c1 := range toC {
if !slices.ContainsFunc(fromC, func(c2 *schema.Check) bool {
return c1.Name == c2.Name
}) {
changes = append(changes, &schema.AddCheck{
C: c1,
})
}
}
return changes
}

// checksSimilarDiff computes the change diff between the 2 tables.
// Unlike ChecksDiff, it does not compare the constraint name, but
// determines if there is any similar constraint by its expression.
// This is an old implementation that is not used anymore by the CLI.
func checksSimilarDiff(from, to *schema.Table, compare ...func(c1, c2 *schema.Check) bool) []schema.Change {
var changes []schema.Change
// Drop or modify checks.
for _, c1 := range checks(from.Attrs) {
Expand Down

0 comments on commit d739d6d

Please # to comment.