topfans/backend/services/userService/repository/fan_profile_repository.go
2026-04-07 22:29:48 +08:00

418 lines
10 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package repository
import (
"errors"
"strings"
"github.com/topfans/backend/pkg/database"
appErrors "github.com/topfans/backend/pkg/errors"
"github.com/topfans/backend/pkg/models"
"gorm.io/gorm"
)
// contains 检查字符串是否包含子串(不区分大小写)
func contains(s, substr string) bool {
return strings.Contains(strings.ToLower(s), strings.ToLower(substr))
}
// FanProfileRepository 粉丝档案Repository接口
type FanProfileRepository interface {
// Create 创建粉丝档案
Create(profile *models.FanProfile) error
// GetByUserAndStar 根据user_id + star_id查询
GetByUserAndStar(userID, starID int64) (*models.FanProfile, error)
// GetByUserID 查询用户的所有粉丝身份
GetByUserID(userID int64) ([]*models.FanProfile, error)
// ExistsByNickname 检查昵称是否已存在
ExistsByNickname(nickname string) (bool, error)
// CountByUserID 统计用户粉丝身份数量
CountByUserID(userID int64) (int64, error)
// Update 更新粉丝档案
Update(profile *models.FanProfile) error
// UpdateNickname 更新昵称
UpdateNickname(userID, starID int64, nickname string) error
// IncrementAssetsCount 增加资产计数
IncrementAssetsCount(userID, starID int64, delta int32) error
// DecrementAssetsCount 减少资产计数
DecrementAssetsCount(userID, starID int64, delta int32) error
// UpdateChainAddress 更新链地址
UpdateChainAddress(userID, starID int64, address string) error
// UpdateSocial 更新好友数量social字段
UpdateSocial(userID, starID int64, delta int32) (int32, error)
// UpdateCrystalBalance 更新水晶余额
UpdateCrystalBalance(userID, starID int64, delta int64) (int64, error)
// UpdateAvatar 更新头像
UpdateAvatar(userID, starID int64, avatarURL string) error
}
// fanProfileRepository 粉丝档案Repository实现
type fanProfileRepository struct {
db *gorm.DB
}
// NewFanProfileRepository 创建粉丝档案Repository实例
func NewFanProfileRepository() FanProfileRepository {
return &fanProfileRepository{
db: database.GetDB(),
}
}
// Create 创建粉丝档案
func (r *fanProfileRepository) Create(profile *models.FanProfile) error {
if profile == nil {
return errors.New("profile cannot be nil")
}
if profile.UserID <= 0 {
return errors.New("user_id must be greater than 0")
}
if profile.StarID <= 0 {
return errors.New("star_id must be greater than 0")
}
if err := r.db.Create(profile).Error; err != nil {
// 检查是否是唯一索引冲突
errStr := err.Error()
if contains(errStr, "duplicate") || contains(errStr, "unique") || contains(errStr, "violates unique constraint") {
// 区分不同的唯一约束冲突
if contains(errStr, "uk_fan_profiles_star_nickname") {
// star_id + nickname 唯一约束冲突
return appErrors.ErrNicknameAlreadyExists
} else if contains(errStr, "uk_fan_profiles_user_star") {
// user_id + star_id 唯一约束冲突
return appErrors.ErrFanProfileAlreadyExists
}
// 其他唯一约束冲突
return appErrors.ErrFanProfileAlreadyExists
}
return err
}
return nil
}
// GetByUserAndStar 根据user_id + star_id查询
func (r *fanProfileRepository) GetByUserAndStar(userID, starID int64) (*models.FanProfile, error) {
if userID <= 0 {
return nil, errors.New("user_id must be greater than 0")
}
if starID <= 0 {
return nil, errors.New("star_id must be greater than 0")
}
var profile models.FanProfile
if err := r.db.Where("user_id = ? AND star_id = ? AND is_active = ?", userID, starID, true).
First(&profile).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, appErrors.ErrFanProfileNotFound
}
return nil, err
}
return &profile, nil
}
// GetByUserID 查询用户的所有粉丝身份
func (r *fanProfileRepository) GetByUserID(userID int64) ([]*models.FanProfile, error) {
if userID <= 0 {
return nil, errors.New("user_id must be greater than 0")
}
var profiles []*models.FanProfile
if err := r.db.Where("user_id = ? AND is_active = ?", userID, true).
Order("created_at ASC").
Find(&profiles).Error; err != nil {
return nil, err
}
return profiles, nil
}
// CountByUserID 统计用户粉丝身份数量
func (r *fanProfileRepository) CountByUserID(userID int64) (int64, error) {
if userID <= 0 {
return 0, errors.New("user_id must be greater than 0")
}
var count int64
if err := r.db.Model(&models.FanProfile{}).
Where("user_id = ? AND is_active = ?", userID, true).
Count(&count).Error; err != nil {
return 0, err
}
return count, nil
}
// ExistsByNickname 检查昵称是否已存在
func (r *fanProfileRepository) ExistsByNickname(nickname string) (bool, error) {
if nickname == "" {
return false, errors.New("nickname cannot be empty")
}
var count int64
if err := r.db.Model(&models.FanProfile{}).
Where("nickname = ? AND is_active = ?", nickname, true).
Count(&count).Error; err != nil {
return false, err
}
return count > 0, nil
}
// Update 更新粉丝档案
func (r *fanProfileRepository) Update(profile *models.FanProfile) error {
if profile == nil {
return errors.New("profile cannot be nil")
}
if profile.ID == 0 {
return errors.New("profile id cannot be zero")
}
if err := r.db.Model(profile).Updates(profile).Error; err != nil {
return err
}
return nil
}
// UpdateNickname 更新昵称
func (r *fanProfileRepository) UpdateNickname(userID, starID int64, nickname string) error {
if userID <= 0 {
return errors.New("user_id must be greater than 0")
}
if starID <= 0 {
return errors.New("star_id must be greater than 0")
}
if nickname == "" {
return errors.New("nickname cannot be empty")
}
result := r.db.Model(&models.FanProfile{}).
Where("user_id = ? AND star_id = ?", userID, starID).
Update("nickname", nickname)
if result.Error != nil {
return result.Error
}
if result.RowsAffected == 0 {
return errors.New("fan profile not found")
}
return nil
}
// IncrementAssetsCount 增加资产计数
func (r *fanProfileRepository) IncrementAssetsCount(userID, starID int64, delta int32) error {
if userID <= 0 {
return errors.New("user_id must be greater than 0")
}
if starID <= 0 {
return errors.New("star_id must be greater than 0")
}
if delta < 0 {
return errors.New("delta must be greater than or equal to 0")
}
return r.db.Model(&models.FanProfile{}).
Where("user_id = ? AND star_id = ?", userID, starID).
UpdateColumn("assets_count", gorm.Expr("assets_count + ?", delta)).Error
}
// DecrementAssetsCount 减少资产计数
func (r *fanProfileRepository) DecrementAssetsCount(userID, starID int64, delta int32) error {
if userID <= 0 {
return errors.New("user_id must be greater than 0")
}
if starID <= 0 {
return errors.New("star_id must be greater than 0")
}
if delta < 0 {
return errors.New("delta must be greater than or equal to 0")
}
return r.db.Model(&models.FanProfile{}).
Where("user_id = ? AND star_id = ? AND assets_count >= ?", userID, starID, delta).
UpdateColumn("assets_count", gorm.Expr("assets_count - ?", delta)).Error
}
// UpdateChainAddress 更新链地址
func (r *fanProfileRepository) UpdateChainAddress(userID, starID int64, address string) error {
if userID <= 0 {
return errors.New("user_id must be greater than 0")
}
if starID <= 0 {
return errors.New("star_id must be greater than 0")
}
if address == "" {
return errors.New("chain address cannot be empty")
}
result := r.db.Model(&models.FanProfile{}).
Where("user_id = ? AND star_id = ?", userID, starID).
Update("chain_address", address)
if result.Error != nil {
return result.Error
}
if result.RowsAffected == 0 {
return errors.New("fan profile not found")
}
return nil
}
// UpdateSocial 更新好友数量social字段
// delta: 变化量,正数表示增加,负数表示减少
// 返回: 更新后的好友数量
func (r *fanProfileRepository) UpdateSocial(userID, starID int64, delta int32) (int32, error) {
if userID <= 0 {
return 0, errors.New("user_id must be greater than 0")
}
if starID <= 0 {
return 0, errors.New("star_id must be greater than 0")
}
// 使用事务确保原子性
var newSocial int32
err := r.db.Transaction(func(tx *gorm.DB) error {
// 先查询当前的 social 值
var profile models.FanProfile
if err := tx.Where("user_id = ? AND star_id = ?", userID, starID).
First(&profile).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return appErrors.ErrFanProfileNotFound
}
return err
}
// 计算新值
newSocial = profile.Social + delta
// 确保不会小于 0
if newSocial < 0 {
newSocial = 0
}
// 更新 social 字段
if err := tx.Model(&models.FanProfile{}).
Where("user_id = ? AND star_id = ?", userID, starID).
Update("social", newSocial).Error; err != nil {
return err
}
return nil
})
if err != nil {
return 0, err
}
return newSocial, nil
}
// UpdateCrystalBalance 更新水晶余额
// delta: 变化量,正数表示增加,负数表示减少
// 返回: 更新后的水晶余额
func (r *fanProfileRepository) UpdateCrystalBalance(userID, starID int64, delta int64) (int64, error) {
if userID <= 0 {
return 0, errors.New("user_id must be greater than 0")
}
if starID <= 0 {
return 0, errors.New("star_id must be greater than 0")
}
// 使用事务确保原子性
var newBalance int64
err := r.db.Transaction(func(tx *gorm.DB) error {
// 先查询当前的 crystal_balance 值
var profile models.FanProfile
if err := tx.Where("user_id = ? AND star_id = ?", userID, starID).
First(&profile).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return appErrors.ErrFanProfileNotFound
}
return err
}
// 计算新值
newBalance = profile.CrystalBalance + delta
// 确保不会小于 0
if newBalance < 0 {
newBalance = 0
}
// 更新 crystal_balance 字段
if err := tx.Model(&models.FanProfile{}).
Where("user_id = ? AND star_id = ?", userID, starID).
Update("crystal_balance", newBalance).Error; err != nil {
return err
}
return nil
})
if err != nil {
return 0, err
}
return newBalance, nil
}
// UpdateAvatar 更新头像
func (r *fanProfileRepository) UpdateAvatar(userID, starID int64, avatarURL string) error {
if userID <= 0 {
return errors.New("user_id must be greater than 0")
}
if starID <= 0 {
return errors.New("star_id must be greater than 0")
}
if avatarURL == "" {
return errors.New("avatar_url cannot be empty")
}
result := r.db.Model(&models.FanProfile{}).
Where("user_id = ? AND star_id = ?", userID, starID).
Update("avatar_url", avatarURL)
if result.Error != nil {
return result.Error
}
if result.RowsAffected == 0 {
return appErrors.ErrFanProfileNotFound
}
return nil
}