183 lines
6.0 KiB
Go
183 lines
6.0 KiB
Go
package repository
|
||
|
||
import (
|
||
"time"
|
||
|
||
"metazone.cc/mce/internal/model"
|
||
"metazone.cc/mce/internal/service"
|
||
|
||
"gorm.io/gorm"
|
||
"gorm.io/gorm/clause"
|
||
)
|
||
|
||
// EnergyRepo 域能数据访问
|
||
type EnergyRepo struct {
|
||
db *gorm.DB
|
||
fundStore service.FundStore // 用于 Transaction 时创建事务范围的 FundStore
|
||
}
|
||
|
||
// NewEnergyRepo 构造函数
|
||
func NewEnergyRepo(db *gorm.DB) *EnergyRepo {
|
||
return &EnergyRepo{db: db}
|
||
}
|
||
|
||
// SetFundStore 设置公户仓储引用(用于跨仓库事务)
|
||
func (r *EnergyRepo) SetFundStore(s service.FundStore) {
|
||
r.fundStore = s
|
||
}
|
||
|
||
// WithTx 基于给定事务连接创建新的 EnergyRepo(确保事务内操作原子性)
|
||
func (r *EnergyRepo) WithTx(tx *gorm.DB) service.EnergyStore {
|
||
return &EnergyRepo{db: tx}
|
||
}
|
||
|
||
// Transaction 在事务内执行业务逻辑,自动管理 EnergyStore 和 FundStore 的事务范围
|
||
func (r *EnergyRepo) Transaction(fn func(txEnergy service.EnergyStore, txFund service.FundStore) error) error {
|
||
return r.db.Transaction(func(tx *gorm.DB) error {
|
||
txEnergy := r.WithTx(tx)
|
||
var txFund service.FundStore
|
||
if r.fundStore != nil {
|
||
txFund = r.fundStore.WithTx(tx)
|
||
}
|
||
return fn(txEnergy, txFund)
|
||
})
|
||
}
|
||
|
||
// FindUserByID 查找用户(获取能量余额等)
|
||
func (r *EnergyRepo) FindUserByID(userID uint) (*model.User, error) {
|
||
var user model.User
|
||
err := r.db.First(&user, userID).Error
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
return &user, nil
|
||
}
|
||
|
||
// FindPostByID 查找帖子
|
||
func (r *EnergyRepo) FindPostByID(postID uint) (*model.Post, error) {
|
||
var post model.Post
|
||
err := r.db.First(&post, postID).Error
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
return &post, nil
|
||
}
|
||
|
||
// AddEnergy 原子增减用户域能余额(amount 可为正负)
|
||
func (r *EnergyRepo) AddEnergy(userID uint, amount int) error {
|
||
return r.db.Model(&model.User{}).
|
||
Where("id = ?", userID).
|
||
UpdateColumn("energy", gorm.Expr("energy + ?", amount)).Error
|
||
}
|
||
|
||
// IncrPostEnergy 原子增减文章累计被赋能域能
|
||
func (r *EnergyRepo) IncrPostEnergy(postID uint, amount int) error {
|
||
return r.db.Model(&model.Post{}).
|
||
Where("id = ?", postID).
|
||
UpdateColumn("total_energy_received", gorm.Expr("total_energy_received + ?", amount)).Error
|
||
}
|
||
|
||
// CreateEnergyLog 创建域能流水
|
||
func (r *EnergyRepo) CreateEnergyLog(log *model.EnergyLog) error {
|
||
return r.db.Create(log).Error
|
||
}
|
||
|
||
// SumUserPostEnergy 统计某用户对某文章累计赋能总量(用于 ≤ 20 检查)
|
||
func (r *EnergyRepo) SumUserPostEnergy(userID, postID uint) (int, error) {
|
||
var total int
|
||
err := r.db.Model(&model.PostEnergizeLog{}).
|
||
Where("user_id = ? AND post_id = ?", userID, postID).
|
||
Select("COALESCE(SUM(amount), 0)").
|
||
Scan(&total).Error
|
||
return total, err
|
||
}
|
||
|
||
// CreateEnergizeLog 创建赋能记录
|
||
func (r *EnergyRepo) CreateEnergizeLog(log *model.PostEnergizeLog) error {
|
||
return r.db.Create(log).Error
|
||
}
|
||
|
||
// GetDailyEnergizeExp 获取用户当日通过赋能获得的经验值
|
||
// 无记录时返回 nil, nil(调用方当作 exp=0 处理)
|
||
func (r *EnergyRepo) GetDailyEnergizeExp(userID uint, date time.Time) (*model.DailyExpSummary, error) {
|
||
var summaries []model.DailyExpSummary
|
||
err := r.db.Where("user_id = ? AND date = ?", userID, date).Limit(1).Find(&summaries).Error
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if len(summaries) == 0 {
|
||
return nil, nil
|
||
}
|
||
return &summaries[0], nil
|
||
}
|
||
|
||
// UpsertDailyExp 创建或更新每日经验汇总
|
||
func (r *EnergyRepo) UpsertDailyExp(summary *model.DailyExpSummary) error {
|
||
return r.db.Clauses(clause.OnConflict{
|
||
Columns: []clause.Column{{Name: "user_id"}, {Name: "date"}},
|
||
DoUpdates: clause.AssignmentColumns([]string{"exp_earned", "updated_at"}),
|
||
}).Create(summary).Error
|
||
}
|
||
|
||
// AddDailyExp 原子增加每日赋能经验值
|
||
func (r *EnergyRepo) AddDailyExp(userID uint, date time.Time, delta int) error {
|
||
return r.db.Model(&model.DailyExpSummary{}).
|
||
Where("user_id = ? AND date = ?", userID, date).
|
||
UpdateColumn("exp_earned", gorm.Expr("exp_earned + ?", delta)).Error
|
||
}
|
||
|
||
// ListEnergyLogsByUser 分页查询用户域能流水(近 N 天)
|
||
func (r *EnergyRepo) ListEnergyLogsByUser(userID uint, days int, offset, limit int) ([]model.EnergyLog, error) {
|
||
var logs []model.EnergyLog
|
||
query := r.db.Where("user_id = ?", userID).Order("created_at DESC")
|
||
if days > 0 {
|
||
since := time.Now().AddDate(0, 0, -days)
|
||
query = query.Where("created_at >= ?", since)
|
||
}
|
||
err := query.Offset(offset).Limit(limit).Find(&logs).Error
|
||
return logs, err
|
||
}
|
||
|
||
// CountEnergyLogsByUser 统计用户域能流水总数
|
||
func (r *EnergyRepo) CountEnergyLogsByUser(userID uint, days int) (int64, error) {
|
||
var count int64
|
||
query := r.db.Model(&model.EnergyLog{}).Where("user_id = ?", userID)
|
||
if days > 0 {
|
||
since := time.Now().AddDate(0, 0, -days)
|
||
query = query.Where("created_at >= ?", since)
|
||
}
|
||
err := query.Count(&count).Error
|
||
return count, err
|
||
}
|
||
|
||
// ListAllEnergyLogs 查询全部域能流水(后台,支持筛选)
|
||
func (r *EnergyRepo) ListAllEnergyLogs(energyType string, offset, limit int) ([]model.EnergyLog, int64, error) {
|
||
query := r.db.Model(&model.EnergyLog{})
|
||
if energyType != "" {
|
||
query = query.Where("type = ?", energyType)
|
||
}
|
||
var total int64
|
||
if err := query.Count(&total).Error; err != nil {
|
||
return nil, 0, err
|
||
}
|
||
var logs []model.EnergyLog
|
||
err := query.Order("created_at DESC").Offset(offset).Limit(limit).Find(&logs).Error
|
||
return logs, total, err
|
||
}
|
||
|
||
// AggregateEnergyByAuthor 按日期聚合赋能值(作者所有文章在时间段内的赋能记录)
|
||
func (r *EnergyRepo) AggregateEnergyByAuthor(userID uint, since string) ([]service.TrendPoint, error) {
|
||
var results []service.TrendPoint
|
||
err := r.db.Table("post_energize_logs").
|
||
Select("TO_CHAR(post_energize_logs.created_at, 'YYYY-MM-DD') AS date, COALESCE(SUM(post_energize_logs.amount), 0) AS value").
|
||
Joins("JOIN posts ON posts.id = post_energize_logs.post_id").
|
||
Where("posts.user_id = ? AND post_energize_logs.created_at >= ?", userID, since).
|
||
Group("TO_CHAR(post_energize_logs.created_at, 'YYYY-MM-DD')").
|
||
Order("date ASC").
|
||
Scan(&results).Error
|
||
if results == nil {
|
||
results = []service.TrendPoint{}
|
||
}
|
||
return results, err
|
||
}
|