Skip to content

Commit

Permalink
chore: export errors, fix amacneil#292
Browse files Browse the repository at this point in the history
  • Loading branch information
gnuletik committed May 31, 2022
1 parent d671075 commit 87ae5d2
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 23 deletions.
40 changes: 27 additions & 13 deletions pkg/dbmate/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,20 @@ const DefaultWaitInterval = time.Second
// DefaultWaitTimeout specifies maximum time for connection attempts
const DefaultWaitTimeout = 60 * time.Second

// Error codes
var (
ErrNoMigrationFiles = errors.New("no migration files found")
ErrInvalidURL = errors.New("invalid url, have you set your --url flag or DATABASE_URL environment variable?")
ErrNoRollback = errors.New("can't rollback: no migrations have been applied")
ErrCantConnect = errors.New("unable to connect to database")
ErrUnsupportedDriver = errors.New("unsupported driver")
ErrNoMigrationName = errors.New("please specify a name for the new migration")
ErrMigrationAlreadyExist = errors.New("file already exists")
ErrMigrationDirNotFound = errors.New("could not find migrations directory")
ErrMigrationNotFound = errors.New("can't find migration file")
ErrCreateDirectory = errors.New("unable to create directory")
)

// DB allows dbmate actions to be performed on a specified database
type DB struct {
AutoDumpSchema bool
Expand Down Expand Up @@ -71,12 +85,12 @@ func New(databaseURL *url.URL) *DB {
// GetDriver initializes the appropriate database driver
func (db *DB) GetDriver() (Driver, error) {
if db.DatabaseURL == nil || db.DatabaseURL.Scheme == "" {
return nil, errors.New("invalid url, have you set your --url flag or DATABASE_URL environment variable?")
return nil, ErrInvalidURL
}

driverFunc := drivers[db.DatabaseURL.Scheme]
if driverFunc == nil {
return nil, fmt.Errorf("unsupported driver: %s", db.DatabaseURL.Scheme)
return nil, fmt.Errorf("%w: %s", ErrUnsupportedDriver, db.DatabaseURL.Scheme)
}

config := DriverConfig{
Expand Down Expand Up @@ -123,7 +137,7 @@ func (db *DB) wait(drv Driver) error {

// if we find outselves here, we could not connect within the timeout
fmt.Fprint(db.Log, "\n")
return fmt.Errorf("unable to connect to database: %s", err)
return fmt.Errorf("%w: %s", ErrCantConnect, err)
}

// CreateAndMigrate creates the database (if necessary) and runs migrations
Expand Down Expand Up @@ -225,13 +239,13 @@ func (db *DB) dumpSchema(drv Driver) error {
}

// write schema to file
return os.WriteFile(db.SchemaFile, schema, 0644)
return os.WriteFile(db.SchemaFile, schema, 0o644)
}

// ensureDir creates a directory if it does not already exist
func ensureDir(dir string) error {
if err := os.MkdirAll(dir, 0755); err != nil {
return fmt.Errorf("unable to create directory `%s`", dir)
if err := os.MkdirAll(dir, 0o755); err != nil {
return fmt.Errorf("%w `%s`", ErrCreateDirectory, dir)
}

return nil
Expand All @@ -244,7 +258,7 @@ func (db *DB) NewMigration(name string) error {
// new migration name
timestamp := time.Now().UTC().Format("20060102150405")
if name == "" {
return fmt.Errorf("please specify a name for the new migration")
return ErrNoMigrationName
}
name = fmt.Sprintf("%s_%s.sql", timestamp, name)

Expand All @@ -258,7 +272,7 @@ func (db *DB) NewMigration(name string) error {
fmt.Fprintf(db.Log, "Creating migration: %s\n", path)

if _, err := os.Stat(path); !os.IsNotExist(err) {
return fmt.Errorf("file already exists")
return ErrMigrationAlreadyExist
}

// write new migration
Expand Down Expand Up @@ -320,7 +334,7 @@ func (db *DB) migrate(drv Driver) error {
}

if len(files) == 0 {
return fmt.Errorf("no migration files found")
return ErrNoMigrationFiles
}

if db.WaitBefore {
Expand Down Expand Up @@ -403,7 +417,7 @@ func (db *DB) printVerbose(result sql.Result) {
func findMigrationFiles(dir string, re *regexp.Regexp) ([]string, error) {
files, err := os.ReadDir(dir)
if err != nil {
return nil, fmt.Errorf("could not find migrations directory `%s`", dir)
return nil, fmt.Errorf("%w `%s`", ErrMigrationDirNotFound, dir)
}

matches := []string{}
Expand Down Expand Up @@ -439,7 +453,7 @@ func findMigrationFile(dir string, ver string) (string, error) {
}

if len(files) == 0 {
return "", fmt.Errorf("can't find migration file: %s*.sql", ver)
return "", fmt.Errorf("%w: %s*.sql", ErrMigrationNotFound, ver)
}

return files[0], nil
Expand Down Expand Up @@ -480,7 +494,7 @@ func (db *DB) Rollback() error {
latest = ver
}
if latest == "" {
return fmt.Errorf("can't rollback: no migrations have been applied")
return ErrNoRollback
}

filename, err := findMigrationFile(db.MigrationsDir, latest)
Expand Down Expand Up @@ -573,7 +587,7 @@ func (db *DB) CheckMigrationsStatus(drv Driver) ([]StatusResult, error) {
}

if len(files) == 0 {
return nil, fmt.Errorf("no migration files found")
return nil, ErrNoMigrationFiles
}

sqlDB, err := drv.Open()
Expand Down
28 changes: 18 additions & 10 deletions pkg/dbmate/migration.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package dbmate

import (
"fmt"
"errors"
"os"
"regexp"
"strings"
Expand Down Expand Up @@ -41,13 +41,21 @@ func parseMigration(path string) (Migration, Migration, error) {
return up, down, err
}

var upRegExp = regexp.MustCompile(`(?m)^--\s*migrate:up(\s*$|\s+\S+)`)
var downRegExp = regexp.MustCompile(`(?m)^--\s*migrate:down(\s*$|\s+\S+)$`)
var emptyLineRegExp = regexp.MustCompile(`^\s*$`)
var commentLineRegExp = regexp.MustCompile(`^\s*--`)
var whitespaceRegExp = regexp.MustCompile(`\s+`)
var optionSeparatorRegExp = regexp.MustCompile(`:`)
var blockDirectiveRegExp = regexp.MustCompile(`^--\s*migrate:[up|down]]`)
var (
upRegExp = regexp.MustCompile(`(?m)^--\s*migrate:up(\s*$|\s+\S+)`)
downRegExp = regexp.MustCompile(`(?m)^--\s*migrate:down(\s*$|\s+\S+)$`)
emptyLineRegExp = regexp.MustCompile(`^\s*$`)
commentLineRegExp = regexp.MustCompile(`^\s*--`)
whitespaceRegExp = regexp.MustCompile(`\s+`)
optionSeparatorRegExp = regexp.MustCompile(`:`)
blockDirectiveRegExp = regexp.MustCompile(`^--\s*migrate:[up|down]]`)
)

// Error codes
var (
ErrParseMissingUp = errors.New("dbmate requires each migration to define an up bock with '-- migrate:up'")
ErrParseUnexpectedStmt = errors.New("dbmate does not support statements defined outside of the '-- migrate:up' or '-- migrate:down' blocks")
)

// parseMigrationContents parses the string contents of a migration.
// It will return two Migration objects, the first representing the "up"
Expand All @@ -62,9 +70,9 @@ func parseMigrationContents(contents string) (Migration, Migration, error) {
downDirectiveStart, downDirectiveEnd, hasDefinedDownBlock := getMatchPositions(contents, downRegExp)

if !hasDefinedUpBlock {
return up, down, fmt.Errorf("dbmate requires each migration to define an up bock with '-- migrate:up'")
return up, down, ErrParseMissingUp
} else if statementsPrecedeMigrateBlocks(contents, upDirectiveStart, downDirectiveStart) {
return up, down, fmt.Errorf("dbmate does not support statements defined outside of the '-- migrate:up' or '-- migrate:down' blocks")
return up, down, ErrParseUnexpectedStmt
}

upEnd := len(contents)
Expand Down

0 comments on commit 87ae5d2

Please sign in to comment.