mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-03-21 23:22:34 +01:00
feat(db): add embedded auto-migrating schema system
Replace 4 independent schema management code paths (Docker shell script, setup wizard pg_restore, test helpers, manual psql) with a single migration runner embedded in the server binary. The new server/migrations/ package uses Go embed to bundle all SQL schemas. On startup, Migrate() creates a schema_version tracking table, detects existing databases (auto-marks baseline as applied), and runs pending migrations in transactions. Key changes: - Consolidated init.sql + 9.2-update + 33 patches into 0001_init.sql - Setup wizard simplified to single "Apply schema" checkbox - Test helpers use migrations.Migrate() instead of pg_restore - Docker no longer needs schema volume mounts or init script - Seed data (shops, events, gacha) embedded and applied via API - Future migrations just add 0002_*.sql files — no manual steps
This commit is contained in:
@@ -6,10 +6,6 @@ import (
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// clientModes returns all supported client version strings.
|
||||
@@ -373,71 +369,3 @@ func createDatabase(host string, port int, user, password, dbName string) error
|
||||
return nil
|
||||
}
|
||||
|
||||
// applyInitSchema runs pg_restore to load the init.sql (PostgreSQL custom dump format).
|
||||
func applyInitSchema(host string, port int, user, password, dbName string) error {
|
||||
pgRestore, err := exec.LookPath("pg_restore")
|
||||
if err != nil {
|
||||
return fmt.Errorf("pg_restore not found in PATH: %w (install PostgreSQL client tools)", err)
|
||||
}
|
||||
|
||||
schemaPath := filepath.Join("schemas", "init.sql")
|
||||
if _, err := os.Stat(schemaPath); err != nil {
|
||||
return fmt.Errorf("schema file not found: %s", schemaPath)
|
||||
}
|
||||
|
||||
cmd := exec.Command(pgRestore,
|
||||
"--host", host,
|
||||
"--port", fmt.Sprint(port),
|
||||
"--username", user,
|
||||
"--dbname", dbName,
|
||||
"--no-owner",
|
||||
"--no-privileges",
|
||||
schemaPath,
|
||||
)
|
||||
cmd.Env = append(os.Environ(), fmt.Sprintf("PGPASSWORD=%s", password))
|
||||
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf("pg_restore failed: %w\n%s", err, string(output))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// collectSQLFiles returns sorted .sql filenames from a directory.
|
||||
func collectSQLFiles(dir string) ([]string, error) {
|
||||
entries, err := os.ReadDir(dir)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("reading directory %s: %w", dir, err)
|
||||
}
|
||||
var files []string
|
||||
for _, e := range entries {
|
||||
if !e.IsDir() && strings.HasSuffix(e.Name(), ".sql") {
|
||||
files = append(files, e.Name())
|
||||
}
|
||||
}
|
||||
sort.Strings(files)
|
||||
return files, nil
|
||||
}
|
||||
|
||||
// applySQLFiles executes all .sql files in a directory in sorted order.
|
||||
func applySQLFiles(db *sql.DB, dir string) ([]string, error) {
|
||||
files, err := collectSQLFiles(dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var applied []string
|
||||
for _, f := range files {
|
||||
path := filepath.Join(dir, f)
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return applied, fmt.Errorf("reading %s: %w", f, err)
|
||||
}
|
||||
_, err = db.Exec(string(data))
|
||||
if err != nil {
|
||||
return applied, fmt.Errorf("executing %s: %w", f, err)
|
||||
}
|
||||
applied = append(applied, f)
|
||||
}
|
||||
return applied, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user