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.
This commit is contained in:
2026-04-18 10:13:37 +08:00
parent 0795e126cc
commit bb7c5e7fe2

View File

@@ -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"