migrate

package
v0.9.7 Latest Latest
Warning

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

Go to latest
Published: Feb 11, 2026 License: MIT Imports: 7 Imported by: 0

README

Velocity Database Migrations

Database schema versioning and evolution system for Velocity.

Features

  • ✅ Timestamp-based versioning (no conflicts in team environments)
  • ✅ Up/Down migrations with rollback support
  • ✅ TableBuilder DSL for type-safe schema definitions
  • ✅ Cross-database support (SQLite, MySQL, PostgreSQL)
  • ✅ Automatic migration tracking (migrations table)
  • ✅ Batch-based rollbacks

Quick Start

1. Create a Migration

migrations/20251009120000_create_users.go:

package migrations

import "github.com/velocitykode/velocity/pkg/orm/migrate"

func init() {
    migrate.Register(&migrate.Migration{
        Version: "20251009120000",
        Up: func(m *migrate.Migrator) error {
            return m.CreateTable("users", func(t *migrate.TableBuilder) {
                t.ID()
                t.String("email").Unique()
                t.String("name")
                t.Timestamps()
            })
        },
        Down: func(m *migrate.Migrator) error {
            return m.DropTable("users")
        },
    })
}
2. Run Migrations
import (
    "github.com/velocitykode/velocity/pkg/orm"
    "github.com/velocitykode/velocity/pkg/orm/migrate"
    _ "myapp/migrations" // Import to register
)

// Initialize ORM
orm.Init("sqlite", map[string]any{"database": "./database.db"})

// Run migrations
migrator := migrate.NewMigrator(orm.DB(), orm.GetDriver())
err := migrator.Up()

TableBuilder API

// Primary Keys
t.ID()                           // Auto-increment integer primary key
t.UUIDPrimary()                  // UUID primary key with auto-generation

// Column Types
t.String("name")                 // VARCHAR(255)
t.String("code", 10)            // VARCHAR(10)
t.Text("bio")                   // TEXT (unlimited)
t.Integer("count")              // INTEGER
t.BigInteger("views")           // BIGINT
t.Boolean("active")             // BOOLEAN
t.UUID("external_id")           // UUID column
t.Timestamp("verified_at")      // Single TIMESTAMP column
t.Date("birth_date")            // DATE
t.Timestamps()                  // created_at, updated_at
t.SoftDeletes()                 // deleted_at (nullable)

// Modifiers
t.String("email").Unique()      // UNIQUE constraint
t.String("bio").Nullable()      // Allow NULL
t.Integer("status").Default(0)  // Default value
UUID Primary Keys

For distributed systems or external-facing APIs where sequential IDs pose security risks:

// Migration
m.CreateTable("projects", func(t *migrate.TableBuilder) {
    t.UUIDPrimary()              // UUID primary key
    t.String("name")
    t.Timestamps()
})

// Model (use UUIDModel instead of Model)
type Project struct {
    orm.UUIDModel[Project]
    Name string `orm:"column:name" json:"name"`
}

Database-specific behavior:

  • PostgreSQL: Uses UUID type with gen_random_uuid() default
  • MySQL: Uses CHAR(36)
  • SQLite: Uses TEXT

Commands

migrator := migrate.NewMigrator(orm.DB(), orm.GetDriver())

// Run pending migrations
migrator.Up()

// Rollback last batch
migrator.Down(1)

// Check status
statuses, _ := migrator.Status()
for _, s := range statuses {
    fmt.Printf("%s: %s\n", s.Version, s.State)
}

Version Format

Migrations use timestamp-based versioning: YYYYMMDDHHmmss

Example: 20251009143052 = December 9, 2025 at 14:30:52

See Also

  • /specs/002-database-testing-system/contracts/migration-api.md - Full API reference
  • /specs/002-database-testing-system/quickstart.md - Complete tutorial

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Down

func Down(steps int) error

Down rolls back the last N batches using the default ORM connection

func Register

func Register(migration *Migration)

Register adds a migration to the global registry

func Up

func Up() error

Up runs all pending migrations using the default ORM connection

Types

type Column

type Column struct {
	Name          string
	Type          string
	Length        int
	Precision     int // For decimal types
	Scale         int // For decimal types
	Nullable      bool
	Default       interface{}
	Unique        bool
	PrimaryKey    bool
	AutoIncrement bool
}

Column represents a table column definition

type ColumnBuilder added in v0.8.0

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

ColumnBuilder provides a fluent API for defining a single column

func NewColumnBuilder added in v0.8.0

func NewColumnBuilder(name, driver string) *ColumnBuilder

NewColumnBuilder creates a new ColumnBuilder for the given column name and driver

func (*ColumnBuilder) BigInteger added in v0.8.0

func (c *ColumnBuilder) BigInteger() *ColumnBuilder

BigInteger sets the column type to BIGINT

func (*ColumnBuilder) Boolean added in v0.8.0

func (c *ColumnBuilder) Boolean() *ColumnBuilder

Boolean sets the column type to BOOLEAN

func (*ColumnBuilder) Date added in v0.8.0

func (c *ColumnBuilder) Date() *ColumnBuilder

Date sets the column type to DATE

func (*ColumnBuilder) Default added in v0.8.0

func (c *ColumnBuilder) Default(v interface{}) *ColumnBuilder

Default sets a default value for the column

func (*ColumnBuilder) Integer added in v0.8.0

func (c *ColumnBuilder) Integer() *ColumnBuilder

Integer sets the column type to INTEGER

func (*ColumnBuilder) JSON added in v0.8.0

func (c *ColumnBuilder) JSON() *ColumnBuilder

JSON sets the column type to JSON

func (*ColumnBuilder) JSONB added in v0.8.0

func (c *ColumnBuilder) JSONB() *ColumnBuilder

JSONB sets the column type to JSONB (binary JSON)

func (*ColumnBuilder) Nullable added in v0.8.0

func (c *ColumnBuilder) Nullable() *ColumnBuilder

Nullable marks the column as allowing NULL values

func (*ColumnBuilder) String added in v0.8.0

func (c *ColumnBuilder) String(length ...int) *ColumnBuilder

String sets the column type to VARCHAR with optional length (default 255)

func (*ColumnBuilder) Text added in v0.8.0

func (c *ColumnBuilder) Text() *ColumnBuilder

Text sets the column type to TEXT

func (*ColumnBuilder) Timestamp added in v0.8.0

func (c *ColumnBuilder) Timestamp() *ColumnBuilder

Timestamp sets the column type to TIMESTAMP

func (*ColumnBuilder) ToSQL added in v0.8.0

func (c *ColumnBuilder) ToSQL() string

ToSQL generates the column definition SQL fragment

func (*ColumnBuilder) Type added in v0.8.0

func (c *ColumnBuilder) Type(t string) *ColumnBuilder

Type sets the column type (string, integer, text, boolean, timestamp, date, biginteger, uuid)

func (*ColumnBuilder) UUID added in v0.8.0

func (c *ColumnBuilder) UUID() *ColumnBuilder

UUID sets the column type to UUID

func (*ColumnBuilder) Unique added in v0.8.0

func (c *ColumnBuilder) Unique() *ColumnBuilder

Unique marks the column as having a unique constraint

type IndexBuilder added in v0.8.0

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

IndexBuilder provides a fluent API for creating database indexes

func (*IndexBuilder) Columns added in v0.8.0

func (b *IndexBuilder) Columns(cols ...string) *IndexBuilder

Columns sets the columns to index

func (*IndexBuilder) IfNotExists added in v0.8.0

func (b *IndexBuilder) IfNotExists() *IndexBuilder

IfNotExists adds IF NOT EXISTS clause

func (*IndexBuilder) Include added in v0.8.0

func (b *IndexBuilder) Include(cols ...string) *IndexBuilder

Include adds covering index columns (PostgreSQL 11+ only) These columns are stored in the index but not used for searching Example: Include("name", "email") for index-only scans

func (*IndexBuilder) ToSQL added in v0.8.0

func (b *IndexBuilder) ToSQL() string

ToSQL generates driver-specific CREATE INDEX SQL

func (*IndexBuilder) Unique added in v0.8.0

func (b *IndexBuilder) Unique() *IndexBuilder

Unique marks the index as unique

func (*IndexBuilder) Using added in v0.8.0

func (b *IndexBuilder) Using(indexType string) *IndexBuilder

Using sets the index type (PostgreSQL only) Supported: btree (default), hash, gin, gist, brin

func (*IndexBuilder) Where added in v0.8.0

func (b *IndexBuilder) Where(condition string) *IndexBuilder

Where adds a partial index condition (PostgreSQL, SQLite) Example: Where("deleted_at IS NULL")

type Migration

type Migration struct {
	Version     string
	Description string
	Up          func(*Migrator) error
	Down        func(*Migrator) error
}

Migration represents a database schema change

func All

func All() []Migration

All returns all registered migrations

func Find

func Find(version string) (*Migration, error)

Find returns a migration by version

func Pending

func Pending(db *sql.DB, driver string) ([]Migration, error)

Pending returns migrations not yet applied

func (*Migration) Validate

func (m *Migration) Validate() error

Validate checks if the migration is valid

type MigrationRegistry

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

MigrationRegistry is a global registry for all migrations

func (*MigrationRegistry) All

func (r *MigrationRegistry) All() []Migration

All returns all registered migrations sorted by version

func (*MigrationRegistry) Find

func (r *MigrationRegistry) Find(version string) (*Migration, error)

Find returns a migration by version

func (*MigrationRegistry) Pending

func (r *MigrationRegistry) Pending(db *sql.DB, driver string) ([]Migration, error)

Pending returns migrations that haven't been applied yet

type MigrationStatus

type MigrationStatus struct {
	Version    string
	State      string // "Applied", "Pending", "Failed"
	Batch      int
	ExecutedAt *string
}

MigrationStatus represents the status of a single migration

func Status

func Status() ([]MigrationStatus, error)

Status returns migration status using the default ORM connection

type Migrator

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

Migrator handles migration execution for a specific database connection

func NewMigrator

func NewMigrator(db *sql.DB, driver string) *Migrator

NewMigrator creates a new Migrator instance

func (*Migrator) AddColumn added in v0.8.0

func (m *Migrator) AddColumn(table, column string, fn func(*ColumnBuilder)) error

AddColumn adds a column to an existing table

func (*Migrator) CreateIndex added in v0.8.0

func (m *Migrator) CreateIndex(name, table string, fn func(*IndexBuilder)) error

CreateIndex creates a new index using the fluent IndexBuilder API

func (*Migrator) CreateTable

func (m *Migrator) CreateTable(name string, fn func(*TableBuilder)) error

CreateTable creates a new database table using the fluent TableBuilder API

func (*Migrator) Down

func (m *Migrator) Down(steps int) error

Down rolls back the last N batches of migrations

func (*Migrator) DropColumn added in v0.8.0

func (m *Migrator) DropColumn(table, column string) error

DropColumn removes a column from a table Note: SQLite does not support DROP COLUMN prior to version 3.35.0

func (*Migrator) DropIndex added in v0.8.0

func (m *Migrator) DropIndex(name string, table ...string) error

DropIndex drops an index

func (*Migrator) DropTable

func (m *Migrator) DropTable(name string) error

DropTable drops a database table

func (*Migrator) Fresh

func (m *Migrator) Fresh() error

Fresh drops all tables and re-runs all migrations

func (*Migrator) Index added in v0.8.0

func (m *Migrator) Index(table string, columns ...string) error

Index is a shorthand for creating a simple index For more options, use CreateIndex with IndexBuilder

func (*Migrator) Raw

func (m *Migrator) Raw(sql string) error

Raw executes arbitrary SQL.

WARNING: This method executes raw SQL directly. The caller is responsible for preventing SQL injection by using parameterized queries with placeholder arguments. Never concatenate user input directly into the sql string.

func (*Migrator) SetMigrationsPath

func (m *Migrator) SetMigrationsPath(path string)

SetMigrationsPath sets the path to migration files

func (*Migrator) Status

func (m *Migrator) Status() ([]MigrationStatus, error)

Status returns the status of all migrations

func (*Migrator) UniqueIndex added in v0.8.0

func (m *Migrator) UniqueIndex(table string, columns ...string) error

UniqueIndex is a shorthand for creating a unique index

func (*Migrator) Up

func (m *Migrator) Up() error

Up runs all pending migrations

type TableBuilder

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

TableBuilder provides a fluent API for defining database tables

func (*TableBuilder) BigInteger added in v0.6.0

func (t *TableBuilder) BigInteger(name string) *TableBuilder

BigInteger adds a BIGINT column

func (*TableBuilder) Boolean

func (t *TableBuilder) Boolean(name string) *TableBuilder

Boolean adds a BOOLEAN column

func (*TableBuilder) Date added in v0.6.0

func (t *TableBuilder) Date(name string) *TableBuilder

Date adds a DATE column

func (*TableBuilder) Decimal added in v0.8.0

func (t *TableBuilder) Decimal(name string, precision, scale int) *TableBuilder

Decimal creates a numeric column with precision and scale e.g., Decimal("price", 10, 2) = numeric(10,2)

func (*TableBuilder) Default

func (t *TableBuilder) Default(value interface{}) *TableBuilder

Default sets a default value for the previous column

func (*TableBuilder) ID

func (t *TableBuilder) ID() *TableBuilder

ID adds an auto-increment primary key column named 'id'

func (*TableBuilder) IP added in v0.8.0

func (t *TableBuilder) IP(name string) *TableBuilder

IP creates a column for IP addresses (varchar 45, supports IPv4 and IPv6)

func (*TableBuilder) Integer

func (t *TableBuilder) Integer(name string) *TableBuilder

Integer adds an INTEGER column

func (*TableBuilder) JSON added in v0.8.0

func (t *TableBuilder) JSON(name string) *TableBuilder

JSON adds a JSON column For PostgreSQL: JSON type (text-based, validates JSON on insert) For MySQL: JSON type (binary storage) For SQLite: TEXT (no native JSON type)

func (*TableBuilder) JSONB added in v0.8.0

func (t *TableBuilder) JSONB(name string) *TableBuilder

JSONB adds a JSONB column (binary JSON) For PostgreSQL: JSONB type (binary storage, indexable, faster queries) For MySQL: JSON type (MySQL has no separate JSONB) For SQLite: TEXT (no native JSON type)

func (*TableBuilder) Nullable

func (t *TableBuilder) Nullable() *TableBuilder

Nullable allows NULL values for the previous column

func (*TableBuilder) Primary added in v0.8.0

func (t *TableBuilder) Primary() *TableBuilder

Primary makes the current column a primary key (for 1:1 relations where FK is the PK)

func (*TableBuilder) PrimaryKey added in v0.8.0

func (t *TableBuilder) PrimaryKey(columns ...string) *TableBuilder

PrimaryKey sets a composite primary key (for junction tables without auto-increment ID)

func (*TableBuilder) SoftDeletes added in v0.5.0

func (t *TableBuilder) SoftDeletes() *TableBuilder

SoftDeletes adds a deleted_at column for soft delete support

func (*TableBuilder) String

func (t *TableBuilder) String(name string, length ...int) *TableBuilder

String adds a VARCHAR column

func (*TableBuilder) Text added in v0.6.0

func (t *TableBuilder) Text(name string) *TableBuilder

Text adds a TEXT column (unlimited length)

func (*TableBuilder) Timestamp added in v0.6.0

func (t *TableBuilder) Timestamp(name string) *TableBuilder

Timestamp adds a single TIMESTAMP column

func (*TableBuilder) Timestamps

func (t *TableBuilder) Timestamps() *TableBuilder

Timestamps adds created_at and updated_at columns

func (*TableBuilder) ToSQL

func (t *TableBuilder) ToSQL() string

ToSQL generates driver-specific CREATE TABLE SQL

func (*TableBuilder) UUID added in v0.8.0

func (t *TableBuilder) UUID(name string) *TableBuilder

UUID adds a UUID column

func (*TableBuilder) UUIDPrimary added in v0.8.0

func (t *TableBuilder) UUIDPrimary() *TableBuilder

UUIDPrimary adds a UUID primary key column named 'id' with auto-generation For PostgreSQL: Uses gen_random_uuid() (built-in since v13) or uuid_generate_v4() (requires pgcrypto) For MySQL: Uses UUID() function For SQLite: Requires application-level UUID generation

func (*TableBuilder) Unique

func (t *TableBuilder) Unique() *TableBuilder

Unique marks the previous column as unique

Jump to

Keyboard shortcuts

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