stonesql/migrator.go
Rene Nochebuena ff1fc8ca0c
All checks were successful
Go CI/CD / go-ci (push) Successful in 19m9s
Release v1.0.0 (#2)
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>
2025-04-13 11:34:45 -06:00

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
}