refactor(数据库): 迁移持久层到 Ent 并清理 GORM
将仓储层/基础设施改为 Ent + 原生 SQL 执行路径,并移除 AutoMigrate 与 GORM 依赖。 重构内容包括: - 仓储层改用 Ent/SQL(含 usage_log/account 等复杂查询),统一错误映射 - 基础设施与 setup 初始化切换为 Ent + SQL migrations - 集成测试与 fixtures 迁移到 Ent 事务模型 - 清理遗留 GORM 模型/依赖,补充迁移与文档说明 - 增加根目录 Makefile 便于前后端编译 测试: - go test -tags unit ./... - go test -tags integration ./...
This commit is contained in:
@@ -4,27 +4,33 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/Wei-Shaw/sub2api/ent"
|
||||
"github.com/Wei-Shaw/sub2api/ent/setting"
|
||||
"github.com/Wei-Shaw/sub2api/internal/service"
|
||||
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
)
|
||||
|
||||
type settingRepository struct {
|
||||
db *gorm.DB
|
||||
client *ent.Client
|
||||
}
|
||||
|
||||
func NewSettingRepository(db *gorm.DB) service.SettingRepository {
|
||||
return &settingRepository{db: db}
|
||||
func NewSettingRepository(client *ent.Client) service.SettingRepository {
|
||||
return &settingRepository{client: client}
|
||||
}
|
||||
|
||||
func (r *settingRepository) Get(ctx context.Context, key string) (*service.Setting, error) {
|
||||
var m settingModel
|
||||
err := r.db.WithContext(ctx).Where("key = ?", key).First(&m).Error
|
||||
m, err := r.client.Setting.Query().Where(setting.KeyEQ(key)).Only(ctx)
|
||||
if err != nil {
|
||||
return nil, translatePersistenceError(err, service.ErrSettingNotFound, nil)
|
||||
if ent.IsNotFound(err) {
|
||||
return nil, service.ErrSettingNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return settingModelToService(&m), nil
|
||||
return &service.Setting{
|
||||
ID: m.ID,
|
||||
Key: m.Key,
|
||||
Value: m.Value,
|
||||
UpdatedAt: m.UpdatedAt,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r *settingRepository) GetValue(ctx context.Context, key string) (string, error) {
|
||||
@@ -36,21 +42,22 @@ func (r *settingRepository) GetValue(ctx context.Context, key string) (string, e
|
||||
}
|
||||
|
||||
func (r *settingRepository) Set(ctx context.Context, key, value string) error {
|
||||
m := &settingModel{
|
||||
Key: key,
|
||||
Value: value,
|
||||
UpdatedAt: time.Now(),
|
||||
}
|
||||
|
||||
return r.db.WithContext(ctx).Clauses(clause.OnConflict{
|
||||
Columns: []clause.Column{{Name: "key"}},
|
||||
DoUpdates: clause.AssignmentColumns([]string{"value", "updated_at"}),
|
||||
}).Create(m).Error
|
||||
now := time.Now()
|
||||
return r.client.Setting.
|
||||
Create().
|
||||
SetKey(key).
|
||||
SetValue(value).
|
||||
SetUpdatedAt(now).
|
||||
OnConflictColumns(setting.FieldKey).
|
||||
UpdateNewValues().
|
||||
Exec(ctx)
|
||||
}
|
||||
|
||||
func (r *settingRepository) GetMultiple(ctx context.Context, keys []string) (map[string]string, error) {
|
||||
var settings []settingModel
|
||||
err := r.db.WithContext(ctx).Where("key IN ?", keys).Find(&settings).Error
|
||||
if len(keys) == 0 {
|
||||
return map[string]string{}, nil
|
||||
}
|
||||
settings, err := r.client.Setting.Query().Where(setting.KeyIn(keys...)).All(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -63,27 +70,24 @@ func (r *settingRepository) GetMultiple(ctx context.Context, keys []string) (map
|
||||
}
|
||||
|
||||
func (r *settingRepository) SetMultiple(ctx context.Context, settings map[string]string) error {
|
||||
return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||
for key, value := range settings {
|
||||
m := &settingModel{
|
||||
Key: key,
|
||||
Value: value,
|
||||
UpdatedAt: time.Now(),
|
||||
}
|
||||
if err := tx.Clauses(clause.OnConflict{
|
||||
Columns: []clause.Column{{Name: "key"}},
|
||||
DoUpdates: clause.AssignmentColumns([]string{"value", "updated_at"}),
|
||||
}).Create(m).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(settings) == 0 {
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
builders := make([]*ent.SettingCreate, 0, len(settings))
|
||||
for key, value := range settings {
|
||||
builders = append(builders, r.client.Setting.Create().SetKey(key).SetValue(value).SetUpdatedAt(now))
|
||||
}
|
||||
return r.client.Setting.
|
||||
CreateBulk(builders...).
|
||||
OnConflictColumns(setting.FieldKey).
|
||||
UpdateNewValues().
|
||||
Exec(ctx)
|
||||
}
|
||||
|
||||
func (r *settingRepository) GetAll(ctx context.Context) (map[string]string, error) {
|
||||
var settings []settingModel
|
||||
err := r.db.WithContext(ctx).Find(&settings).Error
|
||||
settings, err := r.client.Setting.Query().All(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -96,26 +100,6 @@ func (r *settingRepository) GetAll(ctx context.Context) (map[string]string, erro
|
||||
}
|
||||
|
||||
func (r *settingRepository) Delete(ctx context.Context, key string) error {
|
||||
return r.db.WithContext(ctx).Where("key = ?", key).Delete(&settingModel{}).Error
|
||||
}
|
||||
|
||||
type settingModel struct {
|
||||
ID int64 `gorm:"primaryKey"`
|
||||
Key string `gorm:"uniqueIndex;size:100;not null"`
|
||||
Value string `gorm:"type:text;not null"`
|
||||
UpdatedAt time.Time `gorm:"not null"`
|
||||
}
|
||||
|
||||
func (settingModel) TableName() string { return "settings" }
|
||||
|
||||
func settingModelToService(m *settingModel) *service.Setting {
|
||||
if m == nil {
|
||||
return nil
|
||||
}
|
||||
return &service.Setting{
|
||||
ID: m.ID,
|
||||
Key: m.Key,
|
||||
Value: m.Value,
|
||||
UpdatedAt: m.UpdatedAt,
|
||||
}
|
||||
_, err := r.client.Setting.Delete().Where(setting.KeyEQ(key)).Exec(ctx)
|
||||
return err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user