Files
bifrost/core/providers/utils/pagination.go
Beyhan Oğur 880f412e2c first commit
2026-04-26 21:52:23 +03:00

113 lines
3.2 KiB
Go

package utils
import (
schemas "github.com/maximhq/bifrost/core/schemas"
)
// SerialListHelper manages serial key pagination for list operations.
// It ensures that all pages from one key are exhausted before moving to the next,
// guaranteeing only one API call per pagination request regardless of key count.
type SerialListHelper struct {
Keys []schemas.Key
Cursor *schemas.SerialCursor
Logger schemas.Logger
}
// NewSerialListHelper creates a new SerialListHelper from the provided keys and encoded cursor.
// If the cursor is empty or nil, pagination starts from the first key.
// If the cursor is invalid, an error is returned.
func NewSerialListHelper(keys []schemas.Key, encodedCursor *string, logger schemas.Logger) (*SerialListHelper, error) {
helper := &SerialListHelper{
Keys: keys,
Logger: logger,
}
if encodedCursor != nil && *encodedCursor != "" {
cursor, err := schemas.DecodeSerialCursor(*encodedCursor)
if err != nil {
return nil, err
}
helper.Cursor = cursor
}
return helper, nil
}
// GetCurrentKey returns the key to query and its native cursor.
// Returns (key, nativeCursor, true) if there's a key to query.
// Returns (Key{}, "", false) if all keys are exhausted.
func (h *SerialListHelper) GetCurrentKey() (schemas.Key, string, bool) {
if len(h.Keys) == 0 {
return schemas.Key{}, "", false
}
keyIndex := 0
nativeCursor := ""
if h.Cursor != nil {
keyIndex = h.Cursor.KeyIndex
nativeCursor = h.Cursor.Cursor
}
// Check if key index is within bounds
if keyIndex >= len(h.Keys) {
return schemas.Key{}, "", false
}
return h.Keys[keyIndex], nativeCursor, true
}
// BuildNextCursor creates the cursor for the next pagination request.
// Parameters:
// - hasMore: whether the current key has more pages
// - nativeCursor: the native cursor returned by the current key's API
//
// Returns:
// - encodedCursor: the encoded cursor for the next request (empty if all keys exhausted)
// - moreAvailable: true if there are more results available (either from current key or remaining keys)
func (h *SerialListHelper) BuildNextCursor(hasMore bool, nativeCursor string) (string, bool) {
if len(h.Keys) == 0 {
return "", false
}
currentKeyIndex := 0
if h.Cursor != nil {
currentKeyIndex = h.Cursor.KeyIndex
}
if hasMore {
// Current key has more pages - return cursor for same key
nextCursor := schemas.NewSerialCursor(currentKeyIndex, nativeCursor)
return schemas.EncodeSerialCursor(nextCursor), true
}
// Current key exhausted - check if there are more keys
nextKeyIndex := currentKeyIndex + 1
if nextKeyIndex >= len(h.Keys) {
// All keys exhausted
return "", false
}
// Move to next key with empty cursor (start fresh)
nextCursor := schemas.NewSerialCursor(nextKeyIndex, "")
return schemas.EncodeSerialCursor(nextCursor), true
}
// GetCurrentKeyIndex returns the current key index being processed.
func (h *SerialListHelper) GetCurrentKeyIndex() int {
if h.Cursor != nil {
return h.Cursor.KeyIndex
}
return 0
}
// HasMoreKeys returns true if there are more keys after the current one.
func (h *SerialListHelper) HasMoreKeys() bool {
currentKeyIndex := 0
if h.Cursor != nil {
currentKeyIndex = h.Cursor.KeyIndex
}
return currentKeyIndex < len(h.Keys)-1
}