parse.go 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. package autocomplete
  2. import (
  3. "fmt"
  4. "time"
  5. "github.com/opencost/opencost/core/pkg/filter"
  6. "github.com/opencost/opencost/core/pkg/opencost"
  7. "github.com/opencost/opencost/core/pkg/util/httputil"
  8. )
  9. // FilterParser parses a filter query string for autocomplete requests.
  10. type FilterParser func(filterString string) (filter.Filter, error)
  11. // ParseOptions configures ParseRequest.
  12. type ParseOptions struct {
  13. DefaultWindow string
  14. DefaultTenantID string
  15. LabelConfig *opencost.LabelConfig
  16. UTCOffset *time.Duration
  17. WindowValidator WindowValidator
  18. }
  19. // ParseRequest builds a Request from query parameters.
  20. func ParseRequest(qp httputil.QueryParams, opts ParseOptions, validateField FieldValidator, parseFilter FilterParser) (*Request, error) {
  21. windowStr := qp.Get("window", opts.DefaultWindow)
  22. if windowStr == "" {
  23. return nil, fmt.Errorf("%w: missing required 'window' parameter", ErrBadRequest)
  24. }
  25. var window opencost.Window
  26. var err error
  27. if opts.UTCOffset != nil {
  28. window, err = opencost.ParseWindowWithOffset(windowStr, *opts.UTCOffset)
  29. } else {
  30. window, err = opencost.ParseWindowUTC(windowStr)
  31. }
  32. if err != nil {
  33. return nil, fmt.Errorf("%w: invalid window parameter: %w", ErrBadRequest, err)
  34. }
  35. windowValidator := opts.WindowValidator
  36. if windowValidator == nil {
  37. windowValidator = DefaultWindowValidator
  38. }
  39. if err := windowValidator(window); err != nil {
  40. return nil, err
  41. }
  42. field, err := validateField(qp.Get("field", ""))
  43. if err != nil {
  44. return nil, fmt.Errorf("%w: invalid field: %w", ErrBadRequest, err)
  45. }
  46. filterString := qp.Get("filter", "")
  47. var parsedFilter filter.Filter
  48. if filterString != "" {
  49. if parseFilter == nil {
  50. return nil, fmt.Errorf("%w: invalid 'filter' parameter: filter parser is required", ErrBadRequest)
  51. }
  52. parsedFilter, err = parseFilter(filterString)
  53. if err != nil {
  54. return nil, fmt.Errorf("%w: invalid 'filter' parameter: %w", ErrBadRequest, err)
  55. }
  56. }
  57. tenantID := qp.Get("tenantId", opts.DefaultTenantID)
  58. if tenantID == "" {
  59. tenantID = opts.DefaultTenantID
  60. }
  61. labelConfig := opts.LabelConfig
  62. if labelConfig == nil {
  63. labelConfig = opencost.NewLabelConfig()
  64. }
  65. return &Request{
  66. TenantID: tenantID,
  67. Search: SanitizeSearch(qp.Get("search", "")),
  68. Field: field,
  69. Limit: qp.GetInt("limit", 0),
  70. Window: window,
  71. Filter: parsedFilter,
  72. LabelConfig: labelConfig,
  73. }, nil
  74. }