refactor(notification): migrate cursor pagination to use unified cursor package
All checks were successful
Build Backend / build (push) Successful in 3m58s
Build Backend / build-docker (push) Successful in 2m52s

- 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
This commit is contained in:
lafay
2026-03-21 03:21:07 +08:00
parent 639ee55696
commit d7c7a51f77
2 changed files with 69 additions and 7 deletions

View File

@@ -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(&notifications).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