coperator/compare.go

189 lines
4.1 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package coperator
import (
"errors"
"reflect"
)
/*
Compare 比较两个任意类型的值
参数:
a: 第一个比较值
b: 第二个比较值
返回值:
int: 比较结果 (-1:a < b, 0:a == b, 1:a > b)
error: 类型不匹配或不可比较时返回错误
*/
func compare(a, b interface{}) (int, error) {
// 快速返回如果值完全相等直接返回0
// 获取类型信息并验证类型一致性
atype := reflect.TypeOf(a)
btype := reflect.TypeOf(b)
if atype != btype {
return 0, errors.New("types are not equal: " + atype.String() + " != " + btype.String())
}
// 验证类型是否可比较
if !atype.Comparable() {
return 0, errors.New("types are not comparable: " + atype.String())
}
if reflect.DeepEqual(a, b) {
return 0, nil
}
// 处理不同类型的基础类型比较
switch atype.Kind() {
// 处理有符号整数类型比较
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
av := reflect.ValueOf(a).Int()
bv := reflect.ValueOf(b).Int()
if av < bv {
return -1, nil
}
if av > bv {
return 1, nil
}
return 0, nil
// 处理无符号整数类型比较
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
av := reflect.ValueOf(a).Uint()
bv := reflect.ValueOf(b).Uint()
if av < bv {
return -1, nil
}
if av > bv {
return 1, nil
}
return 0, nil
// 处理浮点数类型比较
case reflect.Float32, reflect.Float64:
av := reflect.ValueOf(a).Float()
bv := reflect.ValueOf(b).Float()
if av < bv {
return -1, nil
}
if av > bv {
return 1, nil
}
return 0, nil
// 处理字符串类型比较
case reflect.String:
av := reflect.ValueOf(a).String()
bv := reflect.ValueOf(b).String()
if av < bv {
return -1, nil
}
if av > bv {
return 1, nil
}
return 0, nil
// 布尔类型特殊处理
case reflect.Bool:
return 0, errors.New("cannot compare boolean values")
// 默认不支持的类型
default:
return 0, errors.New("unsupported type for comparison: " + atype.String())
}
}
func comparOp(doc *Document, key string, value interface{}) (int, error) {
v := doc.Get(key)
if v == nil {
return 0, nil
}
ret, err := compare(v, value)
if err != nil {
return 0, err
}
return ret, nil
}
func operatorGt(doc *Document, filter Filter, key string, value interface{}) (ret bool, err error) {
v, e := comparOp(doc, key, value)
if e != nil {
return false, e
}
return v > 0, nil
}
func operatorGe(doc *Document, filter Filter, key string, value interface{}) (ret bool, err error) {
v, e := comparOp(doc, key, value)
if e != nil {
return false, e
}
return v >= 0, nil
}
func operatorLt(doc *Document, filter Filter, key string, value interface{}) (ret bool, err error) {
v, e := comparOp(doc, key, value)
if e != nil {
return false, e
}
return v < 0, nil
}
func operatorLe(doc *Document, filter Filter, key string, value interface{}) (ret bool, err error) {
v, e := comparOp(doc, key, value)
if e != nil {
return false, e
}
return v <= 0, nil
}
func operatorEq(doc *Document, filter Filter, key string, value interface{}) (ret bool, err error) {
v, e := comparOp(doc, key, value)
if e != nil {
return false, e
}
return v == 0, nil
}
func operatorNe(doc *Document, filter Filter, key string, value interface{}) (ret bool, err error) {
v, e := comparOp(doc, key, value)
if e != nil {
return false, e
}
return v != 0, nil
}
func operatorIn(doc *Document, filter Filter, key string, value interface{}) (ret bool, err error) {
if value == nil {
return false, nil
}
slice, ok := value.([]interface{})
if !ok {
return false, errors.New("value for $in operator must be a slice")
}
if len(slice) == 0 {
return false, nil
}
for _, v := range slice {
cmp, err := compare(doc.Get(key), v)
if err != nil {
return false, err
}
if cmp == 0 {
return true, nil
}
}
return false, nil
}
func operatorNotIn(doc *Document, filter Filter, key string, value interface{}) (ret bool, err error) {
lret, err := operatorIn(doc, filter, key, value)
if err != nil {
return false, err
}
return !lret, nil
}