Files
boc/backend/db/migrate.go
T
Bernt (LandveX AI) 67a69ab073 feat(boc): v1.0 - Complete Business Operations Center
- Go backend API with full CRUD for all modules
- Rust analytics service with parallel processing
- C runtime with POSIX shared memory IPC
- PostgreSQL schema with 30+ tables
- Redis cache, Kafka event streaming
- WebSocket hub, automation engine
- PDF generation, Resend email integration
- JWT auth, multi-tenant
- Docker Compose deployment
- Nginx reverse proxy

Refs: BOC-001
2026-07-12 13:21:10 +00:00

94 lines
2.1 KiB
Go

package db
import (
"database/sql"
"fmt"
"os"
"path/filepath"
"sort"
"strings"
)
type Migration struct {
Version string
Name string
SQL string
}
func RunMigrations(db *sql.DB, migrationsDir string) error {
// Ensure migrations table exists
if _, err := db.Exec(`
CREATE TABLE IF NOT EXISTS boc_schema_migrations (
version TEXT PRIMARY KEY,
applied_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
)
`); err != nil {
return fmt.Errorf("create migrations table: %w", err)
}
// Read migration files
files, err := os.ReadDir(migrationsDir)
if err != nil {
return fmt.Errorf("read migrations dir: %w", err)
}
var migrations []Migration
for _, f := range files {
if f.IsDir() || !strings.HasSuffix(f.Name(), ".sql") {
continue
}
content, err := os.ReadFile(filepath.Join(migrationsDir, f.Name()))
if err != nil {
return fmt.Errorf("read migration %s: %w", f.Name(), err)
}
version := strings.Split(f.Name(), "_")[0]
migrations = append(migrations, Migration{
Version: version,
Name: f.Name(),
SQL: string(content),
})
}
// Sort by version
sort.Slice(migrations, func(i, j int) bool {
return migrations[i].Version < migrations[j].Version
})
// Apply migrations in transaction
for _, m := range migrations {
var applied bool
err := db.QueryRow("SELECT EXISTS(SELECT 1 FROM boc_schema_migrations WHERE version = $1)", m.Version).Scan(&applied)
if err != nil {
return fmt.Errorf("check migration %s: %w", m.Version, err)
}
if applied {
continue
}
tx, err := db.Begin()
if err != nil {
return fmt.Errorf("begin transaction: %w", err)
}
if _, err := tx.Exec(m.SQL); err != nil {
tx.Rollback()
return fmt.Errorf("apply migration %s: %w", m.Name, err)
}
if _, err := tx.Exec("INSERT INTO boc_schema_migrations (version) VALUES ($1)", m.Version); err != nil {
tx.Rollback()
return fmt.Errorf("record migration %s: %w", m.Name, err)
}
if err := tx.Commit(); err != nil {
return fmt.Errorf("commit migration %s: %w", m.Name, err)
}
fmt.Printf("✅ Applied migration: %s\n", m.Name)
}
return nil
}