migrate

package module
v0.3.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 2, 2026 License: MIT Imports: 16 Imported by: 0

README

gas-migrate

Test Go Reference Go Version License

Migration manager for the Gas ecosystem. Tracks and applies database migrations across all Gas services with dirty-state detection and rollback support.

Install

go get github.com/gasmod/gas-migrate

Usage

Wiring in main.go
package main

import (
	"github.com/gasmod/gas"
	database "github.com/gasmod/gas-database"
	migrate "github.com/gasmod/gas-migrate"
)

func main() {
	app := gas.NewApp(
		gas.WithSingletonService[*database.Service](database.New()),
		gas.WithSingletonService[*migrate.Service](migrate.New()),
		gas.WithSingletonService[*auth.Service](auth.New),
	)

	app.Run()
}
Registering migrations

Services register their migrations during Init(). There are three ways to register.

Single migration
func (s *Service) Init() error {
	s.migrationMgr.Register(s.Name(), gas.Migration{
		Version:     "20250216001",
		Description: "create users table",
		Up:          "CREATE TABLE users (id SERIAL PRIMARY KEY, email TEXT NOT NULL);",
		Down:        "DROP TABLE users;",
	})
	return nil
}
Slice of migrations
func (s *Service) Init() error {
	s.migrationMgr.RegisterSlice(s.Name(), []gas.Migration{
		{
			Version:     "20250216001",
			Description: "create users table",
			Up:          "CREATE TABLE users (id SERIAL PRIMARY KEY, email TEXT NOT NULL);",
			Down:        "DROP TABLE users;",
		},
		{
			Version:     "20250216002",
			Description: "create sessions table",
			Up:          "CREATE TABLE sessions (id TEXT PRIMARY KEY, user_id INT REFERENCES users(id));",
			Down:        "DROP TABLE sessions;",
		},
	})
	return nil
}
Embedded SQL files
import "embed"

//go:embed migrations/*.sql
var migrationsFS embed.FS

func (s *Service) Init() error {
	return s.migrationMgr.RegisterFS(s.Name(), migrationsFS)
}

Files must follow this naming convention:

migrations/
    20250216001_create_users.up.sql
    20250216001_create_users.down.sql
    20250216002_create_sessions.up.sql
    20250216002_create_sessions.down.sql

The version is the first underscore-delimited segment (e.g. 20250216001), and the description is parsed from the remaining segments (underscores become spaces).

Running migrations
// Apply all pending migrations in global version order.
err := migrationMgr.RunPending()

// Roll back the last 2 applied migrations.
err := migrationMgr.Down(2)

How it works

  • Migrations are tracked in a __gas_migrations table created automatically on Init().
  • Init() selects the correct sqlc-generated query adapter based on the database driver (PostgreSQL, MySQL, or SQLite). Unsupported drivers cause Init() to return an error.
  • RunPending() sorts all registered migrations globally by version across all services and applies any that haven't been applied yet.
  • Each migration runs in its own transaction. If a migration fails, it is marked dirty and all further execution is blocked until the dirty state is manually resolved.
  • Down(n) reverses the last n applied migrations in reverse version order.
  • Version collision detection: If two services register migrations with the same version, RunPending() and Down() return an error identifying the conflicting version and both service names.

Readiness

The service implements gas.ReadyReporter. CheckReady(ctx) returns nil only when the service is initialized, not closed, has no dirty migrations, and has no registered migrations pending application. This maps to a Kubernetes readinessProbe — traffic is gated until migrations have applied successfully. gas.HealthReporter is intentionally not implemented, since gas-migrate owns no live runtime state distinct from the underlying database connection (which gas-database reports on).

Dirty migrations

If a migration fails, it is recorded as dirty in the tracking table. Subsequent calls to RunPending() will return an error listing the dirty versions. To resolve:

  1. Fix the underlying issue (bad SQL, missing dependency, etc.).
  2. Manually remove or update the dirty row in __gas_migrations.
  3. Run RunPending() again.

Documentation

Overview

Package migrate provides database migration management for the Gas ecosystem. Provides registration, RunPending, Down/rollback, dirty-state handling, and sqlc multi-dialect adapters.

See the module README for usage examples and design rationale.

SPDX-License-Identifier: MIT

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func New

func New() func(gas.DatabaseProvider) *Service

New returns a DI-injectable constructor for the migration manager service.

Types

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service implements gas.Service and gas.MigrationManager. It tracks database migrations across all Gas services, applying pending migrations on startup and supporting rollback operations.

func (*Service) CheckReady

func (s *Service) CheckReady(ctx context.Context) error

CheckReady reports whether the service is ready to accept traffic. It returns an error if the service is closed, not initialized, has any dirty migrations, or has registered migrations that have not yet been applied.

func (*Service) Close

func (s *Service) Close() error

Close marks the service as closed.

func (*Service) Down

func (s *Service) Down(n int) error

Down reverses the last n applied migrations in reverse version order.

func (*Service) Init

func (s *Service) Init() error

Init validates dependencies, selects the correct sqlc adapter based on the configured database driver, and creates the migrations tracking table.

func (*Service) Name

func (s *Service) Name() string

Name returns the service identifier.

func (*Service) Register

func (s *Service) Register(service string, migration gas.Migration)

Register adds a migration owned by the given service.

func (*Service) RegisterFS

func (s *Service) RegisterFS(service string, fsys fs.FS) error

RegisterFS reads migration files from an fs.FS and registers them for the given service. Files must follow the naming convention:

{version}_{description}.up.sql   — the up (apply) SQL
{version}_{description}.down.sql — the down (rollback) SQL

The version is the first underscore-delimited segment, and the description is the remaining underscored segments converted to spaces. Every .up.sql file must have a matching .down.sql file.

func (*Service) RegisterSlice

func (s *Service) RegisterSlice(service string, migrations []gas.Migration)

RegisterSlice adds multiple migrations at once for the given service.

func (*Service) RunPending

func (s *Service) RunPending() error

RunPending applies all unapplied migrations in global version order. If any migration is marked dirty, execution is blocked until resolved.

Directories

Path Synopsis
db
Package migratetest provides a mock implementation of gas.MigrationManager for use in tests.
Package migratetest provides a mock implementation of gas.MigrationManager for use in tests.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL