189 lines
4.1 KiB
Go
189 lines
4.1 KiB
Go
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
|
||
}
|