Files
relspecgo/docs/SCRIPTS_EXAMPLES.md
Hein adfe126758
Some checks failed
CI / Test (1.24) (push) Successful in -25m17s
CI / Test (1.25) (push) Successful in -25m15s
CI / Build (push) Successful in -25m45s
CI / Lint (push) Successful in -25m31s
Integration Tests / Integration Tests (push) Failing after -25m58s
Added a scripts execution ability
2025-12-31 00:44:14 +02:00

9.3 KiB

RelSpec Scripts Command - Quick Examples

Basic Workflow

1. Create migration directory structure

mkdir -p migrations

2. Create migration scripts

Both underscore and hyphen formats are supported. Examples below use underscore format, but you can also use: 1-001-create-users-table.sql

# Priority 1: Core schema
cat > migrations/1_001_create_users_table.sql << 'EOF'
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    username VARCHAR(100) NOT NULL UNIQUE,
    email VARCHAR(255) NOT NULL UNIQUE,
    password_hash VARCHAR(255) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_users_username ON users(username);
CREATE INDEX idx_users_email ON users(email);
EOF

cat > migrations/1_002_create_posts_table.sql << 'EOF'
CREATE TABLE posts (
    id SERIAL PRIMARY KEY,
    user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    title VARCHAR(200) NOT NULL,
    content TEXT,
    published BOOLEAN DEFAULT FALSE,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
EOF

# Priority 2: Additional indexes
cat > migrations/2_001_add_post_indexes.sql << 'EOF'
CREATE INDEX idx_posts_user_id ON posts(user_id);
CREATE INDEX idx_posts_published ON posts(published);
CREATE INDEX idx_posts_created_at ON posts(created_at);
EOF

# Priority 3: Seed data
cat > migrations/3_001_seed_admin_user.sql << 'EOF'
INSERT INTO users (username, email, password_hash)
VALUES ('admin', 'admin@example.com', 'hashed_password_here')
ON CONFLICT (username) DO NOTHING;
EOF

3. List scripts to verify order

relspec scripts list --dir migrations

Output:

=== SQL Scripts List ===
Directory: migrations

Found 4 script(s) in execution order:

No.  Priority   Sequence Name                           Lines
---- --------   -------- ------------------------------ -----
1    1          1        create_users_table             13
2    1          2        create_posts_table             11
3    2          1        add_post_indexes               4
4    3          1        seed_admin_user                4

4. Execute against database

relspec scripts execute \
  --dir migrations \
  --conn "postgres://myuser:mypass@localhost:5432/myapp"

Real-World Examples

Example 1: E-commerce Database Setup

# Directory structure
migrations/
├── 1_001_create_users.sql
├── 1_002_create_products.sql
├── 1_003_create_orders.sql
├── 1_004_create_order_items.sql
├── 2_001_add_indexes.sql
├── 2_002_add_constraints.sql
├── 3_001_seed_categories.sql
└── 3_002_seed_sample_products.sql

# Execute
relspec scripts execute \
  --dir migrations \
  --conn "postgres://ecommerce_user:pass@db.example.com:5432/ecommerce_prod?sslmode=require"

Example 2: Multi-Schema Database

# Organize by schema using subdirectories
migrations/
├── public/
│   ├── 1_001_create_users.sql
│   └── 1_002_create_sessions.sql
├── analytics/
│   ├── 1_001_create_events.sql
│   └── 2_001_create_views.sql
└── reporting/
    └── 1_001_create_reports.sql

# Execute (all schemas processed together)
relspec scripts execute \
  --dir migrations \
  --conn "postgres://localhost/multi_schema_db" \
  --schema public

Example 3: Development Environment Setup

# Create local development database
createdb myapp_dev

# Run migrations
relspec scripts execute \
  --dir ./db/migrations \
  --conn "postgres://localhost/myapp_dev?sslmode=disable"

# Verify
psql myapp_dev -c "\dt"

Example 4: CI/CD Pipeline

# .github/workflows/deploy.yml
- name: Run database migrations
  run: |
    relspec scripts list --dir migrations
    relspec scripts execute \
      --dir migrations \
      --conn "${{ secrets.DATABASE_URL }}"

Example 5: Docker Compose Integration

# docker-compose.yml
services:
  postgres:
    image: postgres:16
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: myuser
      POSTGRES_PASSWORD: mypass
    ports:
      - "5432:5432"

  migrate:
    image: relspec:latest
    depends_on:
      - postgres
    volumes:
      - ./migrations:/migrations
    command: >
      scripts execute
      --dir /migrations
      --conn "postgres://myuser:mypass@postgres:5432/myapp"
# Run migrations with docker-compose
docker-compose up -d postgres
sleep 5  # Wait for postgres to be ready
docker-compose run --rm migrate

Example 6: Incremental Feature Rollout

# Feature branch structure
migrations/
├── 1_100_user_profiles_schema.sql      # Feature: User profiles
├── 1_101_user_profiles_constraints.sql
├── 1_102_user_profiles_indexes.sql
├── 2_100_notifications_schema.sql      # Feature: Notifications
├── 2_101_notifications_constraints.sql
└── 2_102_notifications_indexes.sql

# Deploy just user profiles (Priority 1)
# Then later deploy notifications (Priority 2)

Example 7: Rollback Strategy (Manual)

# Forward migration
cat > migrations/1_001_add_column.sql << 'EOF'
ALTER TABLE users ADD COLUMN phone VARCHAR(20);
EOF

# Create manual rollback script (not auto-executed)
cat > rollbacks/1_001_remove_column.sql << 'EOF'
ALTER TABLE users DROP COLUMN phone;
EOF

# If needed, manually execute rollback
psql myapp -f rollbacks/1_001_remove_column.sql

Example 8: Complex Schema Changes

# migrations/1_001_alter_users_table.sql
BEGIN;

-- Add new column
ALTER TABLE users ADD COLUMN full_name VARCHAR(200);

-- Populate from existing data
UPDATE users SET full_name = username WHERE full_name IS NULL;

-- Make it required
ALTER TABLE users ALTER COLUMN full_name SET NOT NULL;

-- Add index
CREATE INDEX idx_users_full_name ON users(full_name);

COMMIT;

Execute:

relspec scripts execute \
  --dir migrations \
  --conn "postgres://localhost/myapp"

File Naming Format Examples

Underscore Format (Traditional)

migrations/
├── 1_001_create_users.sql
├── 1_002_create_posts.sql
├── 2_001_add_indexes.sql
└── 3_001_seed_data.sql

Hyphen Format (Alternative)

migrations/
├── 1-001-create-users.sql
├── 1-002-create-posts.sql
├── 10-10-create-newid.pgsql
└── 2-001-add-indexes.sql

Mixed Format (Both in Same Directory)

migrations/
├── 1_001_create_users.sql          # Underscore format
├── 1-002-create-posts.sql          # Hyphen format
├── 2_001_add_indexes.sql           # Underscore format
└── 10-10-special-migration.pgsql   # Hyphen format

Note: All three approaches work identically - use whichever naming style you prefer!

Common Patterns

Pattern 1: Schema → Indexes → Constraints → Data

1_xxx_*.sql   # Tables and basic structure
2_xxx_*.sql   # Indexes for performance
3_xxx_*.sql   # Foreign keys and constraints
4_xxx_*.sql   # Seed/reference data

Pattern 2: Feature-Based Organization

1_001_feature_auth_users.sql
1_002_feature_auth_sessions.sql
1_003_feature_auth_permissions.sql
2_001_feature_blog_posts.sql
2_002_feature_blog_comments.sql
3_001_feature_payments_transactions.sql

Pattern 3: Date-Based Versioning

1_20250130_create_users.sql
2_20250131_add_user_indexes.sql
3_20250201_create_posts.sql

Pattern 4: Environment-Specific Scripts

# Base migrations (all environments)
migrations/base/
├── 1_001_create_users.sql
├── 1_002_create_products.sql

# Development-specific
migrations/dev/
└── 9_001_seed_test_data.sql

# Production-specific
migrations/prod/
└── 9_001_seed_production_config.sql

# Execute different paths based on environment
ENV=dev
relspec scripts execute \
  --dir migrations/base \
  --conn "postgres://localhost/myapp_${ENV}"

relspec scripts execute \
  --dir migrations/${ENV} \
  --conn "postgres://localhost/myapp_${ENV}"

Troubleshooting

Check script order before execution

relspec scripts list --dir migrations

Test against local database first

# Create test database
createdb myapp_test

# Test migrations
relspec scripts execute \
  --dir migrations \
  --conn "postgres://localhost/myapp_test"

# Inspect results
psql myapp_test

# Cleanup
dropdb myapp_test

Validate SQL syntax

# Use PostgreSQL to check syntax without executing
for f in migrations/*.sql; do
  echo "Checking $f..."
  psql myapp -c "BEGIN; \i $f; ROLLBACK;" --single-transaction
done

Debug connection issues

# Test connection string
psql "postgres://user:pass@localhost:5432/myapp"

# If that works, use the same string for relspec
relspec scripts execute \
  --dir migrations \
  --conn "postgres://user:pass@localhost:5432/myapp"

Tips

  1. Always review execution order with list before running execute
  2. Test in development before running against production
  3. Use zero-padded sequences (001, 002, not 1, 2) for consistent sorting
  4. Keep scripts idempotent when possible (use IF NOT EXISTS, ON CONFLICT, etc.)
  5. Back up production before running migrations
  6. Use transactions for complex multi-statement migrations
  7. Document breaking changes with SQL comments in the migration files
  8. Version control everything - commit migrations with code changes