93 lines
2.9 KiB
Go
93 lines
2.9 KiB
Go
package repository
|
||
|
||
import (
|
||
"context"
|
||
|
||
"fashionapi/internal/model"
|
||
|
||
"gorm.io/gorm"
|
||
"gorm.io/gorm/clause"
|
||
)
|
||
|
||
// FavoriteRepository 收藏数据访问接口。
|
||
//
|
||
// kind 用于区分收藏粒度(gallery=整篇图集 / image=单张图片);传空表示不限粒度。
|
||
type FavoriteRepository interface {
|
||
// ListPaged 分页取某用户收藏,按收藏时间倒序。
|
||
ListPaged(ctx context.Context, userID uint32, page, perPage int, kind string) ([]model.Favorite, error)
|
||
// CountByUser 取某用户收藏总数(分页用)。
|
||
CountByUser(ctx context.Context, userID uint32, kind string) (int64, error)
|
||
// Add 新增收藏;同用户同 target 已存在时幂等忽略(ON DUPLICATE KEY DO NOTHING)。
|
||
Add(ctx context.Context, f *model.Favorite) error
|
||
// Remove 删除某用户对某个 target 的收藏。
|
||
Remove(ctx context.Context, userID uint32, targetUID string) error
|
||
// FilterExisting 返回在给定 ids 中、且属于该用户已收藏的 target_uid 子集(列表页打勾用)。
|
||
FilterExisting(ctx context.Context, userID uint32, ids []string) ([]string, error)
|
||
}
|
||
|
||
type favoriteRepository struct {
|
||
db *gorm.DB
|
||
}
|
||
|
||
// NewFavoriteRepository 创建收藏仓储。
|
||
func NewFavoriteRepository(db *gorm.DB) FavoriteRepository {
|
||
return &favoriteRepository{db: db}
|
||
}
|
||
|
||
func (r *favoriteRepository) ListPaged(ctx context.Context, userID uint32, page, perPage int, kind string) ([]model.Favorite, error) {
|
||
var rows []model.Favorite
|
||
offset := (page - 1) * perPage
|
||
if offset < 0 {
|
||
offset = 0
|
||
}
|
||
q := r.db.WithContext(ctx).Where("user_id = ?", userID)
|
||
if kind != "" {
|
||
q = q.Where("kind = ?", kind)
|
||
}
|
||
err := q.
|
||
Order("created_at DESC").
|
||
Offset(offset).
|
||
Limit(perPage).
|
||
Find(&rows).Error
|
||
return rows, err
|
||
}
|
||
|
||
func (r *favoriteRepository) CountByUser(ctx context.Context, userID uint32, kind string) (int64, error) {
|
||
var n int64
|
||
q := r.db.WithContext(ctx).
|
||
Model(&model.Favorite{}).
|
||
Where("user_id = ?", userID)
|
||
if kind != "" {
|
||
q = q.Where("kind = ?", kind)
|
||
}
|
||
err := q.Count(&n).Error
|
||
return n, err
|
||
}
|
||
|
||
func (r *favoriteRepository) Add(ctx context.Context, f *model.Favorite) error {
|
||
// 复合唯一索引 (user_id, target_uid) 保证不重复;冲突时忽略而非报错,使接口天然幂等。
|
||
return r.db.WithContext(ctx).
|
||
Clauses(clause.OnConflict{
|
||
Columns: []clause.Column{{Name: "user_id"}, {Name: "target_uid"}},
|
||
DoNothing: true,
|
||
}).Create(f).Error
|
||
}
|
||
|
||
func (r *favoriteRepository) Remove(ctx context.Context, userID uint32, targetUID string) error {
|
||
return r.db.WithContext(ctx).
|
||
Where("user_id = ? AND target_uid = ?", userID, targetUID).
|
||
Delete(&model.Favorite{}).Error
|
||
}
|
||
|
||
func (r *favoriteRepository) FilterExisting(ctx context.Context, userID uint32, ids []string) ([]string, error) {
|
||
if len(ids) == 0 {
|
||
return []string{}, nil
|
||
}
|
||
var uids []string
|
||
err := r.db.WithContext(ctx).
|
||
Model(&model.Favorite{}).
|
||
Where("user_id = ? AND target_uid IN ?", userID, ids).
|
||
Pluck("target_uid", &uids).Error
|
||
return uids, err
|
||
}
|