package cursor import ( "encoding/base64" "encoding/json" "errors" ) // SortOrder 游标排序类型 type SortOrder int const ( // SortByCreatedAtDesc 按创建时间降序 SortByCreatedAtDesc SortOrder = iota // SortByCreatedAtAsc 按创建时间升序 SortByCreatedAtAsc // SortByIDDesc 按ID降序 SortByIDDesc // SortByIDAsc 按ID升序 SortByIDAsc // SortBySeqDesc 按序列号降序(用于消息) SortBySeqDesc // SortBySeqAsc 按序列号升序 SortBySeqAsc // SortByUpdatedAtDesc 按更新时间降序 SortByUpdatedAtDesc // SortByUpdatedAtAsc 按更新时间升序 SortByUpdatedAtAsc // SortByJoinTimeDesc 按加入时间降序(用于群成员) SortByJoinTimeDesc // SortByJoinTimeAsc 按加入时间升序(用于群成员) SortByJoinTimeAsc ) // String 返回排序类型的字符串表示 func (s SortOrder) String() string { switch s { case SortByCreatedAtDesc: return "created_at DESC" case SortByCreatedAtAsc: return "created_at ASC" case SortByIDDesc: return "id DESC" case SortByIDAsc: return "id ASC" case SortBySeqDesc: return "seq DESC" case SortBySeqAsc: return "seq ASC" case SortByUpdatedAtDesc: return "updated_at DESC" case SortByUpdatedAtAsc: return "updated_at ASC" case SortByJoinTimeDesc: return "join_time DESC" case SortByJoinTimeAsc: return "join_time ASC" default: return "created_at DESC" } } // IsDescending 是否为降序 func (s SortOrder) IsDescending() bool { return s == SortByCreatedAtDesc || s == SortByIDDesc || s == SortBySeqDesc || s == SortByUpdatedAtDesc || s == SortByJoinTimeDesc } // SortField 返回排序字段名 func (s SortOrder) SortField() string { switch s { case SortByCreatedAtDesc, SortByCreatedAtAsc: return "created_at" case SortByIDDesc, SortByIDAsc: return "id" case SortBySeqDesc, SortBySeqAsc: return "seq" case SortByUpdatedAtDesc, SortByUpdatedAtAsc: return "updated_at" case SortByJoinTimeDesc, SortByJoinTimeAsc: return "join_time" default: return "created_at" } } // cursorJSON 游标 JSON 结构(用于序列化) type cursorJSON struct { SortValue string `json:"sv"` // 排序字段值(时间戳或ID) ID string `json:"id"` // 记录唯一ID Order SortOrder `json:"so"` // 排序方式 } // Cursor 游标数据结构 type Cursor struct { SortValue string // 排序字段值(时间戳或ID) ID string // 记录唯一ID Order SortOrder // 排序方式 } // Encode 编码游标为 Base64URL 字符串 func (c *Cursor) Encode() string { if c == nil { return "" } data, err := json.Marshal(&cursorJSON{ SortValue: c.SortValue, ID: c.ID, Order: c.Order, }) if err != nil { return "" } return base64.URLEncoding.EncodeToString(data) } // DecodeCursor 解码 Base64URL 字符串为游标 func DecodeCursor(encoded string) (*Cursor, error) { if encoded == "" { return nil, nil } data, err := base64.URLEncoding.DecodeString(encoded) if err != nil { // 尝试使用 RawURLEncoding(不带填充的编码) data, err = base64.RawURLEncoding.DecodeString(encoded) if err != nil { return nil, errors.New("invalid cursor encoding: " + err.Error()) } } var cj cursorJSON if err := json.Unmarshal(data, &cj); err != nil { return nil, errors.New("invalid cursor format: " + err.Error()) } return &Cursor{ SortValue: cj.SortValue, ID: cj.ID, Order: cj.Order, }, nil } // NewCursor 创建新的游标 func NewCursor(sortValue, id string, order SortOrder) *Cursor { return &Cursor{ SortValue: sortValue, ID: id, Order: order, } }