stringmatcher.go 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  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 StringFieldMapper[T] to generate instances of
  9. // StringMatcher[T].
  10. type StringMatcherFactory[T any] struct {
  11. fieldMapper StringFieldMapper[T]
  12. }
  13. // NewStringMatcherFactory creates a new StringMatcher factory for a given T type.
  14. func NewStringMatcherFactory[T any](fieldMapper StringFieldMapper[T]) *StringMatcherFactory[T] {
  15. return &StringMatcherFactory[T]{
  16. fieldMapper: fieldMapper,
  17. }
  18. }
  19. // NewStringMatcher creates a new StringMatcher using the provided op, field ident, and value comparison.
  20. func (smf *StringMatcherFactory[T]) NewStringMatcher(op ast.FilterOp, ident ast.Identifier, value string) *StringMatcher[T] {
  21. return &StringMatcher[T]{
  22. Op: op,
  23. Identifier: ident,
  24. Value: value,
  25. fieldMapper: smf.fieldMapper,
  26. }
  27. }
  28. // StringMatcher matches properties of a T instance which are string.
  29. type StringMatcher[T any] struct {
  30. Op ast.FilterOp
  31. Identifier ast.Identifier
  32. Value string
  33. fieldMapper StringFieldMapper[T]
  34. }
  35. func (sm *StringMatcher[T]) String() string {
  36. return fmt.Sprintf(`(%s %s "%s")`, sm.Op, sm.Identifier.String(), sm.Value)
  37. }
  38. // Matches is the canonical in-Go function for determining if T
  39. // matches string property comparison rules.
  40. func (sm *StringMatcher[T]) Matches(that T) bool {
  41. thatString, err := sm.fieldMapper(that, sm.Identifier)
  42. if err != nil {
  43. log.Errorf("Filter: StringMatcher: could not retrieve field %s: %s", sm.Identifier.String(), err.Error())
  44. return false
  45. }
  46. switch sm.Op {
  47. case ast.FilterOpEquals:
  48. return thatString == sm.Value
  49. case ast.FilterOpContains:
  50. return strings.Contains(thatString, sm.Value)
  51. case ast.FilterOpContainsPrefix:
  52. return strings.HasPrefix(thatString, sm.Value)
  53. case ast.FilterOpContainsSuffix:
  54. return strings.HasSuffix(thatString, sm.Value)
  55. default:
  56. log.Errorf("Filter: StringMatcher: Unhandled filter op. This is a filter implementation error and requires immediate patching. Op: %s", sm.Op)
  57. return false
  58. }
  59. }