1package goose
2
3import (
4 "context"
5 "database/sql"
6 "fmt"
7 "sort"
8)
9
10// Reset rolls back all migrations
11func Reset(db *sql.DB, dir string, opts ...OptionsFunc) error {
12 ctx := context.Background()
13 return ResetContext(ctx, db, dir, opts...)
14}
15
16// ResetContext rolls back all migrations
17func ResetContext(ctx context.Context, db *sql.DB, dir string, opts ...OptionsFunc) error {
18 option := &options{}
19 for _, f := range opts {
20 f(option)
21 }
22 migrations, err := CollectMigrations(dir, minVersion, maxVersion)
23 if err != nil {
24 return fmt.Errorf("failed to collect migrations: %w", err)
25 }
26 if option.noVersioning {
27 return DownToContext(ctx, db, dir, minVersion, opts...)
28 }
29
30 statuses, err := dbMigrationsStatus(ctx, db)
31 if err != nil {
32 return fmt.Errorf("failed to get status of migrations: %w", err)
33 }
34 sort.Sort(sort.Reverse(migrations))
35
36 for _, migration := range migrations {
37 if !statuses[migration.Version] {
38 continue
39 }
40 if err = migration.DownContext(ctx, db); err != nil {
41 return fmt.Errorf("failed to db-down: %w", err)
42 }
43 }
44
45 return nil
46}
47
48func dbMigrationsStatus(ctx context.Context, db *sql.DB) (map[int64]bool, error) {
49 dbMigrations, err := store.ListMigrations(ctx, db, TableName())
50 if err != nil {
51 return nil, err
52 }
53 // The most recent record for each migration specifies
54 // whether it has been applied or rolled back.
55 results := make(map[int64]bool)
56
57 for _, m := range dbMigrations {
58 if _, ok := results[m.VersionID]; ok {
59 continue
60 }
61 results[m.VersionID] = m.IsApplied
62 }
63 return results, nil
64}