Skip to content

Commit 052e1b1

Browse files
committed
chore: support last n versions for db reset
1 parent 07a9926 commit 052e1b1

File tree

6 files changed

+39
-41
lines changed

6 files changed

+39
-41
lines changed

cmd/db.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ var (
195195
if noSeed {
196196
utils.Config.Db.Seed.Enabled = false
197197
}
198-
return reset.Run(cmd.Context(), migrationVersion, flags.DbConfig, afero.NewOsFs())
198+
return reset.Run(cmd.Context(), migrationVersion, nLastVersion, flags.DbConfig, afero.NewOsFs())
199199
},
200200
}
201201

@@ -319,6 +319,8 @@ func init() {
319319
resetFlags.BoolVar(&noSeed, "no-seed", false, "Skip running the seed script after reset.")
320320
dbResetCmd.MarkFlagsMutuallyExclusive("db-url", "linked", "local")
321321
resetFlags.StringVar(&migrationVersion, "version", "", "Reset up to the specified version.")
322+
resetFlags.UintVar(&nLastVersion, "last", 0, "Reset up to the last n migration versions.")
323+
dbResetCmd.MarkFlagsMutuallyExclusive("version", "last")
322324
dbCmd.AddCommand(dbResetCmd)
323325
// Build lint command
324326
lintFlags := dbLintCmd.Flags()

cmd/migration.go

Lines changed: 10 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@ import (
44
"fmt"
55
"os"
66
"os/signal"
7-
"strconv"
87

9-
"github.com/go-errors/errors"
108
"github.com/spf13/afero"
119
"github.com/spf13/cobra"
1210
"github.com/spf13/viper"
@@ -93,24 +91,14 @@ var (
9391
},
9492
}
9593

94+
nLastVersion uint
95+
9696
migrationDownCmd = &cobra.Command{
97-
Use: "down [n]",
98-
Short: "Resets local migrations up to the last n versions",
99-
Args: cobra.MaximumNArgs(1),
97+
Use: "down",
98+
Short: "Resets applied migrations up to the last n versions",
99+
Args: cobra.NoArgs,
100100
RunE: func(cmd *cobra.Command, args []string) error {
101-
last := 1
102-
if len(args) > 0 {
103-
var err error
104-
if last, err = strconv.Atoi(args[0]); err != nil {
105-
return errors.Errorf("invalid last version: %w", err)
106-
} else if last <= 0 {
107-
return errors.Errorf("last version must be greater than 0")
108-
}
109-
}
110-
return down.Run(cmd.Context(), last, flags.DbConfig, afero.NewOsFs())
111-
},
112-
PostRun: func(cmd *cobra.Command, args []string) {
113-
fmt.Println("Local database is up to date.")
101+
return down.Run(cmd.Context(), nLastVersion, flags.DbConfig, afero.NewOsFs())
114102
},
115103
}
116104

@@ -166,9 +154,10 @@ func init() {
166154
migrationUpCmd.MarkFlagsMutuallyExclusive("db-url", "linked", "local")
167155
migrationCmd.AddCommand(migrationUpCmd)
168156
downFlags := migrationDownCmd.Flags()
169-
downFlags.String("db-url", "", "Applies migrations to the database specified by the connection string (must be percent-encoded).")
170-
downFlags.Bool("linked", false, "Applies pending migrations to the linked project.")
171-
downFlags.Bool("local", true, "Applies pending migrations to the local database.")
157+
downFlags.UintVar(&nLastVersion, "last", 1, "Reset up to the last n migration versions.")
158+
downFlags.String("db-url", "", "Resets applied migrations on the database specified by the connection string (must be percent-encoded).")
159+
downFlags.Bool("linked", false, "Resets applied migrations on the linked project.")
160+
downFlags.Bool("local", true, "Resets applied migrations on the local database.")
172161
migrationDownCmd.MarkFlagsMutuallyExclusive("db-url", "linked", "local")
173162
migrationCmd.AddCommand(migrationDownCmd)
174163
// Build up command

internal/db/reset/reset.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,33 @@ import (
2323
"github.com/supabase/cli/internal/db/start"
2424
"github.com/supabase/cli/internal/gen/keys"
2525
"github.com/supabase/cli/internal/migration/apply"
26+
"github.com/supabase/cli/internal/migration/list"
2627
"github.com/supabase/cli/internal/migration/repair"
2728
"github.com/supabase/cli/internal/seed/buckets"
2829
"github.com/supabase/cli/internal/utils"
2930
"github.com/supabase/cli/pkg/migration"
3031
"github.com/supabase/cli/pkg/vault"
3132
)
3233

33-
func Run(ctx context.Context, version string, config pgconn.Config, fsys afero.Fs, options ...func(*pgx.ConnConfig)) error {
34+
func Run(ctx context.Context, version string, last uint, config pgconn.Config, fsys afero.Fs, options ...func(*pgx.ConnConfig)) error {
3435
if len(version) > 0 {
3536
if _, err := strconv.Atoi(version); err != nil {
3637
return errors.New(repair.ErrInvalidVersion)
3738
}
3839
if _, err := repair.GetMigrationFile(version, fsys); err != nil {
3940
return err
4041
}
42+
} else if last > 0 {
43+
localMigrations, err := list.LoadLocalVersions(fsys)
44+
if err != nil {
45+
return err
46+
}
47+
if total := uint(len(localMigrations)); last < total {
48+
version = localMigrations[total-last-1]
49+
} else {
50+
// Negative skips all migrations
51+
version = "-"
52+
}
4153
}
4254
if !utils.IsLocalDatabase(config) {
4355
msg := "Do you want to reset the remote database?"

internal/db/reset/reset_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ func TestResetCommand(t *testing.T) {
9696
Reply(http.StatusOK).
9797
JSON([]storage.BucketResponse{})
9898
// Run test
99-
err := Run(context.Background(), "", dbConfig, fsys, conn.Intercept)
99+
err := Run(context.Background(), "", 0, dbConfig, fsys, conn.Intercept)
100100
// Check error
101101
assert.NoError(t, err)
102102
assert.Empty(t, apitest.ListUnmatchedRequests())
@@ -106,7 +106,7 @@ func TestResetCommand(t *testing.T) {
106106
// Setup in-memory fs
107107
fsys := afero.NewMemMapFs()
108108
// Run test
109-
err := Run(context.Background(), "", pgconn.Config{Host: "db.supabase.co"}, fsys)
109+
err := Run(context.Background(), "", 0, pgconn.Config{Host: "db.supabase.co"}, fsys)
110110
// Check error
111111
assert.ErrorIs(t, err, context.Canceled)
112112
})
@@ -116,7 +116,7 @@ func TestResetCommand(t *testing.T) {
116116
// Setup in-memory fs
117117
fsys := afero.NewMemMapFs()
118118
// Run test
119-
err := Run(context.Background(), "", pgconn.Config{Host: "db.supabase.co"}, fsys)
119+
err := Run(context.Background(), "", 0, pgconn.Config{Host: "db.supabase.co"}, fsys)
120120
// Check error
121121
assert.ErrorContains(t, err, "invalid port (outside range)")
122122
})
@@ -131,7 +131,7 @@ func TestResetCommand(t *testing.T) {
131131
Get("/v" + utils.Docker.ClientVersion() + "/containers").
132132
Reply(http.StatusNotFound)
133133
// Run test
134-
err := Run(context.Background(), "", dbConfig, fsys)
134+
err := Run(context.Background(), "", 0, dbConfig, fsys)
135135
// Check error
136136
assert.ErrorIs(t, err, utils.ErrNotRunning)
137137
assert.Empty(t, apitest.ListUnmatchedRequests())
@@ -153,7 +153,7 @@ func TestResetCommand(t *testing.T) {
153153
Delete("/v" + utils.Docker.ClientVersion() + "/containers/" + utils.DbId).
154154
ReplyError(errors.New("network error"))
155155
// Run test
156-
err := Run(context.Background(), "", dbConfig, fsys)
156+
err := Run(context.Background(), "", 0, dbConfig, fsys)
157157
// Check error
158158
assert.ErrorContains(t, err, "network error")
159159
assert.Empty(t, apitest.ListUnmatchedRequests())

internal/migration/down/down.go

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,7 @@ import (
1313
"github.com/supabase/cli/pkg/migration"
1414
)
1515

16-
var errOutOfRange = errors.New("last version must be smaller than total applied migrations")
17-
18-
func Run(ctx context.Context, last int, config pgconn.Config, fsys afero.Fs, options ...func(*pgx.ConnConfig)) error {
16+
func Run(ctx context.Context, last uint, config pgconn.Config, fsys afero.Fs, options ...func(*pgx.ConnConfig)) error {
1917
conn, err := utils.ConnectByConfig(ctx, config, options...)
2018
if err != nil {
2119
return err
@@ -25,14 +23,11 @@ func Run(ctx context.Context, last int, config pgconn.Config, fsys afero.Fs, opt
2523
if err != nil {
2624
return err
2725
}
28-
version := ""
29-
if i := len(remoteMigrations) - last; i > 0 {
30-
version = remoteMigrations[i-1]
31-
} else {
32-
if i == 0 {
33-
utils.CmdSuggestion = fmt.Sprintf("Try %s if you want to revert all migrations.", utils.Aqua("supabase db reset"))
34-
}
35-
return errors.New(errOutOfRange)
26+
total := uint(len(remoteMigrations))
27+
if total <= last {
28+
utils.CmdSuggestion = fmt.Sprintf("Try %s if you want to revert all migrations.", utils.Aqua("supabase db reset"))
29+
return errors.Errorf("--last must be smaller than total applied migrations: %d", total)
3630
}
37-
return reset.Run(ctx, version, config, fsys)
31+
version := remoteMigrations[total-last-1]
32+
return reset.Run(ctx, version, 0, config, fsys)
3833
}

internal/migration/down/down_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ func TestMigrationsDown(t *testing.T) {
5757
// Run test
5858
err := Run(context.Background(), 2, dbConfig, fsys, conn.Intercept)
5959
// Check error
60-
assert.ErrorIs(t, err, errOutOfRange)
60+
assert.ErrorContains(t, err, "--last must be smaller than total applied migrations: 2")
6161
})
6262

6363
t.Run("throws error on missing version", func(t *testing.T) {

0 commit comments

Comments
 (0)