- ReactionStore/FollowStore/EnergyStore/FavoriteStore 接口新增 Transaction 方法 - EnergyStore.Transaction 支持跨仓库事务(EnergyStore + FundStore) - ReactionRepo/FollowRepo/FavoriteRepo/EnergyRepo 实现 Transaction 方法 - ReactionRepo 新增 GetPostLikesCount 方法,消除 Service 直查 DB - ReactionService/FollowService/FavoriteService/EnergyService 移除 db 字段 - EnergyRepo 通过 SetFundStore 注入 FundStore 用于跨仓库事务 - 更新 deps_extra.go 构造函数调用
165 lines
5.4 KiB
Go
165 lines
5.4 KiB
Go
package repository
|
||
|
||
import (
|
||
"metazone.cc/metalab/internal/model"
|
||
"metazone.cc/metalab/internal/service"
|
||
|
||
"gorm.io/gorm"
|
||
)
|
||
|
||
// FavoriteRepo 收藏夹数据访问
|
||
type FavoriteRepo struct {
|
||
db *gorm.DB
|
||
}
|
||
|
||
// NewFavoriteRepo 构造函数
|
||
func NewFavoriteRepo(db *gorm.DB) *FavoriteRepo {
|
||
return &FavoriteRepo{db: db}
|
||
}
|
||
|
||
// WithTx 基于事务连接创建 FavoriteRepo
|
||
func (r *FavoriteRepo) WithTx(tx *gorm.DB) service.FavoriteStore {
|
||
return &FavoriteRepo{db: tx}
|
||
}
|
||
|
||
// Transaction 在事务内执行业务逻辑
|
||
func (r *FavoriteRepo) Transaction(fn func(tx service.FavoriteStore) error) error {
|
||
return r.db.Transaction(func(tx *gorm.DB) error {
|
||
return fn(r.WithTx(tx))
|
||
})
|
||
}
|
||
|
||
// ======================== Folder CRUD ========================
|
||
|
||
// CreateFolder 创建收藏夹
|
||
func (r *FavoriteRepo) CreateFolder(folder *model.Folder) error {
|
||
return r.db.Create(folder).Error
|
||
}
|
||
|
||
// FindFolderByID 按 ID 查找收藏夹
|
||
func (r *FavoriteRepo) FindFolderByID(id uint) (*model.Folder, error) {
|
||
var f model.Folder
|
||
err := r.db.First(&f, id).Error
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
return &f, nil
|
||
}
|
||
|
||
// ListFoldersByUser 列用户的收藏夹(附项目数)
|
||
func (r *FavoriteRepo) ListFoldersByUser(userID uint) ([]model.Folder, error) {
|
||
var folders []model.Folder
|
||
err := r.db.Table("folders").
|
||
Select("folders.*, COUNT(folder_items.id) AS item_count").
|
||
Joins("LEFT JOIN folder_items ON folder_items.folder_id = folders.id").
|
||
Where("folders.user_id = ?", userID).
|
||
Group("folders.id").
|
||
Order("folders.is_default DESC, folders.created_at ASC").
|
||
Scan(&folders).Error
|
||
return folders, err
|
||
}
|
||
|
||
// UpdateFolder 更新收藏夹
|
||
func (r *FavoriteRepo) UpdateFolder(folder *model.Folder) error {
|
||
return r.db.Save(folder).Error
|
||
}
|
||
|
||
// DeleteFolder 删除收藏夹
|
||
func (r *FavoriteRepo) DeleteFolder(id uint) error {
|
||
return r.db.Where("id = ?", id).Delete(&model.Folder{}).Error
|
||
}
|
||
|
||
// DeleteItemsByFolder 删除收藏夹内所有记录
|
||
func (r *FavoriteRepo) DeleteItemsByFolder(folderID uint) error {
|
||
return r.db.Where("folder_id = ?", folderID).Delete(&model.FolderItem{}).Error
|
||
}
|
||
|
||
// CountByNameAndUser 检查同用户下名称是否重复(排除自身)
|
||
func (r *FavoriteRepo) CountByNameAndUser(userID uint, name string, excludeID uint) (int64, error) {
|
||
var count int64
|
||
q := r.db.Model(&model.Folder{}).Where("user_id = ? AND name = ?", userID, name)
|
||
if excludeID > 0 {
|
||
q = q.Where("id != ?", excludeID)
|
||
}
|
||
err := q.Count(&count).Error
|
||
return count, err
|
||
}
|
||
|
||
// HasDefaultFolder 检查用户是否有默认收藏夹
|
||
func (r *FavoriteRepo) HasDefaultFolder(userID uint) (bool, error) {
|
||
var count int64
|
||
err := r.db.Model(&model.Folder{}).Where("user_id = ? AND is_default = ?", userID, true).Count(&count).Error
|
||
return count > 0, err
|
||
}
|
||
|
||
// ======================== FolderItem CRUD ========================
|
||
|
||
// CreateItem 添加收藏
|
||
func (r *FavoriteRepo) CreateItem(item *model.FolderItem) error {
|
||
return r.db.Create(item).Error
|
||
}
|
||
|
||
// DeleteItem 取消收藏
|
||
func (r *FavoriteRepo) DeleteItem(folderID, postID uint) error {
|
||
return r.db.Where("folder_id = ? AND post_id = ?", folderID, postID).Delete(&model.FolderItem{}).Error
|
||
}
|
||
|
||
// FindItemByUserAndPost 查找用户对某文章的收藏记录
|
||
func (r *FavoriteRepo) FindItemByUserAndPost(userID, postID uint) (*model.FolderItem, error) {
|
||
var item model.FolderItem
|
||
err := r.db.Where("user_id = ? AND post_id = ?", userID, postID).First(&item).Error
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
return &item, nil
|
||
}
|
||
|
||
// ListItemsByFolder 列收藏夹内文章(分页,JOIN posts 获取标题)
|
||
func (r *FavoriteRepo) ListItemsByFolder(folderID uint, offset, limit int) ([]model.FolderItem, int64, error) {
|
||
var total int64
|
||
if err := r.db.Model(&model.FolderItem{}).Where("folder_id = ?", folderID).Count(&total).Error; err != nil {
|
||
return nil, 0, err
|
||
}
|
||
|
||
var items []model.FolderItem
|
||
err := r.db.Table("folder_items").
|
||
Select("folder_items.*, posts.title AS post_title").
|
||
Joins("LEFT JOIN posts ON posts.id = folder_items.post_id").
|
||
Where("folder_items.folder_id = ?", folderID).
|
||
Order("folder_items.created_at DESC").
|
||
Offset(offset).Limit(limit).
|
||
Scan(&items).Error
|
||
return items, total, err
|
||
}
|
||
|
||
// CountItemsByFolder 统计收藏夹内文章数
|
||
func (r *FavoriteRepo) CountItemsByFolder(folderID uint) (int64, error) {
|
||
var count int64
|
||
err := r.db.Model(&model.FolderItem{}).Where("folder_id = ?", folderID).Count(&count).Error
|
||
return count, err
|
||
}
|
||
|
||
// ======================== Post 计数器 ========================
|
||
|
||
// IncrPostFavoritesCount 原子更新文章收藏数
|
||
func (r *FavoriteRepo) IncrPostFavoritesCount(postID uint, delta int) error {
|
||
return r.db.Model(&model.Post{}).
|
||
Where("id = ?", postID).
|
||
UpdateColumn("favorites_count", gorm.Expr("favorites_count + ?", delta)).Error
|
||
}
|
||
|
||
// ======================== 趋势聚合 ========================
|
||
|
||
// AggregateFavoritesByAuthor 按日期聚合收藏量(对于某用户的文章)
|
||
func (r *FavoriteRepo) AggregateFavoritesByAuthor(userID uint, since string) ([]service.TrendPoint, error) {
|
||
var results []service.TrendPoint
|
||
err := r.db.Table("folder_items").
|
||
Select("TO_CHAR(folder_items.created_at, 'YYYY-MM-DD') AS date, COUNT(*) AS value").
|
||
Joins("JOIN posts ON posts.id = folder_items.post_id").
|
||
Where("posts.user_id = ? AND folder_items.created_at >= ?", userID, since).
|
||
Group("TO_CHAR(folder_items.created_at, 'YYYY-MM-DD')").
|
||
Order("date ASC").
|
||
Scan(&results).Error
|
||
return results, err
|
||
}
|