Files
oci-portal/internal/database/database.go
T
Wang Defa dbba1f4905
CI / test (push) Successful in 30s
Release / release (push) Successful in 49s
发布 0.1.0:通知渠道、告警规则、令牌版本与安全加固
2026-07-10 17:38:34 +08:00

75 lines
2.4 KiB
Go

package database
import (
"fmt"
"log"
"os"
"time"
"github.com/glebarez/sqlite"
"gorm.io/driver/mysql"
"gorm.io/driver/postgres"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"oci-portal/internal/model"
)
// newDBLogger 构造脱敏的 GORM 日志器(S-08):SQL 一律参数化输出,
// 实参(密码哈希 / token / 任务 payload)不落日志;业务正常路径的
// record-not-found 不打 SQL。
func newDBLogger() logger.Interface {
return logger.New(log.New(os.Stdout, "\r\n", log.LstdFlags), logger.Config{
SlowThreshold: 200 * time.Millisecond,
LogLevel: logger.Warn,
IgnoreRecordNotFoundError: true,
ParameterizedQueries: true,
})
}
// Open 按驱动打开数据库并自动迁移全部模型。
// driver 取值 sqlite(默认)/mysql/postgres;sqlite 用 path,其余用 dsn。
func Open(driver, dsn, path string) (*gorm.DB, error) {
dialector, err := buildDialector(driver, dsn, path)
if err != nil {
return nil, err
}
db, err := gorm.Open(dialector, &gorm.Config{
Logger: newDBLogger(),
})
if err != nil {
return nil, fmt.Errorf("open %s database: %w", dialector.Name(), err)
}
if err := autoMigrate(db); err != nil {
return nil, fmt.Errorf("auto migrate: %w", err)
}
return db, nil
}
// buildDialector 把驱动名映射为 GORM dialector;三个驱动均为纯 Go,不引入 cgo。
// MySQL 设 DefaultStringSize=512:未标 size 的 string 建为 varchar(512),
// 避免 OCID / URL 类字段被默认 varchar(191) 截断(SQLite/PG 的 string 天然无长度上限)。
func buildDialector(driver, dsn, path string) (gorm.Dialector, error) {
switch driver {
case "", "sqlite":
return sqlite.Open(path), nil
case "mysql":
return mysql.New(mysql.Config{DSN: dsn, DefaultStringSize: 512}), nil
case "postgres":
return postgres.Open(dsn), nil
default:
return nil, fmt.Errorf("unsupported DB_DRIVER %q (sqlite/mysql/postgres)", driver)
}
}
func autoMigrate(db *gorm.DB) error {
return db.AutoMigrate(
&model.User{}, &model.UserIdentity{}, &model.OciConfig{}, &model.Task{}, &model.TaskLog{},
&model.CheckSnapshot{}, &model.CostSnapshot{},
&model.RegionCache{}, &model.CompartmentCache{}, &model.Setting{},
&model.SystemLog{}, &model.LogEvent{}, &model.AlertRule{}, &model.AlertRuleHit{}, &model.Proxy{},
&model.AiKey{}, &model.AiChannel{}, &model.AiModelCache{}, &model.AiCallLog{},
&model.AiContentLog{},
)
}