Skip to content

migrate_en.md

maoxiaoyue edited this page May 14, 2026 · 1 revision

pkg/migrate -- Automatic Migration Diff Generation

Scans Go Model struct bun tags, compares against snapshot files, and automatically generates up/down SQL migrations.

Design Philosophy

After AI modifies Model structs, manually writing SQL migrations is error-prone. Migration Diff lets the framework automatically detect changes and generate correct SQL:

Model struct changes -> Reflect & scan bun tags -> Compare with last snapshot -> Generate SQL

Quick Start

1. Register Models

import "github.com/maoxiaoyue/hypgo/pkg/migrate"

type User struct {
    bun.BaseModel `bun:"table:users"`
    ID        int64     `bun:"id,pk,autoincrement"`
    Name      string    `bun:"name,notnull"`
    Email     string    `bun:"email,notnull,unique"`
    Bio       string    `bun:"bio,type:text"`
    CreatedAt time.Time `bun:"created_at,notnull,default:current_timestamp"`
}

registry := migrate.NewRegistry()
registry.Register((*User)(nil))

2. Scan & Diff

// Scan Models -> Extract TableSchema
tables := migrate.ScanModels(registry)

// Load last snapshot
snapshot, _ := migrate.LoadSnapshot(".hyp/schema_snapshot.json")

// Compare -> Generate ChangeSet
changes := migrate.Diff(tables, snapshot)

// Generate SQL
up, down := migrate.GenerateSQL(changes, "postgres")

fmt.Println(up)
// -> ALTER TABLE "users" ADD COLUMN "bio" TEXT;

3. Save

// Save new snapshot
migrate.SaveSnapshot(".hyp/schema_snapshot.json", tables)

// Get migration filenames
upFile, downFile := migrate.MigrationFiles("migrations/")
// -> migrations/20260326_200000_auto.up.sql
// -> migrations/20260326_200000_auto.down.sql

Complete Workflow

func generateMigration() {
    // 1. Register all Models
    registry := migrate.NewRegistry()
    registry.Register(
        (*models.User)(nil),
        (*models.Post)(nil),
        (*models.Comment)(nil),
    )

    // 2. Scan
    tables := migrate.ScanModels(registry)

    // 3. Diff
    snapshot, _ := migrate.LoadSnapshot(".hyp/schema_snapshot.json")
    changes := migrate.Diff(tables, snapshot)

    if len(changes) == 0 {
        fmt.Println("No changes detected")
        return
    }

    // 4. Display changes
    for _, c := range changes {
        fmt.Println(c.String())
    }

    // 5. Generate SQL
    up, down := migrate.GenerateSQL(changes, "postgres")

    // 6. Save migration files
    upFile, downFile := migrate.MigrationFiles("migrations/")
    os.WriteFile(upFile, []byte(up), 0644)
    os.WriteFile(downFile, []byte(down), 0644)

    // 7. Update snapshot
    migrate.SaveSnapshot(".hyp/schema_snapshot.json", tables)
}

Scanner -- bun Tag Parsing

The Scanner extracts field information from struct field bun:"..." tags:

bun tag Parsed Result
bun:"id,pk,autoincrement" PrimaryKey=true, AutoIncrement=true
bun:"name,notnull" NotNull=true
bun:"email,notnull,unique" NotNull=true, Unique=true
bun:"bio,type:text" SQLType="text"
bun:"score,default:0" Default="0"
bun:"table:users,alias:u" TableName="users" (BaseModel tag)
bun:"-" Skip this field

Diff -- Change Detection

Change Type Description
AddTable New table not in snapshot
DropTable Table removed from Models
AddColumn New column added to table
DropColumn Column removed from table
AlterColumn Column attribute changes (type, NotNull, Default, etc.)

SQL Generator -- Multi-Dialect Support

Feature PostgreSQL MySQL
Identifier quotes "users" `users`
Auto-increment PK int64 BIGSERIAL BIGINT AUTO_INCREMENT
Auto-increment PK int SERIAL INT AUTO_INCREMENT
Float DOUBLE PRECISION DOUBLE
Timestamp TIMESTAMPTZ DATETIME
ALTER NOT NULL SET/DROP NOT NULL MODIFY COLUMN

Go -> SQL Type Mapping

Go Type SQL Type
int64 BIGINT
int, int32 INTEGER
int16 SMALLINT
float64 DOUBLE PRECISION / DOUBLE
float32 REAL
bool BOOLEAN
string TEXT
time.Time TIMESTAMPTZ / DATETIME

If a type:xxx tag is present, the specified SQL type takes priority.

Snapshot Format

{
  "tables": {
    "users": {
      "name": "users",
      "columns": [
        {"name": "id", "go_type": "int64", "primary_key": true, "auto_increment": true},
        {"name": "name", "go_type": "string", "not_null": true},
        {"name": "email", "go_type": "string", "not_null": true, "unique": true}
      ]
    }
  }
}

Architecture

pkg/migrate/
├── registry.go     ModelRegistry -- Model registration
├── scanner.go      ScanModel() -- Reflect & extract bun tags -> TableSchema
├── snapshot.go     Snapshot read/write (JSON)
├── diff.go         Diff() -- Compare old/new schema -> ChangeSet
├── generator.go    GenerateSQL() -- ChangeSet -> SQL (pg/mysql)
└── migrate_test.go 22 unit tests

HypGo

繁體中文 | English


中文文件

設計文件

套件

AI 協作工具鏈

CLI 命令


English Docs

Design Docs

Packages

AI Collaboration Toolchain

CLI Commands

Clone this wiki locally