stringslicematcher.go 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. package matcher
  2. import (
  3. "fmt"
  4. "strings"
  5. "github.com/opencost/opencost/pkg/filter21/ast"
  6. "github.com/opencost/opencost/pkg/log"
  7. )
  8. // StringMatcherFactory leverages a single StringSliceFieldMapper[T] to generate instances of
  9. // StringSliceMatcher[T].
  10. type StringSliceMatcherFactory[T any] struct {
  11. fieldMapper SliceFieldMapper[T]
  12. }
  13. // NewStringSliceMatcherFactory creates a new StringMatcher factory for a given T type.
  14. func NewStringSliceMatcherFactory[T any](fieldMapper SliceFieldMapper[T]) *StringSliceMatcherFactory[T] {
  15. return &StringSliceMatcherFactory[T]{
  16. fieldMapper: fieldMapper,
  17. }
  18. }
  19. // NewStringMatcher creates a new StringSliceMatcher using the provided op, field ident, and value comparison.
  20. func (smf *StringSliceMatcherFactory[T]) NewStringSliceMatcher(op ast.FilterOp, ident ast.Identifier, value string) *StringSliceMatcher[T] {
  21. return &StringSliceMatcher[T]{
  22. Op: op,
  23. Identifier: ident,
  24. Value: value,
  25. fieldMapper: smf.fieldMapper,
  26. }
  27. }
  28. // StringSliceProperty is the lowest-level type of filter. It represents
  29. // a filter operation (equality, inequality, etc.) on a property that contains a string slice
  30. type StringSliceMatcher[T any] struct {
  31. Op ast.FilterOp
  32. Identifier ast.Identifier
  33. Value string
  34. fieldMapper SliceFieldMapper[T]
  35. }
  36. func (ssp *StringSliceMatcher[T]) String() string {
  37. return fmt.Sprintf(`(%s %s "%s")`, ssp.Op, ssp.Identifier.String(), ssp.Value)
  38. }
  39. func (ssp *StringSliceMatcher[T]) Matches(that T) bool {
  40. thatSlice, err := ssp.fieldMapper(that, ssp.Identifier)
  41. if err != nil {
  42. log.Errorf("Filter: StringSliceMatcher: could not retrieve field %s: %s", ssp.Identifier.String(), err.Error())
  43. return false
  44. }
  45. switch ssp.Op {
  46. case ast.FilterOpContains:
  47. if len(thatSlice) == 0 {
  48. return ssp.Value == ""
  49. }
  50. for _, s := range thatSlice {
  51. if s == ssp.Value {
  52. return true
  53. }
  54. }
  55. case ast.FilterOpContainsPrefix:
  56. for _, s := range thatSlice {
  57. if strings.HasPrefix(s, ssp.Value) {
  58. return true
  59. }
  60. }
  61. return false
  62. case ast.FilterOpContainsSuffix:
  63. for _, s := range thatSlice {
  64. if strings.HasSuffix(s, ssp.Value) {
  65. return true
  66. }
  67. }
  68. return false
  69. default:
  70. log.Errorf("Filter: StringSliceMatcher: Unhandled filter op. This is a filter implementation error and requires immediate patching. Op: %s", ssp.Op)
  71. return false
  72. }
  73. return false
  74. }