From d7c7a51f774ce16df40d6c81ffedc1e9dfc5fc30 Mon Sep 17 00:00:00 2001 From: lafay <2021211506@stu.hit.edu.cn> Date: Sat, 21 Mar 2026 03:21:07 +0800 Subject: [PATCH] refactor(notification): migrate cursor pagination to use unified cursor package - Add new GetByReceiverIDCursor method with context support and generic cursor types - Rename old implementation to GetByReceiverIDCursorLegacy for backward compatibility - Update handler to use legacy interface temporarily during migration - Use CursorBuilder pattern for consistent pagination across services --- internal/handler/system_message_handler.go | 4 +- .../repository/system_notification_repo.go | 72 +++++++++++++++++-- 2 files changed, 69 insertions(+), 7 deletions(-) diff --git a/internal/handler/system_message_handler.go b/internal/handler/system_message_handler.go index acc6715..23ea641 100644 --- a/internal/handler/system_message_handler.go +++ b/internal/handler/system_message_handler.go @@ -82,8 +82,8 @@ func (h *SystemMessageHandler) GetSystemMessagesByCursor(c *gin.Context) { cursorStr := c.Query("cursor") pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20")) - // 获取当前用户的系统通知 - notifications, nextCursor, hasMore, err := h.notifyRepo.GetByReceiverIDCursor(userID, cursorStr, pageSize) + // 获取当前用户的系统通知(使用兼容旧版接口) + notifications, nextCursor, hasMore, err := h.notifyRepo.GetByReceiverIDCursorLegacy(userID, cursorStr, pageSize) if err != nil { response.InternalServerError(c, "failed to get system messages") return diff --git a/internal/repository/system_notification_repo.go b/internal/repository/system_notification_repo.go index 5e3cb72..4b39930 100644 --- a/internal/repository/system_notification_repo.go +++ b/internal/repository/system_notification_repo.go @@ -1,7 +1,11 @@ package repository import ( + "context" + "strconv" + "carrot_bbs/internal/model" + "carrot_bbs/internal/pkg/cursor" "gorm.io/gorm" ) @@ -114,13 +118,67 @@ func (r *SystemNotificationRepository) GetByType(receiverID string, notifyType m } // GetByReceiverIDCursor 游标分页获取用户的通知列表 -func (r *SystemNotificationRepository) GetByReceiverIDCursor(receiverID string, cursor string, pageSize int) ([]*model.SystemNotification, string, bool, error) { +// 使用统一的 cursor 包进行游标分页 +func (r *SystemNotificationRepository) GetByReceiverIDCursor(ctx context.Context, receiverID string, req *cursor.PageRequest) (*cursor.CursorPageResult[*model.SystemNotification], error) { + // 构建基础查询 + query := r.db.WithContext(ctx).Model(&model.SystemNotification{}).Where("receiver_id = ?", receiverID) + + // 使用 CursorBuilder 构建游标查询 + builder := cursor.NewBuilder(query, cursor.SortByCreatedAtDesc). + WithCursor(req.Cursor, cursor.Direction(req.Direction)). + WithPageSize(req.PageSize) + + if builder.Error() != nil { + return nil, builder.Error() + } + + // 执行查询 + var notifications []*model.SystemNotification + if err := builder.Build().Find(¬ifications).Error; err != nil { + return nil, err + } + + // 构建响应 + pageSize := builder.GetPageSize() + hasMore := cursor.HasMore(len(notifications), pageSize) + if hasMore { + notifications = notifications[:pageSize] + } + + // 生成下一页游标 + var nextCursor string + if hasMore && len(notifications) > 0 { + lastNotification := notifications[len(notifications)-1] + nextCursor = cursor.NewCursor( + cursor.FormatTime(lastNotification.CreatedAt), + strconv.FormatInt(lastNotification.ID, 10), + cursor.SortByCreatedAtDesc, + ).Encode() + } + + return &cursor.CursorPageResult[*model.SystemNotification]{ + Items: notifications, + NextCursor: nextCursor, + HasMore: hasMore, + }, nil +} + +// GetByReceiverIDCursorLegacy 游标分页获取用户的通知列表(旧版兼容接口) +// 已废弃:请使用 GetByReceiverIDCursor +func (r *SystemNotificationRepository) GetByReceiverIDCursorLegacy(receiverID string, cursorStr string, pageSize int) ([]*model.SystemNotification, string, bool, error) { + // 构建基础查询 query := r.db.Model(&model.SystemNotification{}).Where("receiver_id = ?", receiverID) // 如果有游标,解析游标并添加条件 - if cursor != "" { - // 游标格式:createdAt_id - query = query.Where("created_at < ? OR (created_at = ? AND id < ?)", cursor, cursor, cursor) + if cursorStr != "" { + decodedCursor, err := cursor.DecodeCursor(cursorStr) + if err != nil { + // 游标格式无效,返回空结果 + return []*model.SystemNotification{}, "", false, nil + } + // 使用元组比较进行分页 + condition := "(created_at, id) < (?, ?)" + query = query.Where(condition, decodedCursor.SortValue, decodedCursor.ID) } // 多取一条用于判断是否还有下一页 @@ -142,7 +200,11 @@ func (r *SystemNotificationRepository) GetByReceiverIDCursor(receiverID string, var nextCursor string if hasMore && len(notifications) > 0 { lastNotification := notifications[len(notifications)-1] - nextCursor = lastNotification.CreatedAt.Format("2006-01-02 15:04:05.999999999") + nextCursor = cursor.NewCursor( + cursor.FormatTime(lastNotification.CreatedAt), + strconv.FormatInt(lastNotification.ID, 10), + cursor.SortByCreatedAtDesc, + ).Encode() } return notifications, nextCursor, hasMore, nil