229 lines
5.5 KiB
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)
|
|
}
|
|
|