Skip to content

Commit d041a2c

Browse files
authored
arr ops and str fix (#247)
statsig-io/kong#3109
1 parent ce7ee60 commit d041a2c

File tree

1 file changed

+79
-2
lines changed

1 file changed

+79
-2
lines changed

evaluator.go

+79-2
Original file line numberDiff line numberDiff line change
@@ -580,7 +580,7 @@ func (e *evaluator) evalCondition(user User, cond configCondition, depth int, co
580580
case strings.EqualFold(op, "version_neq"):
581581
pass = compareVersions(value, cond.TargetValue, func(x, y []int64) bool { return compareVersionsHelper(x, y) != 0 })
582582

583-
// array operations
583+
// one to array operations
584584
case strings.EqualFold(op, "any"):
585585
pass = arrayAny(cond.TargetValue, value, func(x, y interface{}) bool {
586586
if cond.UserBucket != nil {
@@ -606,6 +606,42 @@ func (e *evaluator) evalCondition(user User, cond configCondition, depth int, co
606606
return compareStrings(x, y, false, func(s1, s2 string) bool { return s1 == s2 })
607607
})
608608

609+
// array to array operations
610+
case strings.EqualFold(op, "array_contains_any"):
611+
targetArr, okTarget := cond.TargetValue.([]interface{})
612+
valArr, okVal := value.([]interface{})
613+
if !(okTarget && okVal) {
614+
pass = false
615+
} else {
616+
pass = arrayContainsAny(targetArr, valArr)
617+
}
618+
case strings.EqualFold(op, "array_contains_none"):
619+
targetArr, okTarget := cond.TargetValue.([]interface{})
620+
valArr, okVal := value.([]interface{})
621+
if !(okTarget && okVal) {
622+
pass = false
623+
} else {
624+
pass = !arrayContainsAny(targetArr, valArr)
625+
}
626+
case strings.EqualFold(op, "array_contains_all"):
627+
targetArr, okTarget := cond.TargetValue.([]interface{})
628+
valArr, okVal := value.([]interface{})
629+
630+
if !(okTarget && okVal) {
631+
pass = false
632+
} else {
633+
pass = arrayContainsAll(targetArr, valArr)
634+
}
635+
case strings.EqualFold(op, "not_array_contains_all"):
636+
targetArr, okTarget := cond.TargetValue.([]interface{})
637+
valArr, okVal := value.([]interface{})
638+
639+
if !(okTarget && okVal) {
640+
pass = false
641+
} else {
642+
pass = !arrayContainsAll(targetArr, valArr)
643+
}
644+
609645
// string operations
610646
case strings.EqualFold(op, "str_starts_with_any"):
611647
pass = arrayAny(cond.TargetValue, value, func(x, y interface{}) bool {
@@ -835,8 +871,15 @@ func convertToString(a interface{}) string {
835871
return strconv.FormatBool(aVal.Bool())
836872
case reflect.String:
837873
return fmt.Sprintf("%v", a)
874+
case reflect.Slice, reflect.Array:
875+
var result []string
876+
for i := 0; i < aVal.Len(); i++ {
877+
result = append(result, fmt.Sprintf("%v", aVal.Index(i).Interface()))
878+
}
879+
return strings.Join(result, ",")
838880
}
839-
return ""
881+
882+
return fmt.Sprintf("%v", a)
840883
}
841884

842885
func compareNumbers(a, b interface{}, fun func(x, y float64) bool) bool {
@@ -950,6 +993,40 @@ func arrayAny(arr interface{}, val interface{}, fun func(x, y interface{}) bool)
950993
return false
951994
}
952995

996+
func arrayContainsAll(target []interface{}, value []interface{}) bool {
997+
valueSet := make(map[string]struct{})
998+
for _, item := range value {
999+
valStr := convertToString(item)
1000+
valueSet[valStr] = struct{}{}
1001+
}
1002+
1003+
for _, t := range target {
1004+
strTarget := convertToString(t)
1005+
_, strExists := valueSet[strTarget]
1006+
if !strExists {
1007+
return false
1008+
}
1009+
}
1010+
return true
1011+
}
1012+
1013+
func arrayContainsAny(target []interface{}, value []interface{}) bool {
1014+
valueSet := make(map[string]struct{})
1015+
for _, item := range value {
1016+
valStr := convertToString(item)
1017+
valueSet[valStr] = struct{}{}
1018+
}
1019+
1020+
for _, t := range target {
1021+
strTarget := convertToString(t)
1022+
_, strExists := valueSet[strTarget]
1023+
if strExists {
1024+
return true
1025+
}
1026+
}
1027+
return false
1028+
}
1029+
9531030
func getTime(a interface{}) time.Time {
9541031
switch v := a.(type) {
9551032
case float64, int64, int32, int:

0 commit comments

Comments
 (0)