normalize.go 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. package autocomplete
  2. import (
  3. "fmt"
  4. "github.com/opencost/opencost/core/pkg/filter/ast"
  5. "github.com/opencost/opencost/core/pkg/opencost"
  6. )
  7. // FieldValidator normalizes and validates an autocomplete field name.
  8. type FieldValidator func(field string) (string, error)
  9. // WindowValidator validates a parsed autocomplete window.
  10. type WindowValidator func(window opencost.Window) error
  11. // DefaultWindowValidator rejects open-ended windows.
  12. func DefaultWindowValidator(window opencost.Window) error {
  13. if window.IsOpen() {
  14. return fmt.Errorf("%w: invalid window: %s", ErrBadRequest, window.String())
  15. }
  16. return nil
  17. }
  18. // NormalizeOptions configures shared request normalization.
  19. type NormalizeOptions struct {
  20. RequireTenantID bool
  21. EnsureLabelConfig bool
  22. WindowValidator WindowValidator
  23. }
  24. // NormalizeRequest validates and normalizes an autocomplete request in place.
  25. func NormalizeRequest(req *Request, validateField FieldValidator, opts NormalizeOptions) (string, error) {
  26. if req == nil {
  27. return "", fmt.Errorf("%w: request is nil", ErrBadRequest)
  28. }
  29. if opts.RequireTenantID && req.TenantID == "" {
  30. return "", fmt.Errorf("%w: tenant ID is required", ErrBadRequest)
  31. }
  32. windowValidator := opts.WindowValidator
  33. if windowValidator == nil {
  34. windowValidator = DefaultWindowValidator
  35. }
  36. if err := windowValidator(req.Window); err != nil {
  37. return "", err
  38. }
  39. field, err := validateField(req.Field)
  40. if err != nil {
  41. return "", fmt.Errorf("%w: invalid field: %w", ErrBadRequest, err)
  42. }
  43. limit, err := NormalizeLimit(req.Limit)
  44. if err != nil {
  45. return "", err
  46. }
  47. req.Field = field
  48. req.Search = SanitizeSearch(req.Search)
  49. req.Limit = limit
  50. if req.Filter == nil {
  51. req.Filter = &ast.VoidOp{}
  52. }
  53. if opts.EnsureLabelConfig && req.LabelConfig == nil {
  54. req.LabelConfig = opencost.NewLabelConfig()
  55. }
  56. return field, nil
  57. }