Documentation
¶
Overview ¶
Package queen provides a lightweight database migration library for Go.
Example ¶
Example demonstrates basic usage of Queen migrations.
package main
import (
"context"
"fmt"
"log"
"github.com/honeynil/queen"
"github.com/honeynil/queen/drivers/mock"
)
func main() {
driver := mock.New()
q := queen.New(driver)
defer func() { _ = q.Close() }()
// Register migrations
q.MustAdd(queen.M{
Version: "001",
Name: "create_users",
UpSQL: `CREATE TABLE users (id SERIAL PRIMARY KEY, email VARCHAR(255))`,
DownSQL: `DROP TABLE users`,
})
q.MustAdd(queen.M{
Version: "002",
Name: "add_users_name",
UpSQL: `ALTER TABLE users ADD COLUMN name VARCHAR(255)`,
DownSQL: `ALTER TABLE users DROP COLUMN name`,
})
// Apply all pending migrations
ctx := context.Background()
if err := q.Up(ctx); err != nil {
log.Fatal(err)
}
fmt.Println("Migrations applied successfully!")
}
Example (Configuration) ¶
Example_configuration demonstrates custom configuration.
package main
import (
"context"
"time"
"github.com/honeynil/queen"
"github.com/honeynil/queen/drivers/mock"
)
func main() {
driver := mock.New()
config := &queen.Config{
TableName: "custom_migrations", // Custom table name
LockTimeout: 30 * time.Minute,
SkipLock: false, // Enable lock protection
}
q := queen.NewWithConfig(driver, config)
defer func() { _ = q.Close() }()
_ = q.Up(context.Background())
}
Example (GoFunctionMigration) ¶
Example_goFunctionMigration demonstrates using Go functions for complex migrations.
package main
import (
"context"
"database/sql"
"strings"
"github.com/honeynil/queen"
"github.com/honeynil/queen/drivers/mock"
)
func main() {
driver := mock.New()
q := queen.New(driver)
defer func() { _ = q.Close() }()
// SQL migration to create table
q.MustAdd(queen.M{
Version: "001",
Name: "create_users",
UpSQL: `CREATE TABLE users (id SERIAL PRIMARY KEY, email VARCHAR(255))`,
DownSQL: `DROP TABLE users`,
})
// Go function migration for complex data transformation
q.MustAdd(queen.M{
Version: "002",
Name: "normalize_emails",
ManualChecksum: "v1", // Track function changes
UpFunc: func(ctx context.Context, tx *sql.Tx) error {
rows, err := tx.QueryContext(ctx, "SELECT id, email FROM users")
if err != nil {
return err
}
defer func() { _ = rows.Close() }()
for rows.Next() {
var id int
var email string
if err := rows.Scan(&id, &email); err != nil {
return err
}
normalized := strings.ToLower(strings.TrimSpace(email))
_, err = tx.ExecContext(ctx,
"UPDATE users SET email = $1 WHERE id = $2",
normalized, id)
if err != nil {
return err
}
}
return rows.Err()
},
})
_ = q.Up(context.Background())
}
Example (ModularMigrations) ¶
Example_modularMigrations demonstrates organizing migrations by domain.
package main
import (
"context"
"github.com/honeynil/queen"
"github.com/honeynil/queen/drivers/mock"
)
func main() {
driver := mock.New()
q := queen.New(driver)
defer func() { _ = q.Close() }()
// Register migrations from different modules
registerUserMigrations(q)
registerPostMigrations(q)
_ = q.Up(context.Background())
}
func registerUserMigrations(q *queen.Queen) {
q.MustAdd(queen.M{
Version: "users_001",
Name: "create_users",
UpSQL: `CREATE TABLE users (id SERIAL PRIMARY KEY)`,
DownSQL: `DROP TABLE users`,
})
}
func registerPostMigrations(q *queen.Queen) {
q.MustAdd(queen.M{
Version: "posts_001",
Name: "create_posts",
UpSQL: `CREATE TABLE posts (id SERIAL PRIMARY KEY)`,
DownSQL: `DROP TABLE posts`,
})
}
Example (Status) ¶
Example_status demonstrates checking migration status.
package main
import (
"context"
"fmt"
"log"
"github.com/honeynil/queen"
"github.com/honeynil/queen/drivers/mock"
)
func main() {
driver := mock.New()
q := queen.New(driver)
defer func() { _ = q.Close() }()
q.MustAdd(queen.M{
Version: "001",
Name: "create_users",
UpSQL: `CREATE TABLE users (id INT)`,
DownSQL: `DROP TABLE users`,
})
ctx := context.Background()
// Check status of all migrations
statuses, err := q.Status(ctx)
if err != nil {
log.Fatal(err)
}
for _, s := range statuses {
fmt.Printf("Version: %s, Name: %s, Status: %s\n",
s.Version, s.Name, s.Status)
}
}
Example (Testing) ¶
Example_testing demonstrates testing migrations.
package main
import (
"testing"
"github.com/honeynil/queen"
"github.com/honeynil/queen/drivers/mock"
)
func main() {
// In your test
testFunc := func(t *testing.T) {
driver := setupTestDB(t) // Your test DB setup
q := queen.NewTest(t, driver) // Auto-cleanup on test end
q.MustAdd(queen.M{
Version: "001",
Name: "create_users",
UpSQL: `CREATE TABLE users (id INT)`,
DownSQL: `DROP TABLE users`,
})
// Test both up and down migrations
q.TestUpDown()
}
// Run the test (in real code, use go test)
t := &testing.T{}
testFunc(t)
}
func setupTestDB(_ *testing.T) queen.Driver {
return mock.New()
}
Index ¶
- Constants
- Variables
- func IsValidMigrationName(name string) bool
- func IsValidMigrationVersion(version string) bool
- type Applied
- type Config
- type Driver
- type Gap
- type GapType
- type IgnoredGap
- type Logger
- type M
- type Migration
- type MigrationError
- type MigrationFunc
- type MigrationMetadata
- type MigrationPlan
- type MigrationStatus
- type MigrationType
- type NamingConfig
- type NamingPattern
- type Option
- type Queen
- func (q *Queen) Add(m M) error
- func (q *Queen) Close() error
- func (q *Queen) DetectGaps(ctx context.Context) ([]Gap, error)
- func (q *Queen) Down(ctx context.Context, n int) error
- func (q *Queen) Driver() Driver
- func (q *Queen) DryRun(ctx context.Context, direction string, limit int) ([]MigrationPlan, error)
- func (q *Queen) Explain(ctx context.Context, version string) (*MigrationPlan, error)
- func (q *Queen) FindMigration(version string) *Migration
- func (q *Queen) MustAdd(m M)
- func (q *Queen) Reset(ctx context.Context) error
- func (q *Queen) Status(ctx context.Context) ([]MigrationStatus, error)
- func (q *Queen) Up(ctx context.Context) error
- func (q *Queen) UpSteps(ctx context.Context, n int) error
- func (q *Queen) Validate(ctx context.Context) error
- type QueenIgnore
- func (qi *QueenIgnore) AddIgnore(version, reason, ignoredBy string) error
- func (qi *QueenIgnore) GetReason(version string) string
- func (qi *QueenIgnore) IsIgnored(version string) bool
- func (qi *QueenIgnore) ListIgnored() []*IgnoredGap
- func (qi *QueenIgnore) RemoveIgnore(version string) error
- func (qi *QueenIgnore) Save() error
- type Status
- type TestHelper
Examples ¶
Constants ¶
const ( DirectionUp = "up" DirectionDown = "down" DriverUnknown = "unknown" )
Variables ¶
var ( ErrNoMigrations = errors.New("no migrations registered") ErrVersionConflict = errors.New("version conflict") ErrMigrationNotFound = errors.New("migration not found") ErrChecksumMismatch = errors.New("checksum mismatch") ErrLockTimeout = errors.New("lock timeout") ErrNoDriver = errors.New("driver not initialized") ErrInvalidMigration = errors.New("invalid migration") ErrNameTooLong = errors.New("migration name exceeds 63 characters") ErrInvalidMigrationName = errors.New("invalid migration name") ErrAlreadyApplied = errors.New("migration already applied") )
Functions ¶
func IsValidMigrationName ¶ added in v0.2.0
IsValidMigrationName reports whether name is a valid migration name. Valid names contain only lowercase letters, digits, and underscores.
func IsValidMigrationVersion ¶ added in v0.3.0
IsValidMigrationVersion reports whether version is a valid migration version. Valid versions contain only letters, digits, dots, dashes, and underscores.
Types ¶
type Applied ¶
type Applied struct {
Version string
Name string
AppliedAt time.Time
Checksum string
AppliedBy string
DurationMS int64
Hostname string
Environment string
Action string
Status string
ErrorMessage string
}
Applied represents a migration that has been applied.
type Config ¶
type Config struct {
TableName string
LockTimeout time.Duration
SkipLock bool
Naming *NamingConfig
IsolationLevel sql.IsolationLevel
}
Config configures Queen behavior.
type Driver ¶
type Driver interface {
Init(ctx context.Context) error
GetApplied(ctx context.Context) ([]Applied, error)
Record(ctx context.Context, m *Migration, meta *MigrationMetadata) error
Remove(ctx context.Context, version string) error
Lock(ctx context.Context, timeout time.Duration) error
Unlock(ctx context.Context) error
Exec(ctx context.Context, isolationLevel sql.IsolationLevel, fn func(*sql.Tx) error) error
Close() error
}
Driver is the interface that database-specific migration drivers must implement.
type IgnoredGap ¶ added in v0.3.0
type Logger ¶ added in v0.2.0
type Logger interface {
InfoContext(ctx context.Context, msg string, args ...any)
WarnContext(ctx context.Context, msg string, args ...any)
ErrorContext(ctx context.Context, msg string, args ...any)
}
Logger is a structured logging interface compatible with slog.Logger.
type Migration ¶
type Migration struct {
Version string
Name string
UpSQL string
DownSQL string
UpFunc MigrationFunc
DownFunc MigrationFunc
ManualChecksum string
IsolationLevel sql.IsolationLevel
// contains filtered or unexported fields
}
Migration represents a database migration.
func (*Migration) HasRollback ¶
func (*Migration) IsDestructive ¶
type MigrationError ¶
type MigrationError struct {
Version string
Name string
Operation string
Driver string
Cause error
}
MigrationError wraps an error with migration context.
func (*MigrationError) Error ¶
func (e *MigrationError) Error() string
func (*MigrationError) Unwrap ¶
func (e *MigrationError) Unwrap() error
type MigrationMetadata ¶ added in v0.3.0
type MigrationMetadata struct {
AppliedBy string
DurationMS int64
Hostname string
Environment string
Action string
Status string
ErrorMessage string
}
MigrationMetadata contains metadata collected during migration execution.
type MigrationPlan ¶ added in v0.2.0
type MigrationPlan struct {
Version string `json:"version"`
Name string `json:"name"`
Direction string `json:"direction"`
Status string `json:"status"`
Type MigrationType `json:"type"`
SQL string `json:"sql,omitempty"`
HasRollback bool `json:"has_rollback"`
IsDestructive bool `json:"is_destructive"`
Checksum string `json:"checksum"`
Warnings []string `json:"warnings,omitempty"`
}
MigrationPlan represents a migration execution plan.
type MigrationStatus ¶
type MigrationStatus struct {
Version string
Name string
Status Status
AppliedAt *time.Time
Checksum string
HasRollback bool
Destructive bool
}
MigrationStatus represents the current state of a migration.
type MigrationType ¶ added in v0.2.0
type MigrationType string
const ( MigrationTypeSQL MigrationType = "sql" MigrationTypeGoFunc MigrationType = "go-func" MigrationTypeMixed MigrationType = "mixed" )
type NamingConfig ¶ added in v0.2.0
type NamingConfig struct {
Pattern NamingPattern
Padding int
Enforce bool
}
func DefaultNamingConfig ¶ added in v0.2.0
func DefaultNamingConfig() *NamingConfig
func (*NamingConfig) FindNextVersion ¶ added in v0.2.0
func (nc *NamingConfig) FindNextVersion(existingVersions []string) (string, error)
func (*NamingConfig) Validate ¶ added in v0.2.0
func (nc *NamingConfig) Validate(version string) error
type NamingPattern ¶ added in v0.2.0
type NamingPattern string
const ( NamingPatternNone NamingPattern = "" NamingPatternSequential NamingPattern = "sequential" NamingPatternSequentialPadded NamingPattern = "sequential-padded" NamingPatternSemver NamingPattern = "semver" )
type Option ¶ added in v0.2.0
type Option func(*Queen)
Option configures a Queen instance.
func WithLogger ¶ added in v0.2.0
WithLogger sets a custom logger. Compatible with *slog.Logger.
type Queen ¶
type Queen struct {
// contains filtered or unexported fields
}
Queen manages database migrations.
func NewWithConfig ¶
NewWithConfig creates a Queen instance with custom configuration.
func (*Queen) Add ¶
Add registers a migration. Returns ErrVersionConflict if version already exists.
func (*Queen) DetectGaps ¶ added in v0.3.0
DetectGaps analyzes migrations and returns any detected gaps.
func (*Queen) Down ¶
Down rolls back the last n migrations. If n <= 0, rolls back only the last migration.
Example ¶
ExampleQueen_Down demonstrates rolling back migrations.
package main
import (
"context"
"fmt"
"log"
"github.com/honeynil/queen"
"github.com/honeynil/queen/drivers/mock"
)
func main() {
driver := mock.New()
q := queen.New(driver)
defer func() { _ = q.Close() }()
ctx := context.Background()
// Rollback last migration
if err := q.Down(ctx, 1); err != nil {
log.Fatal(err)
}
fmt.Println("Rolled back 1 migration")
}
func (*Queen) DryRun ¶ added in v0.2.0
DryRun returns a migration execution plan without applying migrations. Direction can be DirectionUp (pending) or DirectionDown (applied).
func (*Queen) Explain ¶ added in v0.2.0
Explain returns a detailed migration plan for a specific version.
func (*Queen) FindMigration ¶ added in v0.5.0
FindMigration returns a registered migration by version, or nil if not found.
func (*Queen) Reset ¶
Reset rolls back all applied migrations.
Example ¶
ExampleQueen_Reset demonstrates rolling back all migrations.
package main
import (
"context"
"fmt"
"log"
"github.com/honeynil/queen"
"github.com/honeynil/queen/drivers/mock"
)
func main() {
driver := mock.New()
q := queen.New(driver)
defer func() { _ = q.Close() }()
ctx := context.Background()
if err := q.Reset(ctx); err != nil {
log.Fatal(err)
}
fmt.Println("All migrations rolled back")
}
func (*Queen) Status ¶
func (q *Queen) Status(ctx context.Context) ([]MigrationStatus, error)
Status returns the status of all registered migrations.
func (*Queen) Up ¶
Up applies all pending migrations. Equivalent to UpSteps(ctx, 0).
Example ¶
ExampleQueen_Up demonstrates applying all pending migrations.
package main
import (
"context"
"fmt"
"log"
"github.com/honeynil/queen"
"github.com/honeynil/queen/drivers/mock"
)
func main() {
driver := mock.New()
q := queen.New(driver)
defer func() { _ = q.Close() }()
q.MustAdd(queen.M{
Version: "001",
Name: "create_users",
UpSQL: `CREATE TABLE users (id INT)`,
DownSQL: `DROP TABLE users`,
})
ctx := context.Background()
if err := q.Up(ctx); err != nil {
log.Fatal(err)
}
fmt.Println("All migrations applied")
}
func (*Queen) UpSteps ¶
UpSteps applies up to n pending migrations. If n <= 0, applies all.
Example ¶
ExampleQueen_UpSteps demonstrates applying a specific number of migrations.
package main
import (
"context"
"fmt"
"log"
"github.com/honeynil/queen"
"github.com/honeynil/queen/drivers/mock"
)
func main() {
driver := mock.New()
q := queen.New(driver)
defer func() { _ = q.Close() }()
q.MustAdd(queen.M{Version: "001", Name: "migration_1", UpSQL: "..."})
q.MustAdd(queen.M{Version: "002", Name: "migration_2", UpSQL: "..."})
q.MustAdd(queen.M{Version: "003", Name: "migration_3", UpSQL: "..."})
ctx := context.Background()
// Apply only the next 2 migrations
if err := q.UpSteps(ctx, 2); err != nil {
log.Fatal(err)
}
fmt.Println("Applied 2 migrations")
}
func (*Queen) Validate ¶
Validate checks for duplicate versions, invalid migrations, and checksum mismatches.
Example ¶
ExampleQueen_Validate demonstrates validating migrations.
package main
import (
"context"
"fmt"
"log"
"github.com/honeynil/queen"
"github.com/honeynil/queen/drivers/mock"
)
func main() {
driver := mock.New()
q := queen.New(driver)
defer func() { _ = q.Close() }()
q.MustAdd(queen.M{
Version: "001",
Name: "create_users",
UpSQL: `CREATE TABLE users (id INT)`,
})
ctx := context.Background()
if err := q.Validate(ctx); err != nil {
log.Fatalf("Validation failed: %v", err)
}
fmt.Println("All migrations valid")
}
type QueenIgnore ¶ added in v0.3.0
type QueenIgnore struct {
// contains filtered or unexported fields
}
func LoadQueenIgnore ¶ added in v0.3.0
func LoadQueenIgnore() (*QueenIgnore, error)
func LoadQueenIgnoreFrom ¶ added in v0.3.0
func LoadQueenIgnoreFrom(path string) (*QueenIgnore, error)
func (*QueenIgnore) AddIgnore ¶ added in v0.3.0
func (qi *QueenIgnore) AddIgnore(version, reason, ignoredBy string) error
func (*QueenIgnore) GetReason ¶ added in v0.3.0
func (qi *QueenIgnore) GetReason(version string) string
func (*QueenIgnore) IsIgnored ¶ added in v0.3.0
func (qi *QueenIgnore) IsIgnored(version string) bool
func (*QueenIgnore) ListIgnored ¶ added in v0.3.0
func (qi *QueenIgnore) ListIgnored() []*IgnoredGap
func (*QueenIgnore) RemoveIgnore ¶ added in v0.3.0
func (qi *QueenIgnore) RemoveIgnore(version string) error
func (*QueenIgnore) Save ¶ added in v0.3.0
func (qi *QueenIgnore) Save() error
type TestHelper ¶
type TestHelper struct {
*Queen
// contains filtered or unexported fields
}
TestHelper provides testing utilities for migrations.
func NewTest ¶
func NewTest(t *testing.T, driver Driver) *TestHelper
Example ¶
ExampleNewTest demonstrates using the testing helper.
package main
import (
"fmt"
"testing"
"github.com/honeynil/queen"
"github.com/honeynil/queen/drivers/mock"
)
func main() {
testFunc := func(t *testing.T) {
driver := setupTestDB(t)
// NewTest automatically cleans up when test ends
q := queen.NewTest(t, driver)
q.MustAdd(queen.M{
Version: "001",
Name: "create_users",
UpSQL: `CREATE TABLE users (id INT)`,
DownSQL: `DROP TABLE users`,
})
// Test migrations
q.MustUp()
q.MustValidate()
fmt.Println("Test passed")
}
t := &testing.T{}
testFunc(t)
}
func setupTestDB(_ *testing.T) queen.Driver {
return mock.New()
}
func (*TestHelper) MustDown ¶
func (th *TestHelper) MustDown(n int)
func (*TestHelper) MustReset ¶
func (th *TestHelper) MustReset()
func (*TestHelper) MustUp ¶
func (th *TestHelper) MustUp()
func (*TestHelper) MustValidate ¶
func (th *TestHelper) MustValidate()
func (*TestHelper) TestRollback ¶ added in v0.2.0
func (th *TestHelper) TestRollback()
Example ¶
ExampleTestHelper_TestRollback demonstrates thorough testing of down migrations.
package main
import (
"fmt"
"testing"
"github.com/honeynil/queen"
"github.com/honeynil/queen/drivers/mock"
)
func main() {
testFunc := func(t *testing.T) {
driver := setupTestDB(t)
q := queen.NewTest(t, driver)
q.MustAdd(queen.M{
Version: "001",
Name: "create_users",
UpSQL: `CREATE TABLE users (id INT)`,
DownSQL: `DROP TABLE users`,
})
q.MustAdd(queen.M{
Version: "002",
Name: "add_email",
UpSQL: `ALTER TABLE users ADD COLUMN email VARCHAR(255)`,
DownSQL: `ALTER TABLE users DROP COLUMN email`,
})
// TestRollback performs a full cycle: Up -> Down (one by one) -> Up
// This catches broken Down migrations that don't properly undo their Up
q.TestRollback()
fmt.Println("All down migrations work correctly")
}
t := &testing.T{}
testFunc(t)
}
func setupTestDB(_ *testing.T) queen.Driver {
return mock.New()
}
func (*TestHelper) TestUpDown ¶
func (th *TestHelper) TestUpDown()
Example ¶
ExampleTestHelper_TestUpDown demonstrates testing up and down migrations.
package main
import (
"fmt"
"testing"
"github.com/honeynil/queen"
"github.com/honeynil/queen/drivers/mock"
)
func main() {
testFunc := func(t *testing.T) {
driver := setupTestDB(t)
q := queen.NewTest(t, driver)
q.MustAdd(queen.M{
Version: "001",
Name: "create_users",
UpSQL: `CREATE TABLE users (id INT)`,
DownSQL: `DROP TABLE users`,
})
// TestUpDown applies all migrations, then rolls them back
q.TestUpDown()
fmt.Println("Up and down migrations work correctly")
}
t := &testing.T{}
testFunc(t)
}
func setupTestDB(_ *testing.T) queen.Driver {
return mock.New()
}
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package cli provides a command-line interface for Queen migrations.
|
Package cli provides a command-line interface for Queen migrations. |
|
tui
Package tui provides a terminal UI for Queen migrations.
|
Package tui provides a terminal UI for Queen migrations. |
|
drivers
|
|
|
base
Package base provides common functionality for Queen database drivers.
|
Package base provides common functionality for Queen database drivers. |
|
clickhouse
Package clickhouse provides a ClickHouse driver for Queen migrations.
|
Package clickhouse provides a ClickHouse driver for Queen migrations. |
|
cockroachdb
Package cockroachdb provides a CockroachDB driver for Queen migrations.
|
Package cockroachdb provides a CockroachDB driver for Queen migrations. |
|
mock
Package mock provides an in-memory mock driver for testing Queen without a real database.
|
Package mock provides an in-memory mock driver for testing Queen without a real database. |
|
mssql
Package mssql provides a MS SQL Server driver for Queen migrations.
|
Package mssql provides a MS SQL Server driver for Queen migrations. |
|
mysql
Package mysql provides a MySQL driver for Queen migrations.
|
Package mysql provides a MySQL driver for Queen migrations. |
|
postgres
Package postgres provides a PostgreSQL driver for Queen migrations.
|
Package postgres provides a PostgreSQL driver for Queen migrations. |
|
sqlite
Package sqlite provides a SQLite driver for Queen migrations.
|
Package sqlite provides a SQLite driver for Queen migrations. |
|
internal
|
|
|
checksum
Package checksum provides checksum calculation for migrations.
|
Package checksum provides checksum calculation for migrations. |
|
sort
Package sort provides natural sorting for migration versions.
|
Package sort provides natural sorting for migration versions. |