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