1package api 2 3import ( 4 "fmt" 5 "net/http" 6 "net/url" 7 "strconv" 8 "strings" 9) 10 11const ( 12 defaultPerPage = 100 13 defaultPage = 1 14) 15 16const nextPageHeader = "X-Next-Page" 17 18type pageInfo struct { 19 startIndex int 20 endIndex int 21 nextPage int 22} 23 24type searchCriterion struct { 25 Search string `url:"search"` 26 Status string `url:"status"` 27} 28 29func newSearchCriterion(query url.Values) *searchCriterion { 30 if len(query) == 0 { 31 return nil 32 } 33 34 search := query.Get("search") 35 status := query.Get("status") 36 37 if status == "" && search == "" { 38 return nil 39 } 40 41 return &searchCriterion{Search: search, Status: status} 42} 43 44func (c *searchCriterion) withStatus(name string) bool { 45 return c.Status == "" || strings.EqualFold(name, c.Status) 46} 47 48func (c *searchCriterion) searchIn(values ...string) bool { 49 if c.Search == "" { 50 return true 51 } 52 53 for _, v := range values { 54 if strings.Contains(strings.ToLower(v), strings.ToLower(c.Search)) { 55 return true 56 } 57 } 58 59 return false 60} 61 62func pagination(request *http.Request, max int) (pageInfo, error) { 63 perPage, err := getIntParam(request, "per_page", defaultPerPage) 64 if err != nil { 65 return pageInfo{}, err 66 } 67 68 page, err := getIntParam(request, "page", defaultPage) 69 if err != nil { 70 return pageInfo{}, err 71 } 72 73 startIndex := (page - 1) * perPage 74 if startIndex != 0 && startIndex >= max { 75 return pageInfo{}, fmt.Errorf("invalid request: page: %d, per_page: %d", page, perPage) 76 } 77 78 endIndex := startIndex + perPage 79 if endIndex >= max { 80 endIndex = max 81 } 82 83 nextPage := 1 84 if page*perPage < max { 85 nextPage = page + 1 86 } 87 88 return pageInfo{startIndex: startIndex, endIndex: endIndex, nextPage: nextPage}, nil 89} 90 91func getIntParam(request *http.Request, key string, defaultValue int) (int, error) { 92 raw := request.URL.Query().Get(key) 93 if raw == "" { 94 return defaultValue, nil 95 } 96 97 value, err := strconv.Atoi(raw) 98 if err != nil || value <= 0 { 99 return 0, fmt.Errorf("invalid request: %s: %d", key, value) 100 } 101 return value, nil 102} 103