Files
backend/internal/repository/notification_repo.go

141 lines
4.1 KiB
Go
Raw Normal View History

package repository
import (
"carrot_bbs/internal/model"
"carrot_bbs/internal/pkg/cursor"
"context"
"gorm.io/gorm"
)
// NotificationRepository 通知仓储
type NotificationRepository struct {
db *gorm.DB
}
// NewNotificationRepository 创建通知仓储
func NewNotificationRepository(db *gorm.DB) *NotificationRepository {
return &NotificationRepository{db: db}
}
// Create 创建通知
func (r *NotificationRepository) Create(notification *model.Notification) error {
return r.db.Create(notification).Error
}
// GetByID 根据ID获取通知
func (r *NotificationRepository) GetByID(id string) (*model.Notification, error) {
var notification model.Notification
err := r.db.First(&notification, "id = ?", id).Error
if err != nil {
return nil, err
}
return &notification, nil
}
// GetByUserID 获取用户通知
func (r *NotificationRepository) GetByUserID(userID string, page, pageSize int, unreadOnly bool) ([]*model.Notification, int64, error) {
var notifications []*model.Notification
var total int64
query := r.db.Model(&model.Notification{}).Where("user_id = ?", userID)
if unreadOnly {
query = query.Where("is_read = ?", false)
}
query.Count(&total)
offset := (page - 1) * pageSize
err := query.Offset(offset).Limit(pageSize).Order("created_at DESC").Find(&notifications).Error
return notifications, total, err
}
// MarkAsRead 标记为已读
func (r *NotificationRepository) MarkAsRead(id string) error {
return r.db.Model(&model.Notification{}).Where("id = ?", id).Update("is_read", true).Error
}
// MarkAllAsRead 标记所有为已读
func (r *NotificationRepository) MarkAllAsRead(userID string) error {
return r.db.Model(&model.Notification{}).Where("user_id = ?", userID).Update("is_read", true).Error
}
// Delete 删除通知
func (r *NotificationRepository) Delete(id string) error {
return r.db.Delete(&model.Notification{}, "id = ?", id).Error
}
// GetUnreadCount 获取未读数量
func (r *NotificationRepository) GetUnreadCount(userID string) (int64, error) {
var count int64
err := r.db.Model(&model.Notification{}).Where("user_id = ? AND is_read = ?", userID, false).Count(&count).Error
return count, err
}
// DeleteAllByUserID 删除用户所有通知
func (r *NotificationRepository) DeleteAllByUserID(userID string) error {
return r.db.Where("user_id = ?", userID).Delete(&model.Notification{}).Error
}
// ========== Cursor Pagination Methods ==========
// GetNotificationsByCursor 游标分页获取用户通知
// 排序方式created_at DESC
func (r *NotificationRepository) GetNotificationsByCursor(ctx context.Context, userID string, unreadOnly bool, req *cursor.PageRequest) (*cursor.CursorPageResult[*model.Notification], error) {
// 构建基础查询
query := r.db.WithContext(ctx).Model(&model.Notification{}).Where("user_id = ?", userID)
if unreadOnly {
query = query.Where("is_read = ?", false)
}
// 使用游标构建器
builder := cursor.NewBuilder(query, cursor.SortByCreatedAtDesc).
WithCursor(req.Cursor, req.Direction).
WithPageSize(req.PageSize)
if builder.Error() != nil {
// 无效游标,返回空列表
return cursor.NewCursorPageResult[*model.Notification]([]*model.Notification{}, "", "", false), nil
}
// 执行查询
var notifications []*model.Notification
query = builder.Build()
if err := query.Find(&notifications).Error; err != nil {
return nil, err
}
// 构建响应
pageSize := builder.GetPageSize()
hasMore := cursor.HasMore(len(notifications), pageSize)
if hasMore {
notifications = notifications[:pageSize]
}
// 生成游标
var nextCursor, prevCursor string
if len(notifications) > 0 {
// 下一页游标
if hasMore {
lastNotification := notifications[len(notifications)-1]
nextCursor = cursor.NewCursor(
cursor.FormatTime(lastNotification.CreatedAt),
lastNotification.ID,
cursor.SortByCreatedAtDesc,
).Encode()
}
// 上一页游标
firstNotification := notifications[0]
prevCursor = cursor.NewCursor(
cursor.FormatTime(firstNotification.CreatedAt),
firstNotification.ID,
cursor.SortByCreatedAtDesc,
).Encode()
}
return cursor.NewCursorPageResult(notifications, nextCursor, prevCursor, hasMore), nil
}