mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-06-14 18:11:18 +00:00
94 lines
2.4 KiB
Go
94 lines
2.4 KiB
Go
package upgrade
|
|
|
|
import (
|
|
"database/sql"
|
|
"errors"
|
|
"fmt"
|
|
)
|
|
|
|
// SchemaStatus represents the result of a schema compatibility check.
|
|
type SchemaStatus struct {
|
|
CurrentVersion uint
|
|
RequiredVersion uint
|
|
Dirty bool
|
|
Compatible bool
|
|
NeedsMigration bool
|
|
}
|
|
|
|
var (
|
|
ErrSchemaOutdated = errors.New("database schema is outdated")
|
|
ErrSchemaDirty = errors.New("database schema is dirty (failed migration)")
|
|
ErrSchemaAhead = errors.New("database schema is newer than this binary")
|
|
)
|
|
|
|
// CheckSchema queries the schema_migrations table and compares
|
|
// against RequiredSchemaVersion to determine compatibility.
|
|
func CheckSchema(db *sql.DB) (*SchemaStatus, error) {
|
|
var version uint
|
|
var dirty bool
|
|
|
|
err := db.QueryRow("SELECT version, dirty FROM schema_migrations LIMIT 1").Scan(&version, &dirty)
|
|
if err != nil {
|
|
if errors.Is(err, sql.ErrNoRows) {
|
|
return &SchemaStatus{
|
|
RequiredVersion: RequiredSchemaVersion,
|
|
NeedsMigration: true,
|
|
}, nil
|
|
}
|
|
// Table might not exist (fresh DB).
|
|
return &SchemaStatus{
|
|
RequiredVersion: RequiredSchemaVersion,
|
|
NeedsMigration: true,
|
|
}, nil
|
|
}
|
|
|
|
s := &SchemaStatus{
|
|
CurrentVersion: version,
|
|
RequiredVersion: RequiredSchemaVersion,
|
|
Dirty: dirty,
|
|
}
|
|
|
|
if dirty {
|
|
return s, nil
|
|
}
|
|
|
|
switch {
|
|
case version == RequiredSchemaVersion:
|
|
s.Compatible = true
|
|
case version < RequiredSchemaVersion:
|
|
s.NeedsMigration = true
|
|
default:
|
|
// Schema is ahead — binary is too old.
|
|
}
|
|
|
|
return s, nil
|
|
}
|
|
|
|
// FormatError returns a user-friendly error message for the given status.
|
|
func FormatError(s *SchemaStatus) string {
|
|
if s.Dirty {
|
|
return fmt.Sprintf(
|
|
"Database schema is in a dirty state (version %d).\n"+
|
|
"This usually means a migration failed partway.\n\n"+
|
|
" Fix: ./goclaw migrate force %d\n"+
|
|
" Then: ./goclaw upgrade\n",
|
|
s.CurrentVersion, s.CurrentVersion-1,
|
|
)
|
|
}
|
|
if s.CurrentVersion > s.RequiredVersion {
|
|
return fmt.Sprintf(
|
|
"Database schema (v%d) is newer than this binary (requires v%d).\n"+
|
|
"You may be running an older version of goclaw.\n\n"+
|
|
" Fix: upgrade your goclaw binary to the latest version.\n",
|
|
s.CurrentVersion, s.RequiredVersion,
|
|
)
|
|
}
|
|
return fmt.Sprintf(
|
|
"Database schema is outdated: current v%d, required v%d.\n\n"+
|
|
" Run: ./goclaw upgrade\n"+
|
|
" Or: ./goclaw migrate up (SQL-only, no data hooks)\n\n"+
|
|
" Docker/CI: set GOCLAW_AUTO_UPGRADE=true to upgrade automatically on startup.\n",
|
|
s.CurrentVersion, s.RequiredVersion,
|
|
)
|
|
}
|