This commit performs a significant cleanup of the codebase by removing unused functions, methods, and entire files across various internal modules. This reduces technical debt and simplifies the project structure. Key changes include: - **cache**: Removed unused cache key generators and metrics snapshots. - **dto**: Removed redundant converter functions and segment creation helpers. - **middleware**: Deleted the unused `logger.go` middleware and simplified `ratelimit.go` and `casbin.go`. - **model**: Removed unused ID helpers, database closing functions, and batch decryption logic. - **pkg**: Cleaned up unused utility functions in `circuitbreaker`, `crypto`, `cursor`, `hook`, and `utils`. - **service**: Deleted `account_cleanup_service.go` and removed unused helper functions in `log_cleanup_service.go` and `sensitive_service.go`. - **repository**: Removed unused private loading methods in `comment_repo.go`.
164 lines
3.1 KiB
Go
164 lines
3.1 KiB
Go
package cursor
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// CursorBuilder 游标查询构建器
|
|
type CursorBuilder struct {
|
|
db *gorm.DB
|
|
cursor *Cursor
|
|
direction Direction
|
|
pageSize int
|
|
order SortOrder
|
|
err error
|
|
}
|
|
|
|
// NewBuilder 创建新的构建器
|
|
func NewBuilder(db *gorm.DB, order SortOrder) *CursorBuilder {
|
|
return &CursorBuilder{
|
|
db: db,
|
|
order: order,
|
|
pageSize: DefaultPageSize,
|
|
direction: Forward,
|
|
}
|
|
}
|
|
|
|
// WithCursor 设置游标
|
|
func (b *CursorBuilder) WithCursor(cursor string, direction Direction) *CursorBuilder {
|
|
if b.err != nil {
|
|
return b
|
|
}
|
|
|
|
if cursor == "" {
|
|
return b
|
|
}
|
|
|
|
decoded, err := DecodeCursor(cursor)
|
|
if err != nil {
|
|
b.err = err
|
|
return b
|
|
}
|
|
|
|
b.cursor = decoded
|
|
b.direction = direction
|
|
return b
|
|
}
|
|
|
|
// WithPageSize 设置页面大小
|
|
func (b *CursorBuilder) WithPageSize(size int) *CursorBuilder {
|
|
if b.err != nil {
|
|
return b
|
|
}
|
|
|
|
if size <= 0 {
|
|
b.pageSize = DefaultPageSize
|
|
} else if size > MaxPageSize {
|
|
b.pageSize = MaxPageSize
|
|
} else {
|
|
b.pageSize = size
|
|
}
|
|
return b
|
|
}
|
|
|
|
|
|
// Error 返回构建过程中的错误
|
|
func (b *CursorBuilder) Error() error {
|
|
return b.err
|
|
}
|
|
|
|
// Build 构建查询(返回 GORM 查询)
|
|
// 注意:调用者需要自己执行 Find 并处理结果
|
|
func (b *CursorBuilder) Build() *gorm.DB {
|
|
if b.err != nil {
|
|
return b.db.Where("1 = 0") // 返回空结果
|
|
}
|
|
|
|
query := b.db
|
|
|
|
// 应用游标条件
|
|
if b.cursor != nil {
|
|
query = b.applyCursorCondition(query)
|
|
}
|
|
|
|
// 应用排序
|
|
query = b.applyOrder(query)
|
|
|
|
// 多取一条用于判断是否有更多数据
|
|
query = query.Limit(b.pageSize + 1)
|
|
|
|
return query
|
|
}
|
|
|
|
// applyCursorCondition 应用游标条件
|
|
func (b *CursorBuilder) applyCursorCondition(query *gorm.DB) *gorm.DB {
|
|
if b.cursor == nil {
|
|
return query
|
|
}
|
|
|
|
sortField := b.order.SortField()
|
|
sortValue := b.cursor.SortValue
|
|
id := b.cursor.ID
|
|
|
|
// 根据分页方向和排序类型决定比较运算符
|
|
var op string
|
|
if b.direction == Forward {
|
|
// 向前分页:降序用 <,升序用 >
|
|
if b.order.IsDescending() {
|
|
op = "<"
|
|
} else {
|
|
op = ">"
|
|
}
|
|
} else {
|
|
// 向后分页:降序用 >,升序用 <
|
|
if b.order.IsDescending() {
|
|
op = ">"
|
|
} else {
|
|
op = "<"
|
|
}
|
|
}
|
|
|
|
// 使用元组比较:(sort_field, id) op (sort_value, id)
|
|
// 这样可以确保排序稳定且唯一
|
|
condition := fmt.Sprintf("(%s, id) %s (?, ?)", sortField, op)
|
|
return query.Where(condition, sortValue, id)
|
|
}
|
|
|
|
// applyOrder 应用排序
|
|
func (b *CursorBuilder) applyOrder(query *gorm.DB) *gorm.DB {
|
|
// 主排序字段
|
|
orderClause := b.order.String()
|
|
|
|
// 添加 ID 作为第二排序字段,确保排序稳定
|
|
if b.order.IsDescending() {
|
|
orderClause += ", id DESC"
|
|
} else {
|
|
orderClause += ", id ASC"
|
|
}
|
|
|
|
return query.Order(orderClause)
|
|
}
|
|
|
|
// GetPageSize 获取页面大小
|
|
func (b *CursorBuilder) GetPageSize() int {
|
|
return b.pageSize
|
|
}
|
|
|
|
// HasMore 判断是否有更多数据
|
|
// items 是查询结果切片,需要传入指针切片
|
|
func HasMore(itemsLen int, pageSize int) bool {
|
|
return itemsLen > pageSize
|
|
}
|
|
|
|
|
|
|
|
|
|
// FormatTime 格式化时间为字符串(用于游标)
|
|
func FormatTime(t time.Time) string {
|
|
return t.Format(time.RFC3339Nano)
|
|
}
|
|
|