gomog/internal/engine/operators.go

254 lines
4.6 KiB
Go

package engine
import (
"reflect"
"regexp"
"strconv"
"strings"
)
// compareEq 相等比较
func compareEq(a, b interface{}) bool {
if a == nil && b == nil {
return true
}
if a == nil || b == nil {
return false
}
// 类型转换后比较
return normalizeValue(a) == normalizeValue(b)
}
// compareGt 大于比较
func compareGt(a, b interface{}) bool {
return compareNumbers(a, b) > 0
}
// compareGte 大于等于比较
func compareGte(a, b interface{}) bool {
return compareNumbers(a, b) >= 0
}
// compareLt 小于比较
func compareLt(a, b interface{}) bool {
return compareNumbers(a, b) < 0
}
// compareLte 小于等于比较
func compareLte(a, b interface{}) bool {
return compareNumbers(a, b) <= 0
}
// compareNumbers 比较两个数值,返回 -1/0/1
func compareNumbers(a, b interface{}) int {
numA := toFloat64(a)
numB := toFloat64(b)
if numA < numB {
return -1
} else if numA > numB {
return 1
}
return 0
}
// toFloat64 将值转换为 float64
func toFloat64(v interface{}) float64 {
switch val := v.(type) {
case int:
return float64(val)
case int8:
return float64(val)
case int16:
return float64(val)
case int32:
return float64(val)
case int64:
return float64(val)
case uint:
return float64(val)
case uint8:
return float64(val)
case uint16:
return float64(val)
case uint32:
return float64(val)
case uint64:
return float64(val)
case float32:
return float64(val)
case float64:
return val
case string:
// 尝试解析字符串为数字
if num, err := strconv.ParseFloat(val, 64); err == nil {
return num
}
}
return 0
}
// compareIn 检查值是否在数组中
func compareIn(value interface{}, operand interface{}) bool {
arr, ok := operand.([]interface{})
if !ok {
return false
}
for _, item := range arr {
if compareEq(value, item) {
return true
}
}
return false
}
// compareRegex 正则表达式匹配
func compareRegex(value interface{}, operand interface{}) bool {
str, ok := value.(string)
if !ok {
return false
}
pattern, ok := operand.(string)
if !ok {
return false
}
matched, _ := regexp.MatchString(pattern, str)
return matched
}
// compareType 类型检查
func compareType(value interface{}, operand interface{}) bool {
if value == nil {
return operand == "null"
}
var typeName string
switch reflect.TypeOf(value).Kind() {
case reflect.String:
typeName = "string"
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
typeName = "int"
case reflect.Float32, reflect.Float64:
typeName = "double"
case reflect.Bool:
typeName = "bool"
case reflect.Slice, reflect.Array:
typeName = "array"
case reflect.Map:
typeName = "object"
}
// 支持字符串或数组形式的类型检查
switch op := operand.(type) {
case string:
return typeName == op
case []interface{}:
for _, t := range op {
if ts, ok := t.(string); ok && typeName == ts {
return true
}
}
}
return false
}
// compareAll 数组包含所有指定元素
func compareAll(value interface{}, operand interface{}) bool {
arr, ok := value.([]interface{})
if !ok {
return false
}
required, ok := operand.([]interface{})
if !ok {
return false
}
for _, req := range required {
found := false
for _, item := range arr {
if compareEq(item, req) {
found = true
break
}
}
if !found {
return false
}
}
return true
}
// compareElemMatch 数组元素匹配
func compareElemMatch(value interface{}, operand interface{}) bool {
arr, ok := value.([]interface{})
if !ok {
return false
}
filter, ok := operand.(map[string]interface{})
if !ok {
return false
}
for _, item := range arr {
if itemMap, ok := item.(map[string]interface{}); ok {
if MatchFilter(itemMap, filter) {
return true
}
}
}
return false
}
// compareSize 数组大小比较
func compareSize(value interface{}, operand interface{}) bool {
arr, ok := value.([]interface{})
if !ok {
return false
}
size := 0
switch s := operand.(type) {
case int:
size = s
case int64:
size = int(s)
case float64:
size = int(s)
default:
return false
}
return len(arr) == size
}
// normalizeValue 标准化值用于比较
func normalizeValue(v interface{}) interface{} {
if v == nil {
return nil
}
// 处理数字类型
switch val := v.(type) {
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64:
return toFloat64(v)
case string:
// 尝试将字符串解析为数字
if num, err := strconv.ParseFloat(val, 64); err == nil {
return num
}
return strings.ToLower(val)
}
return v
}