Files
silk/server-go/internal/database/db.go
T

125 lines
3.4 KiB
Go

package database
import (
"fmt"
"log/slog"
"silk-server-go/internal/config"
"silk-server-go/internal/model"
"gorm.io/driver/postgres"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)
var DB *gorm.DB
func Init(cfg *config.Config) error {
db, err := gorm.Open(postgres.Open(cfg.PG), &gorm.Config{
Logger: logger.Default.LogMode(logger.Warn),
})
if err != nil {
return err
}
DB = db
if err := RunMigrations(db); err != nil {
return err
}
if err := CheckSchemaVersion(db, CurrentSchemaVersion); err != nil {
return err
}
if cfg.AllowDevAutoMigrate && cfg.AppEnv != "production" {
if err := db.AutoMigrate(
&model.User{}, &model.Room{}, &model.Device{}, &model.Sensor{},
&model.Threshold{}, &model.Alarm{}, &model.Camera{}, &model.VideoClip{},
&model.AuditLog{}, &model.Telemetry{},
&model.Permission{}, &model.RolePermission{},
&model.Disease{}, &model.KnowledgeArticle{},
&model.InspectionRecord{},
&model.OutboxEvent{},
&model.Notification{},
&model.Tray{}, &model.Batch{}, &model.RearingRecord{},
&model.WechatBinding{},
&model.WeatherAlert{},
&model.LampTest{}, &model.LampTestStep{},
&model.Consumable{},
&model.Consultation{},
&model.SpectrumEntry{},
&model.TraceRecord{},
); err != nil {
return fmt.Errorf("开发环境 AutoMigrate 失败: %w", err)
}
slog.Warn("开发环境 AutoMigrate 已启用,SQL 迁移仍是生产 schema 事实来源")
}
// 初始化权限种子数据
seedPermissions(db)
// 初始化知识库种子数据
seedKnowledge(db)
slog.Info("数据库连接成功,版本化迁移完成", "schemaVersion", CurrentSchemaVersion)
return nil
}
// seedKnowledge 初始化知识库种子数据(幂等:按名称/类型+标题判重)
func seedKnowledge(db *gorm.DB) {
for _, d := range model.SeedDiseases {
var cnt int64
db.Model(&model.Disease{}).Where("name = ?", d.Name).Count(&cnt)
if cnt == 0 {
if err := db.Create(&d).Error; err != nil {
slog.Warn("写入病种种子失败", "name", d.Name, "err", err)
}
}
}
for _, a := range model.SeedKnowledgeArticles {
var cnt int64
db.Model(&model.KnowledgeArticle{}).Where("kind = ? AND title = ?", a.Kind, a.Title).Count(&cnt)
if cnt == 0 {
if err := db.Create(&a).Error; err != nil {
slog.Warn("写入知识文章种子失败", "title", a.Title, "err", err)
}
}
}
}
// seedPermissions 初始化权限和角色-权限映射种子数据(幂等)
func seedPermissions(db *gorm.DB) {
// 1. 写入权限定义(已存在则跳过)
codeToID := make(map[string]string)
for _, p := range model.AllPermissions {
var existing model.Permission
if db.Where("code = ?", p.Code).First(&existing).Error == nil {
codeToID[p.Code] = existing.ID
continue
}
desc := p.Description
perm := model.Permission{
Code: p.Code,
Name: p.Name,
Description: &desc,
}
if err := db.Create(&perm).Error; err != nil {
slog.Warn("写入权限种子失败", "code", p.Code, "err", err)
continue
}
codeToID[p.Code] = perm.ID
}
// 2. 写入角色-权限映射(已存在则跳过)
for role, codes := range model.RolePermissionMap {
for _, code := range codes {
pid, ok := codeToID[code]
if !ok {
continue
}
var cnt int64
db.Model(&model.RolePermission{}).
Where("role = ? AND permission_id = ?", role, pid).
Count(&cnt)
if cnt > 0 {
continue
}
db.Create(&model.RolePermission{Role: role, PermissionID: pid})
}
}
}