From bb7c5e7fe2f54b94b0c489224b394c1c308308e2 Mon Sep 17 00:00:00 2001 From: long-agent Date: Sat, 18 Apr 2026 10:13:37 +0800 Subject: [PATCH] fix: P0-08 cursor pagination sort consistency Cursor pagination now only applies when sorting by created_at. Other sort fields (username, last_login_time, updated_at) will not use cursor pagination to prevent data inconsistency. Fixes: UserRepository.ListCursor() allowing sort fields that don't match the cursor predicate. --- internal/repository/user.go | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/internal/repository/user.go b/internal/repository/user.go index 68051ed..386561e 100644 --- a/internal/repository/user.go +++ b/internal/repository/user.go @@ -381,14 +381,9 @@ func (r *UserRepository) ListCursor(ctx context.Context, filter *AdvancedFilter, } // Apply cursor condition - if cursor != nil && cursor.LastID > 0 { - query = query.Where( - "(created_at < ? OR (created_at = ? AND id < ?))", - cursor.LastValue, cursor.LastValue, cursor.LastID, - ) - } - - // Determine sort field + // 安全修复:游标分页必须与排序字段一致。 + // 如果排序字段不是 created_at,游标分页会返回错误结果。 + // 因此只有在按 created_at 排序时才允许使用游标。 sortBy := "created_at" if filter.SortBy != "" { allowedFields := map[string]bool{ @@ -399,6 +394,15 @@ func (r *UserRepository) ListCursor(ctx context.Context, filter *AdvancedFilter, sortBy = filter.SortBy } } + + // 只有在按 created_at 排序时才应用游标条件 + if cursor != nil && cursor.LastID > 0 && sortBy == "created_at" { + query = query.Where( + "(created_at < ? OR (created_at = ? AND id < ?))", + cursor.LastValue, cursor.LastValue, cursor.LastID, + ) + } + sortOrder := "DESC" if filter.SortOrder == "asc" { sortOrder = "ASC"