Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Improve provider apply() errors #660

Merged
merged 4 commits into from
Dec 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -409,8 +409,16 @@ func (p *Provider) apply(
if err != nil && !errors.Is(err, database.ErrVersionNotFound) {
return nil, err
}
// If the migration has already been applied, return an error. But, if the migration is being
// rolled back, we allow the individual migration to be applied again.
// There are a few states here:
// 1. direction is up
// a. migration is applied, this is an error (ErrAlreadyApplied)
// b. migration is not applied, apply it
// 2. direction is down
// a. migration is applied, rollback
// b. migration is not applied, this is an error (ErrNotApplied)
if result == nil && !direction {
return nil, fmt.Errorf("version %d: %w", version, ErrNotApplied)
}
if result != nil && direction {
return nil, fmt.Errorf("version %d: %w", version, ErrAlreadyApplied)
}
Expand Down
14 changes: 10 additions & 4 deletions provider_errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,21 @@ import (
)

var (
// ErrVersionNotFound when a migration version is not found.
// ErrVersionNotFound is returned when a specific migration version is not located. This can
// occur if a .sql file or a Go migration function for the specified version is missing.
ErrVersionNotFound = errors.New("version not found")

// ErrAlreadyApplied when a migration has already been applied.
ErrAlreadyApplied = errors.New("already applied")

// ErrNoMigrations is returned by [NewProvider] when no migrations are found.
ErrNoMigrations = errors.New("no migrations found")

// ErrAlreadyApplied indicates that the migration cannot be applied because it has already been
// executed. This error is returned by [Provider.Apply].
ErrAlreadyApplied = errors.New("migration already applied")

// ErrNotApplied indicates that the rollback cannot be performed because the migration has not
// yet been applied. This error is returned by [Provider.Apply].
ErrNotApplied = errors.New("migration not applied")

// errInvalidVersion is returned when a migration version is invalid.
errInvalidVersion = errors.New("version must be greater than 0")
)
Expand Down
16 changes: 15 additions & 1 deletion provider_run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ func TestProviderRun(t *testing.T) {
_, err = p.ApplyVersion(ctx, 1, true)
check.HasError(t, err)
check.Bool(t, errors.Is(err, goose.ErrAlreadyApplied), true)
check.Contains(t, err.Error(), "version 1: already applied")
check.Contains(t, err.Error(), "version 1: migration already applied")
})
t.Run("status", func(t *testing.T) {
ctx := context.Background()
Expand Down Expand Up @@ -765,6 +765,20 @@ func TestCustomStoreTableExists(t *testing.T) {
check.NoError(t, err)
}

func TestProviderApply(t *testing.T) {
t.Parallel()

ctx := context.Background()
p, err := goose.NewProvider(goose.DialectSQLite3, newDB(t), newFsys())
check.NoError(t, err)
_, err = p.ApplyVersion(ctx, 1, true)
check.NoError(t, err)
// This version has a corresponding down migration, but has never been applied.
_, err = p.ApplyVersion(ctx, 2, false)
check.HasError(t, err)
check.Bool(t, errors.Is(err, goose.ErrNotApplied), true)
}

type customStoreSQLite3 struct {
database.Store
}
Expand Down
19 changes: 18 additions & 1 deletion provider_types.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package goose

import "time"
import (
"fmt"
"path/filepath"
"time"
)

// MigrationType is the type of migration.
type MigrationType string
Expand Down Expand Up @@ -32,6 +36,19 @@ type MigrationResult struct {
Error error
}

func (m *MigrationResult) String() string {
state := "OK"
if m.Empty {
state = "EMPTY"
}
return fmt.Sprintf("%-6s %-4s %s (%s)",
state,
m.Direction,
filepath.Base(m.Source.Path),
truncateDuration(m.Duration),
)
}

// State represents the state of a migration.
type State string

Expand Down