fix: Improve provider apply() errors (#660)

This commit is contained in:
Michael Fridman 2023-12-10 13:27:01 -07:00 committed by GitHub
parent e0a62dc434
commit 31709a3537
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 53 additions and 8 deletions

View File

@ -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)
}

View File

@ -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")
)

View File

@ -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()
@ -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
}

View File

@ -1,6 +1,10 @@
package goose
import "time"
import (
"fmt"
"path/filepath"
"time"
)
// MigrationType is the type of migration.
type MigrationType string
@ -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