Skip to content

Commit 7d9ff7c

Browse files
authored
feat(migrate): add pending migrations function (#286)
1 parent 6ba176a commit 7d9ff7c

File tree

3 files changed

+96
-0
lines changed

3 files changed

+96
-0
lines changed

Diff for: migrate/example/example_test.go

+6
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,12 @@ func TestExample(t *testing.T) {
5050
reg.Add(migrate.CallComment, "3", log)
5151
migrate.Callback = reg.Callback
5252

53+
pending, err := migrate.Pending(context.Background(), session, cql.Files)
54+
if err != nil {
55+
t.Fatal("Pending:", err)
56+
}
57+
t.Log("Pending migrations:", len(pending))
58+
5359
// First run prints data
5460
if err := migrate.FromFS(context.Background(), session, cql.Files); err != nil {
5561
t.Fatal("Migrate:", err)

Diff for: migrate/migrate.go

+42
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,48 @@ func List(ctx context.Context, session gocqlx.Session) ([]*Info, error) {
8787
return v, nil
8888
}
8989

90+
// Pending provides a listing of pending migrations.
91+
func Pending(ctx context.Context, session gocqlx.Session, f fs.FS) ([]*Info, error) {
92+
applied, err := List(ctx, session)
93+
if err != nil {
94+
return nil, err
95+
}
96+
97+
// Create a set of applied migration names
98+
appliedNames := make(map[string]struct{}, len(applied))
99+
for _, migration := range applied {
100+
appliedNames[migration.Name] = struct{}{}
101+
}
102+
103+
fm, err := fs.Glob(f, "*.cql")
104+
if err != nil {
105+
return nil, fmt.Errorf("list migrations: %w", err)
106+
}
107+
108+
pending := make([]*Info, 0)
109+
110+
for _, name := range fm {
111+
baseName := filepath.Base(name)
112+
// Check if the migration is not in the applied set
113+
if _, exists := appliedNames[baseName]; !exists {
114+
c, err := fileChecksum(f, name)
115+
if err != nil {
116+
return nil, fmt.Errorf("calculate checksum for %q: %w", name, err)
117+
}
118+
119+
info := &Info{
120+
Name: baseName,
121+
StartTime: time.Now(),
122+
Checksum: c,
123+
}
124+
125+
pending = append(pending, info)
126+
}
127+
}
128+
129+
return pending, nil
130+
}
131+
90132
func ensureInfoTable(ctx context.Context, session gocqlx.Session) error {
91133
return session.ContextQuery(ctx, infoSchema, nil).ExecRelease()
92134
}

Diff for: migrate/migrate_test.go

+48
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,54 @@ func recreateTables(tb testing.TB, session gocqlx.Session) {
4545
}
4646
}
4747

48+
func TestPending(t *testing.T) {
49+
session := gocqlxtest.CreateSession(t)
50+
defer session.Close()
51+
recreateTables(t, session)
52+
53+
ctx := context.Background()
54+
55+
t.Run("pending", func(t *testing.T) {
56+
defer recreateTables(t, session)
57+
58+
f := memfs.New()
59+
writeFile(f, 0, fmt.Sprintf(insertMigrate, 0)+";")
60+
61+
pending, err := migrate.Pending(ctx, session, f)
62+
if err != nil {
63+
t.Fatal(err)
64+
}
65+
if len(pending) != 1 {
66+
t.Fatal("expected 2 pending migrations got", len(pending))
67+
}
68+
69+
err = migrate.FromFS(ctx, session, f)
70+
if err != nil {
71+
t.Fatal(err)
72+
}
73+
74+
pending, err = migrate.Pending(ctx, session, f)
75+
if err != nil {
76+
t.Fatal(err)
77+
}
78+
if len(pending) != 0 {
79+
t.Fatal("expected no pending migrations got", len(pending))
80+
}
81+
82+
for i := 1; i < 3; i++ {
83+
writeFile(f, i, fmt.Sprintf(insertMigrate, i)+";")
84+
}
85+
86+
pending, err = migrate.Pending(ctx, session, f)
87+
if err != nil {
88+
t.Fatal(err)
89+
}
90+
if len(pending) != 2 {
91+
t.Fatal("expected 2 pending migrations got", len(pending))
92+
}
93+
})
94+
}
95+
4896
func TestMigration(t *testing.T) {
4997
session := gocqlxtest.CreateSession(t)
5098
defer session.Close()

0 commit comments

Comments
 (0)