Files

153 lines
3.5 KiB
Go
Raw Permalink Normal View History

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,
}
}