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
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user