All checks were successful
Go CI/CD / go-ci (push) Successful in 19m9s
Reviewed-on: #2 Reviewed-by: Cloud Administrator <cloud-admin@noreply.gitstormr.dev> Co-authored-by: Rene Nochebuena <code-raider@noreply.gitstormr.dev> Co-committed-by: Rene Nochebuena <code-raider@noreply.gitstormr.dev>
107 lines
2.8 KiB
Go
107 lines
2.8 KiB
Go
package stonesql
|
|
|
|
import (
|
|
"context"
|
|
"embed"
|
|
"io/fs"
|
|
"path/filepath"
|
|
|
|
"gitstormr.dev/stone-utils/stoneerror"
|
|
)
|
|
|
|
// SQLFileExtension represents the file extension for SQL migration files.
|
|
const (
|
|
SQLFileExtension = ".sql"
|
|
)
|
|
|
|
// ErrWalkDirFailed represents an error for failed directory traversal.
|
|
// ErrReadMigrationFailed represents an error for reading migration files.
|
|
// ErrExecuteMigrationFailed represents an error during migration execution.
|
|
// ErrMigrationProcessFailed represents a general migration process failure.
|
|
var (
|
|
ErrWalkDirFailed = stoneerror.New(
|
|
2001,
|
|
"failed to walk migration directory",
|
|
)
|
|
ErrReadMigrationFailed = stoneerror.New(
|
|
2002,
|
|
"failed to read migration file",
|
|
)
|
|
ErrExecuteMigrationFailed = stoneerror.New(
|
|
2003,
|
|
"failed to execute migration",
|
|
)
|
|
ErrMigrationProcessFailed = stoneerror.New(
|
|
2004,
|
|
"migration process failed",
|
|
)
|
|
)
|
|
|
|
// Migrator defines the interface for executing SQL migrations.
|
|
// ExecuteMigration runs a migration given its name and SQL content.
|
|
type Migrator interface {
|
|
ExecuteMigration(ctx context.Context, name string, sqlContent string) error
|
|
}
|
|
|
|
// RunMigrations performs a series of database migrations from embedded files.
|
|
// It traverses the provided filesystem path, reads SQL files, and executes them.
|
|
// If an error occurs during traversal, reading, or execution, it wraps and returns it.
|
|
// Context to be used for execution is passed via the ctx parameter.
|
|
// The migrator parameter executes individual SQL content for migrations.
|
|
// The migrationsFS parameter provides an embedded filesystem for the SQL files.
|
|
// The path parameter specifies the directory within the embedded FS to search in.
|
|
// Returns an error if any step in the migration process fails.
|
|
func RunMigrations(
|
|
ctx context.Context,
|
|
migrator Migrator,
|
|
migrationsFS embed.FS,
|
|
path string,
|
|
) error {
|
|
walkErr := fs.WalkDir(
|
|
migrationsFS,
|
|
path,
|
|
func(path string, d fs.DirEntry, err error) error {
|
|
if err != nil {
|
|
return stoneerror.Wrap(
|
|
err, ErrWalkDirFailed.Code,
|
|
ErrWalkDirFailed.Message,
|
|
).
|
|
WithMetadata("path", path)
|
|
}
|
|
|
|
if !d.IsDir() && filepath.Ext(path) == SQLFileExtension {
|
|
sqlContent, readErr := migrationsFS.ReadFile(path)
|
|
if readErr != nil {
|
|
return stoneerror.Wrap(
|
|
readErr, ErrReadMigrationFailed.Code,
|
|
ErrReadMigrationFailed.Message,
|
|
).
|
|
WithMetadata("file", path)
|
|
}
|
|
|
|
if err = migrator.ExecuteMigration(
|
|
ctx, path, string(sqlContent),
|
|
); err != nil {
|
|
return stoneerror.Wrap(
|
|
err, ErrExecuteMigrationFailed.Code,
|
|
ErrExecuteMigrationFailed.Message,
|
|
).
|
|
WithMetadata("migration", path)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
},
|
|
)
|
|
|
|
if walkErr != nil {
|
|
return stoneerror.Wrap(
|
|
walkErr, ErrMigrationProcessFailed.Code,
|
|
ErrMigrationProcessFailed.Message,
|
|
).
|
|
WithMetadata("rootPath", path)
|
|
}
|
|
|
|
return nil
|
|
}
|