backend/pkg/post/repository/like.go

229 lines
5.5 KiB
Go

package repository
import (
"context"
"fmt"
"backend/pkg/library/cassandra"
"backend/pkg/post/domain/entity"
domainRepo "backend/pkg/post/domain/repository"
"github.com/gocql/gocql"
)
// LikeRepositoryParam 定義 LikeRepository 的初始化參數
type LikeRepositoryParam struct {
DB *cassandra.DB
Keyspace string
}
// LikeRepository 實作 domain repository 介面
type LikeRepository struct {
repo cassandra.Repository[*entity.Like]
db *cassandra.DB
}
// NewLikeRepository 創建新的 LikeRepository
func NewLikeRepository(param LikeRepositoryParam) domainRepo.LikeRepository {
repo, err := cassandra.NewRepository[*entity.Like](param.DB, param.Keyspace)
if err != nil {
panic(fmt.Sprintf("failed to create like repository: %v", err))
}
return &LikeRepository{
repo: repo,
db: param.DB,
}
}
// Insert 插入單筆按讚
func (r *LikeRepository) Insert(ctx context.Context, data *entity.Like) error {
if data == nil {
return ErrInvalidInput
}
// 驗證資料
if err := data.Validate(); err != nil {
return fmt.Errorf("%w: %v", ErrInvalidInput, err)
}
// 設置時間戳
data.SetTimestamps()
// 如果是新按讚,生成 ID
if data.IsNew() {
data.ID = gocql.TimeUUID()
}
return r.repo.Insert(ctx, data)
}
// FindOne 根據 ID 查詢單筆按讚
func (r *LikeRepository) FindOne(ctx context.Context, id gocql.UUID) (*entity.Like, error) {
var zeroUUID gocql.UUID
if id == zeroUUID {
return nil, ErrInvalidInput
}
like, err := r.repo.Get(ctx, id)
if err != nil {
if cassandra.IsNotFound(err) {
return nil, ErrNotFound
}
return nil, fmt.Errorf("failed to find like: %w", err)
}
return like, nil
}
// Delete 刪除按讚
func (r *LikeRepository) Delete(ctx context.Context, id gocql.UUID) error {
var zeroUUID gocql.UUID
if id == zeroUUID {
return ErrInvalidInput
}
return r.repo.Delete(ctx, id)
}
// FindByTargetID 根據目標 ID 查詢按讚列表
func (r *LikeRepository) FindByTargetID(ctx context.Context, targetID gocql.UUID, targetType string) ([]*entity.Like, error) {
var zeroUUID gocql.UUID
if targetID == zeroUUID {
return nil, ErrInvalidInput
}
if targetType != "post" && targetType != "comment" {
return nil, ErrInvalidInput
}
// 構建查詢
query := r.repo.Query().
Where(cassandra.Eq("target_id", targetID)).
Where(cassandra.Eq("target_type", targetType)).
OrderBy("created_at", cassandra.DESC)
var likes []*entity.Like
if err := query.Scan(ctx, &likes); err != nil {
return nil, fmt.Errorf("failed to query likes: %w", err)
}
return likes, nil
}
// FindByUserUID 根據用戶 UID 查詢按讚列表
func (r *LikeRepository) FindByUserUID(ctx context.Context, userUID string, params *domainRepo.LikeQueryParams) ([]*entity.Like, int64, error) {
if userUID == "" {
return nil, 0, ErrInvalidInput
}
query := r.repo.Query().Where(cassandra.Eq("user_uid", userUID))
// 添加目標類型過濾
if params != nil && params.TargetType != nil {
query = query.Where(cassandra.Eq("target_type", *params.TargetType))
}
// 添加目標 ID 過濾
if params != nil && params.TargetID != nil {
query = query.Where(cassandra.Eq("target_id", *params.TargetID))
}
// 添加排序
orderBy := "created_at"
if params != nil && params.OrderBy != "" {
orderBy = params.OrderBy
}
order := cassandra.DESC
if params != nil && params.OrderDirection == "ASC" {
order = cassandra.ASC
}
query = query.OrderBy(orderBy, order)
// 添加分頁
pageSize := int64(20)
if params != nil && params.PageSize > 0 {
pageSize = params.PageSize
}
query = query.Limit(int(pageSize))
var likes []*entity.Like
if err := query.Scan(ctx, &likes); err != nil {
return nil, 0, fmt.Errorf("failed to query likes: %w", err)
}
result := likes
return result, int64(len(result)), nil
}
// FindByTargetAndUser 根據目標和用戶查詢按讚
func (r *LikeRepository) FindByTargetAndUser(ctx context.Context, targetID gocql.UUID, userUID string, targetType string) (*entity.Like, error) {
var zeroUUID gocql.UUID
if targetID == zeroUUID || userUID == "" {
return nil, ErrInvalidInput
}
if targetType != "post" && targetType != "comment" {
return nil, ErrInvalidInput
}
// 構建查詢
query := r.repo.Query().
Where(cassandra.Eq("target_id", targetID)).
Where(cassandra.Eq("user_uid", userUID)).
Where(cassandra.Eq("target_type", targetType)).
Limit(1)
var likes []*entity.Like
if err := query.Scan(ctx, &likes); err != nil {
if cassandra.IsNotFound(err) {
return nil, ErrNotFound
}
return nil, fmt.Errorf("failed to query like: %w", err)
}
if len(likes) == 0 {
return nil, ErrNotFound
}
return likes[0], nil
}
// CountByTargetID 計算目標的按讚數
func (r *LikeRepository) CountByTargetID(ctx context.Context, targetID gocql.UUID, targetType string) (int64, error) {
var zeroUUID gocql.UUID
if targetID == zeroUUID {
return 0, ErrInvalidInput
}
if targetType != "post" && targetType != "comment" {
return 0, ErrInvalidInput
}
// 構建查詢
query := r.repo.Query().
Where(cassandra.Eq("target_id", targetID)).
Where(cassandra.Eq("target_type", targetType))
count, err := query.Count(ctx)
if err != nil {
return 0, fmt.Errorf("failed to count likes: %w", err)
}
return count, nil
}
// DeleteByTargetAndUser 根據目標和用戶刪除按讚
func (r *LikeRepository) DeleteByTargetAndUser(ctx context.Context, targetID gocql.UUID, userUID string, targetType string) error {
// 先查詢按讚
like, err := r.FindByTargetAndUser(ctx, targetID, userUID, targetType)
if err != nil {
return err
}
// 刪除按讚
return r.Delete(ctx, like.ID)
}