create-migration

📁 sjtw/tarkov-build-optimiser 📅 2 days ago
1
总安装量
1
周安装量
#43611
全站排名
安装命令
npx skills add https://github.com/sjtw/tarkov-build-optimiser --skill create-migration

Agent 安装分布

amp 1
opencode 1
kimi-cli 1
codex 1
github-copilot 1
antigravity 1

Skill 文档

Create Migration Skill

Use this skill when making database schema changes.


Scope

  • Adding new tables
  • Modifying columns or constraints
  • Creating or dropping indexes
  • Any DDL operation

Creating a New Migration

Step 1: Generate Migration File

task migrate:create -- your_migration_name

Naming conventions:

  • Use snake_case
  • Be descriptive but concise
  • Use prefixes: add_, create_, drop_, modify_, update_

Examples:

task migrate:create -- add_weapon_stats_table
task migrate:create -- add_index_on_trader_offers
task migrate:create -- modify_item_properties_column

This creates a timestamped file in migrations/:

migrations/YYYYMMDDHHMMSS_your_migration_name.go

Step 2: Write the Migration

The generated file will have this structure:

package migrations

import (
    "database/sql"
    "github.com/pressly/goose/v3"
)

func init() {
    goose.AddMigrationContext(upYourMigrationName, downYourMigrationName)
}

func upYourMigrationName(ctx context.Context, tx *sql.Tx) error {
    // This code is executed when the migration is applied.
    return nil
}

func downYourMigrationName(ctx context.Context, tx *sql.Tx) error {
    // This code is executed when the migration is rolled back.
    return nil
}

In the up function:

  • Write SQL to apply the change
  • Use tx.ExecContext(ctx, "SQL HERE")

In the down function:

  • Write SQL to reverse the change
  • Make it possible to rollback safely

Example:

func upAddWeaponStatsTable(ctx context.Context, tx *sql.Tx) error {
    _, err := tx.ExecContext(ctx, `
        CREATE TABLE weapon_stats (
            id SERIAL PRIMARY KEY,
            weapon_id VARCHAR(255) NOT NULL,
            recoil_vertical INT NOT NULL,
            recoil_horizontal INT NOT NULL,
            ergonomics INT NOT NULL,
            created_at TIMESTAMP DEFAULT NOW()
        );
        CREATE INDEX idx_weapon_stats_weapon_id ON weapon_stats(weapon_id);
    `)
    return err
}

func downAddWeaponStatsTable(ctx context.Context, tx *sql.Tx) error {
    _, err := tx.ExecContext(ctx, `DROP TABLE IF EXISTS weapon_stats;`)
    return err
}

Step 3: Apply the Migration

# Recommended for DevContainer (assuming database is running)
task migrate:up

# Use if database needs to be started via Docker Compose
task migrate:up:docker

What it does:

  1. migrate:up: Builds the migration binary and runs migrations against the existing database.
  2. migrate:up:docker: Ensures PostgreSQL is running via Docker Compose, then applies migrations.

Verify migration applied:

docker compose exec postgres psql -U $POSTGRES_USER -d $POSTGRES_DB -c "\dt"

Step 4: Test the Migration

Test the migration works:

# Apply migration
task migrate:up

# Run integration tests
task test:integration

Test rollback works:

# Rollback the migration
task migrate:down

# Verify database is in previous state
docker compose exec postgres psql -U $POSTGRES_USER -d $POSTGRES_DB -c "\dt"

# Reapply
task migrate:up

Migration Best Practices

DO:

  • ✅ Keep migrations small and focused (one logical change per migration)
  • ✅ Provide a down function that reverses the change when feasible
  • ✅ Test both up and down migrations before merging
  • ✅ goose wraps migrations in transactions automatically
  • ✅ Add indexes for foreign keys and frequently queried columns
  • ✅ Use IF NOT EXISTS / IF EXISTS for safety when appropriate

DON’T:

  • ❌ Modify existing migration files after they’re merged (create a new migration instead)
  • ❌ Use application code in migrations (keep them SQL-only)
  • ❌ Make data changes that can’t be reversed in down
  • ❌ Forget to handle the error return value
  • ❌ Create huge migrations that change many things at once

Common Migration Patterns

Add a Table

func upCreateTableName(ctx context.Context, tx *sql.Tx) error {
    _, err := tx.ExecContext(ctx, `
        CREATE TABLE table_name (
            id SERIAL PRIMARY KEY,
            field1 VARCHAR(255) NOT NULL,
            field2 INTEGER DEFAULT 0,
            created_at TIMESTAMP DEFAULT NOW()
        );
    `)
    return err
}

func downCreateTableName(ctx context.Context, tx *sql.Tx) error {
    _, err := tx.ExecContext(ctx, `DROP TABLE IF EXISTS table_name;`)
    return err
}

Add a Column

func upAddColumnToTable(ctx context.Context, tx *sql.Tx) error {
    _, err := tx.ExecContext(ctx, `
        ALTER TABLE table_name 
        ADD COLUMN new_column VARCHAR(255);
    `)
    return err
}

func downAddColumnToTable(ctx context.Context, tx *sql.Tx) error {
    _, err := tx.ExecContext(ctx, `
        ALTER TABLE table_name 
        DROP COLUMN IF EXISTS new_column;
    `)
    return err
}

Add an Index

func upAddIndexOnTable(ctx context.Context, tx *sql.Tx) error {
    _, err := tx.ExecContext(ctx, `
        CREATE INDEX idx_table_column ON table_name(column_name);
    `)
    return err
}

func downAddIndexOnTable(ctx context.Context, tx *sql.Tx) error {
    _, err := tx.ExecContext(ctx, `
        DROP INDEX IF EXISTS idx_table_column;
    `)
    return err
}

Troubleshooting

Migration fails with “docker”: executable file not found:

  • This happens if you try to run task migrate:up:docker in an environment without Docker (like a devcontainer).
  • Use task migrate:up instead if your database is already running.

Migration fails to apply:

  • Check SQL syntax
  • Verify table/column names exist
  • Check if migration was already partially applied
  • View database logs: docker compose logs postgres

Can’t rollback migration:

  • Check if down function properly reverses the up function
  • Some operations (like dropping columns with data) might need manual intervention
  • Consider if rollback is safe with existing data

Migration applied but tests fail:

  • Verify the schema change matches your model expectations
  • Check if indexes are created correctly
  • Ensure foreign key constraints are correct

“goose: no migrations to run” but migration file exists:

  • Ensure the file is in migrations/ directory
  • Check the filename format: YYYYMMDDHHMMSS_name.go
  • Verify the file has package migrations at the top
  • Rebuild: task migrate:build

Viewing Migration Status

# See applied migrations in database
docker compose exec postgres psql -U $POSTGRES_USER -d $POSTGRES_DB -c "SELECT * FROM goose_db_version;"

# See migration files
ls -la migrations/

CI/CD

In CI, migrations run via:

task migrate:ci

This skips the compose:postgres:up dependency (database already running in CI).