github.com/qri-io/qri@v0.10.1-0.20220104210721-c771715036cb/api/util/page.go (about)

     1  package util
     2  
     3  import (
     4  	"net/http"
     5  	"net/url"
     6  	"strconv"
     7  )
     8  
     9  var (
    10  	// DefaultPageSize is the number NewPage
    11  	DefaultPageSize = 50
    12  	// DefaultMaxPageSize is the max size a page can be by default, set to -1 to
    13  	// ignore maximum sizes
    14  	DefaultMaxPageSize = 100
    15  )
    16  
    17  // Page represents pagination information
    18  type Page struct {
    19  	Number      int    `json:"page,omitempty"`
    20  	Size        int    `json:"pageSize,omitempty"`
    21  	ResultCount int    `json:"resultCount,omitempty"`
    22  	NextURL     string `json:"nextUrl"`
    23  	PrevURL     string `json:"prevUrl"`
    24  }
    25  
    26  // NewPage constructs a basic page struct, setting sensible defaults
    27  func NewPage(number, size int) Page {
    28  	if number <= 0 {
    29  		number = 1
    30  	}
    31  
    32  	if DefaultMaxPageSize != -1 && size > DefaultMaxPageSize {
    33  		size = DefaultMaxPageSize
    34  	}
    35  
    36  	return Page{
    37  		Number: number,
    38  		Size:   size,
    39  	}
    40  }
    41  
    42  // Limit is a convenience accessor for page size
    43  func (p Page) Limit() int {
    44  	return p.Size
    45  }
    46  
    47  // Offset calculates the starting index for pagination based on page
    48  // size & number
    49  func (p Page) Offset() int {
    50  	return (p.Number - 1) * p.Size
    51  }
    52  
    53  // Next returns a page with the number advanced by one
    54  func (p Page) Next() Page {
    55  	return Page{
    56  		Number:      p.Number + 1,
    57  		Size:        p.Size,
    58  		ResultCount: p.ResultCount,
    59  		NextURL:     p.NextURL,
    60  		PrevURL:     p.PrevURL,
    61  	}
    62  }
    63  
    64  // Prev returns a page with the number decremented by 1
    65  func (p Page) Prev() Page {
    66  	return Page{
    67  		Number:      p.Number - 1,
    68  		Size:        p.Size,
    69  		ResultCount: p.ResultCount,
    70  		NextURL:     p.NextURL,
    71  		PrevURL:     p.PrevURL,
    72  	}
    73  }
    74  
    75  // SetQueryParams adds pagination info to a url as query parameters
    76  func (p Page) SetQueryParams(u *url.URL) *url.URL {
    77  	q := u.Query()
    78  	q.Set("page", strconv.Itoa(p.Number))
    79  	if p.Size != DefaultPageSize {
    80  		q.Set("pageSize", strconv.Itoa(p.Size))
    81  	}
    82  
    83  	u.RawQuery = q.Encode()
    84  	return u
    85  }
    86  
    87  // NextPageExists returns false if the next page.ResultCount is a postive
    88  // number and the starting offset of the next page exceeds page.ResultCount
    89  func (p Page) NextPageExists() bool {
    90  	return p.ResultCount <= 0 || !(p.Number*p.Size >= p.ResultCount)
    91  }
    92  
    93  // PrevPageExists returns false if the page number is 1
    94  func (p Page) PrevPageExists() bool {
    95  	return p.Number > 1
    96  }
    97  
    98  // PageFromRequest extracts pagination params from an http request
    99  func PageFromRequest(r *http.Request) Page {
   100  	number := ReqParamInt(r, "page", 1)
   101  	if number <= 0 {
   102  		number = 1
   103  	}
   104  
   105  	size := ReqParamInt(r, "pageSize", DefaultPageSize)
   106  	if size <= 0 {
   107  		size = DefaultPageSize
   108  	}
   109  
   110  	if DefaultMaxPageSize != -1 && size > DefaultMaxPageSize {
   111  		size = DefaultMaxPageSize
   112  	}
   113  
   114  	return Page{
   115  		Number: number,
   116  		Size:   size,
   117  	}
   118  }
   119  
   120  // NewPageFromOffsetAndLimit converts a offset and Limit to a Page struct
   121  func NewPageFromOffsetAndLimit(offset, limit int) Page {
   122  	var number, size int
   123  	size = limit
   124  	if size <= 0 {
   125  		size = DefaultPageSize
   126  	}
   127  	number = offset/size + 1
   128  	return Page{
   129  		Number: number,
   130  		Size:   size,
   131  	}
   132  }