feat(api): add cursor-based pagination for posts, comments, messages, groups, and notifications
All checks were successful
Build Backend / build (push) Successful in 4m42s
Build Backend / build-docker (push) Successful in 3m53s

Implement cursor-based pagination across multiple API endpoints to improve performance and enable efficient infinite scrolling. This replaces traditional offset-based pagination for high-volume data retrieval.

Changes:
- Add cursor pagination DTOs for all entity types (Post, Comment, Message, Conversation, Group, Notification, GroupMember, GroupAnnouncement)
- Implement cursor pagination methods in repositories with support for various sort orders (created_at, updated_at, join_time, seq)
- Add cursor pagination handlers that maintain backward compatibility with existing offset pagination
- Add new API routes for cursor-based endpoints (/cursor suffix)
- Add helper converter functions for pointer slice types in DTO conversions
This commit is contained in:
lafay
2026-03-20 23:03:23 +08:00
parent 98f0c9f2b6
commit 92babe509f
21 changed files with 2087 additions and 3 deletions

View File

@@ -263,12 +263,14 @@ func (r *Router) setupRoutes() {
comments := v1.Group("/comments")
{
comments.GET("/post/:id", middleware.OptionalAuth(r.jwtService), r.commentHandler.GetByPostID)
comments.GET("/post/:id/cursor", middleware.OptionalAuth(r.jwtService), r.commentHandler.GetByPostIDByCursor) // 帖子评论游标分页
comments.GET("/:id", middleware.OptionalAuth(r.jwtService), r.commentHandler.GetByID)
comments.POST("", authMiddleware, r.commentHandler.Create)
comments.PUT("/:id", authMiddleware, r.commentHandler.Update)
comments.DELETE("/:id", authMiddleware, r.commentHandler.Delete)
comments.GET("/:id/replies", middleware.OptionalAuth(r.jwtService), r.commentHandler.GetReplies)
comments.GET("/:id/replies/flat", middleware.OptionalAuth(r.jwtService), r.commentHandler.GetRepliesByRootID) // 扁平化分页获取回复
comments.GET("/:id/replies/flat", middleware.OptionalAuth(r.jwtService), r.commentHandler.GetRepliesByRootID) // 扁平化分页获取回复
comments.GET("/:id/replies/cursor", middleware.OptionalAuth(r.jwtService), r.commentHandler.GetRepliesByRootIDByCursor) // 回复游标分页
// 评论点赞
comments.POST("/:id/like", authMiddleware, r.commentHandler.Like)
comments.DELETE("/:id/like", authMiddleware, r.commentHandler.Unlike)
@@ -282,9 +284,11 @@ func (r *Router) setupRoutes() {
// 新的 RESTful 风格路由(推荐使用)
// ================================================================
conversations.GET("", r.messageHandler.HandleGetConversationList) // 列表
conversations.GET("/cursor", r.messageHandler.GetConversationsByCursor) // 会话列表游标分页
conversations.POST("", r.messageHandler.HandleCreateConversation) // 创建
conversations.GET("/:id", r.messageHandler.HandleGetConversation) // 详情
conversations.GET("/:id/messages", r.messageHandler.HandleGetMessages) // 消息列表
conversations.GET("/:id/messages/cursor", r.messageHandler.GetMessagesByCursor) // 消息列表游标分页
conversations.POST("/:id/messages", r.messageHandler.HandleSendMessage) // 发送消息
conversations.POST("/:id/read", r.messageHandler.HandleMarkRead) // 标记已读
conversations.PUT("/:id/pinned", r.messageHandler.HandleSetConversationPinned) // 置顶设置
@@ -312,6 +316,7 @@ func (r *Router) setupRoutes() {
notifications := v1.Group("/notifications")
{
notifications.GET("", authMiddleware, r.notificationHandler.GetNotifications)
notifications.GET("/cursor", authMiddleware, r.notificationHandler.GetNotificationsByCursor) // 通知游标分页
notifications.POST("/:id/read", authMiddleware, r.notificationHandler.MarkAsRead)
notifications.POST("/read-all", authMiddleware, r.notificationHandler.MarkAllAsRead)
notifications.GET("/unread-count", authMiddleware, r.notificationHandler.GetUnreadCount)
@@ -360,6 +365,7 @@ func (r *Router) setupRoutes() {
// ================================================================
// 群组基本操作
groups.GET("", r.groupHandler.HandleGetUserGroups) // 列表
groups.GET("/cursor", r.groupHandler.GetGroupsByCursor) // 群组游标分页
groups.POST("", r.groupHandler.HandleCreateGroup) // 创建
groups.GET("/:id", r.groupHandler.HandleGetGroupInfo) // 详情
groups.GET("/:id/me", r.groupHandler.HandleGetMyMemberInfo) // 当前用户成员信息
@@ -372,6 +378,7 @@ func (r *Router) setupRoutes() {
groups.POST("/:id/join-requests/respond", r.groupHandler.HandleRespondInvite) // 响应加群邀请/申请
groups.POST("/:id/leave", r.groupHandler.HandleSetGroupLeave) // 退群
groups.GET("/:id/members", r.groupHandler.HandleGetGroupMemberList) // 成员列表
groups.GET("/:id/members/cursor", r.groupHandler.GetMembersByCursor) // 成员游标分页
groups.POST("/:id/members/kick", r.groupHandler.HandleSetGroupKick) // 踢出成员
groups.PUT("/:id/members/:user_id/admin", r.groupHandler.HandleSetGroupAdmin) // 设置管理员
groups.PUT("/:id/members/me/nickname", r.groupHandler.HandleSetNickname) // 设置群昵称
@@ -386,6 +393,7 @@ func (r *Router) setupRoutes() {
// 群公告
groups.POST("/:id/announcements", r.groupHandler.HandleCreateAnnouncement) // 创建公告
groups.GET("/:id/announcements", r.groupHandler.HandleGetAnnouncements) // 公告列表
groups.GET("/:id/announcements/cursor", r.groupHandler.GetAnnouncementsByCursor) // 公告游标分页
groups.DELETE("/:id/announcements/:announcement_id", r.groupHandler.HandleDeleteAnnouncement) // 删除公告
// 加群请求处理