128 lines
3.5 KiB
Go
128 lines
3.5 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.DetectionTask{},
|
|
&model.Sample{},
|
|
&model.DiseaseEvent{},
|
|
&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})
|
|
}
|
|
}
|
|
}
|