github.com/viant/toolbox@v0.34.5/predicates.go (about) 1 package toolbox 2 3 import ( 4 "fmt" 5 "reflect" 6 "strings" 7 "time" 8 ) 9 10 //TrueProvider represents a true provider 11 var TrueProvider = func(input interface{}) bool { 12 return true 13 } 14 15 type withinSecPredicate struct { 16 baseTime time.Time 17 deltaInSeconds int 18 dateLayout string 19 actual string 20 elapsed time.Duration 21 maxAllowedDelay time.Duration 22 } 23 24 func (p *withinSecPredicate) String() string { 25 return fmt.Sprintf("(elapsed: %d, max allowed delay: %d)\n", int(p.elapsed), int(p.maxAllowedDelay)) 26 } 27 28 //Apply returns true if passed in time is within deltaInSeconds from baseTime 29 func (p *withinSecPredicate) Apply(value interface{}) bool { 30 timeValue, err := ToTime(value, p.dateLayout) 31 if err != nil { 32 return false 33 } 34 elapsed := timeValue.Sub(p.baseTime) 35 if elapsed < 0 { 36 elapsed *= -1 37 } 38 var maxAllowedDelay = time.Duration(p.deltaInSeconds) * time.Second 39 var passed = maxAllowedDelay >= elapsed 40 if !passed { 41 p.elapsed = elapsed 42 p.maxAllowedDelay = maxAllowedDelay 43 } 44 return passed 45 } 46 47 func (p *withinSecPredicate) ToString() string { 48 return fmt.Sprintf(" %v within %v s", p.baseTime, p.deltaInSeconds) 49 } 50 51 //NewWithinPredicate returns new NewWithinPredicate predicate, it takes base time, delta in second, and dateLayout 52 func NewWithinPredicate(baseTime time.Time, deltaInSeconds int, dateLayout string) Predicate { 53 return &withinSecPredicate{ 54 baseTime: baseTime, 55 deltaInSeconds: deltaInSeconds, 56 dateLayout: dateLayout, 57 } 58 } 59 60 type betweenPredicate struct { 61 from float64 62 to float64 63 } 64 65 func (p *betweenPredicate) Apply(value interface{}) bool { 66 floatValue := AsFloat(value) 67 return floatValue >= p.from && floatValue <= p.to 68 } 69 70 func (p *betweenPredicate) String() string { 71 return fmt.Sprintf("x BETWEEN %v AND %v", p.from, p.to) 72 } 73 74 //NewBetweenPredicate creates a new BETWEEN predicate, it takes from, and to. 75 func NewBetweenPredicate(from, to interface{}) Predicate { 76 return &betweenPredicate{ 77 from: AsFloat(from), 78 to: AsFloat(to), 79 } 80 } 81 82 type inPredicate struct { 83 predicate Predicate 84 } 85 86 func (p *inPredicate) Apply(value interface{}) bool { 87 return p.predicate.Apply(value) 88 } 89 90 //NewInPredicate creates a new IN predicate 91 func NewInPredicate(values ...interface{}) Predicate { 92 converted, kind := DiscoverCollectionValuesAndKind(values) 93 switch kind { 94 case reflect.Int: 95 predicate := inIntPredicate{values: make(map[int]bool)} 96 SliceToMap(converted, predicate.values, func(item interface{}) int { 97 return AsInt(item) 98 }, TrueProvider) 99 return &predicate 100 case reflect.Float64: 101 predicate := inFloatPredicate{values: make(map[float64]bool)} 102 SliceToMap(converted, predicate.values, func(item interface{}) float64 { 103 return AsFloat(item) 104 }, TrueProvider) 105 return &predicate 106 default: 107 predicate := inStringPredicate{values: make(map[string]bool)} 108 SliceToMap(converted, predicate.values, func(item interface{}) string { 109 return AsString(item) 110 }, TrueProvider) 111 return &predicate 112 } 113 } 114 115 type inFloatPredicate struct { 116 values map[float64]bool 117 } 118 119 func (p *inFloatPredicate) Apply(value interface{}) bool { 120 candidate := AsFloat(value) 121 return p.values[candidate] 122 } 123 124 type inIntPredicate struct { 125 values map[int]bool 126 } 127 128 func (p *inIntPredicate) Apply(value interface{}) bool { 129 candidate := AsInt(value) 130 return p.values[int(candidate)] 131 } 132 133 type inStringPredicate struct { 134 values map[string]bool 135 } 136 137 func (p *inStringPredicate) Apply(value interface{}) bool { 138 candidate := AsString(value) 139 return p.values[candidate] 140 } 141 142 type numericComparablePredicate struct { 143 rightOperand float64 144 operator string 145 } 146 147 func (p *numericComparablePredicate) Apply(value interface{}) bool { 148 leftOperand := AsFloat(value) 149 switch p.operator { 150 case ">": 151 return leftOperand > p.rightOperand 152 case ">=": 153 return leftOperand >= p.rightOperand 154 case "<": 155 return leftOperand < p.rightOperand 156 case "<=": 157 return leftOperand <= p.rightOperand 158 case "=": 159 return leftOperand == p.rightOperand 160 case "!=": 161 return leftOperand != p.rightOperand 162 } 163 return false 164 } 165 166 type stringComparablePredicate struct { 167 rightOperand string 168 operator string 169 } 170 171 func (p *stringComparablePredicate) Apply(value interface{}) bool { 172 leftOperand := AsString(value) 173 174 switch p.operator { 175 case "=": 176 return leftOperand == p.rightOperand 177 case "!=": 178 return leftOperand != p.rightOperand 179 } 180 return false 181 } 182 183 //NewComparablePredicate create a new comparable predicate for =, !=, >=, <= 184 func NewComparablePredicate(operator string, leftOperand interface{}) Predicate { 185 if CanConvertToFloat(leftOperand) { 186 return &numericComparablePredicate{AsFloat(leftOperand), operator} 187 } 188 return &stringComparablePredicate{AsString(leftOperand), operator} 189 } 190 191 type nilPredicate struct{} 192 193 func (p *nilPredicate) Apply(value interface{}) bool { 194 return value == nil || reflect.ValueOf(value).IsNil() 195 } 196 197 //NewNilPredicate returns a new nil predicate 198 func NewNilPredicate() Predicate { 199 return &nilPredicate{} 200 } 201 202 type likePredicate struct { 203 matchingFragments []string 204 } 205 206 func (p *likePredicate) Apply(value interface{}) bool { 207 textValue := strings.ToLower(AsString(value)) 208 for _, matchingFragment := range p.matchingFragments { 209 matchingIndex := strings.Index(textValue, matchingFragment) 210 if matchingIndex == -1 { 211 return false 212 } 213 if matchingIndex < len(textValue) { 214 textValue = textValue[matchingIndex:] 215 } 216 } 217 return true 218 } 219 220 //NewLikePredicate create a new like predicate 221 func NewLikePredicate(matching string) Predicate { 222 return &likePredicate{matchingFragments: strings.Split(strings.ToLower(matching), "%")} 223 }