package pagination import ( "encoding/base64" "encoding/json" "time" "edge-infra.dev/pkg/edge/api/graph/model" "edge-infra.dev/pkg/edge/api/utils" ) var ( // defaultCount is the default count used // when a count is not provided. defaultCount = 20 ) // Pager is a structure that holds pagination details. type Pager struct { Cursor string `json:"cursor"` Offset int `json:"offset"` Previous bool `json:"previous"` } // Parse is used to parse the pagination cursor and count // and set default values if any is not provided. func Parse(cursor *string, count *int) (Pager, int) { // defaultCursor is the default cursor value used // when a cursor value is not provided. defaultCursor := Pager{ Cursor: time.Now().Format(time.RFC3339), Offset: 0, Previous: false, } startCursor := defaultCursor if !utils.IsNullOrEmpty(cursor) { decodedCursor, err := decode(*cursor) if err != nil { return defaultCursor, 0 } decodedPager := Pager{} err = json.Unmarshal(decodedCursor, &decodedPager) if err != nil { return defaultCursor, 0 } startCursor = decodedPager } if count == nil { count = &defaultCount } return startCursor, *count } // Overall returns a pager instance that can be returned // in an API call to paginate data. func Overall(currentCursor Pager, nextCursor, previousTime string, length, totalCount, offset int) *model.PageInfo { encodedPreviousCursor := "" encodedCurrentCursor := encode(currentCursor) encodedNextCursor := "" if length > 0 { encodedNextCursor = encode(Pager{ Cursor: nextCursor, Offset: offset + length, Previous: false, }) } if previousTime != "" { offst := offset - length if offst < 0 { offst = 0 } encodedPreviousCursor = encode(Pager{ Cursor: previousTime, Offset: offst, Previous: true, }) } return &model.PageInfo{ PreviousCursor: encodedPreviousCursor, CurrentCursor: encodedCurrentCursor, NextCursor: encodedNextCursor, HasNextPage: (totalCount - offset) > length, TotalCount: totalCount, } } // Encode base64 encodes the cursor value. func Encode(cursor Pager) string { return encode(cursor) } // Decode decodes the base64 cursor value. func Decode(cursor string) ([]byte, error) { return decode(cursor) } // encode utility value for base64 encoding a string. func encode(value Pager) string { res, err := json.Marshal(value) if err != nil { return "" } return base64.RawStdEncoding.EncodeToString(res) } // decode a utility value for base64 decoding a string. func decode(value string) ([]byte, error) { val, err := base64.RawStdEncoding.DecodeString(value) if err != nil { return nil, err } return val, nil }