l-export-async/page_strategy.go

179 lines
4.4 KiB
Go

package l_export_async
import (
"context"
"time"
)
// PageStrategyType 分页策略类型
type PageStrategyType string
const (
PageStrategyOffset PageStrategyType = "offset"
PageStrategyCursor PageStrategyType = "cursor"
PageStrategyTime PageStrategyType = "time"
)
// PageStrategy 分页策略接口
type PageStrategy interface {
// Type 类型标识
Type() PageStrategyType
// InitialState 获取初始状态
InitialState() interface{}
// NextPage 获取下一页数据
NextPage(ctx context.Context, state interface{}) ([][]interface{}, interface{}, error)
// HasMore 是否还有下一页
HasMore(state interface{}, lastData [][]interface{}) bool
// GetLimit 获取每批数据量
GetLimit() int
}
// DataFetcher 数据获取函数类型
type (
// OffsetDataFetcher 传统分页
OffsetDataFetcher func(ctx context.Context, pageNum, limit int) ([][]interface{}, error)
// CursorDataFetcher 游标分页
CursorDataFetcher func(ctx context.Context, cursor interface{}, limit int) ([][]interface{}, interface{}, error)
// TimeRangeDataFetcher 时间范围分页
TimeRangeDataFetcher func(ctx context.Context, startTime time.Time, limit int) ([][]interface{}, error)
)
// OffsetStrategy 传统分页策略
type OffsetStrategy struct {
fetcher OffsetDataFetcher
limit int
total int // 可选,用于提前知道总数
}
func (s *OffsetStrategy) Type() PageStrategyType {
return PageStrategyOffset
}
func (s *OffsetStrategy) InitialState() interface{} {
return 1 // 初始页码
}
func (s *OffsetStrategy) NextPage(ctx context.Context, state interface{}) ([][]interface{}, interface{}, error) {
pageNum := state.(int)
data, err := s.fetcher(ctx, pageNum, s.limit)
if err != nil {
return nil, nil, err
}
// 下一页页码
nextState := pageNum + 1
return data, nextState, nil
}
func (s *OffsetStrategy) HasMore(state interface{}, lastData [][]interface{}) bool {
if s.total > 0 {
currentPage := state.(int)
totalPages := (s.total + s.limit - 1) / s.limit
return currentPage <= totalPages
}
// 如果没有总数,则根据最后一页数据判断
//return len(lastData) >= s.limit
//这里改为判断是否为空,多查一次
return len(lastData) > 0
}
func (s *OffsetStrategy) GetLimit() int {
return s.limit
}
// CursorStrategy 游标分页策略
type CursorStrategy struct {
fetcher CursorDataFetcher
limit int
initialCursor interface{}
}
func (s *CursorStrategy) Type() PageStrategyType {
return PageStrategyCursor
}
func (s *CursorStrategy) InitialState() interface{} {
return s.initialCursor // nil 或初始游标值
}
func (s *CursorStrategy) NextPage(ctx context.Context, state interface{}) ([][]interface{}, interface{}, error) {
return s.fetcher(ctx, state, s.limit)
}
func (s *CursorStrategy) HasMore(state interface{}, lastData [][]interface{}) bool {
// 这里如果为空,证明已经到最后一夜了
return len(lastData) > 0
}
func (s *CursorStrategy) GetLimit() int {
return s.limit
}
// TimeRangeStrategy 时间范围分页策略
type TimeRangeStrategy struct {
fetcher TimeRangeDataFetcher
limit int
startTime time.Time
endTime time.Time // 可选的结束时间
timeRange time.Duration // 每次查询的时间范围
lastQueryTime *time.Time // 记录最后一次查询的时间
}
func (s *TimeRangeStrategy) Type() PageStrategyType {
return PageStrategyTime
}
func (s *TimeRangeStrategy) InitialState() interface{} {
return s.startTime
}
func (s *TimeRangeStrategy) NextPage(ctx context.Context, state interface{}) ([][]interface{}, interface{}, error) {
currentTime := state.(time.Time)
// 如果设置了结束时间,且当前时间已经超过结束时间
if !s.endTime.IsZero() && currentTime.After(s.endTime) {
return nil, currentTime, nil
}
data, err := s.fetcher(ctx, currentTime, s.limit)
if err != nil {
return nil, nil, err
}
// 更新时间状态
var nextTime time.Time
if len(data) > 0 {
// 这里假设数据按时间排序,可以通过自定义逻辑来调整
nextTime = currentTime.Add(s.timeRange)
} else {
nextTime = currentTime.Add(s.timeRange)
}
s.lastQueryTime = &currentTime
return data, nextTime, nil
}
func (s *TimeRangeStrategy) HasMore(state interface{}, lastData [][]interface{}) bool {
currentTime := state.(time.Time)
// 如果设置了结束时间
if !s.endTime.IsZero() {
return currentTime.Before(s.endTime)
}
return len(lastData) > 0
}
func (s *TimeRangeStrategy) GetLimit() int {
return s.limit
}