migrate

package
v0.9.0 Latest Latest
Warning

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

Go to latest
Published: Feb 8, 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

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