github.com/qri-io/qri@v0.10.1-0.20220104210721-c771715036cb/base/params/list.go (about)

     1  // Package params defines generic input parameter structures
     2  package params
     3  
     4  import (
     5  	"fmt"
     6  	"net/http"
     7  	"strconv"
     8  	"strings"
     9  )
    10  
    11  var (
    12  	// ErrListParamsNotEmpty indicates that there are list values in the params
    13  	ErrListParamsNotEmpty = fmt.Errorf("list params not empty")
    14  	// DefaultListLimit is the default value for a list
    15  	DefaultListLimit = 25
    16  )
    17  
    18  // ListParams can pull list param information from an http.Request
    19  type ListParams interface {
    20  	// ListParamsFromRequest pulls list params from the URL
    21  	ListParamsFromRequest(r *http.Request) error
    22  }
    23  
    24  // ListAll uses a limit of -1 & offset of 0 as a sentinel value for listing
    25  // all items
    26  var ListAll = List{Limit: -1}
    27  
    28  // List defines input parameters for listing operations
    29  type List struct {
    30  	Filter  []string
    31  	OrderBy OrderBy
    32  	Limit   int
    33  	Offset  int
    34  }
    35  
    36  // ListParamsFromRequest satisfies the ListParams interface
    37  func (lp *List) ListParamsFromRequest(r *http.Request) error {
    38  	l := List{}
    39  	limitStr := r.URL.Query().Get("limit")
    40  	if limitStr != "" {
    41  		limit, err := strconv.ParseInt(limitStr, 10, 0)
    42  		if err != nil {
    43  			return err
    44  		}
    45  		l.Limit = int(limit)
    46  	}
    47  	offsetStr := r.URL.Query().Get("offset")
    48  	if offsetStr != "" {
    49  		offset, err := strconv.ParseInt(offsetStr, 10, 0)
    50  		if err != nil {
    51  			return err
    52  		}
    53  		l.Offset = int(offset)
    54  	}
    55  
    56  	filterStr := r.URL.Query().Get("filter")
    57  	if filterStr != "" {
    58  		l = l.WithFilters(strings.Split(r.FormValue("filter"), ",")...)
    59  	}
    60  
    61  	l = l.WithOrderBy(r.URL.Query().Get("orderby"))
    62  
    63  	if l.IsEmpty() {
    64  		return nil
    65  	}
    66  	if !lp.IsEmpty() {
    67  		return ErrListParamsNotEmpty
    68  	}
    69  
    70  	*lp = l
    71  	return nil
    72  }
    73  
    74  // All returns true if List is attempting to list all available items
    75  func (lp List) All() bool {
    76  	return lp.Limit == -1 && lp.Offset == 0
    77  }
    78  
    79  // Validate returns an error if any fields or field combinations are invalid
    80  func (lp List) Validate() error {
    81  	if lp.Limit < 0 && lp.Limit != -1 {
    82  		return fmt.Errorf("limit of %d is out of bounds", lp.Limit)
    83  	}
    84  	if lp.Offset < 0 {
    85  		return fmt.Errorf("offset of %d is out of bounds", lp.Offset)
    86  	}
    87  	return nil
    88  }
    89  
    90  // IsEmpty determines if the List struct is empty
    91  func (lp List) IsEmpty() bool {
    92  	return lp.Limit == 0 &&
    93  		lp.Offset == 0 &&
    94  		len(lp.Filter) == 0 &&
    95  		len(lp.OrderBy) == 0
    96  }
    97  
    98  // WithOffsetLimit returns a new List struct that replaces the offset & limit
    99  // fields
   100  func (lp List) WithOffsetLimit(offset, limit int) List {
   101  	return List{
   102  		Filter:  lp.Filter,
   103  		OrderBy: lp.OrderBy,
   104  		Offset:  offset,
   105  		Limit:   limit,
   106  	}
   107  }
   108  
   109  // WithOrderBy returns a new List struct that replaces the OrderBy field
   110  func (lp List) WithOrderBy(ob string) List {
   111  	return List{
   112  		Filter:  lp.Filter,
   113  		OrderBy: NewOrderByFromString(ob),
   114  		Offset:  lp.Offset,
   115  		Limit:   lp.Limit,
   116  	}
   117  }
   118  
   119  // WithFilters returns a new List struct that replaces the Filters field
   120  func (lp List) WithFilters(f ...string) List {
   121  	return List{
   122  		Filter:  f,
   123  		OrderBy: lp.OrderBy,
   124  		Offset:  lp.Offset,
   125  		Limit:   lp.Limit,
   126  	}
   127  }